Sfoglia il codice sorgente

Reformat part 9 small touches

Considering getting stylecop set up since my change in formatting kinda
aligns with their rules.
habeebweeb 2 anni fa
parent
commit
dfe066e55c
52 ha cambiato i file con 537 aggiunte e 560 eliminazioni
  1. 0 4
      src/MeidoPhotoStudio.Converter/Converters/MMConverter.cs
  2. 0 2
      src/MeidoPhotoStudio.Converter/Converters/MMPngConverter.cs
  3. 7 8
      src/MeidoPhotoStudio.Converter/MultipleMaids/MMConstants.cs
  4. 15 24
      src/MeidoPhotoStudio.Converter/MultipleMaids/MMSceneConverter.cs
  5. 0 1
      src/MeidoPhotoStudio.Converter/Utility/LZMA.cs
  6. 28 18
      src/MeidoPhotoStudio.Plugin/Constants.cs
  7. 9 8
      src/MeidoPhotoStudio.Plugin/DragPoint/CustomGizmo.cs
  8. 5 5
      src/MeidoPhotoStudio.Plugin/DragPoint/DragPoint.cs
  9. 2 0
      src/MeidoPhotoStudio.Plugin/DragPoint/DragPointGeneral.cs
  10. 0 2
      src/MeidoPhotoStudio.Plugin/DragPoint/DragPointGravity.cs
  11. 17 17
      src/MeidoPhotoStudio.Plugin/DragPoint/DragPointLight.cs
  12. 14 14
      src/MeidoPhotoStudio.Plugin/DragPoint/DragPointProp.cs
  13. 6 6
      src/MeidoPhotoStudio.Plugin/GUI/Controls/Button.cs
  14. 10 10
      src/MeidoPhotoStudio.Plugin/GUI/Controls/ComboBox.cs
  15. 3 6
      src/MeidoPhotoStudio.Plugin/GUI/Controls/DropDown.cs
  16. 7 7
      src/MeidoPhotoStudio.Plugin/GUI/Controls/KeyRebindButton.cs
  17. 10 10
      src/MeidoPhotoStudio.Plugin/GUI/Controls/SelectionGrid.cs
  18. 9 11
      src/MeidoPhotoStudio.Plugin/GUI/Controls/Slider.cs
  19. 3 3
      src/MeidoPhotoStudio.Plugin/GUI/Controls/TextArea.cs
  20. 3 3
      src/MeidoPhotoStudio.Plugin/GUI/Controls/TextField.cs
  21. 5 5
      src/MeidoPhotoStudio.Plugin/GUI/Controls/Toggle.cs
  22. 15 15
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindow2Panes/AttachPropPane.cs
  23. 0 1
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindow2Panes/ModPropsPane.cs
  24. 0 3
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindow2Panes/MyRoomPropsPane.cs
  25. 1 1
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/BackgroundSelectorPane.cs
  26. 2 2
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/EffectsPanes/EffectPane.cs
  27. 2 2
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/LightsPane.cs
  28. 1 1
      src/MeidoPhotoStudio.Plugin/GUI/Panes/FaceWindowPanes/MaidFaceSliderPane.cs
  29. 1 1
      src/MeidoPhotoStudio.Plugin/GUI/Panes/MainWindowPanes/BGWindowPane.cs
  30. 1 0
      src/MeidoPhotoStudio.Plugin/GUI/Panes/MainWindowPanes/FaceWindowPane.cs
  31. 1 0
      src/MeidoPhotoStudio.Plugin/GUI/Panes/OtherPanes/MaidSwitcherPane.cs
  32. 2 2
      src/MeidoPhotoStudio.Plugin/GUI/Panes/OtherPanes/TabsPane.cs
  33. 8 8
      src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/GravityControlPane.cs
  34. 9 9
      src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/HandPresetPane.cs
  35. 7 7
      src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/MaidDressingPane.cs
  36. 32 32
      src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/MaidFreeLookPane.cs
  37. 0 10
      src/MeidoPhotoStudio.Plugin/MaidPlacementUtility.cs
  38. 1 1
      src/MeidoPhotoStudio.Plugin/Managers/InputManager.cs
  39. 1 1
      src/MeidoPhotoStudio.Plugin/Meido/IK/IK Chain/DragPointChain.cs
  40. 4 4
      src/MeidoPhotoStudio.Plugin/Meido/Meido.cs
  41. 7 6
      src/MeidoPhotoStudio.Plugin/Meido/MeidoDragPointManager.cs
  42. 18 17
      src/MeidoPhotoStudio.Plugin/MeidoPhotoStudio.cs
  43. 3 2
      src/MeidoPhotoStudio.Plugin/MenuFileUtility.cs
  44. 3 3
      src/MeidoPhotoStudio.Plugin/MenuItem.cs
  45. 0 3
      src/MeidoPhotoStudio.Plugin/ModelUtility.cs
  46. 0 1
      src/MeidoPhotoStudio.Plugin/MyGui.cs
  47. 0 1
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/ManagerSerializers/LightManagerSerializer.cs
  48. 1 0
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/ManagerSerializers/MeidoManagerSerializer.cs
  49. 229 229
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/MeidoSerializer.cs
  50. 1 0
      src/MeidoPhotoStudio.Plugin/Serialization/SimpleSerializers/DragPointPropDTOSerializer.cs
  51. 2 2
      src/MeidoPhotoStudio.Plugin/Translation.cs
  52. 32 32
      src/MeidoPhotoStudio.Plugin/Utility.cs

+ 0 - 4
src/MeidoPhotoStudio.Converter/Converters/MMConverter.cs

