123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using HarmonyLib;
- using UnityEngine;
- namespace MeidoPhotoStudio.Plugin;
- public class MeidoManager : IManager
- {
- public const string Header = "MEIDO";
- private static bool active;
- private int selectedMeido;
- private bool globalGravity;
- private int undress;
- private Meido editingMeido;
- private Meido temporaryEditingMeido;
- static MeidoManager() =>
- InputManager.Register(MpsKey.MeidoUndressing, KeyCode.H, "All maid undressing");
- public MeidoManager() =>
- Activate();
- public event EventHandler<MeidoUpdateEventArgs> UpdateMeido;
- public event EventHandler EndCallMeidos;
- public event EventHandler BeginCallMeidos;
- public Meido[] Meidos { get; private set; }
- public List<Meido> ActiveMeidoList { get; } = new();
- public int SelectedMeido
- {
- get => selectedMeido;
- private set => selectedMeido = Utility.Bound(value, 0, ActiveMeidoList.Count - 1);
- }
- public bool Busy =>
- ActiveMeidoList.Any(meido => meido.Busy);
- public Meido ActiveMeido =>
- ActiveMeidoList.Count > 0 ? ActiveMeidoList[SelectedMeido] : null;
- public Meido EditingMeido
- {
- get => MeidoPhotoStudio.EditMode ? editingMeido : null;
- set
- {
- if (!MeidoPhotoStudio.EditMode || value is null)
- return;
- editingMeido = value;
- temporaryEditingMeido = editingMeido == OriginalEditingMeido ? null : editingMeido;
- SetEditorMaid(editingMeido.Maid);
- }
- }
- public Meido TemporaryEditingMeido =>
- MeidoPhotoStudio.EditMode ? temporaryEditingMeido : null;
- public Meido OriginalEditingMeido =>
- MeidoPhotoStudio.EditMode && OriginalEditingMaidIndex >= 0 ? Meidos[OriginalEditingMaidIndex] : null;
- public bool HasActiveMeido =>
- ActiveMeido is not null;
- public bool GlobalGravity
- {
- get => globalGravity;
- set
- {
- globalGravity = value;
- if (!HasActiveMeido)
- return;
- var activeMeido = ActiveMeido;
- var activeMeidoSlot = activeMeido.Slot;
- foreach (var meido in ActiveMeidoList)
- {
- if (meido.Slot == activeMeidoSlot)
- continue;
- meido.HairGravityActive = value && activeMeido.HairGravityActive;
- meido.SkirtGravityActive = value && activeMeido.SkirtGravityActive;
- }
- }
- }
- private static CharacterMgr CharacterMgr =>
- GameMain.Instance.CharacterMgr;
- private static int OriginalEditingMaidIndex { get; set; }
- public void ChangeMaid(int index) =>
- OnUpdateMeido(null, new(index));
- public void Activate()
- {
- Meidos = CharacterMgr.GetStockMaidList()
- .Select((_, stockNo) => new Meido(stockNo))
- .ToArray();
- CharacterMgr.ResetCharaPosAll();
- if (MeidoPhotoStudio.EditMode)
- {
- temporaryEditingMeido = null;
- editingMeido = OriginalEditingMeido;
- if (OriginalEditingMeido is not null)
- CallMeidos(new List<Meido>() { OriginalEditingMeido });
- }
- else
- {
- CharacterMgr.DeactivateMaid(0);
- }
- active = true;
- }
- public void Deactivate()
- {
- foreach (var meido in Meidos)
- {
- meido.UpdateMeido -= OnUpdateMeido;
- meido.GravityMove -= OnGravityMove;
- meido.Deactivate();
- }
- ActiveMeidoList.Clear();
- if (MeidoPhotoStudio.EditMode && !GameMain.Instance.MainCamera.IsFadeOut())
- {
- var meido = OriginalEditingMeido;
- meido.Maid.Visible = true;
- meido.Stop = false;
- meido.EyeToCam = true;
- SetEditorMaid(meido.Maid);
- }
- active = false;
- }
- public void Update()
- {
- if (InputManager.GetKeyDown(MpsKey.MeidoUndressing))
- UndressAll();
- }
- public void CallMeidos(IList<Meido> meidoToCall)
- {
- BeginCallMeidos?.Invoke(this, EventArgs.Empty);
- SelectedMeido = 0;
- if (MeidoPhotoStudio.EditMode && meidoToCall.Count is 0)
- meidoToCall.Add(OriginalEditingMeido);
- UnloadMeidos(meidoToCall);
- if (meidoToCall.Count is 0)
- {
- OnEndCallMeidos(this, EventArgs.Empty);
- return;
- }
- ActiveMeidoList.AddRange(meidoToCall);
- GameMain.Instance.StartCoroutine(LoadMeidos(meidoToCall));
- }
- public Meido GetMeido(string guid) =>
- string.IsNullOrEmpty(guid) ? null : ActiveMeidoList.Find(meido => meido.Maid.status.guid == guid);
- public Meido GetMeido(int activeIndex) =>
- activeIndex >= 0 && activeIndex < ActiveMeidoList.Count ? ActiveMeidoList[activeIndex] : null;
- public void PlaceMeidos(string placementType) =>
- MaidPlacementUtility.ApplyPlacement(placementType, ActiveMeidoList);
- private static void SetEditorMaid(Maid maid)
- {
- if (!maid)
- {
- Utility.LogWarning("Refusing to change editing maid because the new maid is null!");
- return;
- }
- if (SceneEdit.Instance.maid.status.guid == maid.status.guid)
- {
- Utility.LogDebug("Editing maid is the same as new maid");
- return;
- }
- var uiRoot = GameObject.Find("UI Root");
- if (!TryGetUIControl<PresetCtrl>(uiRoot, "PresetPanel", out var presetCtrl))
- return;
- if (!TryGetUIControl<PresetButtonCtrl>(uiRoot, "PresetButtonPanel", out var presetButtonCtrl))
- return;
- if (!TryGetUIControl<ProfileCtrl>(uiRoot, "ProfilePanel", out var profileCtrl))
- return;
- if (!TryGetUIControl<SceneEditWindow.CustomPartsWindow>(
- uiRoot, "Window/CustomPartsWindow", out var sceneEditWindow))
- return;
- // Preset application
- presetCtrl.m_maid = maid;
- // Preset saving
- presetButtonCtrl.m_maid = maid;
- // Maid profile (name, description, experience etc)
- profileCtrl.m_maidStatus = maid.status;
- // Accessory/Parts placement
- sceneEditWindow.maid = maid;
- // Stopping maid animation and head movement when customizing parts placement
- sceneEditWindow.animation = maid.GetAnimation();
- // Clothing/body in general and maybe other things
- SceneEdit.Instance.m_maid = maid;
- // Body status, parts colours and maybe more
- GameMain.Instance.CharacterMgr.m_gcActiveMaid[0] = maid;
- static bool TryGetUIControl<T>(GameObject root, string hierarchy, out T uiControl)
- where T : MonoBehaviour
- {
- uiControl = null;
- var uiElement = UTY.GetChildObjectNoError(root, hierarchy);
- if (!uiElement)
- return false;
- uiControl = uiElement.GetComponent<T>();
- return uiControl;
- }
- }
- [HarmonyPostfix]
- [HarmonyPatch(typeof(SceneEdit), nameof(SceneEdit.Start))]
- private static void SceneEditStartPostfix()
- {
- if (!SceneEdit.Instance.maid)
- return;
- var originalEditingMaid = SceneEdit.Instance.maid;
- OriginalEditingMaidIndex = GameMain.Instance.CharacterMgr.GetStockMaidList()
- .FindIndex(maid => maid.status.guid == originalEditingMaid.status.guid);
- try
- {
- var editOkCancelButton = UTY.GetChildObject(GameObject.Find("UI Root"), "OkCancel")
- .GetComponent<EditOkCancel>();
- EditOkCancel.OnClick newEditOkCancelDelegate = RestoreOriginalEditingMaid;
- newEditOkCancelDelegate += editOkCancelButton.m_dgOnClickOk;
- editOkCancelButton.m_dgOnClickOk = newEditOkCancelDelegate;
- void RestoreOriginalEditingMaid()
- {
- // Only restore original editing maid when active.
- if (!active)
- return;
- Utility.LogDebug($"Setting Editing maid back to '{originalEditingMaid.status.fullNameJpStyle}'");
- SetEditorMaid(originalEditingMaid);
- // Set SceneEdit's maid regardless of UI integration failing
- SceneEdit.Instance.m_maid = originalEditingMaid;
- }
- }
- catch (Exception e)
- {
- Utility.LogWarning($"Failed to hook onto Edit Mode OK button: {e}");
- }
- }
- private void UnloadMeidos(IList<Meido> meidoToCall)
- {
- foreach (var meido in ActiveMeidoList)
- {
- meido.UpdateMeido -= OnUpdateMeido;
- meido.GravityMove -= OnGravityMove;
- if (!meidoToCall.Contains(meido))
- meido.Unload();
- }
- ActiveMeidoList.Clear();
- }
- private System.Collections.IEnumerator LoadMeidos(IList<Meido> meidoToLoad)
- {
- GameMain.Instance.MainCamera.FadeOut(0.01f, f_bSkipable: false);
- yield return new WaitForSeconds(0.01f);
- for (var meidoSlot = 0; meidoSlot < meidoToLoad.Count; meidoSlot++)
- meidoToLoad[meidoSlot].Load(meidoSlot);
- yield return new WaitForEndOfFrame();
- var waitForSeconds = new WaitForSeconds(0.5f);
- while (Busy)
- yield return waitForSeconds;
- OnEndCallMeidos(this, EventArgs.Empty);
- }
- private void UndressAll()
- {
- if (!HasActiveMeido)
- return;
- undress = ++undress % Enum.GetNames(typeof(Meido.Mask)).Length;
- foreach (var activeMeido in ActiveMeidoList)
- activeMeido.SetMaskMode((Meido.Mask)undress);
- UpdateMeido?.Invoke(ActiveMeido, new(SelectedMeido));
- }
- private void OnUpdateMeido(object sender, MeidoUpdateEventArgs args)
- {
- if (!args.IsEmpty)
- SelectedMeido = args.SelectedMeido;
- UpdateMeido?.Invoke(ActiveMeido, args);
- }
- private void OnEndCallMeidos(object sender, EventArgs args)
- {
- GameMain.Instance.MainCamera.FadeIn(1f);
- EndCallMeidos?.Invoke(this, EventArgs.Empty);
- foreach (var meido in ActiveMeidoList)
- {
- meido.UpdateMeido += OnUpdateMeido;
- meido.GravityMove += OnGravityMove;
- }
- if (MeidoPhotoStudio.EditMode && !ActiveMeidoList.Contains(TemporaryEditingMeido))
- EditingMeido = OriginalEditingMeido;
- }
- private void OnGravityMove(object sender, GravityEventArgs args)
- {
- if (!GlobalGravity)
- return;
- foreach (var meido in ActiveMeidoList)
- meido.ApplyGravity(args.LocalPosition, args.IsSkirt);
- }
- }
|