diff --git a/YotogiShapekeys/0Old/0Old1ShapekeyFetcherSetter.cs b/YotogiShapekeys/0Old/0Old1ShapekeyFetcherSetter.cs deleted file mode 100644 index 8d764be..0000000 --- a/YotogiShapekeys/0Old/0Old1ShapekeyFetcherSetter.cs +++ /dev/null @@ -1,572 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -//using System.Threading.Tasks; -using UnityEngine; -using UnityEngine.SceneManagement; -using static ShapekeyMaster.HelperClasses; -using Debug = UnityEngine.Debug; - -namespace ShapekeyMaster -{ - internal class ShapekeyFetcherSetter - { - private static List maidslist = new List(); - private static readonly List YotogiLvls = new List() { "SceneYotogi", "SceneYotogiOld" }; - private static readonly int OrgasmDeform = 1; - private static readonly bool IsOrgasming = false; - private static readonly List FixList = new List(); - private static readonly List ChangeList = new List(); - private static bool CorouteRunning = false; - - //This func is called in to register a maid into the list of maids. Handy of keeping track of them. - public static void RegisterMaid(Maid maid) - { - if (maidslist.Contains(maid) == false) - { - maidslist.Add(maid); - } - - maidslist = maidslist - .Where(m => m != null) - .Distinct() - .ToList(); - - MissionControlMaid(maid); - } - //This can be called externally to purposefully remove a maid from tracking. Currently unused. - public static void UnRegisterMaid(Maid maid) - { - maidslist.Remove(maid); - } - //Called so external functions can get the maid list in a controlled fashion. - public static List GetMaidsList() - { - return maidslist; - } - //The main idea behind MissionControl is to eventually have it drive everything on first thread and simply instruct the worker threads allowing flexibility for when we need to run something on thread 1. As a result, Mission control will have a few versions. - public static void MissionControlAll() - { - Stopwatch stop = new Stopwatch(); - - stop.Start(); - - List maids = maidslist - .Where(m => m != null) - .ToList(); - - IEnumerable morphs = maids - //.Select(m => GetAllMorphsFromMaid(m)) - //.Select(m => Task.Factory.StartNew(() => GetAllMorphsFromMaid(m))) - .Select(m => GetAllMorphsFromMaid(m)) - //.Select(async n => await n) - //.Select(t => t.Result) - .SelectMany(r => r); - - IEnumerable changes = morphs - //.Select(m => Task.Factory.StartNew(() => GetTMorphChangeForm(m))) - .Select(m => GetTMorphChangeForm(m)) - //.Select(m => RunSingleTMorph(m)) - //.Select(async n => await n) - //.Select(n => n.Result) - .SelectMany(r => r); - - ProcessChanges(changes); - - stop.Stop(); - -#if (DEBUG) - Main.logger.Log($"MissionControlAll finished processing in {stop.Elapsed} ms"); -#endif - } - public static void MissionControlMaid(Maid maid) - { -#if (DEBUG) - Main.logger.Log($"Started"); -#endif - - Stopwatch stop = new Stopwatch(); - - stop.Start(); - -#if (DEBUG) - Main.logger.Log($"Checking maid isn't null."); -#endif - - if (maid == null) - { - return; - } - -#if (DEBUG) - Main.logger.Log($"Fetching morphs"); -#endif - - //var morphs = await Task.Factory.StartNew(() => GetAllMorphsFromMaid(maid)); - IEnumerable morphs = GetAllMorphsFromMaid(maid); - -#if (DEBUG) - Main.logger.Log($"Converting morphs to changes..."); -#endif - - IEnumerable changes = morphs - //.Select(m => Task.Factory.StartNew(() => GetTMorphChangeForm(m))) - .Select(m => GetTMorphChangeForm(m)) - //.Select(async t => await t) - //.Select(n => n.Result) - .SelectMany(r => r); - -#if (DEBUG) - Main.logger.Log($"Processing changes..."); -#endif - ProcessChanges(changes); - - stop.Stop(); - -#if (DEBUG) - Main.logger.Log($"MissionControlMaid finished processing in {stop.Elapsed} ms"); -#endif - } - public static void MissionControlSingleEntry(ShapeKeyEntry sk) - { - Stopwatch stop = new Stopwatch(); - - stop.Start(); - -#if (DEBUG) - Main.logger.Log($"Calculating single entry..."); -#endif - - List maids = new List(); - - if (sk.Maid == "") - { - maids = maidslist - .Where(m => m != null) - .ToList(); - } - else - { - maids = maidslist - .Where(m => m != null && m.status.fullNameJpStyle == sk.Maid) - .ToList(); - } - -#if (DEBUG) - Main.logger.Log($"Fetched Maids"); -#endif - - if (maids.Count <= 0) - { - return; - } - -#if (DEBUG) - Main.logger.Log($"Maids were not zero..."); -#endif - - List morphs = maids - //.Select(m => Task.Factory.StartNew(() => GetAllMorphsFromMaid(m))) - .Select(m => GetAllMorphsFromMaid(m)) - //.Select(async t => await t) - //.Select(n => n.Result) - .SelectMany(r => r) - .Where(m => m.Contains(sk.ShapeKey)) - .ToList(); - -#if (DEBUG) - Main.logger.Log($"Fetched Morphs"); -#endif - - if (morphs.Count <= 0) - { - return; - } - -#if (DEBUG) - Main.logger.Log($"Morphs were not zero"); -#endif - - IEnumerable changes = morphs - //.Select(m => Task.Factory.StartNew(() => GetShapekeyChangeForm(sk,m))) - .Select(m => GetShapekeyChangeForm(sk, m)); - //.Select(async t => await t) - //.Select(n => n.Result); - -#if (DEBUG) - Main.logger.Log($"Turned morphs into changes"); -#endif - - ProcessChanges(changes); - -#if (DEBUG) - Main.logger.Log($"Processed changes..."); -#endif - - stop.Stop(); - -#if (DEBUG) - Main.logger.Log($"MissionControlSingleEntry finished processing in {stop.Elapsed} ms"); -#endif - } - //This function takes a morph and checks every single shapekey entry for one that edits the held morph. If one is found, pushes to modify morph. - public static List GetTMorphChangeForm(TMorph m) - { -#if (DEBUG) - Main.logger.Log($"Working on TMorph holding this many morphs: {m.MorphCount}"); -#endif - - //Filters the list and only returns viable shapekey entries to reduce processing times. - List templist = UI.ShapeKeys.Values - .Where(s => s.Enabled == true - && s.IsProp == false - && (s.Maid.Equals("") || m.bodyskin.body.maid.status.fullNameJpStyle.Equals(s.Maid)) - && m.Contains(s.ShapeKey)) - .ToList(); - - List resultList = new List(); - - //Checks every held shapekeyentry and works as required. - foreach (ShapeKeyEntry s in templist) - { -#if (DEBUG) - Main.logger.Log($"Checking that it isn't a face morph..."); -#endif - - if (m.bodyskin.body.Face != null && m.bodyskin.body.Face.morph.Contains(s.ShapeKey)) - { -#if (DEBUG) - Main.logger.Log($"We are processing a facial key of {s.ShapeKey}"); -#endif - m.bodyskin.body.maid.boMabataki = false; - } - - int shapekeyIndex = (int)m.hash[s.ShapeKey]; - - //If maid is orgasming and orgasms animation is on, we call a run single on the shapekey with parameters supplied by the orgasm animator. - if (s.GetAnimateWithOrgasm() && IsOrgasming) - { - resultList.Add(new ShapekeyChangeForm - { - Morph = m, - Index = shapekeyIndex, - Deform = OrgasmDeform, - ShapekeyName = s.ShapeKey - }); - - continue; - } - - //If the maid is supposed to be animated with excitement and we are in yotogi, we set values according to an excitement deformation calculation. - if (s.AnimateWithExcitement && YotogiLvls.Contains(SceneManager.GetActiveScene().name)) - { - float deform = CalculateExcitementDeformation(s, maidslist); - - resultList.Add(new ShapekeyChangeForm - { - Morph = m, - Index = shapekeyIndex, - Deform = deform, - ShapekeyName = s.ShapeKey - }); - - continue; - } - - resultList.Add(new ShapekeyChangeForm - { - Morph = m, - Index = shapekeyIndex, - Deform = s.Deform, - ShapekeyName = s.ShapeKey - }); -#if (DEBUG) - Main.logger.Log($"Creating change form of {shapekeyIndex} {s.Deform} {s.ShapeKey}"); -#endif - } - return resultList; - } - //This is basically a copy of RunSingleTmorph but made to work with shapekey entries as input instead of morphs. - public static ShapekeyChangeForm GetShapekeyChangeForm(ShapeKeyEntry s, TMorph m) - { -#if (DEBUG) - Main.logger.Log($"Working on TMorph holding this many morphs: {m.MorphCount}"); -#endif - - List resultList = new List(); - -#if (DEBUG) - Main.logger.Log($"Checking that it isn't a face morph..."); -#endif - - if (m.bodyskin.body.Face != null && m.bodyskin.body.Face.morph.Contains(s.ShapeKey)) - { -#if (DEBUG) - Main.logger.Log($"We are processing a facial key of {s.ShapeKey}"); -#endif - m.bodyskin.body.maid.boMabataki = false; - } - - int shapekeyIndex = (int)m.hash[s.ShapeKey]; - - //If maid is orgasming and orgasms animation is on, we call a run single on the shapekey with parameters supplied by the orgasm animator. - if (s.GetAnimateWithOrgasm() && IsOrgasming) - { - return new ShapekeyChangeForm - { - Morph = m, - Index = shapekeyIndex, - Deform = OrgasmDeform, - ShapekeyName = s.ShapeKey - }; - } - - //If the maid is supposed to be animated with excitement and we are in yotogi, we set values according to an excitement deformation calculation. - if (s.AnimateWithExcitement && YotogiLvls.Contains(SceneManager.GetActiveScene().name)) - { - float deform = CalculateExcitementDeformation(s, maidslist); - - return new ShapekeyChangeForm - { - Morph = m, - Index = shapekeyIndex, - Deform = deform, - ShapekeyName = s.ShapeKey - }; - } - - return new ShapekeyChangeForm - { - Morph = m, - Index = shapekeyIndex, - Deform = s.Deform, - ShapekeyName = s.ShapeKey - }; - } - //Even though this goes against my mission control's idea. I wanted to save myself the trouble of rewriting the same code 3 times As such, I decided to go for it. This will be run sync though. - public static void ProcessChanges(IEnumerable changes) - { -#if (DEBUG) - Main.logger.Log($"Processing changes..."); -#endif - - //List taskList = new List(); - -#if (DEBUG) - Main.logger.Log($"Starting foreach..."); -#endif - - if (changes.Count() <= 0) - { -#if (DEBUG) - Main.logger.Log($"There were 0 changes to be made..."); -#endif - } - - ChangeList.AddRange(changes.ToList()); - - if (CorouteRunning == false) - { - Main.@this.StartCoroutine(RunShapekeyChange()); - } - -#if (DEBUG) - Main.logger.Log($"Finished foreach..."); -#endif - } - //The actual changes are pushed to a coroutine. Coroutines have the property of always running on the main thread, in time with the main thread so pushing this function to a coroutine from a worker thread ensures safe changes. However when possible. It should be avoided as creating too many coroutines is asking for trouble. - public static IEnumerator RunShapekeyChange() - { - CorouteRunning = true; - - yield return new WaitForEndOfFrame(); - - //Setting a value of less than 0 can cause the game to crash. As such, we ensure we never set a 0 val. - - while (ChangeList.Count > 0) - { - if (ChangeList[0].Morph != null && ChangeList[0].Morph.GetBlendValues(ChangeList[0].Index) != ChangeList[0].Deform) - { - if (ChangeList[0].Morph == null || ChangeList[0].Morph.bodyskin == null || ChangeList[0].Morph.bodyskin.body == null || ChangeList[0].Morph.bodyskin.body.maid.isActiveAndEnabled == false) - { - yield return new WaitForEndOfFrame(); - } - - if (ChangeList[0].Deform < 0) - { - ChangeList[0].Deform = 0; - } - -#if (DEBUG) - Main.logger.Log($"Value needs setting! Setting value of {ChangeList[0].Deform}"); -#endif - Main.SetBlendValues(ChangeList[0].Index, (ChangeList[0].Deform / 100f), ChangeList[0].Morph); - //FixSingleBlendValues(m, shapekeyIndex); - - try - { - ChangeList[0].Morph.FixBlendValues(); - } - catch - { - } - -#if (DEBUG) - Main.logger.Log($"Checking if was a face morph and needs updating"); -#endif - if (ChangeList[0].Morph.bodyskin != null && ChangeList[0].Morph.bodyskin.body != null && ChangeList[0].Morph.bodyskin.body.Face != null && ChangeList[0].Morph.bodyskin.body.Face.morph != null && ChangeList[0].Morph.bodyskin.body.Face.morph.Contains(ChangeList[0].ShapekeyName)) - { - ChangeList[0].Morph.bodyskin.body.Face.morph.FixBlendValues_Face(); - } - - ChangeList.RemoveAt(0); - -#if (DEBUG) - Main.logger.Log($"Done with single shapekey change."); -#endif - } - } - CorouteRunning = false; - } - /* - public static void FixSingleBlendValues(TMorph morph, int index) - { - int num = 0; - var BlendValuesCHK = AccessTools.DeclaredField(typeof(TMorph), "BlendValuesCHK").GetValue(morph) as float[]; - - var BlendValues = AccessTools.DeclaredField(typeof(TMorph), "BlendValues").GetValue(morph) as float[]; - - if (BlendValuesCHK[index] != BlendValues[index]) - { - num++; - BlendValuesCHK[index] = BlendValues[index]; - } - if (num == 0) - { - return; - } - - var m_vTmpVert = AccessTools.DeclaredField(typeof(TMorph), "m_vTmpVert").GetValue(morph) as Vector3[]; - - var m_vTmpNorm = AccessTools.DeclaredField(typeof(TMorph), "m_vTmpNorm").GetValue(morph) as Vector3[]; - - var m_bMorph = (bool)AccessTools.DeclaredField(typeof(TMorph), "m_bMorph").GetValue(morph); - - morph.m_vOriVert.CopyTo(m_vTmpVert, 0); - morph.m_vOriNorm.CopyTo(m_vTmpNorm, 0); - m_bMorph = true; - if (morph.BlendDatas[index] == null) - { - morph.UruUruScaleX = BlendValues[index]; - } - else - { - float num2 = BlendValues[index]; - if (num2 >= 0.01f || index == morph.m_MayuShapeIn.idx || index == morph.m_MayuShapeOut.idx) - { - int num3 = morph.BlendDatas[index].v_index.Length; - for (int k = 0; k < num3; k++) - { - int num4 = morph.BlendDatas[index].v_index[k]; - m_vTmpVert[num4] += morph.BlendDatas[index].vert[k] * num2; - m_vTmpNorm[num4] += morph.BlendDatas[index].norm[k] * num2; - } - } - } - - var m_mesh = (Mesh)AccessTools.DeclaredField(typeof(TMorph), "m_mesh").GetValue(morph); - - var m_bindposes = AccessTools.DeclaredField(typeof(TMorph), "m_bindposes").GetValue(morph) as Matrix4x4[]; - - m_mesh.vertices = m_vTmpVert; - m_mesh.normals = m_vTmpNorm; - foreach (TAttachPoint tattachPoint in morph.dicAttachPoint.Values) - { - int vidx = tattachPoint.vidx; - morph.BindVert[vidx] = m_bindposes[tattachPoint.bw.boneIndex0].MultiplyPoint3x4(m_vTmpVert[vidx]); - } - }*/ - /* - //The animator can be considered something of a manager. It simply calculates orgasms and - public static IEnumerator OrgasmAnimator() - { -#if (DEBUG) - Main.logger.Log($"Orgasm animator has started!!"); -#endif - - yield return new WaitForSecondsRealtime(2); - - System.Random rand = new System.Random(); - Stopwatch s = new Stopwatch(); - Stopwatch s2 = new Stopwatch(); - s.Start(); - s2.Start(); - IsOrgasming = true; - - Main.@this.StartCoroutine(UpdateOrgasmKeys()); - - while (s.Elapsed < TimeSpan.FromSeconds(4)) - { - s2.Start(); - - while (OrgasmDeform < 100) - { - OrgasmDeform += 25; - - if (OrgasmDeform > 100) - { - OrgasmDeform = 100; - } - - yield return new WaitForSeconds(.1f); - } - - while (OrgasmDeform > 0 && s.Elapsed < TimeSpan.FromSeconds(1)) - { - OrgasmDeform -= 10; - - if (OrgasmDeform < 0) - { - OrgasmDeform = 0; - } - - yield return new WaitForSeconds(.1f); - } - s2.Reset(); - } - s.Stop(); - -#if (DEBUG) - Main.logger.Log($"Finishing..."); -#endif - - while (OrgasmDeform > 0) - { -#if (DEBUG) - Main.logger.Log($"Reducing {OrgasmDeform}"); -#endif - - OrgasmDeform -= 10; - - yield return new WaitForSeconds(.10f); - } - - IsOrgasming = false; - -#if (DEBUG) - Main.logger.Log($"Orgasm animator has finished: {s.Elapsed}"); -#endif - } - private static IEnumerator UpdateOrgasmKeys() - { - while (IsOrgasming) - { - RunAllBackgroundAsync(); - - yield return new WaitForSecondsRealtime(.5f); - } - yield break; - }*/ - } -} \ No newline at end of file diff --git a/YotogiShapekeys/0Old/BlendShapeFetcherSetter.cs b/YotogiShapekeys/0Old/BlendShapeFetcherSetter.cs deleted file mode 100644 index 80872ed..0000000 --- a/YotogiShapekeys/0Old/BlendShapeFetcherSetter.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using UnityEngine; -using UnityEngine.SceneManagement; -using static ShapekeyMaster.HelperClasses; - -namespace ShapekeyMaster -{ - internal static class BlendShapeFetcherSetter - { - public static void RunAll() - { -#if (DEBUG) - Main.logger.Log($"Updated called. Running on all."); -#endif - - UnityEngine.Object.FindObjectsOfType() - .ToList() - //.Where(smr => smr.sharedMesh.blendShapeCount > 0) - .ForEach(sm => RunSkinnedMesh(sm)); - } - static void RunSkinnedMesh(SkinnedMeshRenderer smr) - { -#if (DEBUG) - Main.logger.Log($"Working on skinned mesh: {smr.name}"); -#endif - foreach (KeyValuePair shapekey in UI.ShapeKeys) - { - if (shapekey.Value.IsProp) - { -#if (DEBUG) - Main.logger.Log($"Working on shapekey entry: {shapekey.Value.EntryName}"); -#endif - GetAllBlendShapes(smr.sharedMesh) - .Where(b => b.Equals(shapekey.Value.ShapeKey)) - .ToList() - .ForEach((bs) => - { -#if (DEBUG) - Main.logger.Log($"Working on blendvalue: {bs}"); -#endif - smr.SetBlendShapeWeight(smr.sharedMesh.GetBlendShapeIndex(bs), shapekey.Value.Deform); - }); - } - } - } - } -} \ No newline at end of file diff --git a/YotogiShapekeys/0Old/PrivateSettersContractResolver.cs b/YotogiShapekeys/0Old/PrivateSettersContractResolver.cs deleted file mode 100644 index 6a061f7..0000000 --- a/YotogiShapekeys/0Old/PrivateSettersContractResolver.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; - -namespace ShapekeyMaster -{ - class PrivateSettersContractResolver : DefaultContractResolver - { - protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) - { - var prop = base.CreateProperty(member, memberSerialization); - if (!prop.Writable) - { - var property = member as PropertyInfo; - var hasPrivateSetter = property?.GetSetMethod(true) != null; - prop.Writable = hasPrivateSetter; - } - return prop; - } - } -} \ No newline at end of file diff --git a/YotogiShapekeys/0Old/PropsMenu.cs b/YotogiShapekeys/0Old/PropsMenu.cs deleted file mode 100644 index ab0ad80..0000000 --- a/YotogiShapekeys/0Old/PropsMenu.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace ShapekeyMaster._0Old -{ - class PropsMenu - { - private static void DisplayPropShapeKeyEntriesMenu(SortedDictionary ShapeKeys) - { - if (GUILayout.Button("Add New Shapekey")) - { -#if (DEBUG) - Main.logger. - ("I've been clicked! Oh the humanity!!"); -#endif - - Guid newkey = Guid.NewGuid(); - - ShapeKeys.Add(newkey, new ShapeKeyEntry(newkey, null, true)); - } - - //GUILayout.Label("", seperator); - - foreach (ShapeKeyEntry s in ShapeKeys.Values) - { - if (s.IsProp == false) - { - continue; - } - - if (Filter != "") - { - if (FilterMode == 0) - { - if (s.EntryName.Contains(Filter, StringComparison.OrdinalIgnoreCase) == false) - { - continue; - } - } - else if (FilterMode == 1) - { - if (s.Maid.Contains(Filter, StringComparison.OrdinalIgnoreCase) == false) - { - continue; - } - } - else if (FilterMode == 2) - { - if (s.ShapeKey.Contains(Filter, StringComparison.OrdinalIgnoreCase) == false) - { - continue; - } - } - } - - if (s.Collapsed == false) - { - if (GUILayout.Button($"Collapse {s.EntryName}")) - { - s.Collapsed = !s.Collapsed; - } - - s.SetEnabled(GUILayout.Toggle(s.Enabled, $"Enable")); - GUILayout.BeginHorizontal(); - GUILayout.Label("ShapeKey"); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - - if (GUILayout.Button("+")) - { - } - - s.SetShapeKey(GUILayout.TextField(s.ShapeKey)); - - GUILayout.EndHorizontal(); - - GUILayout.Label($"Shapekey Deformation: {s.DeformMax}"); - s.SetDeform(Mathf.RoundToInt(GUILayout.HorizontalSlider(s.Deform, 0, 100.0F))); - - if (GUILayout.Button($"Rename {s.EntryName}")) - { - OpenRenameMenu = s.Id; - } - - if (GUILayout.Button($"Delete {s.EntryName}")) - { - DeleteList.Add(s.Id); - } - } - else - { - if (GUILayout.Button($"Expand {s.EntryName}")) - { - s.Collapsed = !s.Collapsed; - } - } - //GUILayout.Label("", seperator); - } - } - } -} \ No newline at end of file diff --git a/YotogiShapekeys/0Old/ShapekeyFetcherSetter - Original.cs b/YotogiShapekeys/0Old/ShapekeyFetcherSetter - Original.cs deleted file mode 100644 index 02b5434..0000000 --- a/YotogiShapekeys/0Old/ShapekeyFetcherSetter - Original.cs +++ /dev/null @@ -1,354 +0,0 @@ -using BepInEx; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using UnityEngine; -using UnityEngine.SceneManagement; -using static ShapekeyMaster.HelperClasses; -using Debug = UnityEngine.Debug; - -namespace ShapekeyMaster -{ - internal class ShapekeyFetcherSetter - { - private static List maidslist = new List(); - private static readonly List YotogiLvls = new List() { "SceneYotogi", "SceneYotogiOld" }; - private static int OrgasmDeform = 1; - private static bool IsOrgasming = false; - - //This func is called in to register a maid into the list of maids. Handy of keeping track of them. - public static void RegisterMaid(Maid maid) - { - if (maidslist.Contains(maid) == false) - { - maidslist.Add(maid); - } - - maidslist = maidslist - .Where(m => m != null) - .Distinct() - .ToList(); - - RunSingleMaid(maid); - } - //This can be called externally to purposefully remove a maid from tracking. Currently unused. - public static void UnRegisterMaid(Maid maid) - { - maidslist.Remove(maid); - } - //Called so external functions can get the maid list in a controlled fashion. - public static List GetMaidsList() - { - return maidslist; - } - //The main idea behind MissionControl is to eventually have it drive everything on first thread and simply instruct the worker threads allowing flexibility for when we need to run something on thread 1. As a result, Mission control will have a few versions. - public async Task MissionControl() - { - } - //Async way of running the run all func. - public async static void RunAllBackgroundAsync() - { - //Made async worker threading an optional. This helps debugging and comparisons. - if (Main.BackgroundTasks) - { - //By pushing our func to a worker thread and calling await, we tell our program to process this lengthy and costly function in another thread, allow other code to process in maint thread and reattain control once processing in the worker thread is done. - await Task.Factory.StartNew(() => RunAll()); - } - else - { - await RunAll(); - } - } - //This func fetches all maids and pushes them to a function that works with every maid in turn. - public static Task RunAll() - { - //yield return new WaitForEndOfFrame(); - -#if (DEBUG) - Main.logger.Log($"Running on all!"); -#endif - - maidslist - .Where(m => m != null) - .ToList() - .ForEach(m => RunSingleMaid(m)); - - Main.logger.Log("Finished RunAll"); - - return null; - } - //Another async entry point for run on single maids. Only called by external functions, higher functions in the chain don't call these async as they themselves are already running async. This helps with stability. - public async static void RunSingleMaidBackgroundAsync(Maid maid) - { - if (Main.BackgroundTasks) - { - await Task.Factory.StartNew(() => RunSingleMaid(maid)); - } - else - { - await RunSingleMaid(maid); - } - } - //This simple func just fetches all morphs from a maid and sends it to the single morph func - public static Task RunSingleMaid(Maid maid) - { - //yield return new WaitForEndOfFrame(); -#if (DEBUG) - Main.logger.Log($"Working on maid: {maid.status.fullNameJpStyle} with {GetAllMorphsFromMaid(maid).Count()} TMorphs"); -#endif - GetAllMorphsFromMaid(maid) - .ToList() - .ForEach(tm => ShapekeyFetcherSetter.RunSingleTMorph(tm)); - - return null; - } - //This function takes a morph and checks every single shapekey entry for one that edits the held morph. If one is found, pushes to modify morph. - public static Task RunSingleTMorph(TMorph m) - { -#if (DEBUG) - Main.logger.Log($"Working on TMorph holding this many morphs: {m.MorphCount}"); -#endif - - //Filters the list and only returns viable shapekey entries to reduce processing times. - var templist = UI.ShapeKeys.Values - .Where(s => s.Enabled == true - && s.IsProp == false - && (s.Maid.Equals("") || m.bodyskin.body.maid.status.fullNameJpStyle.Equals(s.Maid)) - && m.Contains(s.ShapeKey)) - .ToList(); - - //Checks every held shapekeyentry and works as required. - foreach (ShapeKeyEntry s in templist) - { -#if (DEBUG) - Main.logger.Log($"Checking that it isn't a face morph..."); -#endif - - if (m.bodyskin.body.Face != null && m.bodyskin.body.Face.morph.Contains(s.ShapeKey)) - { -#if (DEBUG) - Main.logger.Log($"We are processing a facial key of {s.ShapeKey}"); -#endif - m.bodyskin.body.maid.boMabataki = false; - } - - int shapekeyIndex = (int)m.hash[s.ShapeKey]; - - //If maid is orgasming and orgasms animation is on, we call a run single on the shapekey with parameters supplied by the orgasm animator. - if (s.GetAnimateWithOrgasm() && IsOrgasming) - { - Main.@this.StartCoroutine(RunShapekeyChange(m, shapekeyIndex, OrgasmDeform)); - - continue; - } - - //If the maid is supposed to be animated with excitement and we are in yotogi, we set values according to an excitement deformation calculation. - if (s.AnimateWithExcitement && YotogiLvls.Contains(SceneManager.GetActiveScene().name)) - { - float deform = CalculateExcitementDeformation(s, maidslist); - - Main.@this.StartCoroutine(RunShapekeyChange(m, shapekeyIndex, deform)); - - continue; - } - - //If nothing special is happening, - Main.@this.StartCoroutine(RunShapekeyChange(m, shapekeyIndex, s.Deform)); - } - return null; - } - public async static Task RunSingleShapekeyBackgroundAsync(ShapeKeyEntry s) - { - if (Main.BackgroundTasks) - { - await Task.Factory.StartNew(() => RunSingleShapekey(s)); - } - else - { - await RunSingleShapekey(s); - } - -#if (DEBUG) - Main.logger.Log($"Finished shapekey update"); -#endif - - return; - } - //This is basically a copy of RunSingleTmorph but made to work with shapekey entries as input instead of morphs. - public static Task RunSingleShapekey(ShapeKeyEntry s, bool coroute = true) - { - if (s.Enabled == false) - { - return null; - } - if (s.IsProp == true) - { - return null; - } - - List templist = GetAllMorphsFromMaidList(maidslist) - .Where(m => - (s.Maid.Equals("") || m.bodyskin.body.maid.status.fullNameJpStyle.Equals(s.Maid)) - && m.Contains(s.ShapeKey)) - .ToList(); - - foreach (TMorph m in templist) - { -#if (DEBUG) - Main.logger.Log($"Working on TMorph holding this many morphs: {m.MorphCount}"); - Main.logger.Log($"Checking that it isn't a face morph..."); -#endif - - if (m.bodyskin.body.Face != null && m.bodyskin.body.Face.morph.Contains(s.ShapeKey)) - { -#if (DEBUG) - Main.logger.Log($"We are processing a facial key of {s.ShapeKey}"); -#endif - m.bodyskin.body.maid.boMabataki = false; - } - -#if (DEBUG) - Main.logger.Log($"Found! Checking if value needs setting."); -#endif - int shapekeyIndex = (int)m.hash[s.ShapeKey]; - - if (s.AnimateWithExcitement && YotogiLvls.Contains(SceneManager.GetActiveScene().name)) - { - //RunShapekeyChange(m, shapekeyIndex, 0); - - float deform = CalculateExcitementDeformation(s, maidslist); - - Main.@this.StartCoroutine(RunShapekeyChange(m, shapekeyIndex, deform)); -#if (DEBUG) - Main.logger.Log($"Animating with yotogi..."); -#endif - continue; - } - - if (coroute) - { - Main.@this.StartCoroutine(RunShapekeyChange(m, shapekeyIndex, s.Deform)); - } - else - { - RunShapekeyChange(m, shapekeyIndex, s.Deform); - } - } -#if (DEBUG) - Main.logger.Log($"Finished Single Key Change Update"); -#endif - return null; - } - //The actual changes are pushed to a coroutine. Coroutines have the property of always running on the main thread, in time with the main thread so pushing this function to a coroutine from a worker thread ensures safe changes. However when possible. It should be avoided as creating too many coroutines is asking for trouble. - public static IEnumerator RunShapekeyChange(TMorph m, int shapekeyIndex, float deform) - { - yield return new WaitForEndOfFrame(); - - //Setting a value of less than 0 can cause the game to crash. As such, we ensure we never set a 0 val. - if (deform < 0) - { - deform = 0; - } - - if (m.GetBlendValues(shapekeyIndex) != deform) - { -#if (DEBUG) - Main.logger.Log($"Value needs setting! Setting value of {deform}"); -#endif - Main.SetBlendValues(shapekeyIndex, (deform / 100f), m); - } - m.FixBlendValues(); - - if (m.bodyskin.body.maid.boMabataki == false) - { - m.bodyskin.body.Face.morph.FixBlendValues_Face(); - } - } - /* - //The animator can be considered something of a manager. It simply calculates orgasms and - public static IEnumerator OrgasmAnimator() - { -#if (DEBUG) - Main.logger.Log($"Orgasm animator has started!!"); -#endif - - yield return new WaitForSecondsRealtime(2); - - System.Random rand = new System.Random(); - Stopwatch s = new Stopwatch(); - Stopwatch s2 = new Stopwatch(); - s.Start(); - s2.Start(); - IsOrgasming = true; - - Main.@this.StartCoroutine(UpdateOrgasmKeys()); - - while (s.Elapsed < TimeSpan.FromSeconds(4)) - { - s2.Start(); - - while (OrgasmDeform < 100) - { - OrgasmDeform += 25; - - if (OrgasmDeform > 100) - { - OrgasmDeform = 100; - } - - yield return new WaitForSeconds(.1f); - } - - while (OrgasmDeform > 0 && s.Elapsed < TimeSpan.FromSeconds(1)) - { - OrgasmDeform -= 10; - - if (OrgasmDeform < 0) - { - OrgasmDeform = 0; - } - - yield return new WaitForSeconds(.1f); - } - s2.Reset(); - } - s.Stop(); - -#if (DEBUG) - Main.logger.Log($"Finishing..."); -#endif - - while (OrgasmDeform > 0) - { -#if (DEBUG) - Main.logger.Log($"Reducing {OrgasmDeform}"); -#endif - - OrgasmDeform -= 10; - - yield return new WaitForSeconds(.10f); - } - - IsOrgasming = false; - -#if (DEBUG) - Main.logger.Log($"Orgasm animator has finished: {s.Elapsed}"); -#endif - } - private static IEnumerator UpdateOrgasmKeys() - { - while (IsOrgasming) - { - RunAllBackground - - (); - - yield return new WaitForSecondsRealtime(.5f); - } - yield break; - }*/ - } -} \ No newline at end of file diff --git a/YotogiShapekeys/1Old/HarmonyPatchers.cs b/YotogiShapekeys/1Old/HarmonyPatchers.cs deleted file mode 100644 index c726b44..0000000 --- a/YotogiShapekeys/1Old/HarmonyPatchers.cs +++ /dev/null @@ -1,81 +0,0 @@ -using HarmonyLib; -using UnityEngine; - -namespace ShapekeyMaster -{ - internal class HarmonyPatchers - { - [HarmonyPatch(typeof(ImportCM), "LoadSkinMesh_R")] - [HarmonyPostfix] - private static void NotifyOfLoad2(ref TMorph __1) - { -#if (DEBUG) - Main.logger. - ("ShapekeyMaster picked up a maid load! Registering maid..."); -#endif - ShapekeyFetcherSetter.RegisterMaid(__1.bodyskin.body.maid); - } - - //A bit of a shotgun solution but basically it makes it so that our plugin has ultimate say so of what blend values are changed to what. Might not be the most compatible in the long run so a more friendly solution should eventually be seeked out. - [HarmonyPatch(typeof(TMorph), "SetBlendValues")] - [HarmonyPrefix] - private static bool Intercede(ref int __0, ref float __1, ref TMorph __instance) - { - foreach (ShapeKeyEntry s in UI.SKDatabase.AllShapekeyDictionary.Values) - { - if (s.Enabled && __instance.hash.ContainsKey(s.ShapeKey) && (int)__instance.hash[s.ShapeKey] == __0) - { - if (s.Maid == "") - { -#if (DEBUG) - Main.logger.LogDebug("ShapekeyMaster noticed a value not set by it.. Discarding change..."); -#endif - - return false; - } - else if (s.Maid == __instance.bodyskin.body.maid.status.fullNameJpStyle) - { -#if (DEBUG) - Main.logger.LogDebug("ShapekeyMaster noticed a value not set by it. Discarding change..."); -#endif - - return false; - } - } - } - return true; - } - - [HarmonyPatch(typeof(TMorph), "ResetBlendValues")] - [HarmonyPostfix] - private static void Intercede1(ref TMorph __instance) - { - Maid maid = __instance.bodyskin.body.maid; - ShapekeyFetcherSetter.RegisterMaid(maid); - } - - //Patches the setter of the FPS value to run below code afterwards - [HarmonyPatch(typeof(MaidStatus.Status), "currentExcite", MethodType.Setter)] - [HarmonyPostfix] - public static void OnExciteSet(ref MaidStatus.Status __instance) - { - ShapekeyFetcherSetter.RunAll(); - -#if (DEBUG) - - Main.logger.LogDebug($"{__instance.fullNameJpStyle }'s excitement changed to {__instance.currentExcite}! Making changes..."); -#endif - } - //Orgasm was detected! - /* - [HarmonyPatch(typeof(YotogiPlayManager), "PlayNormalClimax")] - [HarmonyPatch(typeof(YotogiOldPlayManager), "PlayNormalClimax")] - [HarmonyPostfix] - public static void OnOrgasm(string __0) - { - Main.@this.StartCoroutine(ShapekeyFetcherSetter.OrgasmAnimator()); - - Main.logger.Log($"Somebody seems to be having an orgasm!"); - }*/ - } -} \ No newline at end of file diff --git a/YotogiShapekeys/1Old/ShapekeyChangeForm.cs b/YotogiShapekeys/1Old/ShapekeyChangeForm.cs deleted file mode 100644 index fefcc71..0000000 --- a/YotogiShapekeys/1Old/ShapekeyChangeForm.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace ShapekeyMaster -{ - internal class ShapekeyChangeForm - { - public TMorph Morph; - public int Index; - public float Deform; - public string ShapekeyName; - - public ShapekeyChangeForm() - { - } - } -} \ No newline at end of file diff --git a/YotogiShapekeys/1Old/ShapekeyFetcherSetter.cs b/YotogiShapekeys/1Old/ShapekeyFetcherSetter.cs deleted file mode 100644 index 33a6bb1..0000000 --- a/YotogiShapekeys/1Old/ShapekeyFetcherSetter.cs +++ /dev/null @@ -1,388 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -//using System.Threading.Tasks; -using UnityEngine; -using UnityEngine.SceneManagement; -using static ShapekeyMaster.HelperClasses; -using Debug = UnityEngine.Debug; - -namespace ShapekeyMaster -{ - internal class ShapekeyFetcherSetter - { - private static List maidslist = new List(); - private static readonly List YotogiLvls = new List() { "SceneYotogi", "SceneYotogiOld" }; - private static readonly int OrgasmDeform = 1; - private static readonly bool IsOrgasming = false; - private static readonly List ChangeList = new List(); - private static bool CorouteRunning = false; - public static void RegisterMaid(Maid maid) - { - if (maidslist.Contains(maid) == false) - { - maidslist.Add(maid); - } - - maidslist = maidslist - .Where(m => m != null) - .Distinct() - .ToList(); - - RunSingleMaid(maid); - } - //Called so external functions can get the maid list in a controlled fashion. - public static List GetMaidsList() - { - return maidslist; - } - public static void RunAll() - { -#if (DEBUG) - Main.logger.LogDebug($"Running on all!"); -#endif - - maidslist - .Where(m => m != null) - .ToList() - .ForEach(m => RunSingleMaid(m)); - - Main.logger.LogDebug("Finished RunAll"); - } - //This simple func just fetches all morphs from a maid and sends it to the single morph func - public static void RunSingleMaid(Maid maid) - { -#if (DEBUG) - Stopwatch stop = new Stopwatch(); - stop.Start(); -#endif - -#if (DEBUG) - Main.logger.LogDebug($"Working on maid: {maid.status.fullNameJpStyle} with {GetAllMorphsFromMaid(maid).Count()} TMorphs"); -#endif - var changeForms = GetAllMorphsFromMaid(maid) - .Select(tm => ShapekeyFetcherSetter.GetTMorphChangeForm(tm)) - .SelectMany(r => r); - - ProcessChanges(changeForms); - -#if (DEBUG) - stop.Stop(); - Main.logger.LogDebug($"MissionControlSingleEntry finished processing in {stop.Elapsed} ms"); -#endif - } - public static void RunSingleEntry(ShapeKeyEntry sk) - { -#if (DEBUG) - Stopwatch stop = new Stopwatch(); - stop.Start(); - Main.logger.LogDebug($"Calculating single entry..."); -#endif - - List maids = new List(); - - if (sk.Maid == "") - { - maids = maidslist - .Where(m => m != null) - .ToList(); - } - else - { - maids = maidslist - .Where(m => m != null && m.status.fullNameJpStyle == sk.Maid) - .ToList(); - } - -#if (DEBUG) - Main.logger.LogDebug($"Fetched {maids.Count} Maids"); -#endif - - if (maids.Count <= 0) - { - return; - } - -#if (DEBUG) - Main.logger.LogDebug($"Maids were not zero..."); -#endif - - var morphs = maids - .Select(m => GetAllMorphsFromMaid(m)) - .SelectMany(r => r) - .Where(m => m.Contains(sk.ShapeKey)); - -#if (DEBUG) - Main.logger.LogDebug($"Fetched Morphs"); -#endif - - if (morphs.ToList().Count <= 0) - { - return; - } - -#if (DEBUG) - Main.logger.LogDebug($"Morphs were not zero"); -#endif - - var changes = morphs - .Select(m => GetTMorphChangeForm(m)) - .SelectMany(r => r); - -#if (DEBUG) - Main.logger.LogDebug($"Turned morphs into changes"); -#endif - - ProcessChanges(changes); - -#if (DEBUG) - Main.logger.LogDebug($"Processed changes..."); - - stop.Stop(); - Main.logger.LogDebug($"MissionControlSingleEntry finished processing in {stop.Elapsed} ms"); -#endif - } - //This function takes a morph and checks every single shapekey entry for one that edits the held morph. If one is found, pushes to modify morph. - public static List GetTMorphChangeForm(TMorph m) - { -#if (DEBUG) - Main.logger.LogDebug($"Working on TMorph holding this many morphs: {m.MorphCount}"); -#endif - - //Filters the list and only returns viable shapekey entries to reduce processing times. - List templist = UI.SKDatabase.AllShapekeyDictionary.Values - .Where(s => (s.Maid.Equals("") || m.bodyskin.body.maid.status.fullNameJpStyle.Equals(s.Maid)) - && m.Contains(s.ShapeKey)) - .ToList(); - - List resultList = new List(); - - //Checks every held shapekeyentry and works as required. - foreach (ShapeKeyEntry s in templist) - { -#if (DEBUG) - Main.logger.LogDebug($"Checking that it isn't a face morph..."); -#endif - - if (m.bodyskin.body.Face != null && m.bodyskin.body.Face.morph != null && m.bodyskin.body.Face.morph.Contains(s.ShapeKey)) - { -#if (DEBUG) - Main.logger.LogDebug($"We are processing a facial key of {s.ShapeKey}"); -#endif - m.bodyskin.body.maid.boMabataki = false; - } - - int shapekeyIndex = (int)m.hash[s.ShapeKey]; - - //If maid is orgasming and orgasms animation is on, we just ask for the orgasm info. Currently unused... - if (s.GetAnimateWithOrgasm() && IsOrgasming) - { - resultList.Add(new ShapekeyChangeForm - { - Morph = m, - Index = shapekeyIndex, - Deform = OrgasmDeform, - ShapekeyName = s.ShapeKey - }); - - continue; - } - - //If the maid is supposed to be animated with excitement and we are in yotogi, we set values according to an excitement deformation calculation. - if (s.AnimateWithExcitement && YotogiLvls.Contains(SceneManager.GetActiveScene().name)) - { - float deform = CalculateExcitementDeformation(s, maidslist); - - resultList.Add(new ShapekeyChangeForm - { - Morph = m, - Index = shapekeyIndex, - Deform = deform, - ShapekeyName = s.ShapeKey - }); - - continue; - } - - resultList.Add(new ShapekeyChangeForm - { - Morph = m, - Index = shapekeyIndex, - Deform = s.Deform, - ShapekeyName = s.ShapeKey - }); -#if (DEBUG) - Main.logger.LogDebug($"Creating change form of {shapekeyIndex} {s.Deform} {s.ShapeKey}"); -#endif - } - return resultList; - } - //Even though this goes against my mission control's idea. I wanted to save myself the trouble of rewriting the same code 3 times As such, I decided to go for it. This will be run sync though. - public static void ProcessChanges(IEnumerable changes) - { -#if (DEBUG) - Main.logger.LogDebug($"Checking if changes are not zero and running coroutine if needed..."); -#endif - if (changes.Count() > 0) - { - ChangeList.AddRange(changes.ToList()); - - if (CorouteRunning == false) - { - Main.@this.StartCoroutine(RunShapekeyChange()); - //RunShapekeyChangeNormal(); - } - } - } - public static IEnumerator RunShapekeyChange() - { - CorouteRunning = true; - -#if (DEBUG) - Main.logger.LogDebug($"Started Changer Coroute..."); -#endif - - yield return null; - - while (ChangeList.Count > 0) - { -#if (DEBUG) - Main.logger.LogDebug($"Running the while..."); -#endif - - ShapekeyChangeForm nextKey = - ChangeList - .FirstOrDefault(t => t.Morph != null && t.Morph.bodyskin != null && t.Morph.bodyskin.body != null && t.Morph.bodyskin.body.maid.isActiveAndEnabled); - - if (nextKey == null) - { -#if (DEBUG) - Main.logger.LogDebug($"It seems no keys were ready to be changed. Waiting for next frame..."); -#endif - yield return null; - continue; - } - - if (nextKey.Morph.GetBlendValues(nextKey.Index) != nextKey.Deform) - { -#if (DEBUG) - Main.logger.LogDebug($"{nextKey.ShapekeyName} could be changed."); -#endif - - if (nextKey.Deform < 0) - { - nextKey.Deform = 0; - } - -#if (DEBUG) - Main.logger.LogDebug($"Value needs setting! Setting value of {nextKey.Deform} to {nextKey.ShapekeyName}"); -#endif - Main.SetBlendValues(nextKey.Index, (nextKey.Deform / 100f), nextKey.Morph); - - try - { - nextKey.Morph.FixBlendValues(); - } - catch - { -#if (DEBUG) - Main.logger.LogWarning($"Had some issues fixing blend values on {nextKey.ShapekeyName}. Be wary."); -#endif - } - -#if (DEBUG) - Main.logger.LogDebug($"Checking if {nextKey.ShapekeyName} was a face morph and needs updating"); -#endif - if (nextKey.Morph.bodyskin.body.Face != null && nextKey.Morph.bodyskin.body.Face.morph != null && nextKey.Morph.bodyskin.body.Face.morph.Contains(nextKey.ShapekeyName)) - { - nextKey.Morph.bodyskin.body.Face.morph.FixBlendValues_Face(); - } - - ChangeList.Remove(nextKey); - -#if (DEBUG) - Main.logger.LogDebug($"Done with single shapekey change on {nextKey.ShapekeyName}."); -#endif - } - else - { - ChangeList.Remove(nextKey); - } - } - -#if (DEBUG) - Main.logger.LogDebug($"Coroute is done. Now exiting..."); -#endif - - CorouteRunning = false; - } - public static void RunShapekeyChangeNormal() - { -#if (DEBUG) - Main.logger.LogDebug($"Started Changer Normal..."); -#endif - - while (ChangeList.Count > 0) - { -#if (DEBUG) - Main.logger.LogDebug($"Running the while..."); -#endif - - ShapekeyChangeForm nextKey = - ChangeList - .FirstOrDefault(t => t.Morph != null && t.Morph.bodyskin != null && t.Morph.bodyskin.body != null && t.Morph.bodyskin.body.maid.isActiveAndEnabled); - - if (nextKey.Morph.GetBlendValues(nextKey.Index) != nextKey.Deform) - { -#if (DEBUG) - Main.logger.LogDebug($"{nextKey.ShapekeyName} could be changed."); -#endif - - if (nextKey.Deform < 0) - { - nextKey.Deform = 0; - } - -#if (DEBUG) - Main.logger.LogDebug($"Value needs setting! Setting value of {nextKey.Deform} to {nextKey.ShapekeyName}"); -#endif - Main.SetBlendValues(nextKey.Index, (nextKey.Deform / 100f), nextKey.Morph); - - try - { - nextKey.Morph.FixBlendValues(); - } - catch - { -#if (DEBUG) - Main.logger.LogWarning($"Had some issues fixing blend values on {nextKey.ShapekeyName}. Be wary."); -#endif - } - -#if (DEBUG) - Main.logger.LogDebug($"Checking if {nextKey.ShapekeyName} was a face morph and needs updating"); -#endif - if (nextKey.Morph.bodyskin.body.Face != null && nextKey.Morph.bodyskin.body.Face.morph != null && nextKey.Morph.bodyskin.body.Face.morph.Contains(nextKey.ShapekeyName)) - { - nextKey.Morph.bodyskin.body.Face.morph.FixBlendValues_Face(); - } - - ChangeList.Remove(nextKey); - -#if (DEBUG) - Main.logger.LogDebug($"Done with single shapekey change on {nextKey.ShapekeyName}."); -#endif - } - else - { - ChangeList.Remove(nextKey); - } - } - -#if (DEBUG) - Main.logger.LogDebug($"Coroute is done. Now exiting..."); -#endif - } - } -} \ No newline at end of file diff --git a/YotogiShapekeys/SlotsFlags.cs b/YotogiShapekeys/CategorySlotHandler.cs similarity index 95% rename from YotogiShapekeys/SlotsFlags.cs rename to YotogiShapekeys/CategorySlotHandler.cs index b813ad4..a7e06ca 100644 --- a/YotogiShapekeys/SlotsFlags.cs +++ b/YotogiShapekeys/CategorySlotHandler.cs @@ -24,7 +24,7 @@ internal enum DisableWhenEquipped internal class SlotChecker { - private static readonly Dictionary SlotToSlotList = new Dictionary() + public static readonly Dictionary SlotToSlotList = new Dictionary() { //Why do you parse the enum?? Because it's way more update proof as the enum number won't slide if they add or subtract values. { DisableWhenEquipped.Wear,(TBody.SlotID)Enum.Parse(typeof(TBody.SlotID),"wear") }, @@ -81,7 +81,7 @@ internal static bool CheckIfSlotDisableApplies(ShapeKeyEntry entry, Maid maid) #if (DEBUG) Main.logger.LogDebug($"Checking {menu}"); #endif - var TBodySkins = HelperClasses + var TBodySkins = Extensions .FetchGoSlot(maid.body0) .Select(tbody => tbody) .Where(str => str.m_mp != null && str.m_mp.strFileName.Contains(menu, StringComparison.OrdinalIgnoreCase)); @@ -129,7 +129,7 @@ internal static bool CheckIfSlotDisableApplies(ShapeKeyEntry entry, Maid maid) #if (DEBUG) Main.logger.LogDebug($"Checking {menu}"); #endif - var TBodySkins = HelperClasses + var TBodySkins = Extensions .FetchGoSlot(maid.body0) .Select(tbody => tbody) .Where(str => str.m_mp != null && str.m_mp.strFileName.Contains(menu, StringComparison.OrdinalIgnoreCase)); diff --git a/YotogiShapekeys/MyGUI/UI.cs b/YotogiShapekeys/GUI/UI.cs similarity index 76% rename from YotogiShapekeys/MyGUI/UI.cs rename to YotogiShapekeys/GUI/UI.cs index 7dfbf32..26980fe 100644 --- a/YotogiShapekeys/MyGUI/UI.cs +++ b/YotogiShapekeys/GUI/UI.cs @@ -3,7 +3,9 @@ using System.Collections.Generic; using System.Linq; using UnityEngine; -using static ShapekeyMaster.MyGUI.Helpers; +using static RootMotion.FinalIK.IKSolverVR; +using static ShapekeyMaster.MyGUI.UIToolbox; +using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window; namespace ShapekeyMaster { @@ -54,6 +56,8 @@ internal static class UI private static bool ExportMenuOpen; public static Rect windowRect = new Rect(Screen.width / 3, Screen.height / 4, Screen.width / 3f, Screen.height / 1.5f); + private static Rect dragWindow = new Rect(0, 0, 10000, 20); + private static Rect closeButton = new Rect(0, 0, 25, 15); private static int currentHeight = 0; private static int currentWidth = 0; @@ -73,24 +77,24 @@ public static void Initialize() { seperator = new GUIStyle(GUI.skin.horizontalSlider); seperator.fixedHeight = 1f; - seperator.normal.background = MyGUI.Helpers.MakeTex(2, 2, new Color(0, 0, 0, 0.8f)); + seperator.normal.background = MyGUI.UIToolbox.MakeTex(2, 2, new Color(0, 0, 0, 0.8f)); seperator.margin.top = 10; seperator.margin.bottom = 10; MainWindow = new GUIStyle(GUI.skin.window); - MainWindow.normal.background = MyGUI.Helpers.MakeWindowTex(new Color(0, 0, 0, 0.05f), new Color(0, 0, 0, 0.5f)); + MainWindow.normal.background = MyGUI.UIToolbox.MakeWindowTex(new Color(0, 0, 0, 0.05f), new Color(0, 0, 0, 0.5f)); MainWindow.normal.textColor = new Color(1, 1, 1, 0.05f); - MainWindow.hover.background = MyGUI.Helpers.MakeWindowTex(new Color(0.3f, 0.3f, 0.3f, 0.3f), new Color(1, 0, 0, 0.5f)); + MainWindow.hover.background = MyGUI.UIToolbox.MakeWindowTex(new Color(0.3f, 0.3f, 0.3f, 0.3f), new Color(1, 0, 0, 0.5f)); MainWindow.hover.textColor = new Color(1, 1, 1, 0.3f); - MainWindow.onNormal.background = MyGUI.Helpers.MakeWindowTex(new Color(0.3f, 0.3f, 0.3f, 0.6f), new Color(1, 0, 0, 0.5f)); + MainWindow.onNormal.background = MyGUI.UIToolbox.MakeWindowTex(new Color(0.3f, 0.3f, 0.3f, 0.6f), new Color(1, 0, 0, 0.5f)); Sections = new GUIStyle(GUI.skin.box); - Sections.normal.background = MyGUI.Helpers.MakeTex(2, 2, new Color(0, 0, 0, 0.3f)); + Sections.normal.background = MyGUI.UIToolbox.MakeTex(2, 2, new Color(0, 0, 0, 0.3f)); Sections2 = new GUIStyle(GUI.skin.box); - Sections2.normal.background = MyGUI.Helpers.MakeTexWithRoundedCorner(new Color(0, 0, 0, 0.6f)); + Sections2.normal.background = MyGUI.UIToolbox.MakeTexWithRoundedCorner(new Color(0, 0, 0, 0.6f)); ShineSections = new GUIStyle(GUI.skin.box); - ShineSections.normal.background = MyGUI.Helpers.MakeTex(2, 2, new Color(0.92f, 0.74f, 0.2f, 0.3f)); + ShineSections.normal.background = MyGUI.UIToolbox.MakeTex(2, 2, new Color(0.92f, 0.74f, 0.2f, 0.3f)); BlacklistedButton = new GUIStyle(GUI.skin.button); BlacklistedButton.normal.textColor = Color.red; @@ -124,12 +128,20 @@ public static void Initialize() currentWidth = Screen.width; } - windowRect = GUILayout.Window(WindowID, windowRect, GuiWindowControls, "ShapekeyMaster", MainWindow); + windowRect = GUILayout.Window(WindowID, windowRect, GuiWindowControls, Main.CurrentLanguage["title"], MainWindow); } private static void GuiWindowControls(int windowID) { - GUI.DragWindow(new Rect(0, 0, 10000, 20)); + closeButton.x = windowRect.width - (closeButton.width + 5); + dragWindow.width = windowRect.width - (closeButton.width + 5); + + GUI.DragWindow(dragWindow); + + if (GUI.Button(closeButton, "X")) + { + Main.enablegui = false; + } scrollPosition = GUILayout.BeginScrollView(scrollPosition); @@ -172,7 +184,7 @@ private static void GuiWindowControls(int windowID) DisplayHeaderMenu(); - Main.SimpleMode.Value = GUILayout.Toggle(Main.SimpleMode.Value, "Simple"); + Main.SimpleMode.Value = GUILayout.Toggle(Main.SimpleMode.Value, Main.CurrentLanguage["simple"]); switch (TabSelection) { @@ -200,13 +212,13 @@ private static void GuiWindowControls(int windowID) break; case 2: - Main.HideInactiveMaids.Value = GUILayout.Toggle(Main.HideInactiveMaids.Value, "Hide Inactive Maids"); + Main.HideInactiveMaids.Value = GUILayout.Toggle(Main.HideInactiveMaids.Value, Main.CurrentLanguage["hideInactiveMaids"]); GUILayout.BeginVertical(Sections); GUILayout.BeginHorizontal(Sections2); GUILayout.FlexibleSpace(); - GUILayout.Label("Maids"); + GUILayout.Label(Main.CurrentLanguage["maids"]); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); @@ -244,17 +256,17 @@ private static void GuiWindowControls(int windowID) GUILayout.EndScrollView(); DisplayFooter(); - ShapekeyMaster.MyGUI.Helpers.ChkMouseClick(windowRect); + ShapekeyMaster.MyGUI.UIToolbox.ChkMouseClick(windowRect); } private static void DisplayHeaderMenu() { GUILayout.BeginHorizontal(Sections2); - var modeLabel = entryComparer.Mode == 0 ? "Date" : entryComparer.Mode == 1 ? "Name" : "Shapekey"; + var modeLabel = entryComparer.Mode == 0 ? Main.CurrentLanguage["date"] : entryComparer.Mode == 1 ? Main.CurrentLanguage["name"] : Main.CurrentLanguage["shapekey"]; var ascendLabel = entryComparer.Ascending ? "↑" : "↓"; - GUILayout.Label("Sort By:"); + GUILayout.Label(Main.CurrentLanguage["sortBy"] + ":"); if (GUILayout.Button(modeLabel)) { ++entryComparer.Mode; @@ -266,17 +278,17 @@ private static void DisplayHeaderMenu() GUILayout.FlexibleSpace(); - if (GUILayout.Button("All")) + if (GUILayout.Button(Main.CurrentLanguage["all"])) { Page = 0; TabSelection = 0; } - else if (GUILayout.Button("Globals")) + else if (GUILayout.Button(Main.CurrentLanguage["globals"])) { Page = 0; TabSelection = 1; } - else if (GUILayout.Button("Maids")) + else if (GUILayout.Button(Main.CurrentLanguage["maids"])) { Page = 0; TabSelection = 2; @@ -293,34 +305,34 @@ private static void DisplaySearchMenu(bool NoModes = false) if (OpenSKMenu != Guid.Empty) { - FilterCommonKeys = GUILayout.Toggle(FilterCommonKeys, "Filter Common Keys"); + FilterCommonKeys = GUILayout.Toggle(FilterCommonKeys, Main.CurrentLanguage["filterCommonKeys"]); - HideBlacklistedKeys = GUILayout.Toggle(HideBlacklistedKeys, "Hide Blacklisted Keys"); + HideBlacklistedKeys = GUILayout.Toggle(HideBlacklistedKeys, Main.CurrentLanguage["hideBlacklistedKeys"]); } GUILayout.FlexibleSpace(); - GUILayout.Label("Search by "); + GUILayout.Label(Main.CurrentLanguage["searchBy"] + ":"); if (NoModes == false) { if (FilterMode == 0) { - if (GUILayout.Button("Entry Name")) + if (GUILayout.Button(Main.CurrentLanguage["name"])) { FilterMode = 1; } } else if (FilterMode == 1) { - if (GUILayout.Button("Maid Name")) + if (GUILayout.Button(Main.CurrentLanguage["maid"])) { FilterMode = 2; } } else if (FilterMode == 2) { - if (GUILayout.Button("Shapekey Name")) + if (GUILayout.Button(Main.CurrentLanguage["shapekey"])) { FilterMode = 0; } @@ -340,7 +352,7 @@ private static void DisplayPageManager(string MaidWithKey = null) switch (TabSelection) { case 1: - headerString = "Globals"; + headerString = Main.CurrentLanguage["globals"]; applicantcount = SKDatabase.GlobalShapekeyDictionary().Count; break; @@ -350,7 +362,7 @@ private static void DisplayPageManager(string MaidWithKey = null) break; default: - headerString = "All"; + headerString = Main.CurrentLanguage["all"]; applicantcount = SKDatabase.AllShapekeyDictionary.Count; break; } @@ -378,7 +390,7 @@ private static void DisplayFooter() GUILayout.BeginVertical(Sections2); if (ExportMenuOpen) { - if (GUILayout.Button("Cancel")) + if (GUILayout.Button(Main.CurrentLanguage["cancel"])) { ExportMenuOpen = false; } @@ -386,7 +398,7 @@ private static void DisplayFooter() else { GUILayout.BeginHorizontal(); - if (GUILayout.Button("Reload")) + if (GUILayout.Button(Main.CurrentLanguage["reload"])) { OpenSKMenu = Guid.Empty; OpenMaidMenu = Guid.Empty; @@ -400,7 +412,7 @@ private static void DisplayFooter() return; } - if (GUILayout.Button("Save")) + if (GUILayout.Button(Main.CurrentLanguage["save"])) { #if (DEBUG) Main.logger.LogDebug("Saving data to configs now!"); @@ -410,11 +422,11 @@ private static void DisplayFooter() } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); - if (GUILayout.Button("Export")) + if (GUILayout.Button(Main.CurrentLanguage["export"])) { ExportMenuOpen = true; } - if (GUILayout.Button("Import")) + if (GUILayout.Button(Main.CurrentLanguage["import"])) { SKDatabase.ConcatenateDictionary(Main.LoadFromJson(null, true).AllShapekeyDictionary); @@ -433,7 +445,7 @@ private static void DisplayMaidOptions() { if (Main.HideInactiveMaids.Value) { - if (!HelperClasses.IsMaidActive(MaidWithKey)) + if (!Extensions.IsMaidActive(MaidWithKey)) { continue; } @@ -480,17 +492,17 @@ private static void DisplayMaidOptions() return; } - if (GUILayout.Button("Rename")) + if (GUILayout.Button(Main.CurrentLanguage["rename"])) { MaidGroupRenameMenu = MaidWithKey; MaidGroupRename = MaidGroupRenameMenu; - MaidNameList = HelperClasses.GetNameOfAllMaids().ToList(); + MaidNameList = Extensions.GetNameOfAllMaids().ToList(); return; } - if (GUILayout.Button("Del")) + if (GUILayout.Button(Main.CurrentLanguage["delete"])) { foreach (ShapeKeyEntry skp in SKDatabase.ShapekeysByMaid(MaidWithKey).Values) { @@ -553,9 +565,9 @@ private static void DisplayMaidOptions() GUILayout.EndVertical(); } - if (GUILayout.Button("New Maid Group")) + if (GUILayout.Button(Main.CurrentLanguage["newMaidGroup"])) { - MaidNameList = HelperClasses.GetNameOfAllMaids().ToList(); + MaidNameList = Extensions.GetNameOfAllMaids().ToList(); MaidGroupCreateOpen = true; @@ -616,15 +628,15 @@ private static void SimpleDisplayShapeKeyEntriesMenu(Dictionary GivenShapeKeys) { - if (TabSelection != 2 && GUILayout.Button("Add New Shapekey")) + if (TabSelection != 2 && GUILayout.Button(Main.CurrentLanguage["addNewShapekey"])) { #if (DEBUG) Main.logger.LogDebug("I've been clicked! Oh the humanity!!"); @@ -758,12 +769,12 @@ private static void DisplayShapeKeyEntriesMenu(Dictionary G } GUILayout.EndHorizontal(); - s.Enabled = GUILayout.Toggle(s.Enabled, $"Enable"); + s.Enabled = GUILayout.Toggle(s.Enabled, Main.CurrentLanguage["enable"]); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); - GUILayout.Label("ShapeKey", GUILayout.Width(200)); + GUILayout.Label(Main.CurrentLanguage["shapekey"], GUILayout.Width(200)); GUILayout.FlexibleSpace(); - GUILayout.Label("Maid (Optional)", GUILayout.Width(200)); + GUILayout.Label(Main.CurrentLanguage["maidOptional"], GUILayout.Width(200)); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); @@ -775,15 +786,15 @@ private static void DisplayShapeKeyEntriesMenu(Dictionary G OpenSKMenu = s.Id; if (String.IsNullOrEmpty(s.Maid)) { - ShapekeysNameList = HelperClasses.GetAllShapeKeysFromAllMaids().ToList(); + ShapekeysNameList = Extensions.GetAllShapeKeysFromAllMaids().ToList(); } else { - ShapekeysNameList = HelperClasses.GetAllShapeKeysFromMaid(HelperClasses.GetMaidByName(s.Maid)).ToList(); + ShapekeysNameList = Extensions.GetMaidByName(s.Maid)?.GetAllShapeKeysFromMaid()?.ToList(); if (ShapekeysNameList == null || ShapekeysNameList.Count == 0) { - ShapekeysNameList = HelperClasses.GetAllShapeKeysFromAllMaids().ToList(); + ShapekeysNameList = Extensions.GetAllShapeKeysFromAllMaids().ToList(); } } @@ -802,7 +813,7 @@ private static void DisplayShapeKeyEntriesMenu(Dictionary G if (GUILayout.Button("+")) { OpenMaidMenu = s.Id; - MaidNameList = HelperClasses.GetNameOfAllMaids().ToList(); + MaidNameList = Extensions.GetNameOfAllMaids().ToList(); return; } GUILayout.Label(s.Maid, GUILayout.Width(200)); @@ -813,67 +824,67 @@ private static void DisplayShapeKeyEntriesMenu(Dictionary G //s.SetAnimateWithOrgasm(GUILayout.Toggle(s.GetAnimateWithOrgasm(), $"Animate during orgasm")); - s.Animate = GUILayout.Toggle(s.Animate, $"Animate"); + s.Animate = GUILayout.Toggle(s.Animate, Main.CurrentLanguage["animate"]); - s.AnimateWithExcitement = GUILayout.Toggle(s.AnimateWithExcitement, $"Animate with yotogi excitement"); + s.AnimateWithExcitement = GUILayout.Toggle(s.AnimateWithExcitement, Main.CurrentLanguage["animateWithYotogiExcitement"]); if (s.Animate) { - GUILayout.Label($"Animation speed = (1000 ms / {s.AnimationPollFloat * 1000} ms) x {s.AnimationRate} = {1000 / (s.AnimationPollFloat * 1000) * s.AnimationRateFloat} %/Second"); - GUILayout.Label($"Shapekey Deformation: {s.Deform}"); + GUILayout.Label($"{Main.CurrentLanguage["animationSpeed"]} = (1000 ms / {s.AnimationPollFloat * 1000} ms) x {s.AnimationRate} = {1000 / (s.AnimationPollFloat * 1000) * s.AnimationRateFloat} %/{Main.CurrentLanguage["seconds"]}"); + GUILayout.Label($"{Main.CurrentLanguage["shapekeyDeformation"]}: {s.Deform}"); s.Deform = (GUILayout.HorizontalSlider(s.Deform, 0, Main.MaxDeform.Value)); - GUILayout.Label($"Max Animation Deformation: {s.AnimationMaximum}"); + GUILayout.Label($"{Main.CurrentLanguage["maxAnimationDeformation"]}: {s.AnimationMaximum}"); s.AnimationMaximum = Mathf.RoundToInt(GUILayout.HorizontalSlider(s.AnimationMaximum, s.AnimationMinimum, Main.MaxDeform.Value)); - GUILayout.Label($"Minimum Animation Deformation: {s.AnimationMinimum}"); + GUILayout.Label($"{Main.CurrentLanguage["minAnimationDeformation"]}: {s.AnimationMinimum}"); s.AnimationMinimum = Mathf.RoundToInt(GUILayout.HorizontalSlider(s.AnimationMinimum, 0, s.AnimationMaximum)); - GUILayout.Label($"Animation Rate (Amount to increase/decrease deformation on poll): {s.AnimationRate}"); + GUILayout.Label($"{Main.CurrentLanguage["animationRate"]}: {s.AnimationRate}"); GUILayout.BeginHorizontal(); //s.SetAnimationRate(GUILayout.HorizontalSlider(s.GetAnimationRate(), 0, 100).ToString()); s.AnimationRate = GUILayout.TextField(s.AnimationRate.ToString()); GUILayout.EndHorizontal(); - GUILayout.Label($"Animation Polling Rate in Seconds (Lower = Faster): {s.AnimationPoll}"); + GUILayout.Label($"{Main.CurrentLanguage["animationPollingRate"]}: {s.AnimationPoll}"); s.AnimationPoll = GUILayout.TextField(s.AnimationPoll.ToString()); } else if (s.Animate == false && s.AnimateWithExcitement) { - GUILayout.Label($"Max Excitement Threshold: {s.ExcitementMax}"); + GUILayout.Label($"{Main.CurrentLanguage["maxExcitementThreshold"]}: {s.ExcitementMax}"); s.ExcitementMax = Mathf.RoundToInt(GUILayout.HorizontalSlider(s.ExcitementMax, s.ExcitementMin, 300.0F)); - GUILayout.Label($"Min Excitement Threshold: {s.ExcitementMin}"); + GUILayout.Label($"{Main.CurrentLanguage["minExcitementThreshold"]}: {s.ExcitementMin}"); s.ExcitementMin = Mathf.RoundToInt(GUILayout.HorizontalSlider(s.ExcitementMin, 0.0F, s.ExcitementMax)); - GUILayout.Label($"Default Shapekey Deformation: {s.Deform}"); + GUILayout.Label($"{Main.CurrentLanguage["defShapekeyDeformation"]}: {s.Deform}"); s.Deform = (Mathf.RoundToInt(GUILayout.HorizontalSlider(s.Deform, 0, Main.MaxDeform.Value))); - GUILayout.Label($"Max Shapekey Deformation: {s.DeformMax}"); + GUILayout.Label($"{Main.CurrentLanguage["maxShapekeyDeformation"]}: {s.DeformMax}"); s.DeformMax = Mathf.RoundToInt(GUILayout.HorizontalSlider(s.DeformMax, s.DeformMin, Main.MaxDeform.Value)); - GUILayout.Label($"Min Shapekey Deformation: {s.DeformMin}"); + GUILayout.Label($"{Main.CurrentLanguage["minShapekeyDeformation"]}: {s.DeformMin}"); s.DeformMin = Mathf.RoundToInt(GUILayout.HorizontalSlider(s.DeformMin, 0.0F, s.DeformMax)); } else { - GUILayout.Label($"Shapekey Deformation: {s.Deform}"); + GUILayout.Label($"{Main.CurrentLanguage["shapekeyDeformation"]}: {s.Deform}"); s.Deform = (Mathf.RoundToInt(GUILayout.HorizontalSlider(s.Deform, 0, Main.MaxDeform.Value))); } GUILayout.BeginHorizontal(Style); - if (GUILayout.Button($"Open Slot Conditions Menu")) + if (GUILayout.Button(Main.CurrentLanguage["openSlotCondMenu"])) { OpenSlotConditions = s.Id; return; } - s.ConditionalsToggle = GUILayout.Toggle(s.ConditionalsToggle, "Enable Conditionals"); + s.ConditionalsToggle = GUILayout.Toggle(s.ConditionalsToggle, Main.CurrentLanguage["enableConditionals"]); GUILayout.FlexibleSpace(); - if (GUILayout.Button($"Rename")) + if (GUILayout.Button(Main.CurrentLanguage["rename"])) { OpenRenameMenu = s.Id; return; } - if (GUILayout.Button($"Delete")) + if (GUILayout.Button(Main.CurrentLanguage["delete"])) { SKDatabase.Remove(s); return; @@ -903,15 +914,25 @@ private static void DisplayShapeKeySelectMenu(ShapeKeyEntry s) GUILayout.BeginHorizontal(); - GUILayout.Label($"{s.EntryName} Select ShapeKey"); + GUILayout.Label($"{s.EntryName}: {Main.CurrentLanguage["selectShapekey"]}"); GUILayout.FlexibleSpace(); - GUILayout.Label($"R-Click To Blacklist!"); + GUILayout.Label(Main.CurrentLanguage["rclickToBlacklist"]); GUILayout.EndHorizontal(); - if (GUILayout.Button("None")) + if (GUILayout.Button(Main.CurrentLanguage["finish"])) + { + OpenSKMenu = Guid.Empty; + oldSKMenuFilter = Filter; + oldSKMenuScrollPosition = scrollPosition; + scrollPosition = oldPreSKMenuScrollPosition; + + Filter = ""; + } + + if (GUILayout.Button(Main.CurrentLanguage["none"])) { OpenSKMenu = Guid.Empty; oldSKMenuFilter = Filter; @@ -926,19 +947,19 @@ private static void DisplayShapeKeySelectMenu(ShapeKeyEntry s) int totalGroupsWorked = 0; var groupedKeys = ShapekeysNameList - .GroupBy(r => r.First) + .GroupBy(r => r.item1) .OrderBy(r => r.Key); var bodyKeys = groupedKeys .Where(r => r.Key.Equals("body")) .SelectMany(r => r) - .Select(t => t.Second) + .Select(t => t.item2) .ToList(); var headKeys = groupedKeys .Where(r => r.Key.Equals("head")) .SelectMany(r => r) - .Select(t => t.Second) + .Select(t => t.item2) .ToList(); foreach (var group in groupedKeys) @@ -951,18 +972,18 @@ private static void DisplayShapeKeySelectMenu(ShapeKeyEntry s) { if (group.Key.Equals("body") == false) { - filteredList = filteredList.Where(t => !bodyKeys.Contains(t.Second)).ToList(); + filteredList = filteredList.Where(t => !bodyKeys.Contains(t.item2)).ToList(); } if (group.Key.Equals("head") == false) { - filteredList = filteredList.Where(t => !headKeys.Contains(t.Second)).ToList(); + filteredList = filteredList.Where(t => !headKeys.Contains(t.item2)).ToList(); } } if (HideBlacklistedKeys) { - filteredList = filteredList.Where(t => SKDatabase.BlacklistedShapekeys.IsBlacklisted(t.Second) == false).ToList(); + filteredList = filteredList.Where(t => SKDatabase.BlacklistedShapekeys.IsBlacklisted(t.item2) == false).ToList(); } if (filteredList.Count > 0) @@ -979,22 +1000,22 @@ private static void DisplayShapeKeySelectMenu(ShapeKeyEntry s) //Header for category GUILayout.BeginHorizontal(Sections2); GUILayout.FlexibleSpace(); - GUILayout.Label($"{group.Key}"); + GUILayout.Label(Main.CurrentLanguage[group.Key]); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); - foreach (var str in filteredList.OrderBy(r => r.Second)) + foreach (var str in filteredList.OrderBy(r => r.item2)) { if (Filter != "") { - if (str.Second.Contains(Filter, StringComparison.OrdinalIgnoreCase) == false) + if (str.item2.Contains(Filter, StringComparison.OrdinalIgnoreCase) == false) { continue; } } - var style = HideBlacklistedKeys == false && SKDatabase.BlacklistedShapekeys.IsBlacklisted(str.Second) ? BlacklistedButton : GUI.skin.button; - if (GUILayout.Button(str.Second, style)) + var style = HideBlacklistedKeys == false && SKDatabase.BlacklistedShapekeys.IsBlacklisted(str.item2) ? BlacklistedButton : GUI.skin.button; + if (GUILayout.Button(str.item2, style)) { /* if (LastMouseButtonUp == 2) @@ -1004,19 +1025,19 @@ private static void DisplayShapeKeySelectMenu(ShapeKeyEntry s) */ if (LastMouseButtonUp == 1) { - if (SKDatabase.BlacklistedShapekeys.IsBlacklisted(str.Second) == false) + if (SKDatabase.BlacklistedShapekeys.IsBlacklisted(str.item2) == false) { - SKDatabase.BlacklistedShapekeys.AddItem(str.Second); + SKDatabase.BlacklistedShapekeys.AddItem(str.item2); } else { - SKDatabase.BlacklistedShapekeys.RemoveItem(str.Second); + SKDatabase.BlacklistedShapekeys.RemoveItem(str.item2); } } else if (LastMouseButtonUp == 0) { OpenSKMenu = Guid.Empty; - s.ShapeKey = str.Second; + s.ShapeKey = str.item2; oldSKMenuFilter = Filter; oldSKMenuScrollPosition = scrollPosition; scrollPosition = oldPreSKMenuScrollPosition; @@ -1040,20 +1061,20 @@ private static void DisplayMaidSelectMenu(ShapeKeyEntry s) { DisplaySearchMenu(true); - GUILayout.Label($"{s.EntryName} Select Maid"); + GUILayout.Label($"{s.EntryName} {Main.CurrentLanguage["selectMaid"]}"); GUILayout.BeginHorizontal(Sections2); s.Maid = GUILayout.TextField(s.Maid, GUILayout.Width(200)); - if (GUILayout.Button("Finish", GUILayout.Width(80))) + if (GUILayout.Button(Main.CurrentLanguage["finish"], GUILayout.Width(80))) { OpenMaidMenu = Guid.Empty; } GUILayout.EndHorizontal(); - if (GUILayout.Button("None")) + if (GUILayout.Button(Main.CurrentLanguage["none"])) { OpenMaidMenu = Guid.Empty; s.Maid = ""; @@ -1083,9 +1104,9 @@ private static void DisplayMaidGroupCreateMenu(Dictionary G { DisplaySearchMenu(true); - GUILayout.Label($"Select Maid To Make New Group For..."); + GUILayout.Label(Main.CurrentLanguage["selectNewMaidGroup"]); - if (GUILayout.Button("None")) + if (GUILayout.Button(Main.CurrentLanguage["none"])) { int i = 0; @@ -1129,11 +1150,11 @@ private static void DisplayMaidGroupCreateMenu(Dictionary G private static void DisplayRenameMenu(ShapeKeyEntry s) { - GUILayout.Label($"Now renaming {s.EntryName}"); + GUILayout.Label($"{Main.CurrentLanguage["nowRenaming"]} {s.EntryName}"); s.EntryName = GUILayout.TextField(s.EntryName); - if (GUILayout.Button("Finish")) + if (GUILayout.Button(Main.CurrentLanguage["finish"])) { OpenRenameMenu = Guid.Empty; } @@ -1145,42 +1166,41 @@ private static void DisplaySlotConditionsMenu(ShapeKeyEntry s) GUILayout.BeginHorizontal(Sections2); GUILayout.FlexibleSpace(); - GUILayout.Label("General Settings"); + GUILayout.Label(Main.CurrentLanguage["generalSettings"]); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); - s.ConditionalsToggle = GUILayout.Toggle(s.ConditionalsToggle, "Enable Conditionals"); + s.ConditionalsToggle = GUILayout.Toggle(s.ConditionalsToggle, Main.CurrentLanguage["enableConditionals"]); - s.IgnoreCategoriesWithShapekey = GUILayout.Toggle(s.IgnoreCategoriesWithShapekey, "Ignore Categories With Shapekey"); + s.IgnoreCategoriesWithShapekey = GUILayout.Toggle(s.IgnoreCategoriesWithShapekey, Main.CurrentLanguage["ignoreCateWithKey"]); if (s.DisableWhen) { - s.DisableWhen = GUILayout.Toggle(s.DisableWhen, "Set Shapekey if"); + s.DisableWhen = GUILayout.Toggle(s.DisableWhen, Main.CurrentLanguage["setShapekeyIf"]); } else { - s.DisableWhen = GUILayout.Toggle(s.DisableWhen, "Do Not Set Shapekey if"); + s.DisableWhen = GUILayout.Toggle(s.DisableWhen, Main.CurrentLanguage["doNotSetShapekeyIf"]); } - GUILayout.Label("Disabled Key Deform"); + GUILayout.Label(Main.CurrentLanguage["disabledKeyDeform"]); s.DisabledDeform = GUILayout.HorizontalSlider(s.DisabledDeform, 0, Main.MaxDeform.Value); if (s.WhenAll) { - s.WhenAll = GUILayout.Toggle(s.WhenAll, "If All in Slots is Equipped"); + s.WhenAll = GUILayout.Toggle(s.WhenAll, Main.CurrentLanguage["ifAllSlotsEquipped"]); } else { - s.WhenAll = GUILayout.Toggle(s.WhenAll, "If Any in Slots is Equipped"); + s.WhenAll = GUILayout.Toggle(s.WhenAll, Main.CurrentLanguage["ifAnySlotEquipped"]); } - GUILayout.EndHorizontal(); GUILayout.BeginVertical(Sections); GUILayout.BeginHorizontal(Sections2); GUILayout.FlexibleSpace(); - GUILayout.Label("Slots"); + GUILayout.Label(Main.CurrentLanguage["slots"]); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); @@ -1193,7 +1213,7 @@ private static void DisplaySlotConditionsMenu(ShapeKeyEntry s) GUILayout.BeginHorizontal(); } - var temp = GUILayout.Toggle(HelperClasses.HasFlag(s.SlotFlags, slot), slot.ToString(), GUILayout.Width(100)); + var temp = GUILayout.Toggle(Extensions.HasFlag(s.SlotFlags, slot), Main.CurrentLanguage[SlotChecker.SlotToSlotList[slot].ToString()], GUILayout.Width(100)); if (i++ == 4) { @@ -1222,7 +1242,7 @@ private static void DisplaySlotConditionsMenu(ShapeKeyEntry s) GUILayout.BeginHorizontal(Sections2); GUILayout.FlexibleSpace(); - GUILayout.Label("Menu Files"); + GUILayout.Label(Main.CurrentLanguage["menuFiles"]); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); @@ -1247,14 +1267,14 @@ private static void DisplaySlotConditionsMenu(ShapeKeyEntry s) GUILayout.EndScrollView(); - if (GUILayout.Button("Add New Menu File")) + if (GUILayout.Button(Main.CurrentLanguage["addNewMenuFile"])) { s.MenuFileConditionals[Guid.NewGuid()] = ""; } GUILayout.EndVertical(); - if (GUILayout.Button("Finish")) + if (GUILayout.Button(Main.CurrentLanguage["finish"])) { OpenSlotConditions = Guid.Empty; } @@ -1264,13 +1284,13 @@ private static void DisplayMaidRenameMenu(string s) { DisplaySearchMenu(true); - GUILayout.Label($"Now renaming maid group: {s}"); + GUILayout.Label($"{Main.CurrentLanguage["renamingMaidGroup"]}: {s}"); GUILayout.BeginHorizontal(); MaidGroupRename = GUILayout.TextField(MaidGroupRename); - if (GUILayout.Button("Apply")) + if (GUILayout.Button(Main.CurrentLanguage["apply"])) { SKDatabase.AllShapekeyDictionary.Values.ToList().ForEach(sk => { @@ -1316,11 +1336,11 @@ private static void DisplayMaidRenameMenu(string s) private static void DisplayExportMenu() { - Main.HideInactiveMaids.Value = GUILayout.Toggle(Main.HideInactiveMaids.Value, "Hide Inactive Maids"); + Main.HideInactiveMaids.Value = GUILayout.Toggle(Main.HideInactiveMaids.Value, Main.CurrentLanguage["hideInactiveMaids"]); - if (Main.HideInactiveMaids.Value == false && GUILayout.Button("All")) + if (Main.HideInactiveMaids.Value == false && GUILayout.Button(Main.CurrentLanguage["all"])) { - Main.logger.LogMessage("Exporting All"); + Main.logger.LogMessage(Main.CurrentLanguage["exportingAll"]); Main.SaveToJson(null, SKDatabase, true); } @@ -1332,11 +1352,11 @@ private static void DisplayExportMenu() ThingsToExport["global"] = false; } - ThingsToExport["global"] = GUILayout.Toggle(ThingsToExport["global"], "Global"); + ThingsToExport["global"] = GUILayout.Toggle(ThingsToExport["global"], Main.CurrentLanguage["global"]); foreach (string m in SKDatabase.ListOfMaidsWithKeys()) { - if (Main.HideInactiveMaids.Value == false || HelperClasses.IsMaidActive(m)) + if (Main.HideInactiveMaids.Value == false || Extensions.IsMaidActive(m)) { if (ThingsToExport.ContainsKey(m) == false) { @@ -1349,7 +1369,7 @@ private static void DisplayExportMenu() GUILayout.EndVertical(); - if (GUILayout.Button("Done")) + if (GUILayout.Button(Main.CurrentLanguage["done"])) { var SelectionDataBase = new ShapekeyDatabase(); diff --git a/YotogiShapekeys/MyGUI/Helpers.cs b/YotogiShapekeys/GUI/UIToolbox.cs similarity index 96% rename from YotogiShapekeys/MyGUI/Helpers.cs rename to YotogiShapekeys/GUI/UIToolbox.cs index ca9c6ce..7066f86 100644 --- a/YotogiShapekeys/MyGUI/Helpers.cs +++ b/YotogiShapekeys/GUI/UIToolbox.cs @@ -4,7 +4,7 @@ namespace ShapekeyMaster.MyGUI { - internal class Helpers + internal class UIToolbox { public static int LastMouseButtonUp { private set; get; } = -1; @@ -155,6 +155,9 @@ public static Texture2D MakeWindowTex(Color col, Color col2) return result; } + /// + /// This whole class is used to compare our classes for sorting via LINQ OrderBy which is what we use to populate the UI. + /// public class ShapekeyEntryComparer : IComparer { public bool Ascending = true; diff --git a/YotogiShapekeys/HarmonyPatchers.cs b/YotogiShapekeys/HarmonyPatchers.cs index 4446d7f..e32802b 100644 --- a/YotogiShapekeys/HarmonyPatchers.cs +++ b/YotogiShapekeys/HarmonyPatchers.cs @@ -130,7 +130,7 @@ private static void VerifyBlendValuesBeforeSet(ref TMorph __instance) Main.logger.LogDebug($"Applying Excitement Deformation @ {__instance.bodyskin.body.maid.status.fullNameJpStyle} :: {__instance.Category} ::: {shapeKeyEntry.EntryName} :::: {shapeKeyEntry.ShapeKey}"); #endif - var deform = HelperClasses.CalculateExcitementDeformation(shapeKeyEntry); + var deform = Extensions.CalculateExcitementDeformation(shapeKeyEntry); __instance.BlendValues[index] = deform / 100; __instance.BlendValuesBackup[index] = deform / 100; @@ -202,7 +202,7 @@ public static void OnExciteSet(ref MaidStatus.Status __instance, ref int __0) [HarmonyPrefix] public static bool InputCheck() { - if (MyGUI.Helpers.IsMouseOnGUI()) + if (MyGUI.UIToolbox.IsMouseOnGUI()) { return false; } diff --git a/YotogiShapekeys/Main.cs b/YotogiShapekeys/Main.cs index 4905fad..26594b2 100644 --- a/YotogiShapekeys/Main.cs +++ b/YotogiShapekeys/Main.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Security; using System.Security.Permissions; using System.Windows.Forms; @@ -18,142 +19,33 @@ namespace ShapekeyMaster { - [BepInPlugin("ShapekeyMaster", "ShapekeyMaster", "1.4.4")] + [BepInPlugin("ShapekeyMaster", "ShapekeyMaster", "1.5")] [BepInDependency("deathweasel.com3d2.api")] public class Main : BaseUnityPlugin { - internal static Main @this; + internal static Main @this { get; private set; } - internal static BepInEx.Logging.ManualLogSource logger; + internal static BepInEx.Logging.ManualLogSource logger { get; private set; } - public static bool enablegui { get; private set; } = false; + public static bool enablegui { get; internal set; } = false; private static SaveFileDialog FileSave = new SaveFileDialog(); - private static OpenFileDialog FileOpen = new OpenFileDialog(); private static readonly string iconBase64 = "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANRSURBVEhLzVZdK6RhGL6G8TFjFTOrEWnGiRgRocmhA2rbAzmwp+IfOPMLHDsnKaG2FA5WkhSJspPPGSTyEWYyFsn4Zp/rnvfVDLNrD2amverufZ73fue+nvvrmdsA4JOSz0psSqxKTEqSlMQCz0qCSn4p8Sk5UwJ7RUVF8+rqquclTpifn/9JDsXlIKGLLzRd3ECHyMWQflH7H2SONwwGw1fmyhzaJgQmEsaqQP4FSYkkE/xfhEtLS+jt7UVXVxdGRkZwcnKiaaLD7Xajr68PT09Pst/Z2UFPTw8WFxdlT/yRcG5uDmNjYwgEAsjNzcXm5iYGBgY07Xs8PDxgamoK+/v72N3dhcfjke+Pjo5wf3+vffUBodVqRXt7OxobG5GXl4fb21tN+x480M3NjaxnZ2cxPDwM1W5ITk6Ganp5Txi1p4CnGRoawvX1texpoLOzU9ZEWVmZtnoPhpPGzWYzDg8PkZ+fL/aKi4uRkZGhffWGMDU1FVVVVbLe2tqC3++H3W4XycrKQnl5ueiYS+bl+PhY1XkS6uvrJZSlpaUoKSmRtdFoFELdno6IkObk5MDhcOD09FS8SUlJgc/nE6LKykrxYHp6Gt3d3VJQFxcXsFgsWFtbk9/TOEl5gOXlZUlJYWGh6HREELKq+vv7cXBwgKKiIjQ1NeHu7g6jo6OiJ8nMzIyQtLW1oaOjQ/LL/IUbV/empIOHfIsIQhpOT09HS0uLeMvw0FPmhF7TO3pJfUFBgfxmfX1djIeHbmNjQ56Xl5dYWVmRtY5XQiqvrq7gdDqFTAcPQDC01LNaMzMz5R37jRWZlpYWUYksGB6MeWZUwvFaNCwYgoWgg+FkeNQtL71IsC/Zc8Tk5CTOz8/hcrlgMvF/O4S6ujqRaODfU7Pql+/cDA4OYnt7GzabTTzxer1CWltbi4aGBrlFWIF6mbN9+G1ra6t4+RHUwb9FENLAxMSEEDFc2dnZqKmpEUKCYR8fH8fe3p60CXNcXV0d0Wd/Awn5JGEEHh8fX4LBoLaLHcgV9WpjwsNzEktEJYwnSMhRLlF4JmHoik8MgiQ8U3ehN7SPHxYWFtzqwYEYDg6p8ZxNOZNqg7BdH/U54vMqsSjh2BirYmJ9MGUc8f0AAr8BwP7aKtdTkPoAAAAASUVORK5CYII="; - private readonly List DefaultBlacklistVals = new List() -{ - "arml", - "hara", - "munel", - "munes", - "munetare", - "regfat", - "regmeet", - "eyeclose", - "eyeclose2", - "eyeclose5", - "eyeclose6", - "eyeclose7", - "eyeclose8", - "fera1", - "earelf", - "earnone", - "eyebig", - "eyeclose1_normal", - "eyeclose1_tare", - "eyeclose1_tsuri", - "eyeclose2_normal", - "eyeclose2_tare", - "eyeclose2_tsuri", - "eyeclose3", - "eyeclose5_normal", - "eyeclose5_tare", - "eyeclose5_tsuri", - "eyeclose6_normal", - "eyeclose6_tare", - "eyeclose6_tsuri", - "eyeclose7_normal", - "eyeclose7_tare", - "eyeclose7_tsuri", - "eyeclose8_normal", - "eyeclose8_tare", - "eyeclose8_tsuri", - "eyeeditl1_dw", - "eyeeditl1_up", - "eyeeditl2_dw", - "eyeeditl2_up", - "eyeeditl3_dw", - "eyeeditl3_up", - "eyeeditl4_dw", - "eyeeditl4_up", - "eyeeditl5_dw", - "eyeeditl5_up", - "eyeeditl6_dw", - "eyeeditl6_up", - "eyeeditl7_dw", - "eyeeditl7_up", - "eyeeditl8_dw", - "eyeeditl8_up", - "eyeeditr1_dw", - "eyeeditr1_up", - "eyeeditr2_dw", - "eyeeditr2_up", - "eyeeditr3_dw", - "eyeeditr3_up", - "eyeeditr4_dw", - "eyeeditr4_up", - "eyeeditr5_dw", - "eyeeditr5_up", - "eyeeditr6_dw", - "eyeeditr6_up", - "eyeeditr7_dw", - "eyeeditr7_up", - "eyeeditr8_dw", - "eyeeditr8_up", - "hitomih", - "hitomis", - "hoho", - "hoho2", - "hohol", - "hohos", - "mayueditin", - "mayueditout", - "mayuha", - "mayuup", - "mayuv", - "mayuvhalf", - "mayuw", - "moutha", - "mouthc", - "mouthdw", - "mouthfera", - "mouthferar", - "mouthhe", - "mouthi", - "mouths", - "mouthup", - "mouthuphalf", - "namida", - "nosefook", - "shape", - "shapehoho", - "shapehohopushr", - "shapeslim", - "shock", - "tangopen", - "tangout", - "tangup", - "tear1", - "tear2", - "tear3", - "toothoff", - "uru-uru", - "yodare" - }; - internal static ConfigEntry MaxDeform; + internal static ConfigEntry Autosave; + internal static ConfigEntry SimpleMode; internal static ConfigEntry HideInactiveMaids; - internal static ConfigEntry HotkeyEnabled; internal static ConfigEntry EntriesPerPage; + internal static ConfigEntry Language; + + internal static ConfigEntry HotkeyEnabled; internal static ConfigEntry Hotkey; - internal static ConfigEntry Autosave; - internal static bool BackgroundTasks = true; + internal static TranslationResource CurrentLanguage { get; private set; } private void Awake() { @@ -161,14 +53,44 @@ private void Awake() logger = Logger; + if (Directory.Exists(BepInEx.Paths.ConfigPath + $"\\ShapekeyMaster\\") == false) + { + logger.LogFatal("It seems we're lacking any translation folder for ShapekeyMaster! This is bad and we can't start without that and the translation files! Please download the translation files, they come with the plugin, and place them in the proper directory!"); + + return; + } + + var translationFiles = Directory.GetFiles(BepInEx.Paths.ConfigPath + $"\\ShapekeyMaster\\", "*.*") + .Where(s => s.ToLower().EndsWith(".json")) + .Select(file => Path.GetFileName(file)) + .ToArray(); + + if (translationFiles.Count() <= 0) + { + logger.LogFatal("It seems we're lacking any translation files for ShapekeyMaster! This is bad and we can't start without them! Please download the translation files, they come with the plugin, and place them in the proper directory!"); + + return; + } + + var acceptableValues = new AcceptableValueList(translationFiles); + MaxDeform = Config.Bind("General", "1. Max Deformation", 100f, "The max limit of the sliders in UI."); Autosave = Config.Bind("General", "2. Autosave", true, "Will the config be saved automatically at set points."); SimpleMode = Config.Bind("UI", "1. Simple Mode", true, "Simple mode is a simplified view of your shapekeys holding only the most basic of settings. All you really need in most cases."); HideInactiveMaids = Config.Bind("UI", "2. Hide Inactive Maids", false, "In the maids view, maids that are not present or loaded are hidden from the menu options."); EntriesPerPage = Config.Bind("UI", "3. Entries Per Page", 10, "How many entries to display per an entry page."); + Language = Config.Bind("UI", "4. Language", "english.json", new ConfigDescription("The language for SKM's UI.", acceptableValues)); + + Language.SettingChanged += (e, s) => + { + CurrentLanguage = new TranslationResource(BepInEx.Paths.ConfigPath + $"\\ShapekeyMaster\\" + Language.Value); + }; + + CurrentLanguage = new TranslationResource(BepInEx.Paths.ConfigPath + $"\\ShapekeyMaster\\" + Language.Value); + HotkeyEnabled = Config.Bind("Hotkey", "1. Enable Hotkey", false, "Use a hotkey to open ShapekeyMaster."); - Hotkey = Config.Bind("Hotkey", "2. Hotkey", new KeyboardShortcut(KeyCode.F4, KeyCode.LeftControl), "Hotkey to open ShapekeyMaster with."); + Hotkey = Config.Bind("Hotkey", "2. Hotkey", new KeyboardShortcut(KeyCode.F4, KeyCode.LeftControl, KeyCode.LeftAlt), "Hotkey to open ShapekeyMaster with."); Harmony.CreateAndPatchAll(typeof(HarmonyPatchers)); diff --git a/YotogiShapekeys/SMEventsAndArgs.cs b/YotogiShapekeys/SMEventsAndArgs.cs deleted file mode 100644 index 84d732f..0000000 --- a/YotogiShapekeys/SMEventsAndArgs.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; - -namespace ShapekeyMaster -{ - internal class SMEventsAndArgs - { - //Cleaner for instancing. - public class MorphEventArgs : EventArgs - { - public TMorph Morph { get; private set; } - public bool Creation { get; private set; } - - public MorphEventArgs(TMorph changedMorph, bool wasCreated = true) - { - Morph = changedMorph; - Creation = wasCreated; - } - } - - public class ExcitementChangeEvent : EventArgs - { - public string Maid { get; private set; } - public int Excitement { get; private set; } - - public ExcitementChangeEvent(string maid, int excite) - { - Maid = maid; - Excitement = excite; - } - } - - public class ClothingMaskChangeEvent : EventArgs - { - public string Maid { get; private set; } - - public ClothingMaskChangeEvent(string maid) - { - Maid = maid; - } - } - } -} \ No newline at end of file diff --git a/YotogiShapekeys/ShapeKeyEntry.cs b/YotogiShapekeys/ShapeKeyEntry.cs index d21aa5f..714b26e 100644 --- a/YotogiShapekeys/ShapeKeyEntry.cs +++ b/YotogiShapekeys/ShapeKeyEntry.cs @@ -22,17 +22,18 @@ public bool Enabled { enabled = value; - if (animate && !enabled) + if (animate) { - if (Animator != null) + if (!enabled && Animator != null) { Main.@this.StopCoroutine(Animator); + Animator = null; + } + else if (enabled && Animator == null) + { + Animator = AnimateCoRoute(this); + Main.@this.StartCoroutine(Animator); } - } - else if (animate) - { - Animator = AnimateCoRoute(this); - Main.@this.StartCoroutine(Animator); } RunUpdate(); @@ -127,6 +128,7 @@ public bool Animate if (value == false) { Main.@this.StopCoroutine(Animator); + Animator = null; } else { @@ -388,7 +390,6 @@ public bool WhenAll } private DisableWhenEquipped slotFlags; - public DisableWhenEquipped SlotFlags { get => slotFlags; @@ -483,7 +484,7 @@ private static IEnumerator AnimateCoRoute(ShapeKeyEntry key) { if (key.animate == true) { - if (key.enabled && HelperClasses.IsMaidActive(key.maid)) + if (key.enabled && Extensions.IsMaidActive(key.maid)) { if (key.deform >= key.animationMaximum) { @@ -540,5 +541,6 @@ private static IEnumerator AnimateCoRoute(ShapeKeyEntry key) } } } + } } \ No newline at end of file diff --git a/YotogiShapekeys/ShapekeyDatabase.cs b/YotogiShapekeys/ShapekeyDatabase.cs index 8d1828e..f5bef6a 100644 --- a/YotogiShapekeys/ShapekeyDatabase.cs +++ b/YotogiShapekeys/ShapekeyDatabase.cs @@ -233,6 +233,11 @@ internal void Remove(ShapeKeyEntry newVal) internal void ConcatenateDictionary(Dictionary newDictionary, bool overwrite = false) { + if (newDictionary is null) + { + return; + } + if (!overwrite) { allShapekeyDictionary = new Dictionary( diff --git a/YotogiShapekeys/ShapekeyMaster.csproj b/YotogiShapekeys/ShapekeyMaster.csproj index 3bbd5a9..7e3f483 100644 --- a/YotogiShapekeys/ShapekeyMaster.csproj +++ b/YotogiShapekeys/ShapekeyMaster.csproj @@ -38,22 +38,14 @@ - - - + + - - - - + + - - - - - - + diff --git a/YotogiShapekeys/ShapekeyUpdate.cs b/YotogiShapekeys/ShapekeyUpdate.cs index 3c4ce2a..71c5a3c 100644 --- a/YotogiShapekeys/ShapekeyUpdate.cs +++ b/YotogiShapekeys/ShapekeyUpdate.cs @@ -21,8 +21,7 @@ internal class ShapekeyUpdate private static readonly Dictionary CoroutinesUpdatingMorph = new Dictionary(); private static IEnumerator UpdateAllCo; - - private static IEnumerator PreviewKeyCo; + //private static IEnumerator PreviewKeyCo; internal static void UpdateKeys(bool avoidwait = false) { @@ -257,4 +256,6 @@ private static IEnumerator PreviewKey() } */ } + + } \ No newline at end of file diff --git a/YotogiShapekeys/HelperClasses.cs b/YotogiShapekeys/Toolbox.cs similarity index 63% rename from YotogiShapekeys/HelperClasses.cs rename to YotogiShapekeys/Toolbox.cs index 6793efa..e0126e9 100644 --- a/YotogiShapekeys/HelperClasses.cs +++ b/YotogiShapekeys/Toolbox.cs @@ -7,28 +7,45 @@ namespace ShapekeyMaster { - public class Tuple + internal class SMEventsAndArgs { - public T1 First { get; private set; } - public T2 Second { get; private set; } + //Cleaner for instancing. + public class MorphEventArgs : EventArgs + { + public TMorph Morph { get; private set; } + public bool Creation { get; private set; } - internal Tuple(T1 first, T2 second) + public MorphEventArgs(TMorph changedMorph, bool wasCreated = true) + { + Morph = changedMorph; + Creation = wasCreated; + } + } + + public class ExcitementChangeEvent : EventArgs { - First = first; - Second = second; + public string Maid { get; private set; } + public int Excitement { get; private set; } + + public ExcitementChangeEvent(string maid, int excite) + { + Maid = maid; + Excitement = excite; + } } - } - public static class Tuple - { - public static Tuple New(T1 first, T2 second) + public class ClothingMaskChangeEvent : EventArgs { - var tuple = new Tuple(first, second); - return tuple; + public string Maid { get; private set; } + + public ClothingMaskChangeEvent(string maid) + { + Maid = maid; + } } } - internal static class HelperClasses + internal static class Extensions { private static readonly FieldInfo goSlotField = typeof(TBody).GetField("goSlot", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); @@ -36,27 +53,20 @@ internal static class HelperClasses private static readonly MethodInfo goSlotMethod = goSlotType.GetMethod("GetListParents", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public) ?? null; - public static List FetchGoSlot(TBody body) + /// + /// A convenience method meant to provide support for 2.00 and 3.00 which vary in this field. The ultimate values are the same, they just need to be fetched differently. :P + /// + /// + /// + public static List FetchGoSlot(this TBody body) { - List result; - if (goSlotField.FieldType == typeof(List)) { - result = (List)goSlotField.GetValue(body); - } - else - { - var goSlotVal = goSlotField.GetValue(body); - - result = (List)goSlotMethod.Invoke(goSlotVal, new object[0]); - } - - if (result != null) - { - return result; + return (List)goSlotField.GetValue(body) ?? null; } - return null; + var goSlotVal = goSlotField.GetValue(body); + return (List)goSlotMethod.Invoke(goSlotVal, new object[0]) ?? null; } public static bool HasFlag(this Enum variable, Enum value) @@ -74,6 +84,11 @@ public static bool HasFlag(this Enum variable, Enum value) return (num2 & num) == num; } + public static bool IsMaidActive(this Maid maid) + { + return maid != null && maid.isActiveAndEnabled; + } + public static bool IsMaidActive(string name) { if (name == "") @@ -81,9 +96,8 @@ public static bool IsMaidActive(string name) bool result = GameMain.Instance.CharacterMgr .GetStockMaidList() - .Where(m => m != null) + .Where(m => m.IsMaidActive()) .Count() > 0; - #if (DEBUG) Main.logger.LogDebug("Maids active to edit = " + result); @@ -92,23 +106,16 @@ public static bool IsMaidActive(string name) return result; } - return - GameMain.Instance.CharacterMgr - .GetStockMaidList() - .FirstOrDefault(m => m != null && m.isActiveAndEnabled && m.status.fullNameJpStyle == name) != null; + return GetMaidByName(name).IsMaidActive(); } public static Maid GetMaidByName(string name) { - if (name == "") - { - return null; - } - - return + //If name string is empty, return null. Otherwise, execute link to find. + return name.IsNullOrWhiteSpace() ? null : GameMain.Instance.CharacterMgr .GetStockMaidList() - .FirstOrDefault(m => m != null && m.isActiveAndEnabled && m.status.fullNameJpStyle == name); + .FirstOrDefault(m => m != null && m.status.fullNameJpStyle.Equals(name)); } public static IEnumerable> GetAllMorphsFromMaidList(List list) @@ -116,19 +123,18 @@ public static IEnumerable> GetAllMorphsFromMaidList(List GetAllMorphsFromMaid(m)) - .Select(r => new Tuple(r.First, r.Second)); + .Select(r => new Tuple(r.item1, r.item2)); } - public static IEnumerable> GetAllMorphsFromMaid(Maid maid) + public static IEnumerable> GetAllMorphsFromMaid(this Maid maid) { return - FetchGoSlot(maid - .body0) - .Concat(maid.body0.goSlot) - .Where(s => s != null && s.morph != null) + maid + .body0 + .FetchGoSlot() + .Where(s => s?.morph != null) .Select(r => new Tuple(r.Category, r.morph)); } - public static bool DoesCategoryContainKey(this Maid maid, TBody.SlotID category, string shapekey) { return @@ -136,7 +142,6 @@ public static bool DoesCategoryContainKey(this Maid maid, TBody.SlotID category, .FirstOrDefault(r => r.Equals(shapekey)) .IsNullOrWhiteSpace() == false; } - public static IEnumerable GetAllShapekeysInCategory(this Maid maid, TBody.SlotID category) { return @@ -148,15 +153,9 @@ public static IEnumerable GetAllShapekeysInCategory(this Maid maid, TBod public static IEnumerable GetAllMorphsInMaidOfCategory(this Maid maid, TBody.SlotID category) { return - FetchGoSlot(maid - .body0) - .Concat(maid.body0.goSlot) - .Where(s => s != null && s.morph != null && s.Category == category.ToString()) - .Select(m => m.morph); - } - public static bool ContainsShapekey(this TMorph morph, string shapekey) - { - return morph.hash != null && morph.hash.Keys.Cast().Contains(shapekey); + maid.GetAllMorphsFromMaid() + .Where(r => r.item1.Equals(category.ToString())) + .Select(m => m.item2); } public static IEnumerable> GetAllShapeKeysFromMaidList(List maids) { @@ -166,7 +165,7 @@ public static IEnumerable> GetAllShapeKeysFromMaidList(Lis .SelectMany(r => r); } - public static IEnumerable> GetAllShapeKeysFromMaid(Maid maid) + public static IEnumerable> GetAllShapeKeysFromMaid(this Maid maid) { if (maid == null) { @@ -177,16 +176,16 @@ public static IEnumerable> GetAllShapeKeysFromMaid(Maid ma foreach (var keyPair in GetAllMorphsFromMaid(maid)) { - var keyNameList = keyPair.Second.hash.Keys.Cast(); + var keyNameList = keyPair.item2.hash.Keys.Cast(); foreach (var stringKey in keyNameList) { - result.Add(new Tuple(keyPair.First, stringKey)); + result.Add(new Tuple(keyPair.item1, stringKey)); } } result = result - .GroupBy(p => new { p.First, p.Second }) + .GroupBy(p => new { p.item1, p.item2 }) .Select(g => g.First()) .ToList(); @@ -198,12 +197,12 @@ public static IEnumerable> GetAllShapeKeysFromAllMaids() var result = GetAllShapeKeysFromMaidList (GameMain.Instance.CharacterMgr .GetStockMaidList() - .Where(m => m.isActiveAndEnabled) + .Where(m => m.IsMaidActive()) .ToList() ); result = result - .GroupBy(p => new { p.First, p.Second }) + .GroupBy(p => new { p.item1, p.item2 }) .Select(g => g.First()) .ToList(); @@ -213,7 +212,7 @@ public static IEnumerable> GetAllShapeKeysFromAllMaids() public static bool IsFaceKey(string Keyname) { return GameMain.Instance.CharacterMgr.GetStockMaidList() - .Where(maid => maid != null && maid.body0 != null && maid.body0.Face != null && maid.body0.Face.morph != null) + .Where(maid => maid?.body0?.Face?.morph != null) .Select(m => m.body0.Face.morph) .Where(mr => mr.Contains(Keyname)) .Count() > 0; @@ -221,41 +220,17 @@ public static bool IsFaceKey(string Keyname) public static IEnumerable GetNameOfAllMaids() { - var result = GameMain.Instance.CharacterMgr.GetStockMaidList().Select(m => m.status.fullNameJpStyle).ToList(); + var result = GameMain.Instance.CharacterMgr + .GetStockMaidList() + .Select(m => m.status.fullNameJpStyle) + .ToList(); result.Sort(); return result; } - public static IEnumerable GetAllBlendShapes(Mesh mesh) - { -#if (DEBUG) - Main.logger.LogDebug($"Was called, getting all blendshapes in {mesh.name}, there should be {mesh.blendShapeCount} blendshapes."); -#endif - string blendshape; - - List res = new List(); - - int shapecount = 0; - - for (int i = 0; mesh.blendShapeCount > i && shapecount < mesh.blendShapeCount; i++) - { -#if (DEBUG) - Main.logger.LogDebug($"Found blendshape with name {mesh.GetBlendShapeName(i)}"); -#endif - - if ((blendshape = mesh.GetBlendShapeName(i)) != null) - { - res.Add(blendshape); - ++shapecount; - } - } - - return res; - } - - public static float CalculateExcitementDeformation(ShapeKeyEntry sk) + public static float CalculateExcitementDeformation(this ShapeKeyEntry sk) { float excitement = GetHighestExcitement(); #if (DEBUG) @@ -299,6 +274,13 @@ public static float GetHighestExcitement() return 0; } + /// + /// A faster way to check if a string contains another while using StringComparison. + /// + /// + /// + /// + /// public static bool Contains(this string source, string cont, StringComparison compare) { return source.IndexOf(cont, compare) >= 0; diff --git a/YotogiShapekeys/TranslationResource.cs b/YotogiShapekeys/TranslationResource.cs new file mode 100644 index 0000000..9e62029 --- /dev/null +++ b/YotogiShapekeys/TranslationResource.cs @@ -0,0 +1,46 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using static Product; + +namespace ShapekeyMaster +{ + internal class TranslationResource + { + public readonly string filePath; + private Dictionary Map; + public TranslationResource(string filePath) + { + Map = new Dictionary(); + var translation = JsonConvert.DeserializeObject>(File.ReadAllText(filePath)); + this.filePath = filePath; + + foreach (var tran in translation) + { + Map[tran.Key.ToLower()] = tran.Value; + } + } + + public string this[string name] + { + get + { + name = name.ToLower(); + + if (Map.TryGetValue(name, out var transString)) + { + return transString; + } + + Main.logger.LogWarning($"The translation resource is missing key {name}! Will fallback to using the key as the result!"); + + Map[name] = name; + return name; + } + } + } +}