@@ -81,14 +81,10 @@ public class MMConverter : IConverter
     private static string GenerateFilename(string iniFilePath, IniKey sceneKey)
     {
         var background = int.Parse(sceneKey.Key.Substring(1)) >= 10000;
-
         var iniFilename = Path.GetFileNameWithoutExtension(iniFilePath);
-
         var sceneName = sceneKey.Key;
-
         var data = sceneKey.Value;
         var date = DateTime.Parse(data.Substring(0, data.IndexOf(',')));
-
         var sceneDate = MPSSceneSerializer.FormatDate(date);
 
         return $"mm{(background ? "kankyo" : "scene")}_{iniFilename}_{sceneName}_{sceneDate}.png";

+ 0 - 2
src/MeidoPhotoStudio.Converter/Converters/MMPngConverter.cs

@@ -36,9 +36,7 @@ public class MMPngConverter : IConverter
     private static void ConvertScene(string pngFile, string outputFilename)
     {
         var fileStream = File.OpenRead(pngFile);
-
         var thumbnailData = PngUtility.ExtractPng(fileStream) ?? MPSSceneSerializer.NoThumb;
-
         var kankyo = new byte[KankyoHeader.Length];
         fileStream.Read(kankyo, 0, KankyoHeader.Length);
 

+ 7 - 8
src/MeidoPhotoStudio.Converter/MultipleMaids/MMConstants.cs

@@ -12,20 +12,19 @@ public static class MMConstants
 
     public static readonly string[] FaceKeys =
     {
-        "eyeclose", "eyeclose2", "eyeclose3", "eyeclose6", "hitomih", "hitomis", "mayuha",
-        "mayuup", "mayuv", "mayuvhalf", "moutha", "mouths", "mouthdw", "mouthup", "tangout",
-        "tangup", "eyebig", "eyeclose5", "mayuw", "mouthhe", "mouthc", "mouthi", "mouthuphalf",
-        "tangopen",
-        "namida", "tear1", "tear2", "tear3", "shock", "yodare", "hoho", "hoho2", "hohos", "hohol",
-        "toothoff", "nosefook"
+        "eyeclose", "eyeclose2", "eyeclose3", "eyeclose6", "hitomih", "hitomis", "mayuha", "mayuup", "mayuv",
+        "mayuvhalf", "moutha", "mouths", "mouthdw", "mouthup", "tangout", "tangup", "eyebig", "eyeclose5", "mayuw",
+        "mouthhe", "mouthc", "mouthi", "mouthuphalf", "tangopen", "namida", "tear1", "tear2", "tear3", "shock",
+        "yodare", "hoho", "hoho2", "hohos", "hohol", "toothoff", "nosefook",
     };
 
     public static readonly string[] MpnAttachProps =
     {
-        /* "", "", "", "", "", "", "", "", "", */
+        // NOTE: MPS only allows a subset of attached MPN props because MPS has a better method of attaching props.
+        // "", "", "", "", "", "", "", "", "",
         "kousokuu_tekaseone_i_.menu", "kousokuu_tekasetwo_i_.menu", "kousokul_ashikaseup_i_.menu",
         "kousokuu_tekasetwo_i_.menu", "kousokul_ashikasedown_i_.menu", "kousokuu_tekasetwodown_i_.menu",
-        "kousokuu_ushirode_i_.menu", "kousokuu_smroom_haritsuke_i_.menu"
+        "kousokuu_ushirode_i_.menu", "kousokuu_smroom_haritsuke_i_.menu",
     };
 
     private static Dictionary<string, PlacementData.Data>? myrAssetNameToData;

+ 15 - 24
src/MeidoPhotoStudio.Converter/MultipleMaids/MMSceneConverter.cs

@@ -75,7 +75,6 @@ public static class MMSceneConverter
     {
         var dataSegments = data.Split('_');
         var strArray2 = dataSegments[1].Split(';');
-
         var meidoCount = environment ? MeidoPhotoStudio.Plugin.MeidoPhotoStudio.kankyoMagic : strArray2.Length;
 
         return new()
@@ -220,18 +219,16 @@ public static class MMSceneConverter
 
                 // check special case for ClavicleL
                 if (index is ClavicleLIndex)
-                    /*
-                     * Versions of MM possibly serialized ClavicleL improperly.
-                     * At least I think that's what happened otherwise why would they make this check at all.
-                     * https://git.coder.horse/meidomustard/modifiedMM/src/master/MultipleMaids/CM3D2/MultipleMaids/Plugin/MultipleMaids.Update.cs#L4355
-                     *
-                     * Look at the way MM serializes rotations.
-                     * https://git.coder.horse/meidomustard/modifiedMM/src/master/MultipleMaids/CM3D2/MultipleMaids/Plugin/MultipleMaids.Update.cs#L2364
-                     * It is most definitely possible MM dev missed a component.
-                     *
-                     * Also why is strArray9.Length == 2 acceptable? If the length were only 2,
-                     * float.Parse(strArray9[2]) would throw an index out of range exception???
-                     */
+                    // NOTE: Versions of MM possibly serialized ClavicleL improperly.
+                    // At least I think that's what happened otherwise why would they make this check at all.
+                    // https://git.coder.horse/meidomustard/modifiedMM/src/master/MultipleMaids/CM3D2/MultipleMaids/Plugin/MultipleMaids.Update.cs#L4355
+                    // 
+                    // Look at the way MM serializes rotations.
+                    // https://git.coder.horse/meidomustard/modifiedMM/src/master/MultipleMaids/CM3D2/MultipleMaids/Plugin/MultipleMaids.Update.cs#L2364
+                    // It is most definitely possible MM dev missed a component.
+                    // 
+                    // Also why is strArray9.Length == 2 acceptable? If the length were only 2,
+                    // float.Parse(strArray9[2]) would throw an index out of range exception???
                     writer.Write(ConversionUtility.TryParseEulerAngle(data, out rotation));
                 else
                     rotation = ConversionUtility.ParseEulerAngle(data);
@@ -265,7 +262,6 @@ public static class MMSceneConverter
             // MPN attach props
             var kousokuUpperMenu = string.Empty;
             var kousokuLowerMenu = string.Empty;
-
             var sixtyFourFlag = maidData.Length is 64;
 
             if (!sixtyFourFlag)
@@ -340,7 +336,6 @@ public static class MMSceneConverter
         var showingMessage = false;
         var name = string.Empty;
         var message = string.Empty;
-
         var strArray3 = data[0].Split(',');
 
         if (strArray3.Length > 16)
@@ -370,7 +365,6 @@ public static class MMSceneConverter
         writer.Write(1);
 
         var strArray3 = data[0].Split(',');
-
         var cameraTargetPos = DefaultCameraInfo.TargetPos;
         var cameraDistance = DefaultCameraInfo.Distance;
         var cameraRotation = DefaultCameraInfo.Angle;
@@ -406,7 +400,6 @@ public static class MMSceneConverter
         var strArray4 = greaterThan5 ? data[2].Split(',') : null;
         var strArray5 = greaterThan5 ? data[3].Split(';') : null;
         var strArray7 = data.Length >= 6 ? data[5].Split(';') : null;
-
         var numberOfLights = 1 + (strArray5?.Length - 1 ?? 0);
 
         writer.Write(numberOfLights);
@@ -446,12 +439,10 @@ public static class MMSceneConverter
             writer.WriteVersion(1);
 
             for (var i = 0; i < 3; i++)
-            {
                 if (i == lightType || i is 0 && lightType is 3)
                     lightPropertySerializer.Serialize(lightProperty, writer);
                 else
                     lightPropertySerializer.Serialize(DefaultLightProperty, writer);
-            }
 
             var lightPosition = strArray7 is null
                 ? LightProperty.DefaultPosition
@@ -487,6 +478,7 @@ public static class MMSceneConverter
         {
             var lightProperties = strArray5[i].Split(',');
             var spotAngle = float.Parse(lightProperties[7]);
+
             var lightProperty = new LightProperty
             {
                 Rotation = Quaternion.Euler(float.Parse(lightProperties[4]), float.Parse(lightProperties[5]), 18f),
@@ -496,8 +488,8 @@ public static class MMSceneConverter
                 // MM does not save shadow strength for other lights 
                 ShadowStrength = 0.098f,
                 LightColour = new(
-                     float.Parse(lightProperties[1]), float.Parse(lightProperties[2]), float.Parse(lightProperties[3]),
-                     1f
+                    float.Parse(lightProperties[1]), float.Parse(lightProperties[2]), float.Parse(lightProperties[3]),
+                    1f
                 ),
             };
 
@@ -563,6 +555,7 @@ public static class MMSceneConverter
         writer.WriteVersion(1);
 
         var blurSize = float.Parse(effectData[13]);
+
         writer.Write(blurSize > 0f); // active
         writer.Write(blurSize); // blur size
 
@@ -611,7 +604,6 @@ public static class MMSceneConverter
         writer.WriteVersion(1);
 
         var environmentData = data[0].Split(',');
-
         var bgAsset = EnvironmentManager.defaultBg;
 
         if (!int.TryParse(environmentData[2], out _))
@@ -643,9 +635,9 @@ public static class MMSceneConverter
     {
         var strArray3 = data[0].Split(',');
         var strArray6 = data.Length >= 5 ? data[4].Split(';') : null;
-
         var hasWProp = strArray3.Length > 37 && !string.IsNullOrEmpty(strArray3[37]);
         var propCount = strArray6?.Length - 1 ?? 0;
+
         propCount += hasWProp ? 1 : 0;
 
         writer.Write(PropManager.header);
@@ -689,7 +681,6 @@ public static class MMSceneConverter
         {
             var prop = strArray6[i];
             var assetParts = prop.Split(',');
-
             var propInfo = AssetToPropInfo(assetParts[0]);
 
             var propDto = new DragPointPropDTO

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

@@ -8,7 +8,6 @@ internal static class LZMA
     public static MemoryStream Decompress(Stream inStream)
     {
         var outStream = new MemoryStream();
-
         var properties = new byte[5];
 
         if (inStream.Read(properties, 0, 5) is not 5)

+ 28 - 18
src/MeidoPhotoStudio.Plugin/Constants.cs

@@ -412,7 +412,10 @@ public static class Constants
         static void AddDefaultPose()
         {
             if (!PoseDict.ContainsKey("normal"))
-                PoseDict["normal"] = new() { "maid_stand01" };
+                PoseDict["normal"] = new()
+                {
+                    "maid_stand01",
+                };
 
             if (!PoseGroupList.Contains("normal"))
                 PoseGroupList.Insert(0, "normal");
@@ -456,7 +459,6 @@ public static class Constants
 
     public static void InitializeHandPresets()
     {
-
         CustomHandGroupList.Clear();
         CustomHandDict.Clear();
 
@@ -641,6 +643,7 @@ public static class Constants
 
                 if (string.IsNullOrEmpty(iconFile))
                 {
+                    // TODO: Remove '{iconFile}' since it will not add anymore information.
                     Utility.LogWarning($"Could not find icon '{iconFile}' for menu '{item.MenuFile}");
 
                     return true;
@@ -766,6 +769,8 @@ public static class Constants
 
         var com3d2DeskDogu = DoguDict[customDoguCategories[DoguCategory.Desk]];
 
+        GetDeskItems(GameUty.FileSystem);
+
         void GetDeskItems(AFileSystemBase fs)
         {
             using var csvParser = OpenCsvParser("desk_item_detail.nei", fs);
@@ -791,8 +796,6 @@ public static class Constants
                     com3d2DeskDogu.Add(dogu);
             }
         }
-
-        GetDeskItems(GameUty.FileSystem);
     }
 
     private static void InitializePhotoBGItems()
@@ -919,12 +922,14 @@ public static class Constants
 
         if (!MenuFilesReady)
         {
-            if (!beginMpnAttachInit)
-                MenuFilesReadyChange += (_, _) =>
-                    InitializeMpnAttachProps();
+            if (beginMpnAttachInit)
+                return;
 
             beginMpnAttachInit = true;
 
+            MenuFilesReadyChange += (_, _) =>
+                InitializeMpnAttachProps();
+
             return;
         }
 
@@ -959,16 +964,7 @@ public static class Constants
 
         var myRoomData = PlacementData.GetAllDatas(false);
 
-        myRoomData.Sort((a, b) =>
-            {
-                var res = a.categoryID.CompareTo(b.categoryID);
-
-                if (res is 0)
-                    res = a.ID.CompareTo(b.ID);
-
-                return res;
-            }
-        );
+        myRoomData.Sort(MyRoomDataComparator);
 
         foreach (var data in myRoomData)
         {
@@ -981,10 +977,24 @@ public static class Constants
             }
 
             var asset = !string.IsNullOrEmpty(data.resourceName) ? data.resourceName : data.assetName;
-            var item = new MyRoomItem() { PrefabName = asset, ID = data.ID };
+            var item = new MyRoomItem()
+            {
+                PrefabName = asset,
+                ID = data.ID,
+            };
 
             MyRoomPropDict[category].Add(item);
         }
+
+        static int MyRoomDataComparator(PlacementData.Data a, PlacementData.Data b)
+        {
+            var res = a.categoryID.CompareTo(b.categoryID);
+
+            if (res is 0)
+                res = a.ID.CompareTo(b.ID);
+
+            return res;
+        }
     }
 
     private static void InitializeModProps()

+ 9 - 8
src/MeidoPhotoStudio.Plugin/DragPoint/CustomGizmo.cs

@@ -36,8 +36,6 @@ public class CustomGizmo : GizmoRender
     private Vector3 deltaScale = Vector3.zero;
     private Vector3 scaleOld = Vector3.one;
     private GizmoType gizmoTypeOld;
-    private int SelectedType =>
-        (int)beSelectedType.GetValue(this);
 
     public GizmoType CurrentGizmoType
     {
@@ -71,6 +69,9 @@ public class CustomGizmo : GizmoRender
         }
     }
 
+    private int SelectedType =>
+        (int)beSelectedType.GetValue(this);
+
     public static CustomGizmo Make(Transform target, float scale = 0.25f, GizmoMode mode = GizmoMode.Local)
     {
         var gizmoGo = new GameObject($"[MPS Gizmo {target.gameObject.name}]");
@@ -88,12 +89,6 @@ public class CustomGizmo : GizmoRender
         return gizmo;
     }
 
-    public void SetAlternateTarget(Transform trans)
-    {
-        positionTransform = trans;
-        hasAlternateTarget = trans != null;
-    }
-
     public override void Update()
     {
         BeginUpdate();
@@ -108,6 +103,12 @@ public class CustomGizmo : GizmoRender
         EndUpdate();
     }
 
+    public void SetAlternateTarget(Transform trans)
+    {
+        positionTransform = trans;
+        hasAlternateTarget = trans != null;
+    }
+
     private void BeginUpdate()
     {
         var rotation = transform.rotation;

+ 5 - 5
src/MeidoPhotoStudio.Plugin/DragPoint/DragPoint.cs

@@ -39,14 +39,14 @@ public abstract class DragPoint : MonoBehaviour
     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 GameObject MyGameObject =>
+        MyObject.gameObject;
+
     public Vector3 BaseScale
     {
         get => baseScale;
@@ -205,8 +205,8 @@ public abstract class DragPoint : MonoBehaviour
     {
         screenPoint = camera.WorldToScreenPoint(transform.position);
         startMousePosition = Utility.MousePosition;
-        startOffset =
-            transform.position - camera.ScreenToWorldPoint(new(startMousePosition.x, startMousePosition.y, screenPoint.z));
+        startOffset = transform.position
+            - camera.ScreenToWorldPoint(new(startMousePosition.x, startMousePosition.y, screenPoint.z));
         newOffset = transform.position - MyObject.position;
     }
 

+ 2 - 0
src/MeidoPhotoStudio.Plugin/DragPoint/DragPointGeneral.cs

@@ -144,6 +144,8 @@ public abstract class DragPointGeneral : DragPoint
         var cursorPosition = CursorPosition();
         var mouseDelta = MouseDelta();
 
+        // CurrentDragType can only be one thing at a time afaik so maybe refactor to else if chain
+
         if (CurrentDragType is DragType.MoveXZ)
         {
             MyObject.position = new(cursorPosition.x, MyObject.position.y, cursorPosition.z);

+ 0 - 2
src/MeidoPhotoStudio.Plugin/DragPoint/DragPointGravity.cs

@@ -20,7 +20,6 @@ public class DragPointGravity : DragPointGeneral
     public static GravityTransformControl MakeGravityControl(Maid maid, bool skirt = false)
     {
         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);
@@ -50,7 +49,6 @@ public class DragPointGravity : DragPointGeneral
         }
 
         var gravityControl = gravityTransform.gameObject.AddComponent<GravityTransformControl>();
-
         var slots = skirt ? skirtSlots : hairSlots;
 
         gravityControl.SetTargetSlods(slots);

+ 17 - 17
src/MeidoPhotoStudio.Plugin/DragPoint/DragPointLight.cs

@@ -149,6 +149,23 @@ public class DragPointLight : DragPointGeneral
             light.transform.localScale = Vector3.one * prop.Range;
     }
 
+    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;
+    }
+
     public void SetLightType(MPSLightType type)
     {
         const string spotName = "spot";
@@ -235,23 +252,6 @@ public class DragPointLight : DragPointGeneral
     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)

+ 14 - 14
src/MeidoPhotoStudio.Plugin/DragPoint/DragPointProp.cs

@@ -28,12 +28,23 @@ public class DragPointProp : DragPointGeneral
         }
     }
 
+    public override void Set(Transform myObject)
+    {
+        base.Set(myObject);
+
+        DefaultRotation = MyObject.rotation;
+        DefaultPosition = MyObject.position;
+        DefaultScale = MyObject.localScale;
+        renderers = new(MyObject.GetComponentsInChildren<Renderer>());
+    }
+
     public void AttachTo(Meido meido, AttachPoint point, bool keepWorldPosition = true)
     {
         var attachPoint = meido?.IKManager.GetAttachPointTransform(point);
 
         AttachPointInfo = meido is null ? AttachPointInfo.Empty : new(point, meido);
 
+        // TODO: Use transform.SetPositionAndRotation MyObject.position = position;
         var position = MyObject.position;
         var rotation = MyObject.rotation;
         var scale = MyObject.localScale;
@@ -41,7 +52,6 @@ public class DragPointProp : DragPointGeneral
         MyObject.transform.SetParent(attachPoint, keepWorldPosition);
 
         if (keepWorldPosition)
-            // TODO: Use transform.SetPositionAndRotation MyObject.position = position;
             MyObject.rotation = rotation;
         else
         {
@@ -64,16 +74,6 @@ public class DragPointProp : DragPointGeneral
         Utility.FixGameObjectScale(MyGameObject);
     }
 
-    public override void Set(Transform myObject)
-    {
-        base.Set(myObject);
-
-        DefaultRotation = MyObject.rotation;
-        DefaultPosition = MyObject.position;
-        DefaultScale = MyObject.localScale;
-        renderers = new(MyObject.GetComponentsInChildren<Renderer>());
-    }
-
     protected override void ApplyDragType()
     {
         var active = DragPointEnabled && Transforming || Special;
@@ -100,9 +100,6 @@ public class PropInfo
     public string SubFilename { get; set; }
     public int MyRoomID { get; set; }
 
-    public PropInfo(PropType type) =>
-        Type = type;
-
     public static PropInfo FromModItem(ModItem modItem) =>
         new(PropType.Mod)
         {
@@ -122,4 +119,7 @@ public class PropInfo
 
     public static PropInfo FromGameProp(string name) =>
         new(PropType.Odogu) { Filename = name };
+
+    public PropInfo(PropType type) =>
+        Type = type;
 }

+ 6 - 6
src/MeidoPhotoStudio.Plugin/GUI/Controls/Button.cs

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

+ 10 - 10
src/MeidoPhotoStudio.Plugin/GUI/Controls/ComboBox.cs

@@ -23,6 +23,16 @@ public class ComboBox : BaseControl
         Value = itemList[0];
     }
 
+    public override void Draw(params GUILayoutOption[] layoutOptions)
+    {
+        var buttonStyle = new GUIStyle(GUI.skin.button)
+        {
+            alignment = TextAnchor.MiddleCenter,
+        };
+
+        Draw(buttonStyle, layoutOptions);
+    }
+
     public void SetDropdownItems(string[] itemList)
     {
         var oldValue = Value;
@@ -44,14 +54,4 @@ public class ComboBox : BaseControl
         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);
-    }
 }

+ 3 - 6
src/MeidoPhotoStudio.Plugin/GUI/Controls/DropDown.cs

@@ -28,6 +28,9 @@ public class Dropdown : BaseControl
     public Vector2 ScrollPos =>
         scrollPos;
 
+    public string SelectedItem =>
+        DropdownList[SelectedItemIndex];
+
     public Rect ButtonRect
     {
         get => buttonRect;
@@ -47,9 +50,6 @@ public class Dropdown : BaseControl
         }
     }
 
-    public string SelectedItem =>
-        DropdownList[SelectedItemIndex];
-
     public Dropdown(string label, string[] itemList, int selectedItemIndex = 0)
         : this(itemList, selectedItemIndex)
     {
@@ -262,12 +262,9 @@ public static class DropdownHelper
         buttonRect = dropdown.ButtonRect;
 
         var calculatedSize = dropdown.ElementSize;
-
         var calculatedListHeight = calculatedSize.y * dropdownList.Length;
-
         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));
 

