소스 검색

Add full support for edit mode

Closes #10
habeebweeb 3 년 전
부모
커밋
d6ce339df4

+ 35 - 0
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/GUI/Panes/OtherPanes/MaidSwitcherPane.cs

@@ -7,16 +7,21 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         private readonly MeidoManager meidoManager;
         private readonly Button previousButton;
         private readonly Button nextButton;
+        private readonly Toggle editToggle;
 
         public MaidSwitcherPane(MeidoManager meidoManager)
         {
             this.meidoManager = meidoManager;
+            this.meidoManager.UpdateMeido += (s, a) => UpdatePane();
 
             previousButton = new Button("<");
             previousButton.ControlEvent += (s, a) => ChangeMaid(-1);
 
             nextButton = new Button(">");
             nextButton.ControlEvent += (s, a) => ChangeMaid(1);
+
+            editToggle = new Toggle("Edit", true);
+            editToggle.ControlEvent += (s, a) => SetEditMaid();
         }
 
         public override void Draw()
@@ -60,6 +65,8 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
 
             Rect previousRect = GUILayoutUtility.GetLastRect();
 
+            if (MeidoPhotoStudio.EditMode) editToggle.Draw(new Rect(previousRect.x + 4f, previousRect.y, 40f, 20f));
+
             Rect labelRect = new Rect(previousRect.width - 45f, previousRect.y, 40f, 20f);
             GUIStyle slotStyle = new GUIStyle()
             {
@@ -72,6 +79,16 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             if (meidoManager.HasActiveMeido) GUI.Label(labelRect, $"{meidoManager.ActiveMeido.Slot + 1}", slotStyle);
         }
 
+        public override void UpdatePane()
+        {
+            if (meidoManager.HasActiveMeido)
+            {
+                this.updating = true;
+                editToggle.Value = meidoManager.ActiveMeido.IsEditMaid;
+                this.updating = false;
+            }
+        }
+
         private void ChangeMaid(int dir)
         {
             int selected = Utility.Wrap(
@@ -80,5 +97,23 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
 
             meidoManager.ChangeMaid(selected);
         }
+
+        private void SetEditMaid()
+        {
+            if (updating) return;
+
+            if (!editToggle.Value)
+            {
+                updating = true;
+                editToggle.Value = true;
+                updating = false;
+                return;
+            }
+
+            if (meidoManager.HasActiveMeido)
+            {
+                meidoManager.SetEditMaid(meidoManager.ActiveMeido);
+            }
+        }
     }
 }

+ 87 - 1
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Managers/MeidoManager.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Reflection;
 using System.Linq;
 using UnityEngine;
 
@@ -11,11 +12,13 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         private static readonly CharacterMgr characterMgr = GameMain.Instance.CharacterMgr;
         private int undress;
         private int numberOfMeidos;
+        private int tempEditMaidIndex = -1;
         public Meido[] Meidos { get; private set; }
         public HashSet<int> SelectedMeidoSet { get; } = new HashSet<int>();
         public List<int> SelectMeidoList { get; } = new List<int>();
         public List<Meido> ActiveMeidoList { get; } = new List<Meido>();
         public Meido ActiveMeido => ActiveMeidoList.Count > 0 ? ActiveMeidoList[SelectedMeido] : null;
+        public Meido EditMeido => tempEditMaidIndex >= 0 ? Meidos[tempEditMaidIndex] : Meidos[EditMaidIndex];
         public bool HasActiveMeido => ActiveMeido != null;
         public event EventHandler<MeidoUpdateEventArgs> UpdateMeido;
         public event EventHandler EndCallMeidos;
@@ -64,6 +67,8 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             numberOfMeidos = characterMgr.GetStockMaidCount();
             Meidos = new Meido[numberOfMeidos];
 
+            tempEditMaidIndex = -1;
+
             for (int stockMaidIndex = 0; stockMaidIndex < numberOfMeidos; stockMaidIndex++)
             {
                 Meidos[stockMaidIndex] = new Meido(stockMaidIndex);
@@ -73,6 +78,19 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             {
                 Maid editMaid = GameMain.Instance.CharacterMgr.GetMaid(0);
                 EditMaidIndex = Array.FindIndex(Meidos, meido => meido.Maid.status.guid == editMaid.status.guid);
+                EditMeido.IsEditMaid = true;
+
+                var editOkCancel = UTY.GetChildObject(GameObject.Find("UI Root"), "OkCancel")
+                    .GetComponent<EditOkCancel>();
+
+                // Ensure MPS resets editor state before setting maid
+                EditOkCancel.OnClick newEditOnClick = () => SetEditMaid(Meidos[EditMaidIndex]);
+                newEditOnClick += OkCancelDelegate();
+
+                Utility.SetFieldValue(editOkCancel, "m_dgOnClickOk", newEditOnClick);
+
+                // Only for setting custom parts placement animation just in case body was changed before activating MPS
+                SetEditMaid(Meidos[EditMaidIndex]);
             }
 
             ClearSelectList();
@@ -88,7 +106,6 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             }
 
             ActiveMeidoList.Clear();
