Jelajahi Sumber

"Rewrite" meido related stuff

habeebweeb 4 tahun lalu
induk
melakukan
4aee71f02a
22 mengubah file dengan 323 tambahan dan 389 penghapusan
  1. 3 3
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/DragPoint/DragPointMeido.cs
  2. 1 1
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/BackgroundWindow2Panes/AttachPropPane.cs
  3. 2 2
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/CallWindowPanes/MaidSelectorPane.cs
  4. 3 8
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/MainWindowPanes/PoseWindowPane.cs
  5. 8 7
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/OtherPanes/MaidSwitcherPane.cs
  6. 2 2
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/PoseWindowPanes/CopyPosePane.cs
  7. 17 42
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/PoseWindowPanes/MaidDressingPane.cs
  8. 2 4
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/PoseWindowPanes/MaidFreeLookPane.cs
  9. 7 7
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/PoseWindowPanes/MaidIKPane.cs
  10. 1 1
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/PoseWindowPanes/MaidPoseSelectorPane.cs
  11. 1 1
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/PoseWindowPanes/SaveHandPane.cs
  12. 51 61
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Managers/MeidoManager.cs
  13. 3 2
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Managers/PropManager.cs
  14. 1 1
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/IK/DragPointChain.cs
  15. 1 1
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/IK/DragPointFinger.cs
  16. 2 2
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/IK/DragPointHead.cs
  17. 1 1
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/IK/DragPointPelvis.cs
  18. 1 1
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/IK/DragPointSpine.cs
  19. 1 1
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/IK/DragPointTorso.cs
  20. 184 205
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/Meido.cs
  21. 27 32
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/MeidoDragPointManager.cs
  22. 4 4
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/MeidoPhotoStudio.cs

+ 3 - 3
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/DragPoint/DragPointMeido.cs

@@ -31,7 +31,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             base.Initialize(position, rotation);
             this.meido = meido;
             this.maid = meido.Maid;
-            this.isPlaying = !meido.IsStop;
+            this.isPlaying = !meido.Stop;
         }
 
         public override void AddGizmo(float scale = 0.25f, GizmoMode mode = GizmoMode.Local)
@@ -39,7 +39,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             base.AddGizmo(scale, mode);
             Gizmo.GizmoDrag += (s, a) =>
             {
-                meido.IsStop = true;
+                meido.Stop = true;
                 isPlaying = false;
             };
         }
@@ -47,7 +47,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         protected override void OnMouseDown()
         {
             base.OnMouseDown();
-            isPlaying = !meido.IsStop;
+            isPlaying = !meido.Stop;
         }
 
         protected void InitializeIK(TBody.IKCMO iKCmo, Transform upper, Transform middle, Transform lower)

+ 1 - 1
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/BackgroundWindow2Panes/AttachPropPane.cs

@@ -225,7 +225,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             string[] dropdownList = this.meidoManager.ActiveMeidoList.Count == 0
                 ? new[] { Translation.Get("systemMessage", "noMaids") }
                 : this.meidoManager.ActiveMeidoList.Select(
-                    meido => $"{meido.ActiveSlot + 1}: {meido.FirstName} {meido.LastName}"
+                    meido => $"{meido.Slot + 1}: {meido.FirstName} {meido.LastName}"
                 ).ToArray();
             this.updating = true;
             this.meidoDropdown.SetDropdownItems(dropdownList, index);

+ 2 - 2
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/CallWindowPanes/MaidSelectorPane.cs

@@ -70,10 +70,10 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
                     );
                 }
 
-                GUI.DrawTexture(new Rect(5, y, buttonHeight, buttonHeight), meido.Image);
+                GUI.DrawTexture(new Rect(5, y, buttonHeight, buttonHeight), meido.Portrait);
                 GUI.Label(
                     new Rect(95, y + 30, buttonWidth - 80, buttonHeight),
-                    meido.NameJP, selectedMaid ? labelSelectedStyle : labelStyle
+                    $"{meido.LastName}\n{meido.FirstName}", selectedMaid ? labelSelectedStyle : labelStyle
                 );
 
             }

+ 3 - 8
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/MainWindowPanes/PoseWindowPane.cs

@@ -57,7 +57,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             this.saveHandPane = AddPane(new SaveHandPane(meidoManager));
 
             this.flipButton = new Button(Translation.Get("flipIK", "flipButton"));
-            this.flipButton.ControlEvent += (s, a) => this.meidoManager.ActiveMeido.Flip();
+            this.flipButton.ControlEvent += (s, a) => this.meidoManager.ActiveMeido.IKManager.Flip();
 
             this.handPresetHeader = Translation.Get("handPane", "header");
             this.flipIKHeader = Translation.Get("flipIK", "header");
@@ -119,7 +119,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         private void SetMaidFreeLook()
         {
             if (this.updating) return;
-            this.meidoManager.ActiveMeido.IsFreeLook = this.freeLookToggle.Value;
+            this.meidoManager.ActiveMeido.FreeLook = this.freeLookToggle.Value;
         }
 
         public override void UpdatePanes()
@@ -129,15 +129,10 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             if (ActiveWindow)
             {
                 this.updating = true;
-                this.freeLookToggle.Value = this.meidoManager.ActiveMeido?.IsFreeLook ?? false;
+                this.freeLookToggle.Value = this.meidoManager.ActiveMeido?.FreeLook ?? false;
                 this.updating = false;
                 base.UpdatePanes();
             }
         }
-
-        private void UpdateMeido(object sender, EventArgs args)
-        {
-            this.UpdatePanes();
-        }
     }
 }

+ 8 - 7
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/OtherPanes/MaidSwitcherPane.cs

@@ -34,18 +34,19 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             PreviousButton.Draw(buttonStyle, GUILayout.Height(40), GUILayout.ExpandWidth(false));
 
             if (meidoManager.HasActiveMeido)
-                MiscGUI.DrawTexture(meidoManager.ActiveMeido.Image, GUILayout.Width(70), GUILayout.Height(70));
+                MiscGUI.DrawTexture(meidoManager.ActiveMeido.Portrait, GUILayout.Width(70), GUILayout.Height(70));
             else
                 GUILayout.Box("", boxStyle, GUILayout.Height(70), GUILayout.Width(70));
 
             GUILayout.BeginVertical();
             GUILayout.Space(30);
-            GUILayout.Label(
-                meidoManager.HasActiveMeido
-                    ? meidoManager.ActiveMeido.NameJP
-                    : "",
-                labelStyle, GUILayout.ExpandWidth(false)
-            );
+            string label = "";
+            if (meidoManager.HasActiveMeido)
+            {
+                Meido meido = meidoManager.ActiveMeido;
+                label = $"{meido.LastName}\n{meido.FirstName}";
+            }
+            GUILayout.Label(label, labelStyle, GUILayout.ExpandWidth(false));
             GUILayout.EndVertical();
 
             NextButton.Draw(buttonStyle, GUILayout.Height(40), GUILayout.ExpandWidth(false));