+ 7 - 7
src/MeidoPhotoStudio.Plugin/GUI/Controls/KeyRebindButton.cs

@@ -27,13 +27,6 @@ public class KeyRebindButton : BaseControl
             StartListening();
     }
 
-    public void Draw(GUIStyle buttonStyle, params GUILayoutOption[] layoutOptions)
-    {
-        GUI.enabled = !listening && !InputManager.Listening;
-        button.Draw(buttonStyle, layoutOptions);
-        GUI.enabled = true;
-    }
-
     public override void Draw(params GUILayoutOption[] layoutOptions)
     {
         var buttonStyle = new GUIStyle(GUI.skin.button);
@@ -41,6 +34,13 @@ public class KeyRebindButton : BaseControl
         Draw(buttonStyle, layoutOptions);
     }
 
+    public void Draw(GUIStyle buttonStyle, params GUILayoutOption[] layoutOptions)
+    {
+        GUI.enabled = !listening && !InputManager.Listening;
+        button.Draw(buttonStyle, layoutOptions);
+        GUI.enabled = true;
+    }
+
     private void StartListening()
     {
         listening = true;

+ 10 - 10
src/MeidoPhotoStudio.Plugin/GUI/Controls/SelectionGrid.cs

@@ -28,6 +28,16 @@ public class SelectionGrid : BaseControl
         toggles = MakeToggles(items);
     }
 
+    public override void Draw(params GUILayoutOption[] layoutOptions)
+    {
+        GUILayout.BeginHorizontal();
+
+        foreach (var toggle in toggles)
+            toggle.Draw(layoutOptions);
+
+        GUILayout.EndHorizontal();
+    }
+
     public void SetItems(string[] items, int selectedItemIndex = -1)
     {
         if (selectedItemIndex < 0)
@@ -47,16 +57,6 @@ public class SelectionGrid : BaseControl
         SelectedItemIndex = Mathf.Clamp(selectedItemIndex, 0, items.Length - 1);
     }
 
-    public override void Draw(params GUILayoutOption[] layoutOptions)
-    {
-        GUILayout.BeginHorizontal();
-
-        foreach (var toggle in toggles)
-            toggle.Draw(layoutOptions);
-
-        GUILayout.EndHorizontal();
-    }
-
     private SimpleToggle[] MakeToggles(string[] items)
     {
         var toggles = new SimpleToggle[items.Length];

+ 9 - 11
src/MeidoPhotoStudio.Plugin/GUI/Controls/Slider.cs

@@ -15,6 +15,8 @@ public class Slider : BaseControl
     private string textFieldValue;
     private bool hasTextField;
 
+    public bool HasReset { get; set; }
+
     public string Label
     {
         get => label;
@@ -77,8 +79,6 @@ public class Slider : BaseControl
         }
     }
 
-    public bool HasReset { get; set; }
-
     public Slider(string label, float left, float right, float value = 0, float defaultValue = 0)
     {
         Label = label;
@@ -93,17 +93,9 @@ public class Slider : BaseControl
 
     public Slider(SliderProp prop) : this(string.Empty, prop.Left, prop.Right, prop.Initial, prop.Default) { }
 
-    public void SetBounds(float left, float right)
-    {
-        this.left = left;
-        this.right = right;
-        value = Utility.Bound(value, left, right);
-    }
-
     public override void Draw(params GUILayoutOption[] layoutOptions)
     {
         var hasUpper = hasLabel || HasTextField || HasReset;
-
         var tempText = string.Empty;
 
         if (hasUpper)
@@ -130,7 +122,6 @@ public class Slider : BaseControl
         }
 
         var sliderStyle = hasUpper ? MpsGui.SliderStyle : MpsGui.SliderStyleNoLabel;
-
         var tempValue =
             GUILayout.HorizontalSlider(Value, Left, Right, sliderStyle, MpsGui.SliderThumbStyle, layoutOptions);
 
@@ -155,6 +146,13 @@ public class Slider : BaseControl
             Value = tempValue;
     }
 
+    public void SetBounds(float left, float right)
+    {
+        this.left = left;
+        this.right = right;
+        value = Utility.Bound(value, left, right);
+    }
+
     private static string FormatValue(float value) =>
         value.ToString("0.####", CultureInfo.InvariantCulture);
 }

+ 3 - 3
src/MeidoPhotoStudio.Plugin/GUI/Controls/TextArea.cs

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

+ 3 - 3
src/MeidoPhotoStudio.Plugin/GUI/Controls/TextField.cs

@@ -14,6 +14,9 @@ public class TextField : BaseControl
 
     public string Value { get; set; } = string.Empty;
 
+    public override void Draw(params GUILayoutOption[] layoutOptions) =>
+        Draw(new(GUI.skin.textField), layoutOptions);
+
     public void Draw(GUIStyle textFieldStyle, params GUILayoutOption[] layoutOptions)
     {
         GUI.SetNextControlName(controlName);
@@ -22,7 +25,4 @@ public class TextField : BaseControl
         if (Event.current.isKey && Event.current.keyCode is KeyCode.Return)
             OnControlEvent(EventArgs.Empty);
     }
-
-    public override void Draw(params GUILayoutOption[] layoutOptions) =>
-        Draw(new(GUI.skin.textField), layoutOptions);
 }

+ 5 - 5
src/MeidoPhotoStudio.Plugin/GUI/Controls/Toggle.cs

@@ -7,6 +7,8 @@ public class Toggle : BaseControl
 {
     private bool value;
 
+    public string Label { get; set; }
+
     public bool Value
     {
         get => value;
@@ -18,14 +20,15 @@ public class Toggle : BaseControl
         }
     }
 
-    public string Label { get; set; }
-
     public Toggle(string label, bool state = false)
     {
         Label = label;
         value = state;
     }
 