-            ClearSelectList();
 
             if (MeidoPhotoStudio.EditMode)
             {
@@ -96,9 +113,25 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
                 meido.Maid.Visible = true;
                 meido.Stop = false;
                 meido.EyeToCam = true;
+
+                SetEditMaid(meido);
+
+                // Restore original OK button functionality
+                GameObject okButton = UTY.GetChildObjectNoError(GameObject.Find("UI Root"), "OkCancel");
+                if (okButton)
+                {
+                    EditOkCancel editOkCancel = okButton.GetComponent<EditOkCancel>();
+                    Utility.SetFieldValue(editOkCancel, "m_dgOnClickOk", OkCancelDelegate());
+                }
             }
         }
 
+        private EditOkCancel.OnClick OkCancelDelegate()
+        {
+            return (EditOkCancel.OnClick)Delegate
+                .CreateDelegate(typeof(EditOkCancel.OnClick), SceneEdit.Instance, "OnEditOk");
+        }
+
         public void Update()
         {
             if (InputManager.GetKeyDown(MpsKey.MeidoUndressing)) UndressAll();
@@ -212,6 +245,54 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             }
         }
 
+        public void SetEditMaid(Meido meido)
+        {
+            if (!MeidoPhotoStudio.EditMode) return;
+
+            EditMeido.IsEditMaid = false;
+
+            tempEditMaidIndex = meido.Maid.status.guid == Meidos[EditMaidIndex].Maid.status.guid
+                ? -1
+                : Array.FindIndex(Meidos, maid => maid.Maid.status.guid == meido.Maid.status.guid);
+
+            EditMeido.IsEditMaid = true;
+
+            Maid newEditMaid = EditMeido.Maid;
+
+            GameObject uiRoot = GameObject.Find("UI Root");
+
+            var presetCtrl = UTY.GetChildObjectNoError(uiRoot, "PresetPanel")?.GetComponent<PresetCtrl>();
+            var presetButton = UTY.GetChildObjectNoError(uiRoot, "PresetButtonPanel")?.GetComponent<PresetButtonCtrl>();
+            var profileCtrl = UTY.GetChildObjectNoError(uiRoot, "ProfilePanel")?.GetComponent<ProfileCtrl>();
+            var customPartsWindow = UTY.GetChildObjectNoError(uiRoot, "Window/CustomPartsWindow")
+                ?.GetComponent<SceneEditWindow.CustomPartsWindow>();
+
+            if (!(presetCtrl || presetButton || profileCtrl || customPartsWindow)) return;
+
+            // Preset application
+            Utility.SetFieldValue(presetCtrl, "m_maid", newEditMaid);
+
+            // Preset saving
+            Utility.SetFieldValue(presetButton, "m_maid", newEditMaid);
+
+            // Maid profile (name, description, experience etc)
+            Utility.SetFieldValue(profileCtrl, "m_maidStatus", newEditMaid.status);
+
+            // Accessory/Parts placement
+            Utility.SetFieldValue(customPartsWindow, "maid", newEditMaid);
+
+            // Stopping maid animation and head movement when customizing parts placement
+            Utility.SetFieldValue(customPartsWindow, "animation", newEditMaid.GetAnimation());
+
+            // Clothing/body in general and maybe other things
+            Utility.SetFieldValue(SceneEdit.Instance, "m_maid", newEditMaid);
+
+            // Body status, parts colours and maybe more
+            Utility.GetFieldValue<CharacterMgr, Maid[]>(
+                GameMain.Instance.CharacterMgr, "m_gcActiveMaid"
+            )[0] = newEditMaid;
+        }
+
         public Meido GetMeido(string guid)
         {
             return string.IsNullOrEmpty(guid) ? null : ActiveMeidoList.Find(meido => meido.Maid.status.guid == guid);
@@ -262,6 +343,11 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
                 meido.UpdateMeido += OnUpdateMeido;
                 meido.GravityMove += OnGravityMove;
             }
