123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574 |
- using System;
- using System.IO;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEngine;
- using UnityEngine.Rendering;
- using BepInEx.Configuration;
- namespace COM3D2.MeidoPhotoStudio.Plugin
- {
- using static MenuFileUtility;
- public class PropManager : IManager, ISerializable
- {
- public const string header = "PROP";
- public const int propDataVersion = 1000;
- private static readonly ConfigEntry<bool> modItemsOnly;
- public static bool ModItemsOnly => modItemsOnly.Value;
- private readonly MeidoManager meidoManager;
- private static bool cubeActive = true;
- public static bool CubeActive
- {
- get => cubeActive;
- set
- {
- if (value != cubeActive)
- {
- cubeActive = value;
- CubeActiveChange?.Invoke(null, EventArgs.Empty);
- }
- }
- }
- private static bool cubeSmall;
- public static bool CubeSmall
- {
- get => cubeSmall;
- set
- {
- if (value != cubeSmall)
- {
- cubeSmall = value;
- CubeSmallChange?.Invoke(null, EventArgs.Empty);
- }
- }
- }
- private static event EventHandler CubeActiveChange;
- private static event EventHandler CubeSmallChange;
- private readonly List<DragPointDogu> doguList = new List<DragPointDogu>();
- public int DoguCount => doguList.Count;
- public event EventHandler DoguListChange;
- public event EventHandler DoguSelectChange;
- public string[] PropNameList => doguList.Count == 0
- ? new[] { Translation.Get("systemMessage", "noProps") }
- : doguList.Select(dogu => dogu.Name).ToArray();
- public int CurrentDoguIndex { get; private set; }
- public DragPointDogu CurrentDogu => DoguCount == 0 ? null : doguList[CurrentDoguIndex];
- static PropManager()
- {
- modItemsOnly = Configuration.Config.Bind(
- "Prop", "ModItemsOnly",
- false,
- "Disable waiting for and loading base game clothing"
- );
- }
- public PropManager(MeidoManager meidoManager)
- {
- this.meidoManager = meidoManager;
- this.meidoManager.BeginCallMeidos += DetachProps;
- this.meidoManager.EndCallMeidos += OnEndCall;
- Activate();
- }
- public void Serialize(BinaryWriter binaryWriter)
- {
- binaryWriter.Write(header);
- binaryWriter.Write(propDataVersion);
- binaryWriter.Write(doguList.Count);
- foreach (DragPointDogu dogu in doguList)
- {
- binaryWriter.WriteVector3(dogu.MyObject.position);
- binaryWriter.WriteQuaternion(dogu.MyObject.rotation);
- binaryWriter.WriteVector3(dogu.MyObject.localScale);
- dogu.attachPointInfo.Serialize(binaryWriter);
- binaryWriter.Write(dogu.ShadowCasting);
- binaryWriter.Write(dogu.assetName);
- }
- }
- public void Deserialize(BinaryReader binaryReader)
- {
- Dictionary<string, string> modToModPath = null;
- ClearDogu();
- int version = binaryReader.ReadInt32();
- int numberOfProps = binaryReader.ReadInt32();
- int doguIndex = 0;
- for (int i = 0; i < numberOfProps; i++)
- {
- Vector3 position = binaryReader.ReadVector3();
- Quaternion rotation = binaryReader.ReadQuaternion();
- Vector3 scale = binaryReader.ReadVector3();
- AttachPointInfo info = AttachPointInfo.Deserialize(binaryReader);
- bool shadowCasting = binaryReader.ReadBoolean();
- string assetName = binaryReader.ReadString();
- if (assetName.EndsWith(".menu") && assetName.Contains('#') && modToModPath == null)
- {
- modToModPath = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
- foreach (string mod in Menu.GetModFiles()) modToModPath.Add(Path.GetFileName(mod), mod);
- }
- if (SpawnFromAssetString(assetName, modToModPath))
- {
- DragPointDogu dogu = doguList[doguIndex++];
- Transform obj = dogu.MyObject;
- obj.position = position;
- obj.rotation = rotation;
- obj.localScale = scale;
- dogu.attachPointInfo = info;
- dogu.ShadowCasting = shadowCasting;
- }
- }
- CurrentDoguIndex = 0;
- GameMain.Instance.StartCoroutine(DeserializeAttach());
- }
- private System.Collections.IEnumerator DeserializeAttach()
- {
- yield return new WaitForEndOfFrame();
- foreach (DragPointDogu dogu in doguList)
- {
- AttachPointInfo info = dogu.attachPointInfo;
- if (info.AttachPoint != AttachPoint.None)
- {
- Meido parent = meidoManager.GetMeido(info.MaidIndex);
- if (parent != null)
- {
- Transform obj = dogu.MyObject;
- Vector3 position = obj.position;
- Vector3 scale = obj.localScale;
- Quaternion rotation = obj.rotation;
- Transform point = parent.IKManager.GetAttachPointTransform(info.AttachPoint);
- dogu.MyObject.SetParent(point, true);
- info = new AttachPointInfo(
- info.AttachPoint,
- parent.Maid.status.guid,
- parent.Slot
- );
- dogu.attachPointInfo = info;
- obj.position = position;
- obj.localScale = scale;
- obj.rotation = rotation;
- }
- }
- }
- }
- public void Activate()
- {
- CubeSmallChange += OnCubeSmall;
- CubeActiveChange += OnCubeActive;
- }
- public void Deactivate()
- {
- ClearDogu();
- CubeSmallChange -= OnCubeSmall;
- CubeActiveChange -= OnCubeActive;
- }
- public void Update() { }
- private GameObject GetDeploymentObject()
- {
- return GameObject.Find("Deployment Object Parent")
- ?? new GameObject("Deployment Object Parent");
- }
- public bool SpawnModItemProp(ModItem modItem)
- {
- GameObject dogu = LoadModel(modItem);
- string name = modItem.MenuFile;
- if (modItem.IsOfficialMod) name = Path.GetFileName(name);
- if (dogu != null) AttachDragPoint(dogu, modItem.ToString(), name, new Vector3(0f, 0f, 0.5f));
- return dogu != null;
- }
- public bool SpawnMyRoomProp(MyRoomItem item)
- {
- MyRoomCustom.PlacementData.Data data = MyRoomCustom.PlacementData.GetData(item.ID);
- GameObject dogu = GameObject.Instantiate(data.GetPrefab());
- string name = Translation.Get("myRoomPropNames", item.PrefabName);
- if (dogu != null)
- {
- GameObject finalDogu = new GameObject();
- dogu.transform.SetParent(finalDogu.transform, true);
- finalDogu.transform.SetParent(GetDeploymentObject().transform, false);
- AttachDragPoint(finalDogu, item.ToString(), name, new Vector3(0f, 0f, 0.5f));
- }
- else Utility.LogInfo($"Could not load MyRoomCreative prop '{item.PrefabName}'");
- return dogu != null;
- }
- public bool SpawnBG(string assetName)
- {
- if (assetName.StartsWith("BG_")) assetName = assetName.Substring(3);
- GameObject obj = GameMain.Instance.BgMgr.CreateAssetBundle(assetName)
- ?? Resources.Load<GameObject>("BG/" + assetName)
- ?? Resources.Load<GameObject>("BG/2_0/" + assetName);
- if (obj != null)
- {
- GameObject dogu = GameObject.Instantiate(obj);
- string name = Translation.Get("bgNames", assetName);
- dogu.transform.localScale = Vector3.one * 0.1f;
- AttachDragPoint(dogu, $"BG_{assetName}", name, new Vector3(0f, 0f, 0.5f));
- }
- return obj != null;
- }
- public bool SpawnObject(string assetName)
- {
- // TODO: Add a couple more things to ignore list
- GameObject dogu = null;
- string doguName = Translation.Get("propNames", assetName, false);
- Vector3 doguPosition = new Vector3(0f, 0f, 0.5f);
- if (assetName.EndsWith(".menu"))
- {
- dogu = LoadModel(assetName);
- string handItem = Utility.HandItemToOdogu(assetName);
- if (Translation.Has("propNames", handItem)) doguName = Translation.Get("propNames", handItem);
- }
- else if (assetName.StartsWith("mirror"))
- {
- Material mirrorMaterial = new Material(Shader.Find("Mirror"));
- dogu = GameObject.CreatePrimitive(PrimitiveType.Plane);
- Renderer mirrorRenderer = dogu.GetComponent<Renderer>();
- mirrorRenderer.material = mirrorMaterial;
- mirrorRenderer.enabled = true;
- MirrorReflection2 mirrorReflection = dogu.AddComponent<MirrorReflection2>();
- mirrorReflection.m_TextureSize = 2048;
- Vector3 localPosition = new Vector3(0f, 0.96f, 0f);
- dogu.transform.Rotate(dogu.transform.right, 90f);
- dogu.transform.localPosition = localPosition;
- switch (assetName)
- {
- case "mirror1":
- dogu.transform.localScale = new Vector3(0.2f, 0.4f, 0.2f);
- break;
- case "mirror2":
- dogu.transform.localScale = new Vector3(0.1f, 0.4f, 0.2f);
- break;
- case "mirror3":
- localPosition.y = 0.85f;
- dogu.transform.localScale = new Vector3(0.03f, 0.18f, 0.124f);
- break;
- default:
- GameObject.Destroy(dogu);
- dogu = null;
- break;
- }
- }
- else if (assetName.IndexOf(':') >= 0)
- {
- string[] assetParts = assetName.Split(':');
- GameObject obj = GameMain.Instance.BgMgr.CreateAssetBundle(assetParts[0])
- ?? Resources.Load<GameObject>("BG/" + assetParts[0]);
- try
- {
- GameObject bg = GameObject.Instantiate(obj);
- int num = int.Parse(assetParts[1]);
- dogu = bg.transform.GetChild(num).gameObject;
- dogu.transform.SetParent(null);
- GameObject.Destroy(bg);
- }
- catch { }
- }
- else
- {
- GameObject obj = GameMain.Instance.BgMgr.CreateAssetBundle(assetName)
- ?? Resources.Load<GameObject>("Prefab/" + assetName)
- ?? Resources.Load<GameObject>("BG/" + assetName);
- try
- {
- dogu = GameObject.Instantiate<GameObject>(obj);
- dogu.transform.localPosition = Vector3.zero;
- MeshRenderer[] meshRenderers = dogu.GetComponentsInChildren<MeshRenderer>();
- for (int i = 0; i < meshRenderers.Length; i++)
- {
- if (meshRenderers[i])
- {
- string name = meshRenderers[i].gameObject.name;
- if (name.IndexOf("castshadow", StringComparison.OrdinalIgnoreCase) < 0)
- {
- meshRenderers[i].shadowCastingMode = ShadowCastingMode.Off;
- }
- }
- }
- Collider collider = dogu.transform.GetComponent<Collider>();
- if (collider != null) collider.enabled = false;
- foreach (Transform transform in dogu.transform)
- {
- collider = transform.GetComponent<Collider>();
- if (collider != null)
- {
- collider.enabled = false;
- }
- }
- }
- catch { }
- #region particle system experiment
- // if (asset.StartsWith("Particle/"))
- // {
- // ParticleSystem particleSystem = go.GetComponent<ParticleSystem>();
- // if (particleSystem != null)
- // {
- // ParticleSystem.MainModule main;
- // main = particleSystem.main;
- // main.loop = true;
- // main.duration = Mathf.Infinity;
- // ParticleSystem[] particleSystems = particleSystem.GetComponents<ParticleSystem>();
- // foreach (ParticleSystem part in particleSystems)
- // {
- // ParticleSystem.EmissionModule emissionModule = part.emission;
- // ParticleSystem.Burst[] bursts = new ParticleSystem.Burst[emissionModule.burstCount];
- // emissionModule.GetBursts(bursts);
- // for (int i = 0; i < bursts.Length; i++)
- // {
- // bursts[i].cycleCount = Int32.MaxValue;
- // }
- // emissionModule.SetBursts(bursts);
- // main = part.main;
- // main.loop = true;
- // main.duration = Mathf.Infinity;
- // }
- // }
- // }
- #endregion particle system experiment
- }
- if (dogu != null)
- {
- AttachDragPoint(dogu, assetName, doguName, doguPosition);
- return true;
- }
- Utility.LogInfo($"Could not spawn object '{assetName}'");
- return false;
- }
- private bool SpawnFromAssetString(string assetName, Dictionary<string, string> modDict = null)
- {
- bool result;
- if (assetName.EndsWith(".menu"))
- {
- if (assetName.Contains('#'))
- {
- string[] assetParts = assetName.Split('#');
- string menuFile = modDict == null ? Menu.GetModPathFileName(assetParts[0]) : modDict[assetParts[0]];
- ModItem item = ModItem.OfficialMod(menuFile);
- item.BaseMenuFile = assetParts[1];
- result = SpawnModItemProp(item);
- }
- else if (assetName.StartsWith("handitem")) result = SpawnObject(assetName);
- else result = SpawnModItemProp(ModItem.Mod(assetName));
- }
- else if (assetName.StartsWith("MYR_"))
- {
- string[] assetParts = assetName.Split('#');
- int id = int.Parse(assetParts[0].Substring(4));
- string prefabName;
- if (assetParts.Length == 2 && !string.IsNullOrEmpty(assetParts[1])) prefabName = assetParts[1];
- else
- {
- // deserialize modifiedMM and maybe MM 23.0+.
- MyRoomCustom.PlacementData.Data data = MyRoomCustom.PlacementData.GetData(id);
- prefabName = !string.IsNullOrEmpty(data.resourceName) ? data.resourceName : data.assetName;
- }
- result = SpawnMyRoomProp(new MyRoomItem() { ID = id, PrefabName = prefabName });
- }
- else if (assetName.StartsWith("BG_")) result = SpawnBG(assetName);
- else result = SpawnObject(assetName);
- return result;
- }
- private void AttachDragPoint(GameObject dogu, string assetName, string name, Vector3 position)
- {
- // TODO: Figure out why some props aren't centred properly
- // Doesn't happen in MM but even after copy pasting the code, it doesn't work :/
- dogu.name = name;
- dogu.transform.position = position;
- DragPointDogu dragDogu = DragPoint.Make<DragPointDogu>(PrimitiveType.Cube, Vector3.one * 0.12f);
- dragDogu.Initialize(() => dogu.transform.position, () => Vector3.zero);
- dragDogu.Set(dogu.transform);
- dragDogu.AddGizmo(scale: 0.45f, mode: CustomGizmo.GizmoMode.World);
- dragDogu.ConstantScale = true;
- dragDogu.Delete += DeleteDogu;
- dragDogu.Select += SelectDogu;
- dragDogu.DragPointScale = CubeSmall ? DragPointGeneral.smallCube : 1f;
- dragDogu.assetName = assetName;
- doguList.Add(dragDogu);
- OnDoguListChange();
- }
- public void SetCurrentDogu(int doguIndex)
- {
- if (doguIndex >= 0 && doguIndex < DoguCount)
- {
- CurrentDoguIndex = doguIndex;
- DoguSelectChange?.Invoke(this, EventArgs.Empty);
- }
- }
- public void RemoveDogu(int doguIndex)
- {
- if (doguIndex >= 0 && doguIndex < DoguCount)
- {
- DestroyDogu(doguList[doguIndex]);
- doguList.RemoveAt(doguIndex);
- CurrentDoguIndex = Utility.Bound(CurrentDoguIndex, 0, DoguCount - 1);
- OnDoguListChange();
- }
- }
- public void CopyDogu(int doguIndex)
- {
- if (doguIndex >= 0 && doguIndex < DoguCount)
- {
- SpawnFromAssetString(doguList[doguIndex].assetName);
- }
- }
- public void AttachProp(
- int doguIndex, AttachPoint attachPoint, Meido meido, bool worldPositionStays = true
- )
- {
- if (doguList.Count == 0 || doguIndex >= doguList.Count || doguIndex < 0) return;
- AttachProp(doguList[doguIndex], attachPoint, meido, worldPositionStays);
- }
- private void AttachProp(
- DragPointDogu dragDogu, AttachPoint attachPoint, Meido meido, bool worldPositionStays = true
- )
- {
- GameObject dogu = dragDogu.MyGameObject;
- 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.Slot
- );
- Vector3 position = dogu.transform.position;
- Quaternion rotation = dogu.transform.rotation;
- Vector3 scale = dogu.transform.localScale;
- dogu.transform.SetParent(attachPointTransform, worldPositionStays);
- if (worldPositionStays)
- {
- dogu.transform.position = position;
- dogu.transform.rotation = rotation;
- }
- else
- {
- dogu.transform.localPosition = Vector3.zero;
- dogu.transform.rotation = Quaternion.identity;
- }
- dogu.transform.localScale = scale;
- if (meido == null) Utility.FixGameObjectScale(dogu);
- }
- private void DetachProps(object sender, EventArgs args)
- {
- foreach (DragPointDogu dogu in doguList)
- {
- if (dogu.attachPointInfo.AttachPoint != AttachPoint.None)
- {
- dogu.MyObject.SetParent(null, /*GetDeploymentObject().transform*/ true);
- }
- }
- }
- private void ClearDogu()
- {
- for (int i = DoguCount - 1; i >= 0; i--)
- {
- DestroyDogu(doguList[i]);
- }
- doguList.Clear();
- CurrentDoguIndex = 0;
- }
- private void OnEndCall(object sender, EventArgs args) => ReattachProps(useGuid: true);
- private void ReattachProps(bool useGuid, bool forceStay = false)
- {
- foreach (DragPointDogu dragDogu in doguList)
- {
- AttachPointInfo info = dragDogu.attachPointInfo;
- Meido meido = useGuid
- ? meidoManager.GetMeido(info.MaidGuid)
- : meidoManager.GetMeido(info.MaidIndex);
- bool worldPositionStays = forceStay || meido == null;
- AttachProp(dragDogu, dragDogu.attachPointInfo.AttachPoint, meido, worldPositionStays);
- }
- }
- private void DeleteDogu(object sender, EventArgs args)
- {
- DragPointDogu dogu = (DragPointDogu)sender;
- RemoveDogu(doguList.FindIndex(dragDogu => dragDogu == dogu));
- }
- private void DestroyDogu(DragPointDogu dogu)
- {
- if (dogu == null) return;
- dogu.Delete -= DeleteDogu;
- dogu.Select -= SelectDogu;
- GameObject.Destroy(dogu.gameObject);
- }
- private void SelectDogu(object sender, EventArgs args)
- {
- DragPointDogu dogu = (DragPointDogu)sender;
- SetCurrentDogu(doguList.IndexOf(dogu));
- }
- private void OnCubeSmall(object sender, EventArgs args)
- {
- foreach (DragPointDogu dogu in doguList)
- {
- dogu.DragPointScale = CubeSmall ? DragPointGeneral.smallCube : 1f;
- }
- }
- private void OnCubeActive(object sender, EventArgs args)
- {
- foreach (DragPointDogu dragPoint in doguList)
- {
- dragPoint.gameObject.SetActive(CubeActive);
- }
- }
- private void OnDoguListChange() => DoguListChange?.Invoke(this, EventArgs.Empty);
- }
- }
|