+    public override void Draw(params GUILayoutOption[] layoutOptions) =>
+        Draw(new(GUI.skin.toggle), layoutOptions);
+
     public void Draw(GUIStyle toggleStyle, params GUILayoutOption[] layoutOptions)
     {
         var value = GUILayout.Toggle(Value, Label, toggleStyle, layoutOptions);
@@ -41,7 +44,4 @@ public class Toggle : BaseControl
         if (value != Value)
             Value = value;
     }
-
-    public override void Draw(params GUILayoutOption[] layoutOptions) =>
-        Draw(new(GUI.skin.toggle), layoutOptions);
 }

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

@@ -30,7 +30,7 @@ public class AttachPropPane : BasePane
             [AttachPoint.Spine1a] = "spine1a",
             [AttachPoint.Spine1] = "spine1",
             [AttachPoint.Spine0a] = "spine0a",
-            [AttachPoint.Spine0] = "spine0"
+            [AttachPoint.Spine0] = "spine0",
         };
 
     private readonly PropManager propManager;
@@ -95,20 +95,6 @@ public class AttachPropPane : BasePane
         }
     }
 
-    protected override void ReloadTranslation()
-    {
-        header = Translation.Get("attachPropPane", "header");
-        keepWorldPositionToggle.Label = Translation.Get("attachPropPane", "keepWorldPosition");
-
-        foreach (var attachPoint in Enum.GetValues(typeof(AttachPoint)).Cast<AttachPoint>())
-        {
-            if (attachPoint is AttachPoint.None)
-                continue;
-
-            toggles[attachPoint].Label = Translation.Get("attachPropPane", toggleTranslation[attachPoint]);
-        }
-    }
-
     public override void Draw()
     {
         const float dropdownButtonHeight = 30;
@@ -141,6 +127,20 @@ public class AttachPropPane : BasePane
         GUI.enabled = true;
     }
 
+    protected override void ReloadTranslation()
+    {
+        header = Translation.Get("attachPropPane", "header");
+        keepWorldPositionToggle.Label = Translation.Get("attachPropPane", "keepWorldPosition");
+
+        foreach (var attachPoint in Enum.GetValues(typeof(AttachPoint)).Cast<AttachPoint>())
+        {
+            if (attachPoint is AttachPoint.None)
+                continue;
+
+            toggles[attachPoint].Label = Translation.Get("attachPropPane", toggleTranslation[attachPoint]);
+        }
+    }
+
     private void DrawToggleGroup(params AttachPoint[] attachPoints)
     {
         GUILayout.BeginHorizontal();

+ 0 - 1
src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindow2Panes/ModPropsPane.cs

@@ -112,7 +112,6 @@ public class ModPropsPane : BasePane
             const int columns = 4;
 
             var buttonSize = windowWidth / columns - 10f;
-
             var positionRect = new Rect(5f, offsetTop + dropdownButtonHeight, windowWidth - 10f, windowHeight - 145f);
 
             var viewRect = new Rect(

+ 0 - 3
src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindow2Panes/MyRoomPropsPane.cs

@@ -44,7 +44,6 @@ public class MyRoomPropsPane : BasePane
         GUILayout.EndHorizontal();
 
         var windowRect = parent.WindowRect;
-
         var windowHeight = windowRect.height;
         var windowWidth = windowRect.width;
 
@@ -52,9 +51,7 @@ public class MyRoomPropsPane : BasePane
         const int columns = 3;
 
         var buttonSize = windowWidth / columns - 10f;
-
         var listCount = myRoomPropList.Count;
-
         var positionRect = new Rect(5f, offsetTop + dropdownButtonHeight, windowWidth - 10f, windowHeight - 145f);
         var viewRect = new Rect(0f, 0f, buttonSize * columns, buttonSize * Mathf.Ceil(listCount / (float)columns) + 5f);
 

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

@@ -16,7 +16,6 @@ public class BackgroundSelectorPane : BasePane
         this.environmentManager = environmentManager;
 
         var theaterIndex = Constants.BGList.FindIndex(bg => bg == EnvironmentManager.defaultBg);
-
         var bgList = new List<string>(Translation.GetList("bgNames", Constants.BGList));
 
         if (Constants.MyRoomCustomBGIndex >= 0)
@@ -79,6 +78,7 @@ public class BackgroundSelectorPane : BasePane
 
         var selectedIndex = bgDropdown.SelectedItemIndex;
         var isCreative = bgDropdown.SelectedItemIndex >= Constants.MyRoomCustomBGIndex;
+
         var bg = isCreative
             ? Constants.MyRoomCustomBGList[selectedIndex - Constants.MyRoomCustomBGIndex].Key
             : Constants.BGList[selectedIndex];

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

@@ -7,8 +7,6 @@ public abstract class EffectPane<T> : BasePane where T : IEffectManager
     protected readonly Toggle effectToggle;
     protected readonly Button resetEffectButton;
 
-    protected abstract T EffectManager { get; set; }
-
     private bool enabled;
 
     public override bool Enabled
@@ -25,6 +23,8 @@ public abstract class EffectPane<T> : BasePane where T : IEffectManager
         }
     }
 