+
+            if (MeidoPhotoStudio.EditMode && tempEditMaidIndex >= 0 && !SelectedMeidoSet.Contains(tempEditMaidIndex))
+            {
+                SetEditMaid(Meidos[EditMaidIndex]);
+            }
         }
 
         private void OnGravityMove(object sender, GravityEventArgs args)

+ 34 - 19
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/Meido.cs

@@ -12,6 +12,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
     internal class Meido : ISerializable
     {
         private bool initialized;
+        private float[] BlendSetValueBackup;
         public DragPointGravity HairGravityControl { get; private set; }
         public DragPointGravity SkirtGravityControl { get; private set; }
         public bool HairGravityActive
@@ -36,7 +37,6 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
                 }
             }
         }
-        private float[] BlendSetValueBackup;
         public const int meidoDataVersion = 1000;
         public static readonly PoseInfo DefaultPose =
             new PoseInfo(Constants.PoseGroupList[0], Constants.PoseDict[Constants.PoseGroupList[0]][0]);
@@ -65,7 +65,8 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         public Maid Maid { get; }
         public TBody Body => Maid.body0;
         public MeidoDragPointManager IKManager { get; }
-        public Texture2D Portrait { get; }
+        public Texture2D Portrait => Maid.GetThumIcon();
+        public bool IsEditMaid { get; set; }
         public PoseInfo CachedPose { get; private set; } = DefaultPose;
         public string CurrentFaceBlendSet { get; private set; } = defaultFaceBlendSet;
         public int Slot { get; private set; }
@@ -160,7 +161,6 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         {
             StockNo = stockMaidIndex;
             Maid = GameMain.Instance.CharacterMgr.GetStockMaid(stockMaidIndex);
-            Portrait = Maid.GetThumIcon();
             IKManager = new MeidoDragPointManager(this);
             IKManager.SelectMaid += (s, args) => OnUpdateMeido(args);
         }
@@ -241,22 +241,13 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
                 if (Maid.GetProp(MPN.body).boDut)
                 {
                     IKManager.Destroy();
-                    StartLoad(() =>
-                    {
-                        IKManager.Initialize();
-                        Stop = false;
-                    });
+                    StartLoad(reinitializeBody);
                 }
                 // Change face
                 else if (Maid.GetProp(MPN.head).boDut)
                 {
                     SetFaceBlendSet(defaultFaceBlendSet);
-                    StartLoad(() =>
-                    {
-                        DefaultEyeRotL = Body.quaDefEyeL;
-                        DefaultEyeRotR = Body.quaDefEyeR;
-                        BackupBlendSetValues();
-                    });
+                    StartLoad(reinitializeFace);
                 }
                 // Gravity control clothing/hair change
                 else if (gravityControlProps.Any(prop => Maid.GetProp(prop).boDut))
@@ -264,14 +255,38 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
                     if (HairGravityControl) GameObject.Destroy(HairGravityControl.gameObject);
                     if (SkirtGravityControl) GameObject.Destroy(SkirtGravityControl.gameObject);
 
-                    StartLoad(() =>
-                    {
-                        InitializeGravityControls();
-                        OnUpdateMeido();
-                    });
+                    StartLoad(reinitializeGravity);
                 }
                 // Clothing/accessory changes
+                // Includes null_mpn too but any button click results in null_mpn bodut I think
                 else StartLoad(() => OnUpdateMeido());
+
+                void reinitializeBody()
+                {
+                    IKManager.Initialize();
+                    Stop = false;
+
+                    // Maid animation needs to be set again for custom parts edit
+                    GameObject uiRoot = GameObject.Find("UI Root");
+
+                    var customPartsWindow = UTY.GetChildObject(uiRoot, "Window/CustomPartsWindow")
+                        .GetComponent<SceneEditWindow.CustomPartsWindow>();
+
+                    Utility.SetFieldValue(customPartsWindow, "animation", Maid.GetAnimation());
+                }
+
+                void reinitializeFace()
+                {
+                    DefaultEyeRotL = Body.quaDefEyeL;
+                    DefaultEyeRotR = Body.quaDefEyeR;
+                    BackupBlendSetValues();
+                }
+
+                void reinitializeGravity()
+                {
+                    InitializeGravityControls();
+                    OnUpdateMeido();
+                }
             }
         }