+ 2 - 2
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/PoseWindowPanes/CopyPosePane.cs

@@ -71,9 +71,9 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             if (this.meidoManager.ActiveMeidoList.Count >= 2)
             {
                 IEnumerable<Meido> copyMeidoList = this.meidoManager.ActiveMeidoList
-                    .Where(meido => meido.ActiveSlot != this.meidoManager.ActiveMeido.ActiveSlot);
+                    .Where(meido => meido.Slot != this.meidoManager.ActiveMeido.Slot);
 
-                copyMeidoSlot = copyMeidoList.Select(meido => meido.ActiveSlot).ToArray();
+                copyMeidoSlot = copyMeidoList.Select(meido => meido.Slot).ToArray();
 
                 string[] dropdownList = copyMeidoList
                     .Select((meido, i) => $"{copyMeidoSlot[i] + 1}: {meido.LastName} {meido.FirstName}").ToArray();

+ 17 - 42
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/PoseWindowPanes/MaidDressingPane.cs

@@ -9,11 +9,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         private MeidoManager meidoManager;
         private Dictionary<SlotID, Toggle> ClothingToggles;
         private Dictionary<SlotID, bool> LoadedSlots;
-        public enum Curl
-        {
-            front, back, shift
-        }
-        private static readonly SlotID[] clothingSlots = {
+        public static readonly SlotID[] clothingSlots = {
             // main slots
             SlotID.wear, SlotID.skirt, SlotID.bra, SlotID.panz, SlotID.headset, SlotID.megane,
             SlotID.accUde, SlotID.glove, SlotID.accSenaka, SlotID.stkg, SlotID.shoes, SlotID.body,
@@ -25,18 +21,15 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             // 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
         };
-
-        private static readonly SlotID[] wearSlots = {
+        public static readonly SlotID[] wearSlots = {
             SlotID.wear, SlotID.mizugi, SlotID.onepiece
         };
-
-        private static readonly SlotID[] headwearSlots = {
+        public static readonly SlotID[] headwearSlots = {
             SlotID.headset, SlotID.accHat, SlotID.accKamiSubL,
             SlotID.accKamiSubR, SlotID.accKami_1_, SlotID.accKami_2_, SlotID.accKami_3_
         };
@@ -65,11 +58,11 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             detailedClothingToggle.ControlEvent += (s, a) => UpdateDetailedClothing();
 
             curlingFrontToggle = new Toggle(Translation.Get("clothing", "curlingFront"));
-            curlingFrontToggle.ControlEvent += (s, a) => ToggleCurling(Curl.front, curlingFrontToggle.Value);
+            curlingFrontToggle.ControlEvent += (s, a) => ToggleCurling(Meido.Curl.front, curlingFrontToggle.Value);
             curlingBackToggle = new Toggle(Translation.Get("clothing", "curlingBack"));
-            curlingBackToggle.ControlEvent += (s, a) => ToggleCurling(Curl.back, curlingBackToggle.Value);
+            curlingBackToggle.ControlEvent += (s, a) => ToggleCurling(Meido.Curl.back, curlingBackToggle.Value);
             pantsuShiftToggle = new Toggle(Translation.Get("clothing", "shiftPanties"));
-            pantsuShiftToggle.ControlEvent += (s, a) => ToggleCurling(Curl.shift, pantsuShiftToggle.Value);
+            pantsuShiftToggle.ControlEvent += (s, a) => ToggleCurling(Meido.Curl.shift, pantsuShiftToggle.Value);
 
             UpdateDetailedClothing();
         }
@@ -137,38 +130,25 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             }
         }
 
-        public void ToggleCurling(Curl curl, bool enabled)
+        public void ToggleCurling(Meido.Curl curl, bool enabled)
         {
             if (updating) return;
-            Maid maid = this.meidoManager.ActiveMeido.Maid;
-            string[] name = curl == Curl.shift
-                ? new[] { "panz", "mizugi" }
-                : new[] { "skirt", "onepiece" };
+
+            this.meidoManager.ActiveMeido.SetCurling(curl, enabled);
+
             if (enabled)
             {
-                string action = curl == Curl.shift
-                    ? "パンツずらし"
-                    : curl == Curl.front
-                        ? "めくれスカート" : "めくれスカート後ろ";
-                maid.ItemChangeTemp(name[0], action);
-                maid.ItemChangeTemp(name[1], action);
                 this.updating = true;
-                if (curl == Curl.front && curlingBackToggle.Value)
+                if (curl == Meido.Curl.front && curlingBackToggle.Value)
                 {
                     curlingBackToggle.Value = false;
                 }
-                else if (curl == Curl.back && curlingFrontToggle.Value)
+                else if (curl == Meido.Curl.back && curlingFrontToggle.Value)
                 {
                     curlingFrontToggle.Value = false;
                 }
                 this.updating = false;
             }
-            else
-            {
-                maid.ResetProp(name[0]);
-                maid.ResetProp(name[1]);
-            }
-            maid.AllProcProp();
         }
 
         public override void UpdatePane()
@@ -177,8 +157,8 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
 
             this.updating = true;
 
-            Maid maid = this.meidoManager.ActiveMeido.Maid;
-            TBody body = maid.body0;
+            Meido meido = this.meidoManager.ActiveMeido;
+            TBody body = meido.Maid.body0;
             foreach (SlotID clothingSlot in clothingSlots)
             {
                 bool toggleValue = false;
@@ -216,14 +196,9 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
                 LoadedSlots[clothingSlot] = hasSlot;
             }
 
-            curlingFrontToggle.Value = maid.IsItemChange("skirt", "めくれスカート")
-                || maid.IsItemChange("onepiece", "めくれスカート");
-
-            curlingBackToggle.Value = maid.IsItemChange("skirt", "めくれスカート後ろ")
-                || maid.IsItemChange("onepiece", "めくれスカート後ろ");
-
-            pantsuShiftToggle.Value = maid.IsItemChange("panz", "パンツずらし")
-                || maid.IsItemChange("mizugi", "パンツずらし");
+            curlingFrontToggle.Value = meido.CurlingFront;
+            curlingBackToggle.Value = meido.CurlingBack;
+            pantsuShiftToggle.Value = meido.PantsuShift;
 
             this.updating = false;
         }

+ 2 - 4
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/PoseWindowPanes/MaidFreeLookPane.cs