+    protected abstract T EffectManager { get; set; }
+
     protected EffectPane(EffectManager effectManager)
     {
         EffectManager = effectManager.Get<T>();

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

@@ -14,7 +14,7 @@ public class LightsPane : BasePane
     {
         { "lights", "x" }, { "lights", "y" }, { "lights", "intensity" }, { "lights", "shadow" }, { "lights", "spot" },
         { "lights", "range" }, { "backgroundWindow", "red" }, { "backgroundWindow", "green" },
-        { "backgroundWindow", "blue" }
+        { "backgroundWindow", "blue" },
     };
 
     private readonly LightManager lightManager;
@@ -99,6 +99,7 @@ public class LightsPane : BasePane
         {
             var lightProp = (LightProp)i;
             var sliderProp = lightSliderProp[lightProp];
+
             var slider = new Slider(Translation.Get(sliderNames[i, 0], sliderNames[i, 1]), sliderProp)
             {
                 HasTextField = true,
@@ -156,7 +157,6 @@ public class LightsPane : BasePane
     public override void Draw()
     {
         var isMain = lightManager.SelectedLightIndex is 0;
-
         var noExpandWidth = GUILayout.ExpandWidth(false);
 
         MpsGui.Header(lightHeader);

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

@@ -59,7 +59,7 @@ public class MaidFaceSliderPane : BasePane
         // Tongue Up
         ["tangup"] = 1f,
         // Tongue Base
-        ["tangopen"] = 1f
+        ["tangopen"] = 1f,
     };
 
     private readonly MeidoManager meidoManager;

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

@@ -30,7 +30,7 @@ public class BGWindowPane : BaseMainWindowPane
             ["bloom"] = new BloomPane(effectManager),
             ["dof"] = new DepthOfFieldPane(effectManager),
             ["vignette"] = new VignettePane(effectManager),
-            ["fog"] = new FogPane(effectManager)
+            ["fog"] = new FogPane(effectManager),
         });
 
         otherEffectsPane = AddPane(new OtherEffectsPane(effectManager));

+ 1 - 0
src/MeidoPhotoStudio.Plugin/GUI/Panes/MainWindowPanes/FaceWindowPane.cs

@@ -10,6 +10,7 @@ public class FaceWindowPane : BaseMainWindowPane
     private readonly MaidSwitcherPane maidSwitcherPane;
     private readonly SaveFacePane saveFacePane;
     private readonly Toggle saveFaceToggle;
+
     private bool saveFaceMode;
 
     public FaceWindowPane(MeidoManager meidoManager, MaidSwitcherPane maidSwitcherPane)

+ 1 - 0
src/MeidoPhotoStudio.Plugin/GUI/Panes/OtherPanes/MaidSwitcherPane.cs

@@ -96,6 +96,7 @@ public class MaidSwitcherPane : BasePane
             editToggle.Draw(new Rect(previousRect.x + 4f, previousRect.y, 40f, 20f));
 
         var labelRect = new Rect(previousRect.width - 45f, previousRect.y, 40f, 20f);
+
         var slotStyle = new GUIStyle()
         {
             alignment = TextAnchor.UpperRight,

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

@@ -9,10 +9,10 @@ public class TabsPane : BasePane
 
     private readonly SelectionGrid Tabs;
 
-    private Constants.Window selectedTab;
-
     public event EventHandler TabChange;
 
+    private Constants.Window selectedTab;
+
     public Constants.Window SelectedTab
     {
         get => selectedTab;

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

@@ -30,14 +30,6 @@ public class GravityControlPane : BasePane
         header = Translation.Get("gravityControlPane", "gravityHeader");
     }
 
-    protected override void ReloadTranslation()
-    {
-        hairToggle.Label = Translation.Get("gravityControlPane", "hairToggle");
-        skirtToggle.Label = Translation.Get("gravityControlPane", "skirtToggle");
-        globalToggle.Label = Translation.Get("gravityControlPane", "globalToggle");
-        header = Translation.Get("gravityControlPane", "gravityHeader");
-    }
-
     public override void Draw()
     {
         var enabled = meidoManager.HasActiveMeido;
@@ -80,6 +72,14 @@ public class GravityControlPane : BasePane
         updating = false;
     }
 
+    protected override void ReloadTranslation()
+    {
+        hairToggle.Label = Translation.Get("gravityControlPane", "hairToggle");
+        skirtToggle.Label = Translation.Get("gravityControlPane", "skirtToggle");
+        globalToggle.Label = Translation.Get("gravityControlPane", "globalToggle");
+        header = Translation.Get("gravityControlPane", "gravityHeader");
+    }
+
     private void ToggleGravity(bool value, bool skirt = false)
     {
         if (updating)

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

@@ -69,15 +69,6 @@ public class HandPresetPane : BasePane
         presetListEnabled = CurrentPresetList.Count > 0;
     }
 
-    protected override void ReloadTranslation()
-    {
-        leftHandButton.Label = Translation.Get("handPane", "leftHand");
-        rightHandButton.Label = Translation.Get("handPane", "rightHand");
-
-        if (CurrentPresetList.Count is 0)
-            presetDropdown.SetDropdownItems(UIPresetList());
-    }
-
     public override void Draw()
     {
         var dropdownWidth = GUILayout.Width(156f);
@@ -107,6 +98,15 @@ public class HandPresetPane : BasePane
         GUI.enabled = true;
     }
 
+    protected override void ReloadTranslation()
+    {
+        leftHandButton.Label = Translation.Get("handPane", "leftHand");
+        rightHandButton.Label = Translation.Get("handPane", "rightHand");
+
+        if (CurrentPresetList.Count is 0)
+            presetDropdown.SetDropdownItems(UIPresetList());
+    }
+
     private void ChangePresetCategory()
     {
         presetListEnabled = CurrentPresetList.Count > 0;

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

@@ -15,23 +15,23 @@ public class MaidDressingPane : BasePane
         // detailed slots
         SlotID.accAshi, SlotID.accHana, SlotID.accHat, SlotID.accHeso, SlotID.accKamiSubL, SlotID.accKamiSubR,
         SlotID.accKami_1_, SlotID.accKami_2_, SlotID.accKami_3_, SlotID.accKubi, SlotID.accKubiwa, SlotID.accMiMiL,
-        SlotID.accMiMiR, SlotID.accNipL, SlotID.accNipR, SlotID.accShippo, SlotID.accXXX
-            // unused slots
-            // SlotID.mizugi, SlotID.onepiece, SlotID.accHead,
+        SlotID.accMiMiR, SlotID.accNipL, SlotID.accNipR, SlotID.accShippo, SlotID.accXXX,
+        // unused slots
+        // SlotID.mizugi, SlotID.onepiece, SlotID.accHead,
     };
 
     public static readonly SlotID[] BodySlots =
     {
-        SlotID.body, SlotID.head, SlotID.eye, SlotID.hairF, SlotID.hairR, SlotID.hairS, SlotID.hairT,
-        SlotID.hairAho, SlotID.chikubi, SlotID.underhair, SlotID.moza, SlotID.accHa
+        SlotID.body, SlotID.head, SlotID.eye, SlotID.hairF, SlotID.hairR, SlotID.hairS, SlotID.hairT, SlotID.hairAho,
+        SlotID.chikubi, SlotID.underhair, SlotID.moza, SlotID.accHa,
     };
 
     public static readonly SlotID[] WearSlots = { SlotID.wear, SlotID.mizugi, SlotID.onepiece };
 
     public static readonly SlotID[] HeadwearSlots =
     {
-        SlotID.headset, SlotID.accHat, SlotID.accKamiSubL, SlotID.accKamiSubR, SlotID.accKami_1_,
-        SlotID.accKami_2_, SlotID.accKami_3_
+        SlotID.headset, SlotID.accHat, SlotID.accKamiSubL, SlotID.accKamiSubR, SlotID.accKami_1_, SlotID.accKami_2_,
+        SlotID.accKami_3_,
     };
 
     private static readonly string[] maskLabels = { "all", "underwear", "nude" };

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

@@ -35,6 +35,38 @@ public class MaidFaceLookPane : BasePane
         bindLabel = Translation.Get("freeLookPane", "bindLabel");
     }
 
+    public override void Draw()
+    {
+        GUI.enabled = meidoManager.HasActiveMeido && meidoManager.ActiveMeido.FreeLook;
+        GUILayout.BeginHorizontal();
+        lookXSlider.Draw();
+        lookYSlider.Draw();
+        GUILayout.EndHorizontal();
+
+        GUI.enabled = meidoManager.HasActiveMeido;
+
+        GUILayout.BeginHorizontal();
+        GUILayout.Label(bindLabel, GUILayout.ExpandWidth(false));
+        eyeToCamToggle.Draw();
+        headToCamToggle.Draw();
+        GUILayout.EndHorizontal();
+
+        GUI.enabled = true;
+    }
+
+    public override void UpdatePane()
+    {
+        var meido = meidoManager.ActiveMeido;
+
+        updating = true;
+        SetBounds();
+        lookXSlider.Value = meido.Body.offsetLookTarget.z;
+        lookYSlider.Value = meido.Body.offsetLookTarget.x;
+        eyeToCamToggle.Value = meido.EyeToCam;
+        headToCamToggle.Value = meido.HeadToCam;
+        updating = false;
+    }
+
     public void SetHeadToCam(bool value, bool eye = false)
     {
         if (updating)
@@ -72,38 +104,6 @@ public class MaidFaceLookPane : BasePane
         lookYSlider.SetBounds(left, right);
     }
 
-    public override void UpdatePane()
-    {
-        var meido = meidoManager.ActiveMeido;
-
-        updating = true;
-        SetBounds();
-        lookXSlider.Value = meido.Body.offsetLookTarget.z;
-        lookYSlider.Value = meido.Body.offsetLookTarget.x;
-        eyeToCamToggle.Value = meido.EyeToCam;
-        headToCamToggle.Value = meido.HeadToCam;
-        updating = false;
-    }
-
-    public override void Draw()
-    {
-        GUI.enabled = meidoManager.HasActiveMeido && meidoManager.ActiveMeido.FreeLook;
-        GUILayout.BeginHorizontal();
-        lookXSlider.Draw();
-        lookYSlider.Draw();
-        GUILayout.EndHorizontal();
-
-        GUI.enabled = meidoManager.HasActiveMeido;
-
-        GUILayout.BeginHorizontal();
-        GUILayout.Label(bindLabel, GUILayout.ExpandWidth(false));
-        eyeToCamToggle.Draw();
-        headToCamToggle.Draw();
-        GUILayout.EndHorizontal();
-
-        GUI.enabled = true;
-    }
-
     protected override void ReloadTranslation()
     {
         lookXSlider.Label = Translation.Get("freeLookPane", "xSlider");

+ 0 - 10
src/MeidoPhotoStudio.Plugin/MaidPlacementUtility.cs

@@ -79,9 +79,7 @@ public static class MaidPlacementUtility
         for (var i = 0; i < list.Count; i++)
         {
             var position = Vector3.zero;
-
             var maid = list[i].Maid;
-
             var a = AlternatingSequence(i) * 0.6f;
 
             if (vertical)
@@ -112,7 +110,6 @@ public static class MaidPlacementUtility
         for (var i = 0; i < list.Count; i++)
         {
             var maid = list[i].Maid;
-
             var x = AlternatingSequence(i) * 0.4f;
             var z = (inverse ? -1 : 1) * Mathf.Cos(AlternatingSequence(i) * pi) * 0.35f;
 
@@ -126,7 +123,6 @@ public static class MaidPlacementUtility
         for (var i = 0; i < list.Count; i++)
         {
             var maid = list[i].Maid;
-
             var x = AlternatingSequence(i) * 0.4f;
             var z = (inverse ? 1 : -1) * Mathf.Abs(AlternatingSequence(i)) * 0.4f;
 
@@ -144,9 +140,7 @@ public static class MaidPlacementUtility
         for (var i = 0; i < maidCount; i++)
         {
             var maid = list[i].Maid;
-
             var angle = pi / 2f + tau * AlternatingSequence(i) / maidCount;
-
             var x = Mathf.Cos(angle) * radius;
             var z = Mathf.Sin(angle) * radius;
 
@@ -163,7 +157,6 @@ public static class MaidPlacementUtility
     public static void PlacementFan(IList<Meido> list, bool outer = false)
     {
         var maidCount = list.Count;
-
         var radius = 0.2f + 0.2f * maidCount;
 
         list[0].Maid.SetPos(Vector3.zero);
@@ -172,12 +165,9 @@ public static class MaidPlacementUtility
         for (var i = 1; i < maidCount; i++)
         {
             var maid = list[i].Maid;
-
             var angle = pi * AlternatingSequence(i - 1) / maidCount;
-
             var x = Mathf.Sin(angle) * radius;
             var z = Mathf.Cos(angle) * radius;
-
             var rotation = Mathf.Atan2(x, z);
 
             if (outer)

+ 1 - 1
src/MeidoPhotoStudio.Plugin/Managers/InputManager.cs

@@ -17,7 +17,7 @@ public enum MpsKey
     // Dragpoint
     DragSelect, DragDelete, DragMove, DragRotate, DragScale, DragFinger,
     // Scene management
-    SaveScene, LoadScene, OpenSceneManager
+    SaveScene, LoadScene, OpenSceneManager,
 }
 
 public static class InputManager

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

@@ -18,7 +18,7 @@ public abstract class DragPointChain : DragPointMeido
         {
             myObject.parent,
             myObject.parent,
-            myObject
+            myObject,
         };
 
         ikCtrlData = IkCtrlData;

+ 4 - 4
src/MeidoPhotoStudio.Plugin/Meido/Meido.cs

@@ -24,7 +24,7 @@ public class Meido
             "eyeclose", "eyeclose2", "eyeclose3", "eyebig", "eyeclose6", "eyeclose5", "hitomih",
             "hitomis", "mayuha", "mayuw", "mayuup", "mayuv", "mayuvhalf", "moutha", "mouths",
             "mouthc", "mouthi", "mouthup", "mouthdw", "mouthhe", "mouthuphalf", "tangout",
-            "tangup", "tangopen"
+            "tangup", "tangopen",
         };
 
     public static readonly string[] faceToggleKeys =
@@ -33,7 +33,7 @@ public class Meido
             // blush, shade, nose up, tears, drool, teeth
             "hoho2", "shock", "nosefook", "namida", "yodare", "toothoff",
             // cry 1, cry 2, cry 3, blush 1, blush 2, blush 3
-            "tear1", "tear2", "tear3", "hohos", "hoho", "hohol"
+            "tear1", "tear2", "tear3", "hohos", "hoho", "hohol",
         };
 
     private readonly FieldInfo m_eMaskMode = Utility.GetFieldInfo<TBody>("m_eMaskMode");
@@ -645,7 +645,7 @@ public class Meido
             {
                 Curl.Shift => "パンツずらし",
                 Curl.Front => "めくれスカート",
-                _ => "めくれスカート後ろ"
+                _ => "めくれスカート後ろ",
             };
 
             Maid.ItemChangeTemp(name[0], action);
@@ -753,7 +753,7 @@ public class Meido
             new[]
             {
                 MPN.skirt, MPN.onepiece, MPN.mizugi, MPN.panz, MPN.set_maidwear, MPN.set_mywear, MPN.set_underwear,
-                MPN.hairf, MPN.hairr, MPN.hairs, MPN.hairt
+                MPN.hairf, MPN.hairr, MPN.hairs, MPN.hairt,
             };
 
         Action action = null;

+ 7 - 6
src/MeidoPhotoStudio.Plugin/Meido/MeidoDragPointManager.cs

@@ -9,7 +9,7 @@ namespace MeidoPhotoStudio.Plugin;
 public enum AttachPoint
 {
     None, Head, Neck, UpperArmL, UpperArmR, ForearmL, ForearmR, MuneL, MuneR, HandL, HandR, Pelvis, ThighL, ThighR,
-    CalfL, CalfR, FootL, FootR, Spine1a, Spine1, Spine0a, Spine0
+    CalfL, CalfR, FootL, FootR, Spine1a, Spine1, Spine0a, Spine0,
 }
 
 public class MeidoDragPointManager
@@ -55,7 +55,7 @@ public class MeidoDragPointManager
         Toe2L, Toe21L, Toe2NubL,
         Toe0R, Toe01R, Toe0NubR,
         Toe1R, Toe11R, Toe1NubR,
-        Toe2R, Toe21R, Toe2NubR
+        Toe2R, Toe21R, Toe2NubR,
     }
 
     private static readonly Dictionary<AttachPoint, Bone> PointToBone = new()
@@ -80,12 +80,12 @@ public class MeidoDragPointManager
         [AttachPoint.Spine1a] = Bone.Spine1a,
         [AttachPoint.Spine1] = Bone.Spine1,
         [AttachPoint.Spine0a] = Bone.Spine0a,
-        [AttachPoint.Spine0] = Bone.Spine
+        [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
+        Bone.Neck, Bone.Spine, Bone.Spine0a, Bone.Spine1, Bone.Spine1a, Bone.Hip, Bone.ThighL, Bone.ThighR,
     };
 
     private static bool cubeActive;
@@ -279,6 +279,7 @@ public class MeidoDragPointManager
                 if (!reader.ReadBoolean())
                 {
                     reader.ReadQuaternion();
+
                     continue;
                 }
             }
@@ -303,7 +304,7 @@ public class MeidoDragPointManager
         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
+                Bone.ThighL, Bone.ThighR, Bone.CalfL, Bone.CalfR, Bone.HandL, Bone.HandR, Bone.FootL, Bone.FootR,
             };
 
         var singleRotations = single.Select(bone => BoneTransform[bone].eulerAngles).ToList();
@@ -804,7 +805,7 @@ public class MeidoDragPointManager
             [Bone.Toe1NubR] = CMT.SearchObjName(transform, "Bip01 R Toe1Nub"),
             [Bone.Toe2R] = CMT.SearchObjName(transform, "Bip01 R Toe2"),
             [Bone.Toe21R] = CMT.SearchObjName(transform, "Bip01 R Toe21"),
-            [Bone.Toe2NubR] = CMT.SearchObjName(transform, "Bip01 R Toe2Nub")
+            [Bone.Toe2NubR] = CMT.SearchObjName(transform, "Bip01 R Toe2Nub"),
         };
     }
 }

+ 18 - 17
src/MeidoPhotoStudio.Plugin/MeidoPhotoStudio.cs

@@ -24,14 +24,14 @@ public class MeidoPhotoStudio : BaseUnityPlugin
     public static readonly byte[] SceneHeader = Encoding.UTF8.GetBytes("MPSSCENE");
     public static readonly string pluginString = $"{pluginName} {pluginVersion}";
 
-    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;
 
+    public static bool EditMode =>
+        currentScene is Constants.Scene.Edit;
+
     private HarmonyLib.Harmony harmony;
     private WindowManager windowManager;
     private SceneManager sceneManager;
@@ -158,7 +158,8 @@ public class MeidoPhotoStudio : BaseUnityPlugin
 
                         break;
                     case MessageWindowManager.header:
-                        Serialization.Get<MessageWindowManager>().Deserialize(messageWindowManager, dataReader, metadata);
+                        Serialization.Get<MessageWindowManager>()
+                            .Deserialize(messageWindowManager, dataReader, metadata);
 
                         break;
                     case CameraManager.header:
@@ -305,7 +306,7 @@ public class MeidoPhotoStudio : BaseUnityPlugin
             MeidoDragPointManager.CubeActive,
             PropManager.CubeActive,
             LightManager.CubeActive,
-            EnvironmentManager.CubeActive
+            EnvironmentManager.CubeActive,
         };
 
         MeidoDragPointManager.CubeActive = false;
@@ -335,6 +336,7 @@ public class MeidoPhotoStudio : BaseUnityPlugin
 
             CameraUtility.MainCamera.camera.targetTexture = null;
             RenderTexture.active = null;
+
             DestroyImmediate(renderTexture);
         }
         else
@@ -430,7 +432,6 @@ public class MeidoPhotoStudio : BaseUnityPlugin
             uiActive = true;
 
         var maidSwitcherPane = new MaidSwitcherPane(meidoManager);
-
         var sceneWindow = new SceneWindow(sceneManager);
 
         windowManager = new()
@@ -443,10 +444,10 @@ public class MeidoPhotoStudio : BaseUnityPlugin
                 [Constants.Window.BG] =
                     new BGWindowPane(environmentManager, lightManager, effectManager, sceneWindow, cameraManager),
                 [Constants.Window.BG2] = new BG2WindowPane(meidoManager, propManager),
-                [Constants.Window.Settings] = new SettingsWindowPane()
+                [Constants.Window.Settings] = new SettingsWindowPane(),
             },
             [Constants.Window.Message] = new MessageWindow(messageWindowManager),
-            [Constants.Window.Save] = sceneWindow
+            [Constants.Window.Save] = sceneWindow,
         };
     }
 
@@ -505,17 +506,17 @@ public class MeidoPhotoStudio : BaseUnityPlugin
         }
 
         sysDialog.Show(
-            string.Format(Translation.Get("systemMessage", "exitConfirm"), pluginName),
-            SystemDialog.TYPE.OK_CANCEL,
-            Exit,
-            () =>
-            {
-                sysDialog.Close();
-                uiActive = true;
-                active = true;
-            }
+            string.Format(Translation.Get("systemMessage", "exitConfirm"), pluginName), SystemDialog.TYPE.OK_CANCEL,
+            Exit, Resume
         );
 
+        void Resume()
+        {
+            sysDialog.Close();
+            uiActive = true;
+            active = true;
+        }
+
         void Exit()
         {
             sysDialog.Close();

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

@@ -15,8 +15,8 @@ public static class MenuFileUtility
     public static readonly string[] MenuCategories =
     {
         noCategory, "acchat", "headset", "wear", "skirt", "onepiece", "mizugi", "bra", "panz", "stkg", "shoes",
-        "acckami", "megane", "acchead", "acchana", "accmimi", "glove", "acckubi", "acckubiwa", "acckamisub",
-        "accnip", "accude", "accheso", "accashi", "accsenaka", "accshippo", "accxxx"
+        "acckami", "megane", "acchead", "acchana", "accmimi", "glove", "acckubi", "acckubiwa", "acckamisub", "accnip",
+        "accude", "accheso", "accashi", "accsenaka", "accshippo", "accxxx",
     };
 
     private static readonly HashSet<string> accMpn = new(StringComparer.InvariantCultureIgnoreCase);
@@ -43,6 +43,7 @@ public static class MenuFileUtility
             return null;
         }
 
+        // INFO: Don't really understand what this does.
         ref var buffer = ref GetFileBuffer(aFileBase.GetSize());
 
         aFileBase.Read(ref buffer, aFileBase.GetSize());

+ 3 - 3
src/MeidoPhotoStudio.Plugin/MenuItem.cs

@@ -26,14 +26,14 @@ public class ModItem : MenuItem
             MenuFile = menuFile,
             IsMod = true,
             IsOfficialMod = true,
-            Priority = 1000f
+            Priority = 1000f,
         };
 
     public static ModItem Mod(string menuFile) =>
         new()
         {
             MenuFile = menuFile,
-            IsMod = true
+            IsMod = true,
         };
 
     public static ModItem Deserialize(BinaryReader binaryReader) =>
@@ -46,7 +46,7 @@ public class ModItem : MenuItem
             Category = binaryReader.ReadNullableString(),
             Priority = float.Parse(binaryReader.ReadNullableString()),
             IsMod = binaryReader.ReadBoolean(),
-            IsOfficialMod = binaryReader.ReadBoolean()
+            IsOfficialMod = binaryReader.ReadBoolean(),
         };
 
     public ModItem() { }

+ 0 - 3
src/MeidoPhotoStudio.Plugin/ModelUtility.cs

@@ -216,7 +216,6 @@ public static class ModelUtility
 
         var rootName = binaryReader.ReadString();
         var boneCount = binaryReader.ReadInt32();
-
         var boneDict = new Dictionary<string, GameObject>();
         var boneList = new List<GameObject>(boneCount);
 
@@ -278,11 +277,9 @@ public static class ModelUtility
             meshRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion;
 
             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++)

+ 0 - 1
src/MeidoPhotoStudio.Plugin/MyGui.cs

@@ -94,5 +94,4 @@ public static class MpsGui
 
     private static void Line(GUIStyle style) =>
         GUILayout.Box(GUIContent.none, style, GUILayout.Height(1));
-
 }

+ 0 - 1
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/ManagerSerializers/LightManagerSerializer.cs

@@ -33,7 +33,6 @@ public class LightManagerSerializer : Serializer<LightManager>
         _ = reader.ReadVersion();
 
         var lightCount = reader.ReadInt32();
-
         var list = GetLightList(manager);
 
         LightSerializer.Deserialize(list[0], reader, metadata);

+ 1 - 0
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/ManagerSerializers/MeidoManagerSerializer.cs

@@ -59,6 +59,7 @@ public class MeidoManagerSerializer : Serializer<MeidoManager>
         _ = reader.ReadVersion();
 
         var meidoCount = reader.ReadInt32();