@@ -11,8 +11,6 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         public MaidFaceLookPane(MeidoManager meidoManager)
         {
             this.meidoManager = meidoManager;
-            // this.meidoManager.AnimeChange += (s, a) => SetBounds();
-
             this.lookXSlider = new Slider(Translation.Get("freeLook", "x"), -0.6f, 0.6f);
             this.lookXSlider.ControlEvent += (s, a) => SetMaidLook();
 
@@ -39,7 +37,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         {
             float left = 0.5f;
             float right = -0.55f;
-            if (this.meidoManager.ActiveMeido.IsStop)
+            if (this.meidoManager.ActiveMeido.Stop)
             {
                 left *= 0.6f;
                 right *= 0.6f;
@@ -59,7 +57,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
 
         public override void Draw()
         {
-            GUI.enabled = this.meidoManager.HasActiveMeido && this.meidoManager.ActiveMeido.IsFreeLook;
+            GUI.enabled = this.meidoManager.HasActiveMeido && this.meidoManager.ActiveMeido.FreeLook;
             GUILayout.BeginHorizontal();
             lookXSlider.Draw();
             lookYSlider.Draw();

+ 7 - 7
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/PoseWindowPanes/MaidIKPane.cs

@@ -37,17 +37,17 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         private void SetIK(IKToggle toggle, bool value)
         {
             if (updating) return;
-            if (toggle == IKToggle.IK) this.meidoManager.ActiveMeido.IsIK = value;
-            else if (toggle == IKToggle.Release) this.meidoManager.ActiveMeido.IsStop = false;
-            else if (toggle == IKToggle.Bone) this.meidoManager.ActiveMeido.IsBone = value;
+            if (toggle == IKToggle.IK) this.meidoManager.ActiveMeido.IK = value;
+            else if (toggle == IKToggle.Release) this.meidoManager.ActiveMeido.Stop = false;
+            else if (toggle == IKToggle.Bone) this.meidoManager.ActiveMeido.Bone = value;
         }
 
         public override void UpdatePane()
         {
             this.updating = true;
-            this.ikToggle.Value = this.meidoManager.ActiveMeido.IsIK;
-            this.releaseIKToggle.Value = this.meidoManager.ActiveMeido.IsStop;
-            this.boneIKToggle.Value = this.meidoManager.ActiveMeido.IsBone;
+            this.ikToggle.Value = this.meidoManager.ActiveMeido.IK;
+            this.releaseIKToggle.Value = this.meidoManager.ActiveMeido.Stop;
+            this.boneIKToggle.Value = this.meidoManager.ActiveMeido.Bone;
             this.updating = false;
         }
 
@@ -59,7 +59,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             GUI.enabled = active;
             this.ikToggle.Draw();
 
-            GUI.enabled = active ? this.meidoManager.ActiveMeido.IsStop : false;
+            GUI.enabled = active ? this.meidoManager.ActiveMeido.Stop : false;
             this.releaseIKToggle.Draw();
 
             GUI.enabled = active ? this.ikToggle.Value : false;

+ 1 - 1
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/PoseWindowPanes/MaidPoseSelectorPane.cs

@@ -91,7 +91,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
                 GUILayout.Width(dropdownButtonWidth)
             };
 
-            GUI.enabled = meidoManager.HasActiveMeido && !meidoManager.ActiveMeido.IsStop;
+            GUI.enabled = meidoManager.HasActiveMeido && !meidoManager.ActiveMeido.Stop;
 
             this.poseModeGrid.Draw();
             MiscGUI.WhiteLine();

+ 1 - 1
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/PoseWindowPanes/SaveHandPane.cs

@@ -64,7 +64,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
 
         private void SaveHand(bool right)
         {
-            byte[] handBinary = this.meidoManager.ActiveMeido.SerializeHand(right);
+            byte[] handBinary = this.meidoManager.ActiveMeido.IKManager.SerializeHand(right);
             Constants.AddHand(handBinary, right, this.handNameTextField.Value, this.categoryComboBox.Value);
             this.handNameTextField.Value = string.Empty;
         }

+ 51 - 61
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Managers/MeidoManager.cs

@@ -22,19 +22,9 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         public int SelectedMeido
         {
             get => selectedMeido;
-            private set => selectedMeido = Mathf.Clamp(value, 0, ActiveMeidoList.Count - 1);
-        }
-        public bool IsBusy
-        {
-            get
-            {
-                foreach (Meido meido in ActiveMeidoList)
-                {
-                    if (meido.Maid.IsBusy) return true;
-                }
-                return false;
-            }
+            private set => selectedMeido = Utility.Bound(value, 0, ActiveMeidoList.Count - 1);
         }
+        public bool Busy => ActiveMeidoList.Any(meido => meido.Busy);
 
         public void ChangeMaid(int index)
         {
@@ -67,57 +57,70 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         public void Update()
         {
             if (Input.GetKeyDown(KeyCode.H)) UndressAll();
+        }
 
-            foreach (Meido activeMeido in ActiveMeidoList)
+        private void UnloadMeidos()
+        {
+            SelectedMeido = 0;
+            foreach (Meido meido in ActiveMeidoList)
             {
-                activeMeido.Update();
+                meido.UpdateMeido -= OnUpdateMeido;
+                meido.Unload();
             }
+            ActiveMeidoList.Clear();
         }
 
         public void CallMeidos()
         {
             this.BeginCallMeidos?.Invoke(this, EventArgs.Empty);
-            GameMain.Instance.MainCamera.FadeOut(0.01f, false, () =>
+
+            bool hadActiveMeidos = HasActiveMeido;
+
+            UnloadMeidos();
+
+            if (SelectMeidoList.Count == 0)
             {
-                UnloadMeidos();
-
-                foreach (int slot in this.SelectMeidoList)
-                {
-                    Meido meido = meidos[slot];
-                    ActiveMeidoList.Add(meido);
-                    meido.BodyLoad += OnEndCallMeidos;
-                    meido.UpdateMeido += OnUpdateMeido;
-                }
-
-                for (int i = 0; i < ActiveMeidoList.Count; i++)
-                {
-                    Meido meido = ActiveMeidoList[i];
-                    meido.Load(i, this.SelectMeidoList[i]);
-                }
-
-                SelectedMeido = 0;
-
-                if (this.SelectMeidoList.Count == 0) OnEndCallMeidos(this, EventArgs.Empty);
-            }, false);
+                if (hadActiveMeidos) OnEndCallMeidos(this, EventArgs.Empty);
+                return;
+            }
+
+            GameMain.Instance.MainCamera.FadeOut(0.01f, f_bSkipable: false, f_dg: () =>
+            {
+                GameMain.Instance.StartCoroutine(LoadMeidos());
+            });
         }
 
-        public Meido GetMeido(string guid)
+        private System.Collections.IEnumerator LoadMeidos()
         {
-            foreach (Meido meido in ActiveMeidoList)
+            foreach (int slot in this.SelectMeidoList)
             {
-                if (meido.Maid.status.guid == guid) return meido;
+                Meido meido = meidos[slot];
+                ActiveMeidoList.Add(meido);
+                meido.BeginLoad();
             }
 
-            return null;
+            for (int i = 0; i < ActiveMeidoList.Count; i++)
+            {
+                ActiveMeidoList[i].Load(i);
+            }
+
+            while (Busy) yield return null;
+
+            yield return new WaitForEndOfFrame();
+
+            OnEndCallMeidos(this, EventArgs.Empty);
+        }
+
+        public Meido GetMeido(string guid)
+        {
+            if (string.IsNullOrEmpty(guid)) return null;
+            else return ActiveMeidoList.FirstOrDefault(meido => meido.Maid.status.guid == guid);
         }
 
         public Meido GetMeido(int activeIndex)
         {
-            if (activeIndex >= 0 && activeIndex < ActiveMeidoList.Count)
-            {
-                return ActiveMeidoList[activeIndex];
-            }
-            return null;
+            if (activeIndex >= 0 && activeIndex < ActiveMeidoList.Count) return ActiveMeidoList[activeIndex];
+            else return null;
         }
 
         private void UndressAll()
@@ -140,16 +143,6 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             this.UpdateMeido?.Invoke(ActiveMeido, new MeidoUpdateEventArgs(SelectedMeido));
         }
 
-        private void UnloadMeidos()
-        {
-            foreach (Meido meido in ActiveMeidoList)
-            {
-                meido.UpdateMeido -= OnUpdateMeido;
-                meido.Unload();
-            }
-            ActiveMeidoList.Clear();
-        }
-
         private void OnUpdateMeido(object sender, MeidoUpdateEventArgs args)
         {
             if (!args.IsEmpty) this.SelectedMeido = args.SelectedMeido;
@@ -158,14 +151,11 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
 
         private void OnEndCallMeidos(object sender, EventArgs args)
         {
-            if (!IsBusy)
+            GameMain.Instance.MainCamera.FadeIn(1f);
+            EndCallMeidos?.Invoke(this, EventArgs.Empty);
+            foreach (Meido meido in ActiveMeidoList)
             {
-                GameMain.Instance.MainCamera.FadeIn(1f);
-                EndCallMeidos?.Invoke(this, EventArgs.Empty);
-                foreach (Meido meido in ActiveMeidoList)
-                {
-                    meido.BodyLoad -= OnEndCallMeidos;
-                }
+                meido.UpdateMeido += OnUpdateMeido;
             }
         }
     }

+ 3 - 2
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Managers/PropManager.cs

@@ -283,12 +283,13 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         {
             GameObject dogu = dragDogu.MyGameObject;
 
-            Transform attachPointTransform = meido?.GetBoneTransform(attachPoint) ?? GetDeploymentObject().transform;
+            Transform attachPointTransform = meido?.IKManager.GetAttachPointTransform(attachPoint)
+                ?? GetDeploymentObject().transform;
 
             dragDogu.attachPointInfo = new AttachPointInfo(
                 attachPoint: meido == null ? AttachPoint.None : attachPoint,
                 maidGuid: meido == null ? String.Empty : meido.Maid.status.guid,
-                maidIndex: meido == null ? -1 : meido.ActiveSlot
+                maidIndex: meido == null ? -1 : meido.Slot
             );
 
             worldPositionStays = meido == null ? true : worldPositionStays;

+ 1 - 1
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/IK/DragPointChain.cs

@@ -115,7 +115,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
 
         protected override void Drag()
         {
-            if (isPlaying) meido.IsStop = true;
+            if (isPlaying) meido.Stop = true;
 
             bool altRotation = CurrentDragType == DragType.MoveXZ || CurrentDragType == DragType.RotY;
 

+ 1 - 1
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/IK/DragPointFinger.cs

@@ -65,7 +65,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
 
         protected override void Drag()
         {
-            if (isPlaying) meido.IsStop = true;
+            if (isPlaying) meido.Stop = true;
 
             if (CurrentDragType == DragType.MoveXZ)
             {

+ 2 - 2
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/IK/DragPointHead.cs

@@ -73,7 +73,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             }
             else if (CurrentDragType == DragType.RotLocalY || CurrentDragType == DragType.RotLocalXZ)
             {
-                meido.IsFreeLook = !meido.IsFreeLook;
+                meido.FreeLook = !meido.FreeLook;
             }
         }
 
@@ -83,7 +83,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
 
             if (!(CurrentDragType == DragType.MoveXZ || CurrentDragType == DragType.MoveY))
             {
-                if (isPlaying) meido.IsStop = true;
+                if (isPlaying) meido.Stop = true;
             }
 
             Vector3 mouseDelta = MouseDelta();

+ 1 - 1
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/IK/DragPointPelvis.cs

@@ -40,7 +40,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         {
             if (CurrentDragType == DragType.None) return;
 
-            if (isPlaying) meido.IsStop = true;
+            if (isPlaying) meido.Stop = true;
 
             Vector3 mouseDelta = MouseDelta();
 

+ 1 - 1
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/IK/DragPointSpine.cs

@@ -69,7 +69,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
 
         protected override void Drag()
         {
-            if (isPlaying) meido.IsStop = true;
+            if (isPlaying) meido.Stop = true;
 
             if (CurrentDragType == DragType.None)
             {

+ 1 - 1
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/IK/DragPointTorso.cs

@@ -57,7 +57,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         {
             if (CurrentDragType == DragType.None) return;
 
-            if (isPlaying) meido.IsStop = true;
+            if (isPlaying) meido.Stop = true;
 
             Vector3 mouseDelta = MouseDelta();
 

+ 184 - 205
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/Meido.cs

@@ -1,16 +1,20 @@
 using System;
-using System.Collections;
 using System.IO;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
 using System.Xml.Linq;
 using UnityEngine;
+using static TBody;
 
 namespace COM3D2.MeidoPhotoStudio.Plugin
 {
     internal class Meido
     {
-        private const int MAX_MAIDS = 12;
-        private static CharacterMgr characterMgr = GameMain.Instance.CharacterMgr;
-        public readonly int stockNo;
+        private const int maxMaids = 12;
+        public static readonly PoseInfo DefaultPose =
+            new PoseInfo(Constants.PoseGroupList[0], Constants.PoseDict[Constants.PoseGroupList[0]][0]);
+        public static readonly string defaultFaceBlendSet = "通常";
         public static readonly string[] faceKeys = new string[24]
         {
             "eyeclose", "eyeclose2", "eyeclose3", "eyebig", "eyeclose6", "eyeclose5", "hitomih",
@@ -26,44 +30,52 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             // cry 1, cry 2, cry 3, blush 1, blush 2, blush 3
             "tear1", "tear2", "tear3", "hohos", "hoho", "hohol"
         };
-        public static readonly PoseInfo defaultPose
-            = new PoseInfo(Constants.PoseGroupList[0], Constants.PoseDict[Constants.PoseGroupList[0]][0]);
-        public static readonly string defaultFaceBlendSet = "通常";
-        private MeidoDragPointManager dragPointManager;
-        private bool initialized = false;
-        public Maid Maid { get; private set; }
-        public Texture2D Image { get; private set; }
-        public string FirstName { get; private set; }
-        public string LastName { get; private set; }
-        public string NameJP => $"{LastName}\n{FirstName}";
-        public string NameEN => $"{FirstName}\n{LastName}";
-        public Quaternion DefaultEyeRotL { get; private set; }
-        public Quaternion DefaultEyeRotR { get; private set; }
-        public int ActiveSlot { get; private set; }
+        public enum Curl
+        {
+            front, back, shift
+        }
+        private bool initialized;
         public event EventHandler<MeidoUpdateEventArgs> UpdateMeido;
-        public event EventHandler BodyLoad;
-        private bool isLoading = false;
-        public float[] BlendValuesBackup { get; private set; }
-        public float[] BlendValues { get; private set; }
-        public bool IsIK
+        public int StockNo { get; }
+        public Maid Maid { get; private set; }
+        public TBody Body => Maid.body0;
+        public MeidoDragPointManager IKManager { get; private set; }
+        public Texture2D Portrait { get; private set; }
+        public PoseInfo CachedPose { get; private set; } = DefaultPose;
+        public string FaceBlendSet { get; private set; } = defaultFaceBlendSet;
+        public int Slot { get; private set; }
+        public bool Loading { get; private set; }
+        public string FirstName => Maid.status.firstName;
+        public string LastName => Maid.status.lastName;
+        public bool Busy => Maid.IsBusy && Loading;
+        public bool CurlingFront => Maid.IsItemChange("skirt", "めくれスカート")
+            || Maid.IsItemChange("onepiece", "めくれスカート");
+        public bool CurlingBack => Maid.IsItemChange("skirt", "めくれスカート後ろ")
+            || Maid.IsItemChange("onepiece", "めくれスカート後ろ");
+        public bool PantsuShift => Maid.IsItemChange("panz", "パンツずらし")
+            || Maid.IsItemChange("mizugi", "パンツずらし");
+        private bool freeLook;
+        public bool FreeLook
         {
-            get => dragPointManager?.Active ?? false;
+            get => freeLook;
             set
             {
-                if (dragPointManager == null || value == dragPointManager.Active) return;
-                else dragPointManager.Active = value;
+                if (this.freeLook == value) return;
+                this.freeLook = value;
+                Body.trsLookTarget = this.freeLook ? null : GameMain.Instance.MainCamera.transform;
+                OnUpdateMeido();
             }
         }
-        public bool IsStop
+        public bool Stop
         {
             get
             {
-                if (!Maid.body0.isLoadedBody) return true;
+                if (!Body.isLoadedBody) return true;
                 else return !Maid.GetAnimation().isPlaying;
             }
             set
             {
-                if (!Maid.body0.isLoadedBody || value == !Maid.GetAnimation().isPlaying) return;
+                if (!Body.isLoadedBody || value == Stop) return;
                 else
                 {
                     if (value) Maid.GetAnimation().Stop();
@@ -72,160 +84,87 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
                 }
             }
         }
-        // private bool isBone = false;
-        public bool IsBone
+        public bool IK
         {
-            get => dragPointManager?.IsBone ?? false;
+            get => IKManager.Active;
             set
             {
-                if (dragPointManager == null || value == dragPointManager.IsBone) return;
-                else dragPointManager.IsBone = value;
-                OnUpdateMeido();
+                if (value == IKManager.Active) return;
+                else IKManager.Active = value;
             }
         }
-        private bool isFreeLook;
-        public bool IsFreeLook
+        public bool Bone
         {
-            get => isFreeLook;
+            get => IKManager.IsBone;
             set
             {
-                if (this.isFreeLook == value) return;
-                this.isFreeLook = value;
-                Maid.body0.trsLookTarget = this.isFreeLook ? null : GameMain.Instance.MainCamera.transform;
+                if (value == Bone) return;
+                else IKManager.IsBone = value;
                 OnUpdateMeido();
             }
         }
-        public PoseInfo CachedPose { get; private set; }
-        public string FaceBlendSet { get; private set; } = defaultFaceBlendSet;
+        public float[] BlendValuesBackup { get; private set; }
+        public float[] BlendValues { get; private set; }
+        public Quaternion DefaultEyeRotL { get; private set; }
+        public Quaternion DefaultEyeRotR { get; private set; }
 
         public Meido(int stockMaidIndex)
         {
-            this.Maid = characterMgr.GetStockMaid(stockMaidIndex);
-            this.stockNo = stockMaidIndex;
-            this.Image = Maid.GetThumIcon();
-            this.FirstName = Maid.status.firstName;
-            this.LastName = Maid.status.lastName;
-            this.CachedPose = defaultPose;
-            // I don't know why I put this here. Must've fixed something with proc loading
+            this.StockNo = stockMaidIndex;
+            this.Maid = GameMain.Instance.CharacterMgr.GetStockMaid(stockMaidIndex);
+            this.Portrait = Maid.GetThumIcon();
             Maid.boAllProcPropBUSY = false;
+            IKManager = new MeidoDragPointManager(this);
+            IKManager.SelectMaid += (s, args) => OnUpdateMeido((MeidoUpdateEventArgs)args);
         }
 
-        public void Update()
+        public void BeginLoad()
         {
-            if (isLoading)
-            {
-                if (!Maid.IsBusy)
-                {
-                    isLoading = false;
-                    OnBodyLoad();
-                }
-            }
-        }
-
-        public void Flip()
-        {
-            if (this.dragPointManager == null) return;
-            IsStop = true;
-            this.dragPointManager.Flip();
+            FreeLook = false;
+            Maid.Visible = true;
+            Body.boHeadToCam = true;
+            Body.boEyeToCam = true;
+            Body.SetBoneHitHeightY(-1000f);
         }
 
-        public byte[] SerializePose()
+        public void Load(int slot)
         {
-            CacheBoneDataArray cache = this.Maid.gameObject.GetComponent<CacheBoneDataArray>();
+            Slot = slot;
+            Loading = true;
 
-            if (cache == null)
+            if (!Body.isLoadedBody)
             {
-                cache = this.Maid.gameObject.AddComponent<CacheBoneDataArray>();
-                cache.CreateCache(this.Maid.body0.GetBone("Bip01"));
+                Maid.DutPropAll();
+                Maid.AllProcPropSeqStart();
             }
 
-            return cache.GetAnmBinary(true, true);
+            GameMain.Instance.StartCoroutine(Load());
         }
 
-        public void SetHandPreset(string filename, bool right)
+        private IEnumerator Load()
         {
-            if (this.dragPointManager == null) return;
-
-            XDocument handDocument = XDocument.Load(filename);
-            XElement handElement = handDocument.Element("FingerData");
-            if (handElement.IsEmpty || handElement.Element("GameVersion").IsEmpty
-                || handElement.Element("RightData").IsEmpty || handElement.Element("BinaryData").IsEmpty)
-            {
-                return;
-            }
-
-            IsStop = true;
-
-            bool rightData = bool.Parse(handElement.Element("RightData").Value);
-            string base64Data = handElement.Element("BinaryData").Value;
-
-            byte[] handData = Convert.FromBase64String(base64Data);
+            while (Maid.IsBusy) yield return null;
 
-            this.dragPointManager.DeserializeHand(handData, right, rightData != right);
-        }
-
-        public byte[] SerializeHand(bool right) => this.dragPointManager?.SerializeHand(right);
-
-        public Maid Load(int activeSlot, int maidSlot)
-        {
-            isLoading = true;
-            this.ActiveSlot = activeSlot;
-
-            Maid.Visible = true;
-
-            if (!Maid.body0.isLoadedBody)
-            {
-                if (maidSlot >= MAX_MAIDS)
-                {
-                    Maid.DutPropAll();
-                    Maid.AllProcPropSeqStart();
-                }
-                else
-                {
-                    GameMain.Instance.CharacterMgr.Activate(maidSlot, maidSlot, false, false);
-                    GameMain.Instance.CharacterMgr.CharaVisible(maidSlot, true, false);
-                }
-            }
-            else
-            {
-                SetPose(defaultPose);
-            }
-
-            dragPointManager = new MeidoDragPointManager(this);
-            dragPointManager.SelectMaid += OnMeidoSelect;
-
-            this.IsFreeLook = false;
-            Maid.body0.boHeadToCam = true;
-            Maid.body0.boEyeToCam = true;
-            Maid.body0.SetBoneHitHeightY(-1000f);
-
-            return Maid;
+            OnBodyLoad();
         }
 
         public void Unload()
         {
-            if (Maid.body0.isLoadedBody)
+            if (Body.isLoadedBody)
             {
-                Maid.body0.MuneYureL(1f);
-                Maid.body0.MuneYureR(1f);
-                Maid.body0.jbMuneL.enabled = true;
-                Maid.body0.jbMuneR.enabled = true;
-                Maid.body0.quaDefEyeL = DefaultEyeRotL;
-                Maid.body0.quaDefEyeR = DefaultEyeRotR;
+                Body.jbMuneL.enabled = true;
+                Body.jbMuneR.enabled = true;
             }
 
-            Maid.body0.SetMaskMode(TBody.MaskMode.None);
+            Body.MuneYureL(1f);
+            Body.MuneYureR(1f);
 
-            Maid.body0.trsLookTarget = GameMain.Instance.MainCamera.transform;
+            Body.SetMaskMode(MaskMode.None);
+            Body.SetBoneHitHeightY(0f);
 
             Maid.Visible = false;
 
-            if (dragPointManager != null)
-            {
-                dragPointManager.Destroy();
-                dragPointManager.SelectMaid -= OnMeidoSelect;
-                dragPointManager = null;
-            }
+            IKManager.Destroy();
         }
 
         public void Deactivate()
@@ -235,41 +174,44 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             Maid.SetPos(Vector3.zero);
             Maid.SetRot(Vector3.zero);
             Maid.SetPosOffset(Vector3.zero);
-            Maid.body0.SetBoneHitHeightY(0f);
+            Body.transform.localScale = Vector3.one;
 
             Maid.DelPrefabAll();
-
             Maid.ActiveSlotNo = -1;
         }
 
         public void SetPose(PoseInfo poseInfo)
         {
-            this.CachedPose = poseInfo;
+            CachedPose = poseInfo;
             SetPose(poseInfo.Pose);
         }
 
         public void SetPose(string pose)
         {
-            if (!Maid.body0.isLoadedBody) return;
+            if (!Body.isLoadedBody) return;
+
             if (pose.StartsWith(Constants.customPosePath))
             {
-                SetPoseCustom(pose);
-                return;
+                byte[] poseBuffer = File.ReadAllBytes(pose);
+                string hash = Path.GetFileName(pose).GetHashCode().ToString();
+                Body.CrossFade(hash, poseBuffer, loop: true, fade: 0f);
             }
+            else
+            {
+                string[] poseComponents = pose.Split(',');
+                pose = poseComponents[0] + ".anm";
 
-            string[] poseComponents = pose.Split(',');
-            pose = poseComponents[0] + ".anm";
-
-            Maid.CrossFade(pose, false, true, false, 0f);
-            Maid.SetAutoTwistAll(true);
-            Maid.GetAnimation().Play();
+                Maid.CrossFade(pose, loop: true, val: 0f);
+                Maid.GetAnimation().Play();
 
-            if (poseComponents.Length > 1)
-            {
-                Maid.GetAnimation()[pose].time = float.Parse(poseComponents[1]);
-                Maid.GetAnimation()[pose].speed = 0f;
+                if (poseComponents.Length > 1)
+                {
+                    Maid.GetAnimation()[pose].time = float.Parse(poseComponents[1]);
+                    Maid.GetAnimation()[pose].speed = 0f;
+                }
             }
 
+            Maid.SetAutoTwistAll(true);
             SetMune();
         }
 
@@ -277,37 +219,51 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         {
             byte[] poseBinary = fromMeido.SerializePose();
             string tag = $"copy_{fromMeido.Maid.status.guid}";
-            Maid.body0.CrossFade(tag, poseBinary, false, true, false, 0f);
+            Body.CrossFade(tag, poseBinary, false, true, false, 0f);
             Maid.SetAutoTwistAll(true);
             Maid.transform.rotation = fromMeido.Maid.transform.rotation;
             SetMune();
         }
 
-        public void SetPoseCustom(string path)
+        public void SetMune(bool drag = false)
         {
-            if (!Maid.body0.isLoadedBody) return;
-            byte[] bytes = File.ReadAllBytes(path);
-            string hash = Path.GetFileName(path).GetHashCode().ToString();
-            Maid.body0.CrossFade(hash, bytes, false, true, false, 0f);
-            Maid.SetAutoTwistAll(true);
-            SetMune();
+            bool momiOrPaizuri = CachedPose.Pose.Contains("_momi") || CachedPose.Pose.Contains("paizuri_");
+            float onL = (drag || momiOrPaizuri) ? 0f : 1f;
+            Body.MuneYureL(onL);
+            Body.MuneYureR(onL);
+            Body.jbMuneL.enabled = !drag;
+            Body.jbMuneR.enabled = !drag;
         }
 
-        public void SetMune(bool drag = false)
+        public void SetHandPreset(string filename, bool right)
+        {
+            XDocument handDocument = XDocument.Load(filename);
+            XElement handElement = handDocument.Element("FingerData");
+            if (handElement.IsEmpty || handElement.Element("GameVersion").IsEmpty
+                || handElement.Element("RightData").IsEmpty || handElement.Element("BinaryData").IsEmpty
+            ) return;
+
+            Stop = true;
+
+            bool rightData = bool.Parse(handElement.Element("RightData").Value);
+            string base64Data = handElement.Element("BinaryData").Value;
+
+            byte[] handData = Convert.FromBase64String(base64Data);
+
+            IKManager.DeserializeHand(handData, right, rightData != right);
+        }
+
+        public byte[] SerializePose(bool frameBinary = false)
         {
-            bool isMomiOrPaizuri = CachedPose.Pose.Contains("_momi") || CachedPose.Pose.Contains("paizuri_");
-            float onL = (drag || isMomiOrPaizuri) ? 0f : 1f;
-            Maid.body0.MuneYureL(onL);
-            Maid.body0.MuneYureR(onL);
-            Maid.body0.jbMuneL.enabled = !drag;
-            Maid.body0.jbMuneR.enabled = !drag;
+            CacheBoneDataArray cache = GetCacheBoneData();
+            return frameBinary ? cache.GetFrameBinary(true, true) : cache.GetAnmBinary(true, true);
         }
 
         public void SetFaceBlendSet(string blendSet)
         {
             FaceBlendSet = blendSet;
             Maid.boMabataki = false;
-            TMorph morph = Maid.body0.Face.morph;
+            TMorph morph = Body.Face.morph;
             morph.EyeMabataki = 0f;
             morph.MulBlendValues(blendSet, 1f);
             morph.FixBlendValues_Face();
@@ -316,7 +272,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
 
         public void SetFaceBlendValue(string hash, float value)
         {
-            TMorph morph = Maid.body0.Face.morph;
+            TMorph morph = Body.Face.morph;
             if (hash == "nosefook")
             {
                 morph.boNoseFook = value > 0f;
@@ -342,60 +298,83 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             morph.FixBlendValues_Face();
         }
 
-        public void SetMaskMode(TBody.MaskMode maskMode)
+        public void SetMaskMode(MaskMode maskMode)
         {
-            TBody body = Maid.body0;
-            bool invisibleBody = !body.GetMask(TBody.SlotID.body);
-            body.SetMaskMode(maskMode);
+            bool invisibleBody = !Body.GetMask(SlotID.body);
+            Body.SetMaskMode(maskMode);
             if (invisibleBody) SetBodyMask(false);
         }
 
         public void SetBodyMask(bool enabled)
         {
-            TBody body = Maid.body0;
-            Hashtable table = Utility.GetFieldValue<TBody, Hashtable>(body, "m_hFoceHide");
-            foreach (TBody.SlotID bodySlot in MaidDressingPane.bodySlots)
+            Hashtable table = Utility.GetFieldValue<TBody, Hashtable>(Body, "m_hFoceHide");
+            foreach (SlotID bodySlot in MaidDressingPane.bodySlots)
             {
                 table[bodySlot] = enabled;
             }
-            if (body.goSlot[19].m_strModelFileName.Contains("melala_body"))
+            if (Body.goSlot[19].m_strModelFileName.Contains("melala_body"))
             {
-                table[TBody.SlotID.accHana] = enabled;
+                table[SlotID.accHana] = enabled;
             }
-            body.FixMaskFlag();
-            body.FixVisibleFlag(false);
+            Body.FixMaskFlag();
+            Body.FixVisibleFlag(false);
         }
 
-        public Transform GetBoneTransform(AttachPoint point) => this.dragPointManager?.GetAttachPointTransform(point);
+        public void SetCurling(Curl curling, bool enabled)
+        {
+            string[] name = curling == Curl.shift
+                ? new[] { "panz", "mizugi" }
+                : new[] { "skirt", "onepiece" };
+            if (enabled)
+            {
+                string action = curling == Curl.shift
+                    ? "パンツずらし" : curling == Curl.front
+                        ? "めくれスカート" : "めくれスカート後ろ";
+                Maid.ItemChangeTemp(name[0], action);
+                Maid.ItemChangeTemp(name[1], action);
+            }
+            else
+            {
+                Maid.ResetProp(name[0]);
+                Maid.ResetProp(name[1]);
+            }
+            Maid.AllProcProp();
+        }
 
-        private void OnBodyLoad()
+        private CacheBoneDataArray GetCacheBoneData()
         {
-            BodyLoad?.Invoke(this, EventArgs.Empty);
+            CacheBoneDataArray cache = this.Maid.gameObject.GetComponent<CacheBoneDataArray>();
+            if (cache == null)
+            {
+                cache = this.Maid.gameObject.AddComponent<CacheBoneDataArray>();
+                cache.CreateCache(this.Maid.body0.GetBone("Bip01"));
+            }
+            return cache;
+        }
 
+        private void OnBodyLoad()
+        {
             if (!initialized)
             {
-                TMorph morph = Maid.body0.Face.morph;
-                this.BlendValuesBackup = Utility.GetFieldValue<TMorph, float[]>(morph, "BlendValuesBackup");
-                this.BlendValues = Utility.GetFieldValue<TMorph, float[]>(morph, "BlendValues");
-
-                this.DefaultEyeRotL = this.Maid.body0.quaDefEyeL;
-                this.DefaultEyeRotR = this.Maid.body0.quaDefEyeR;
+                TMorph faceMorph = Body.Face.morph;
+                BlendValuesBackup = Utility.GetFieldValue<TMorph, float[]>(faceMorph, "BlendValuesBackup");
+                BlendValues = Utility.GetFieldValue<TMorph, float[]>(faceMorph, "BlendValues");
+                DefaultEyeRotL = Body.quaDefEyeL;
+                DefaultEyeRotR = Body.quaDefEyeR;
                 initialized = true;
             }
 
-            this.IsIK = true;
-            this.IsStop = false;
-            this.IsBone = false;
-        }
+            IKManager.Initialize();
 
-        private void OnUpdateMeido(MeidoUpdateEventArgs args = null)
-        {
-            this.UpdateMeido?.Invoke(this, args ?? MeidoUpdateEventArgs.Empty);
+            IK = true;
+            Stop = false;
+            Bone = false;
+            Loading = false;
         }
 
-        private void OnMeidoSelect(object sender, MeidoUpdateEventArgs args)
+        public void OnUpdateMeido(MeidoUpdateEventArgs args = null)
         {
-            UpdateMeido?.Invoke(this, args);
+            this.UpdateMeido?.Invoke(this, args ?? MeidoUpdateEventArgs.Empty);
         }
     }
 

+ 27 - 32
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/MeidoDragPointManager.cs

@@ -18,7 +18,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         {
             Head, HeadNub, ClavicleL, ClavicleR,
             UpperArmL, UpperArmR, ForearmL, ForearmR,
-            HandL, HandR, IKHandL, IKHandR,
+            HandL, HandR, /*IKHandL, IKHandR,*/
             MuneL, MuneSubL, MuneR, MuneSubR,
             Neck, Spine, Spine0a, Spine1, Spine1a, ThighL, ThighR,
             Pelvis, Hip,
@@ -92,10 +92,10 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         }
         private static EventHandler CubeActiveChange;
         private static EventHandler CubeSmallChange;
+        private bool initialized = false;
         private Meido meido;
-        private Maid maid;
-        private Dictionary<Bone, Transform> BoneTransform;
-        private Dictionary<Bone, DragPointMeido> DragPoints;
+        private Dictionary<Bone, Transform> BoneTransform = new Dictionary<Bone, Transform>();
+        private Dictionary<Bone, DragPointMeido> DragPoints = new Dictionary<Bone, DragPointMeido>();
         private DragPointBody dragBody;
         private DragPointBody dragCube;
         public event EventHandler<MeidoUpdateEventArgs> SelectMaid;
@@ -135,12 +135,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             }
         }
 
-        public MeidoDragPointManager(Meido meido)
-        {
-            this.meido = meido;
-            this.maid = meido.Maid;
-            this.meido.BodyLoad += Initialize;
-        }
+        public MeidoDragPointManager(Meido meido) => this.meido = meido;
 
         public Transform GetAttachPointTransform(AttachPoint point)
         {
@@ -163,10 +158,10 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             Transform hip = BoneTransform[Bone.Hip];
             Vector3 vecHip = hip.eulerAngles;
 
-            Transform hipL = maid.body0.GetBone("Hip_L");
+            Transform hipL = meido.Maid.body0.GetBone("Hip_L");
             Vector3 vecHipL = hipL.eulerAngles;
 
-            Transform hipR = maid.body0.GetBone("Hip_R");
+            Transform hipR = meido.Maid.body0.GetBone("Hip_R");
             Vector3 vecHipR = hipR.eulerAngles;
 
             hip.rotation = Quaternion.Euler(
@@ -288,19 +283,24 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         {
             foreach (DragPointMeido dragPoint in DragPoints.Values)
             {
-                GameObject.Destroy(dragPoint.gameObject);
+                if (dragPoint != null)
+                {
+                    GameObject.Destroy(dragPoint.gameObject);
+                }
             }
-            GameObject.Destroy(dragCube.gameObject);
-            GameObject.Destroy(dragBody.gameObject);
+            if (dragCube != null) GameObject.Destroy(dragCube.gameObject);
+            if (dragBody != null) GameObject.Destroy(dragBody.gameObject);
             BoneTransform.Clear();
             DragPoints.Clear();
             CubeActiveChange -= OnCubeActive;
             CubeSmallChange -= OnCubeSmall;
+            initialized = false;
         }
 
-        private void Initialize(object sender, EventArgs args)
+        public void Initialize()
         {
-            meido.BodyLoad -= Initialize;
+            if (initialized) return;
+            initialized = true;
             CubeActiveChange += OnCubeActive;
             CubeSmallChange += OnCubeSmall;
             InitializeBones();
@@ -309,13 +309,11 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
 
         private void InitializeDragPoints()
         {
-            DragPoints = new Dictionary<Bone, DragPointMeido>();
-
             dragCube = DragPoint.Make<DragPointBody>(
                 PrimitiveType.Cube, Vector3.one * 0.12f, DragPoint.Blue
             );
-            dragCube.Initialize(() => maid.transform.position, () => Vector3.zero);
-            dragCube.Set(maid.transform);
+            dragCube.Initialize(() => meido.Maid.transform.position, () => Vector3.zero);
+            dragCube.Set(meido.Maid.transform);
 
             dragCube.IsCube = true;
             dragCube.ConstantScale = true;
@@ -338,7 +336,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
                     BoneTransform[Bone.Spine0a].eulerAngles.z + 90f
                 )
             );
-            dragBody.Set(maid.transform);
+            dragBody.Set(meido.Maid.transform);
             dragBody.Select += OnSelectBody;
             dragBody.EndScale += OnSetDragPointScale;
 
@@ -525,17 +523,17 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
 
         private void OnSetDragPointScale(object sender, EventArgs args)
         {
-            this.SetDragPointScale(maid.transform.localScale.x);
+            this.SetDragPointScale(meido.Maid.transform.localScale.x);
         }
 
         private void OnSelectBody(object sender, EventArgs args)
         {
-            SelectMaid?.Invoke(this, new MeidoUpdateEventArgs(meido.ActiveSlot, fromMaid: true, isBody: true));
+            SelectMaid?.Invoke(this, new MeidoUpdateEventArgs(meido.Slot, fromMaid: true, isBody: true));
         }
 
         private void OnSelectFace(object sender, EventArgs args)
         {
-            SelectMaid?.Invoke(this, new MeidoUpdateEventArgs(meido.ActiveSlot, fromMaid: true, isBody: false));
+            SelectMaid?.Invoke(this, new MeidoUpdateEventArgs(meido.Slot, fromMaid: true, isBody: false));
         }
 
         private void SetDragPointScale(float scale)
@@ -550,14 +548,14 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         private void InitializeBones()
         {
             // TODO: Move to external file somehow
-            Transform transform = maid.body0.m_Bones.transform;
+            Transform transform = meido.Body.m_Bones.transform;
             BoneTransform = new Dictionary<Bone, Transform>()
             {
                 [Bone.Head] = CMT.SearchObjName(transform, "Bip01 Head"),
                 [Bone.Neck] = CMT.SearchObjName(transform, "Bip01 Neck"),
                 [Bone.HeadNub] = CMT.SearchObjName(transform, "Bip01 HeadNub"),
-                [Bone.IKHandL] = CMT.SearchObjName(transform, "_IK_handL"),
-                [Bone.IKHandR] = CMT.SearchObjName(transform, "_IK_handR"),
+                /*[Bone.IKHandL] = CMT.SearchObjName(transform, "_IK_handL"),
+                [Bone.IKHandR] = CMT.SearchObjName(transform, "_IK_handR"),*/
                 [Bone.MuneL] = CMT.SearchObjName(transform, "Mune_L"),
                 [Bone.MuneSubL] = CMT.SearchObjName(transform, "Mune_L_sub"),
                 [Bone.MuneR] = CMT.SearchObjName(transform, "Mune_R"),
@@ -651,10 +649,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         public AttachPoint AttachPoint { get; }
         public string MaidGuid { get; }
         public int MaidIndex { get; }
-        public static AttachPointInfo Empty
-        {
-            get => new AttachPointInfo(AttachPoint.None, String.Empty, -1);
-        }
+        public static AttachPointInfo Empty => new AttachPointInfo(AttachPoint.None, String.Empty, -1);
 
         public AttachPointInfo(AttachPoint attachPoint, string maidGuid, int maidIndex)
         {

+ 4 - 4
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/MeidoPhotoStudio.cs

@@ -83,8 +83,8 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             for (int i = 0; i < activeMeidoList.Count; i++)
             {
                 Meido meido = activeMeidoList[i];
-                isIK[i] = meido.IsIK;
-                if (meido.IsIK) meido.IsIK = false;
+                isIK[i] = meido.IK;
+                if (meido.IK) meido.IK = false;
             }
 
             GizmoRender.UIVisible = false;
@@ -110,7 +110,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             for (int i = 0; i < activeMeidoList.Count; i++)
             {
                 Meido meido = activeMeidoList[i];
-                if (isIK[i]) meido.IsIK = true;
+                if (isIK[i]) meido.IK = true;
             }
 
             GizmoRender.UIVisible = true;
@@ -182,7 +182,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
 
         private void Deactivate()
         {
-            if (meidoManager.IsBusy) return;
+            if (meidoManager.Busy) return;
 
             uiActive = false;
             isActive = false;