+
         for (var i = 0; i < meidoCount; i++)
         {
             if (i >= manager.ActiveMeidoList.Count)

+ 229 - 229
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/MeidoSerializer.cs

@@ -19,327 +19,327 @@ public class MeidoSerializer : Serializer<Meido>
     private static SimpleSerializer<TransformDTO> TransformDtoSerializer =>
         Serialization.GetSimple<TransformDTO>();
 
-    private static void SerializeHead(Meido meido, BinaryWriter writer)
+    public override void Serialize(Meido meido, BinaryWriter writer)
     {
-        var body = meido.Body;
-
-        writer.WriteVersion(headVersion);
-
-        // eye direction
-        writer.WriteQuaternion(body.quaDefEyeL * Quaternion.Inverse(meido.DefaultEyeRotL));
-        writer.WriteQuaternion(body.quaDefEyeR * Quaternion.Inverse(meido.DefaultEyeRotR));
-
-        // free look
-        writer.Write(meido.FreeLook);
-        writer.WriteVector3(body.offsetLookTarget);
-        writer.WriteVector3(Utility.GetFieldValue<TBody, Vector3>(body, "HeadEulerAngle"));
+        var maid = meido.Maid;
 
-        // Head/eye to camera
-        writer.Write(meido.HeadToCam);
-        writer.Write(meido.EyeToCam);
+        using var memoryStream = new MemoryStream();
+        using var tempWriter = new BinaryWriter(memoryStream, Encoding.UTF8);
 
-        // face
-        var faceDict = meido.SerializeFace();
+        tempWriter.WriteVersion(version);
 
-        writer.Write(faceDict.Count);
+        TransformDtoSerializer.Serialize(new TransformDTO(maid.transform), tempWriter);
 
-        foreach (var (hash, value) in faceDict)
-        {
-            writer.Write(hash);
-            writer.Write(value);
-        }
-    }
+        SerializeHead(meido, tempWriter);
 
-    private static void SerializeBody(Meido meido, BinaryWriter writer)
-    {
-        writer.WriteVersion(bodyVersion);
+        SerializeBody(meido, tempWriter);
 
-        // pose
-        var poseBuffer = meido.SerializePose(true);
+        SerializeClothing(meido, tempWriter);
 
-        writer.Write(poseBuffer.Length);
-        writer.Write(poseBuffer);
+        writer.Write(memoryStream.Length);
+        writer.Write(memoryStream.ToArray());
 
-        PoseInfoSerializer.Serialize(meido.CachedPose, writer);
+        static void SerializeHead(Meido meido, BinaryWriter writer)
+        {
+            var body = meido.Body;
 
-        // TODO: Think about how to indicate code for new versions of serialization.
-        #region v2
-        // sub mune rotation
-        var body = meido.Body;
+            writer.WriteVersion(headVersion);
 
-        writer.WriteQuaternion(body.GetBone("Mune_L_sub").localRotation);
-        writer.WriteQuaternion(body.GetBone("Mune_R_sub").localRotation);
-        #endregion
-    }
+            // eye direction
+            writer.WriteQuaternion(body.quaDefEyeL * Quaternion.Inverse(meido.DefaultEyeRotL));
+            writer.WriteQuaternion(body.quaDefEyeR * Quaternion.Inverse(meido.DefaultEyeRotR));
 
-    private static void SerializeClothing(Meido meido, BinaryWriter writer)
-    {
-        var maid = meido.Maid;
-        var body = meido.Body;
+            // free look
+            writer.Write(meido.FreeLook);
+            writer.WriteVector3(body.offsetLookTarget);
+            writer.WriteVector3(Utility.GetFieldValue<TBody, Vector3>(body, "HeadEulerAngle"));
 
-        writer.WriteVersion(clothingVersion);
+            // Head/eye to camera
+            writer.Write(meido.HeadToCam);
+            writer.Write(meido.EyeToCam);
 
-        // body visible
-        writer.Write(body.GetMask(TBody.SlotID.body));
+            // face
+            var faceDict = meido.SerializeFace();
 
-        // clothing
-        foreach (var clothingSlot in MaidDressingPane.ClothingSlots)
-        {
-            var value = true;
+            writer.Write(faceDict.Count);
 
-            if (clothingSlot is TBody.SlotID.wear)
+            foreach (var (hash, value) in faceDict)
             {
-                if (MaidDressingPane.WearSlots.Any(slot => body.GetSlotLoaded(slot)))
-                    value = MaidDressingPane.WearSlots.Any(slot => body.GetMask(slot));
+                writer.Write(hash);
+                writer.Write(value);
             }
-            else if (clothingSlot is 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));
-            }
-            else if (body.GetSlotLoaded(clothingSlot))
-                value = body.GetMask(clothingSlot);
-
-            writer.Write(value);
         }
 
-        // zurashi and mekure
-        writer.Write(meido.CurlingFront);
-        writer.Write(meido.CurlingBack);
-        writer.Write(meido.PantsuShift);
-
-        // 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);
+        static void SerializeBody(Meido meido, BinaryWriter writer)
+        {
+            writer.WriteVersion(bodyVersion);
 
-        writer.Write(hasKousokuLower);
-        writer.Write(maid.GetProp(MPN.kousoku_lower).strTempFileName);
+            // pose
+            var poseBuffer = meido.SerializePose(true);
 
-        // hair/skirt gravity
-        writer.Write(meido.HairGravityActive);
-        writer.Write(meido.HairGravityControl.Control.transform.localPosition);
+            writer.Write(poseBuffer.Length);
+            writer.Write(poseBuffer);
 
-        writer.Write(meido.SkirtGravityActive);
-        writer.Write(meido.SkirtGravityControl.Control.transform.localPosition);
-    }
+            PoseInfoSerializer.Serialize(meido.CachedPose, writer);
 
-    private static void DeserializeHead(Meido meido, BinaryReader reader, SceneMetadata metadata)
-    {
-        var body = meido.Body;
+            // TODO: Think about how to indicate code for new versions of serialization.
+            #region v2
+            // sub mune rotation
+            var body = meido.Body;
 
-        _ = reader.ReadVersion();
+            writer.WriteQuaternion(body.GetBone("Mune_L_sub").localRotation);
+            writer.WriteQuaternion(body.GetBone("Mune_R_sub").localRotation);
+            #endregion
+        }
 
-        var mmConverted = metadata.MMConverted;
+        static void SerializeClothing(Meido meido, BinaryWriter writer)
+        {
+            var maid = meido.Maid;
+            var body = meido.Body;
 
-        var eyeRotationL = reader.ReadQuaternion();
-        var eyeRotationR = reader.ReadQuaternion();
+            writer.WriteVersion(clothingVersion);
 
-        if (!mmConverted)
-        {
-            eyeRotationL *= meido.DefaultEyeRotL;
-            eyeRotationR *= meido.DefaultEyeRotR;
-        }
+            // body visible
+            writer.Write(body.GetMask(TBody.SlotID.body));
 
-        body.quaDefEyeL = eyeRotationL;
-        body.quaDefEyeR = eyeRotationR;
+            // clothing
+            foreach (var clothingSlot in MaidDressingPane.ClothingSlots)
+            {
+                var value = true;
+
+                if (clothingSlot is TBody.SlotID.wear)
+                {
+                    if (MaidDressingPane.WearSlots.Any(slot => body.GetSlotLoaded(slot)))
+                        value = MaidDressingPane.WearSlots.Any(slot => body.GetMask(slot));
+                }
+                else if (clothingSlot is 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));
+                }
+                else if (body.GetSlotLoaded(clothingSlot))
+                    value = body.GetMask(clothingSlot);
+
+                writer.Write(value);
+            }
 
-        var freeLook = meido.FreeLook = reader.ReadBoolean();
-        var offsetLookTarget = reader.ReadVector3();
-        var headEulerAngle = reader.ReadVector3();
+            // zurashi and mekure
+            writer.Write(meido.CurlingFront);
+            writer.Write(meido.CurlingBack);
+            writer.Write(meido.PantsuShift);
 
-        if (freeLook)
-            body.offsetLookTarget = offsetLookTarget;
+            // mpn attach props
+            var hasKousokuUpper = body.GetSlotLoaded(TBody.SlotID.kousoku_upper);
 
-        if (!metadata.MMConverted)
-        {
-            Utility.SetFieldValue(body, "HeadEulerAngleG", Vector3.zero);
-            Utility.SetFieldValue(body, "HeadEulerAngle", headEulerAngle);
-        }
+            writer.Write(hasKousokuUpper);
+            writer.Write(maid.GetProp(MPN.kousoku_upper).strTempFileName);
 
-        meido.HeadToCam = reader.ReadBoolean();
-        meido.EyeToCam = reader.ReadBoolean();
+            var hasKousokuLower = body.GetSlotLoaded(TBody.SlotID.kousoku_lower);
 
-        var faceBlendCount = reader.ReadInt32();
+            writer.Write(hasKousokuLower);
+            writer.Write(maid.GetProp(MPN.kousoku_lower).strTempFileName);
 
-        for (var i = 0; i < faceBlendCount; i++)
-        {
-            var hash = reader.ReadString();
-            var value = reader.ReadSingle();
+            // hair/skirt gravity
+            writer.Write(meido.HairGravityActive);
+            writer.Write(meido.HairGravityControl.Control.transform.localPosition);
 
-            meido.SetFaceBlendValue(hash, value);
+            writer.Write(meido.SkirtGravityActive);
+            writer.Write(meido.SkirtGravityControl.Control.transform.localPosition);
         }
     }
 
-    private static void DeserializeBody(Meido meido, BinaryReader reader, SceneMetadata metadata)
+    public override void Deserialize(Meido meido, BinaryReader reader, SceneMetadata metadata)
     {
-        var version = reader.ReadVersion();
+        var maid = meido.Maid;
 
-        var muneSetting = new KeyValuePair<bool, bool>(true, true);
+        maid.GetAnimation().Stop();
+        meido.DetachAllMpnAttach();
+        meido.StopBlink();
 
-        if (metadata.MMConverted)
-            meido.IKManager.Deserialize(reader);
-        else
-        {
-            var poseBufferLength = reader.ReadInt32();
-            var poseBuffer = reader.ReadBytes(poseBufferLength);
+        reader.ReadInt64(); // data length
 
-            muneSetting = meido.SetFrameBinary(poseBuffer);
-        }
+        _ = reader.ReadVersion();
 
-        var poseInfo = PoseInfoSerializer.Deserialize(reader, metadata);
+        var transformDto = TransformDtoSerializer.Deserialize(reader, metadata);
+        var maidTransform = maid.transform;
 
-        Utility.SetPropertyValue(meido, nameof(Meido.CachedPose), poseInfo);
+        // TODO: use transform.SetRotationAndPosition
+        maidTransform.position = transformDto.Position;
+        maidTransform.rotation = transformDto.Rotation;
+        maidTransform.localScale = transformDto.LocalScale;
+
+        meido.IKManager.SetDragPointScale(maidTransform.localScale.x);
 
-        meido.SetMune(!muneSetting.Key, true);
-        meido.SetMune(!muneSetting.Value);
+        DeserializeHead(meido, reader, metadata);
 
-        if (version < 2)
-            return;
+        DeserializeBody(meido, reader, metadata);
 
-        var muneLSubRotation = reader.ReadQuaternion();
-        var muneSubRRotation = reader.ReadQuaternion();
+        DeserializeClothing(meido, reader, metadata);
 
-        var body = meido.Body;
+        static void DeserializeHead(Meido meido, BinaryReader reader, SceneMetadata metadata)
+        {
+            var body = meido.Body;
 
-        if (muneSetting.Key)
-            body.GetBone("Mune_L_sub").localRotation = muneLSubRotation;
+            _ = reader.ReadVersion();
 
-        if (muneSetting.Value)
-            body.GetBone("Mune_R_sub").localRotation = muneSubRRotation;
-    }
+            var mmConverted = metadata.MMConverted;
 
-    private static void DeserializeClothing(Meido meido, BinaryReader reader, SceneMetadata metadata)
-    {
-        var body = meido.Body;
+            var eyeRotationL = reader.ReadQuaternion();
+            var eyeRotationR = reader.ReadQuaternion();
 
-        _ = reader.ReadVersion();
+            if (!mmConverted)
+            {
+                eyeRotationL *= meido.DefaultEyeRotL;
+                eyeRotationR *= meido.DefaultEyeRotR;
+            }
 
-        meido.SetBodyMask(reader.ReadBoolean());
+            body.quaDefEyeL = eyeRotationL;
+            body.quaDefEyeR = eyeRotationR;
 
-        foreach (var clothingSlot in MaidDressingPane.ClothingSlots)
-        {
-            var value = reader.ReadBoolean();
+            var freeLook = meido.FreeLook = reader.ReadBoolean();
+            var offsetLookTarget = reader.ReadVector3();
+            var headEulerAngle = reader.ReadVector3();
 
-            if (metadata.MMConverted)
-                continue;
+            if (freeLook)
+                body.offsetLookTarget = offsetLookTarget;
 
-            if (clothingSlot is TBody.SlotID.wear)
+            if (!metadata.MMConverted)
             {
-                body.SetMask(TBody.SlotID.wear, value);
-                body.SetMask(TBody.SlotID.mizugi, value);
-                body.SetMask(TBody.SlotID.onepiece, value);
+                Utility.SetFieldValue(body, "HeadEulerAngleG", Vector3.zero);
+                Utility.SetFieldValue(body, "HeadEulerAngle", headEulerAngle);
             }
-            else if (clothingSlot is TBody.SlotID.megane)
+
+            meido.HeadToCam = reader.ReadBoolean();
+            meido.EyeToCam = reader.ReadBoolean();
+
+            var faceBlendCount = reader.ReadInt32();
+
+            for (var i = 0; i < faceBlendCount; i++)
             {
-                body.SetMask(TBody.SlotID.megane, value);
-                body.SetMask(TBody.SlotID.accHead, value);
+                var hash = reader.ReadString();
+                var value = reader.ReadSingle();
+
+                meido.SetFaceBlendValue(hash, value);
             }
-            else if (body.GetSlotLoaded(clothingSlot))
-                body.SetMask(clothingSlot, value);
         }
 
-        // zurashi and mekure
-        var curlingFront = reader.ReadBoolean();
-        var curlingBack = reader.ReadBoolean();
-        var curlingPantsu = reader.ReadBoolean();
-
-        if (!metadata.MMConverted)
+        static void DeserializeBody(Meido meido, BinaryReader reader, SceneMetadata metadata)
         {
-            if (meido.CurlingFront != curlingFront)
-                meido.SetCurling(Meido.Curl.Front, curlingFront);
-
-            if (meido.CurlingBack != curlingBack)
-                meido.SetCurling(Meido.Curl.Back, curlingBack);
+            var version = reader.ReadVersion();
 
-            meido.SetCurling(Meido.Curl.Shift, curlingPantsu);
-        }
+            var muneSetting = new KeyValuePair<bool, bool>(true, true);
 
-        // MPN attach upper prop
-        var hasKousokuUpper = reader.ReadBoolean();
-        var upperMenuFile = reader.ReadString();
+            if (metadata.MMConverted)
+                meido.IKManager.Deserialize(reader);
+            else
+            {
+                var poseBufferLength = reader.ReadInt32();
+                var poseBuffer = reader.ReadBytes(poseBufferLength);
 
-        if (hasKousokuUpper)
-            meido.SetMpnProp(new MpnAttachProp(MPN.kousoku_upper, upperMenuFile), false);
+                muneSetting = meido.SetFrameBinary(poseBuffer);
+            }
 
-        // MPN attach lower prop
-        var hasKousokuLower = reader.ReadBoolean();
-        var lowerMenuFile = reader.ReadString();
+            var poseInfo = PoseInfoSerializer.Deserialize(reader, metadata);
 
-        if (hasKousokuLower)
-            meido.SetMpnProp(new MpnAttachProp(MPN.kousoku_lower, lowerMenuFile), false);
+            Utility.SetPropertyValue(meido, nameof(Meido.CachedPose), poseInfo);
 
-        // hair gravity
-        var hairGravityActive = reader.ReadBoolean();
-        var hairPosition = reader.ReadVector3();
+            meido.SetMune(!muneSetting.Key, true);
+            meido.SetMune(!muneSetting.Value);
 
-        meido.HairGravityActive = hairGravityActive;
+            if (version < 2)
+                return;
 
-        if (meido.HairGravityActive)
-            meido.ApplyGravity(hairPosition);
+            var muneLSubRotation = reader.ReadQuaternion();
+            var muneSubRRotation = reader.ReadQuaternion();
 
-        // skirt gravity
-        var skirtGravityActive = reader.ReadBoolean();
-        var skirtPosition = reader.ReadVector3();
+            var body = meido.Body;
 
-        meido.SkirtGravityActive = skirtGravityActive;
+            if (muneSetting.Key)
+                body.GetBone("Mune_L_sub").localRotation = muneLSubRotation;
 
-        if (meido.SkirtGravityActive)
-            meido.ApplyGravity(skirtPosition, true);
-    }
+            if (muneSetting.Value)
+                body.GetBone("Mune_R_sub").localRotation = muneSubRRotation;
+        }
 
-    public override void Serialize(Meido meido, BinaryWriter writer)
-    {
-        var maid = meido.Maid;
+        static void DeserializeClothing(Meido meido, BinaryReader reader, SceneMetadata metadata)
+        {
+            var body = meido.Body;
 
-        using var memoryStream = new MemoryStream();
-        using var tempWriter = new BinaryWriter(memoryStream, Encoding.UTF8);
+            _ = reader.ReadVersion();
 
-        tempWriter.WriteVersion(version);
+            meido.SetBodyMask(reader.ReadBoolean());
 
-        TransformDtoSerializer.Serialize(new TransformDTO(maid.transform), tempWriter);
+            foreach (var clothingSlot in MaidDressingPane.ClothingSlots)
+            {
+                var value = reader.ReadBoolean();
+
+                if (metadata.MMConverted)
+                    continue;
+
+                if (clothingSlot is TBody.SlotID.wear)
+                {
+                    body.SetMask(TBody.SlotID.wear, value);
+                    body.SetMask(TBody.SlotID.mizugi, value);
+                    body.SetMask(TBody.SlotID.onepiece, value);
+                }
+                else if (clothingSlot is TBody.SlotID.megane)
+                {
+                    body.SetMask(TBody.SlotID.megane, value);
+                    body.SetMask(TBody.SlotID.accHead, value);
+                }
+                else if (body.GetSlotLoaded(clothingSlot))
+                    body.SetMask(clothingSlot, value);
+            }
 
-        SerializeHead(meido, tempWriter);
+            // zurashi and mekure
+            var curlingFront = reader.ReadBoolean();
+            var curlingBack = reader.ReadBoolean();
+            var curlingPantsu = reader.ReadBoolean();
 
-        SerializeBody(meido, tempWriter);
+            if (!metadata.MMConverted)
+            {
+                if (meido.CurlingFront != curlingFront)
+                    meido.SetCurling(Meido.Curl.Front, curlingFront);
 
-        SerializeClothing(meido, tempWriter);
+                if (meido.CurlingBack != curlingBack)
+                    meido.SetCurling(Meido.Curl.Back, curlingBack);
 
-        writer.Write(memoryStream.Length);
-        writer.Write(memoryStream.ToArray());
-    }
+                meido.SetCurling(Meido.Curl.Shift, curlingPantsu);
+            }
 
-    public override void Deserialize(Meido meido, BinaryReader reader, SceneMetadata metadata)
-    {
-        var maid = meido.Maid;
+            // MPN attach upper prop
+            var hasKousokuUpper = reader.ReadBoolean();
+            var upperMenuFile = reader.ReadString();
 
-        maid.GetAnimation().Stop();
-        meido.DetachAllMpnAttach();
-        meido.StopBlink();
+            if (hasKousokuUpper)
+                meido.SetMpnProp(new MpnAttachProp(MPN.kousoku_upper, upperMenuFile), false);
 
-        reader.ReadInt64(); // data length
+            // MPN attach lower prop
+            var hasKousokuLower = reader.ReadBoolean();
+            var lowerMenuFile = reader.ReadString();
 
-        _ = reader.ReadVersion();
+            if (hasKousokuLower)
+                meido.SetMpnProp(new MpnAttachProp(MPN.kousoku_lower, lowerMenuFile), false);
 
-        var transformDto = TransformDtoSerializer.Deserialize(reader, metadata);
-        var maidTransform = maid.transform;
+            // hair gravity
+            var hairGravityActive = reader.ReadBoolean();
+            var hairPosition = reader.ReadVector3();
 
-        // TODO: use transform.SetRotationAndPosition
-        maidTransform.position = transformDto.Position;
-        maidTransform.rotation = transformDto.Rotation;
-        maidTransform.localScale = transformDto.LocalScale;
+            meido.HairGravityActive = hairGravityActive;
 
-        meido.IKManager.SetDragPointScale(maidTransform.localScale.x);
+            if (meido.HairGravityActive)
+                meido.ApplyGravity(hairPosition);
 
-        DeserializeHead(meido, reader, metadata);
+            // skirt gravity
+            var skirtGravityActive = reader.ReadBoolean();
+            var skirtPosition = reader.ReadVector3();
 
-        DeserializeBody(meido, reader, metadata);
+            meido.SkirtGravityActive = skirtGravityActive;
 
-        DeserializeClothing(meido, reader, metadata);
+            if (meido.SkirtGravityActive)
+                meido.ApplyGravity(skirtPosition, true);
+        }
     }
 }

+ 1 - 0
src/MeidoPhotoStudio.Plugin/Serialization/SimpleSerializers/DragPointPropDTOSerializer.cs

@@ -42,6 +42,7 @@ public class DragPointPropDTOSerializer : SimpleSerializer<DragPointPropDTO>
     }
 }
 
+// TODO: Extract other classes to another file
 public class DragPointPropDTO
 {
     public TransformDTO TransformDTO { get; set; }

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

@@ -15,12 +15,12 @@ public static class Translation
     private static readonly ConfigEntry<string> currentLanguage;
     private static readonly ConfigEntry<bool> suppressWarnings;
 
+    public static event EventHandler ReloadTranslationEvent;
+
     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;

+ 32 - 32
src/MeidoPhotoStudio.Plugin/Utility.cs

@@ -19,12 +19,6 @@ public static class Utility
     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 =
@@ -32,6 +26,12 @@ public static class Utility
     internal static readonly GameObject mousePositionGo;
     internal static readonly MousePosition mousePosition;
 
+    public static string Timestamp =>
+        $"{DateTime.Now:yyyyMMddHHmmss}";
+
+    public static Vector3 MousePosition =>
+        mousePosition.Position;
+
     static Utility()
     {
         mousePositionGo = new();
@@ -255,32 +255,6 @@ public static class Utility
         File.WriteAllBytes(Path.Combine(Constants.configPath, name), data);
 }
 
-public class MousePosition : MonoBehaviour
-{
-    public Vector3 Position =>
-        mousePosition;
-
-    private Vector3 mousePosition;
-
-    private void Awake()
-    {
-        DontDestroyOnLoad(this);
-
-        mousePosition = Input.mousePosition;
-    }
-
-    private void Update()
-    {
-        if (Input.GetMouseButton(0))
-        {
-            mousePosition.x += Input.GetAxis("Mouse X") * 20;
-            mousePosition.y += Input.GetAxis("Mouse Y") * 20;
-        }
-        else
-            mousePosition = Input.mousePosition;
-    }
-}
-
 public static class KeyValuePairExtensions
 {
     public static void Deconstruct<TKey, TValue>(this KeyValuePair<TKey, TValue> kvp, out TKey key, out TValue value)
@@ -447,3 +421,29 @@ public static class BinaryExtensions
         return matrix;
     }
 }
+
+public class MousePosition : MonoBehaviour
+{
+    private Vector3 mousePosition;
+
+    public Vector3 Position =>
+        mousePosition;
+
+    private void Awake()
+    {
+        DontDestroyOnLoad(this);
+
+        mousePosition = Input.mousePosition;
+    }
+
+    private void Update()
+    {
+        if (Input.GetMouseButton(0))
+        {
+            mousePosition.x += Input.GetAxis("Mouse X") * 20;
+            mousePosition.y += Input.GetAxis("Mouse Y") * 20;
+        }
+        else
+            mousePosition = Input.mousePosition;
+    }
+}