diff --git a/YotogiShapekeys/0Old/0Old1ShapekeyFetcherSetter.cs b/YotogiShapekeys/0Old/0Old1ShapekeyFetcherSetter.cs index a8859f9..8d764be 100644 --- a/YotogiShapekeys/0Old/0Old1ShapekeyFetcherSetter.cs +++ b/YotogiShapekeys/0Old/0Old1ShapekeyFetcherSetter.cs @@ -48,7 +48,6 @@ public static List GetMaidsList() //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(); @@ -83,8 +82,6 @@ public static void MissionControlAll() } public static void MissionControlMaid(Maid maid) { - - #if (DEBUG) Main.logger.Log($"Started"); #endif @@ -93,7 +90,6 @@ public static void MissionControlMaid(Maid maid) stop.Start(); - #if (DEBUG) Main.logger.Log($"Checking maid isn't null."); #endif @@ -103,7 +99,6 @@ public static void MissionControlMaid(Maid maid) return; } - #if (DEBUG) Main.logger.Log($"Fetching morphs"); #endif @@ -111,7 +106,6 @@ public static void MissionControlMaid(Maid maid) //var morphs = await Task.Factory.StartNew(() => GetAllMorphsFromMaid(maid)); IEnumerable morphs = GetAllMorphsFromMaid(maid); - #if (DEBUG) Main.logger.Log($"Converting morphs to changes..."); #endif @@ -123,7 +117,6 @@ public static void MissionControlMaid(Maid maid) //.Select(n => n.Result) .SelectMany(r => r); - #if (DEBUG) Main.logger.Log($"Processing changes..."); #endif @@ -237,7 +230,6 @@ public static List GetTMorphChangeForm(TMorph m) //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 @@ -355,7 +347,6 @@ public static ShapekeyChangeForm GetShapekeyChangeForm(ShapeKeyEntry s, TMorph m //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 @@ -383,12 +374,10 @@ public static void ProcessChanges(IEnumerable changes) #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(); @@ -397,10 +386,8 @@ public static IEnumerator RunShapekeyChange() 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(); @@ -423,7 +410,6 @@ public static IEnumerator RunShapekeyChange() } catch { - } #if (DEBUG) @@ -444,7 +430,7 @@ public static IEnumerator RunShapekeyChange() CorouteRunning = false; } /* - public static void FixSingleBlendValues(TMorph morph, int index) + public static void FixSingleBlendValues(TMorph morph, int index) { int num = 0; var BlendValuesCHK = AccessTools.DeclaredField(typeof(TMorph), "BlendValuesCHK").GetValue(morph) as float[]; @@ -502,8 +488,8 @@ public static void FixSingleBlendValues(TMorph morph, int index) } }*/ /* - //The animator can be considered something of a manager. It simply calculates orgasms and - public static IEnumerator OrgasmAnimator() + //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!!"); @@ -524,7 +510,7 @@ public static IEnumerator OrgasmAnimator() { s2.Start(); - while (OrgasmDeform < 100) + while (OrgasmDeform < 100) { OrgasmDeform += 25; @@ -536,12 +522,11 @@ public static IEnumerator OrgasmAnimator() yield return new WaitForSeconds(.1f); } - while (OrgasmDeform > 0 && s.Elapsed < TimeSpan.FromSeconds(1)) + while (OrgasmDeform > 0 && s.Elapsed < TimeSpan.FromSeconds(1)) { - OrgasmDeform -= 10; - if (OrgasmDeform < 0) + if (OrgasmDeform < 0) { OrgasmDeform = 0; } @@ -573,9 +558,9 @@ public static IEnumerator OrgasmAnimator() Main.logger.Log($"Orgasm animator has finished: {s.Elapsed}"); #endif } - private static IEnumerator UpdateOrgasmKeys() + private static IEnumerator UpdateOrgasmKeys() { - while (IsOrgasming) + while (IsOrgasming) { RunAllBackgroundAsync(); @@ -584,4 +569,4 @@ private static IEnumerator UpdateOrgasmKeys() yield break; }*/ } -} +} \ No newline at end of file diff --git a/YotogiShapekeys/0Old/BlendShapeFetcherSetter.cs b/YotogiShapekeys/0Old/BlendShapeFetcherSetter.cs index 36b9344..80872ed 100644 --- a/YotogiShapekeys/0Old/BlendShapeFetcherSetter.cs +++ b/YotogiShapekeys/0Old/BlendShapeFetcherSetter.cs @@ -12,7 +12,6 @@ internal static class BlendShapeFetcherSetter { public static void RunAll() { - #if (DEBUG) Main.logger.Log($"Updated called. Running on all."); #endif @@ -48,4 +47,4 @@ static void RunSkinnedMesh(SkinnedMeshRenderer smr) } } } -} +} \ No newline at end of file diff --git a/YotogiShapekeys/0Old/PrivateSettersContractResolver.cs b/YotogiShapekeys/0Old/PrivateSettersContractResolver.cs index 7d41dd2..6a061f7 100644 --- a/YotogiShapekeys/0Old/PrivateSettersContractResolver.cs +++ b/YotogiShapekeys/0Old/PrivateSettersContractResolver.cs @@ -10,16 +10,16 @@ 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; - } - } -} + 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 index 9e56a4e..ab0ad80 100644 --- a/YotogiShapekeys/0Old/PropsMenu.cs +++ b/YotogiShapekeys/0Old/PropsMenu.cs @@ -25,7 +25,6 @@ private static void DisplayPropShapeKeyEntriesMenu(SortedDictionary 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() - { - + public async Task MissionControl() + { } //Async way of running the run all func. public async static void RunAllBackgroundAsync() @@ -80,7 +79,6 @@ public static Task RunAll() 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) @@ -89,7 +87,7 @@ public async static void RunSingleMaidBackgroundAsync(Maid maid) { await Task.Factory.StartNew(() => RunSingleMaid(maid)); } - else + else { await RunSingleMaid(maid); } @@ -116,16 +114,15 @@ public static Task RunSingleTMorph(TMorph m) //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)) + .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 @@ -158,7 +155,7 @@ public static Task RunSingleTMorph(TMorph m) continue; } - //If nothing special is happening, + //If nothing special is happening, Main.@this.StartCoroutine(RunShapekeyChange(m, shapekeyIndex, s.Deform)); } return null; @@ -169,7 +166,7 @@ public async static Task RunSingleShapekeyBackgroundAsync(ShapeKeyEntry s) { await Task.Factory.StartNew(() => RunSingleShapekey(s)); } - else + else { await RunSingleShapekey(s); } @@ -191,9 +188,9 @@ public static Task RunSingleShapekey(ShapeKeyEntry s, bool coroute = true) { return null; } - + List templist = GetAllMorphsFromMaidList(maidslist) - .Where(m => + .Where(m => (s.Maid.Equals("") || m.bodyskin.body.maid.status.fullNameJpStyle.Equals(s.Maid)) && m.Contains(s.ShapeKey)) .ToList(); @@ -234,7 +231,8 @@ public static Task RunSingleShapekey(ShapeKeyEntry s, bool coroute = true) if (coroute) { Main.@this.StartCoroutine(RunShapekeyChange(m, shapekeyIndex, s.Deform)); - } else + } + else { RunShapekeyChange(m, shapekeyIndex, s.Deform); } @@ -245,12 +243,12 @@ public static Task RunSingleShapekey(ShapeKeyEntry s, bool coroute = true) 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) + 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) + if (deform < 0) { deform = 0; } @@ -270,8 +268,8 @@ public static IEnumerator RunShapekeyChange(TMorph m, int shapekeyIndex, float d } } /* - //The animator can be considered something of a manager. It simply calculates orgasms and - public static IEnumerator OrgasmAnimator() + //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!!"); @@ -292,7 +290,7 @@ public static IEnumerator OrgasmAnimator() { s2.Start(); - while (OrgasmDeform < 100) + while (OrgasmDeform < 100) { OrgasmDeform += 25; @@ -304,12 +302,11 @@ public static IEnumerator OrgasmAnimator() yield return new WaitForSeconds(.1f); } - while (OrgasmDeform > 0 && s.Elapsed < TimeSpan.FromSeconds(1)) + while (OrgasmDeform > 0 && s.Elapsed < TimeSpan.FromSeconds(1)) { - OrgasmDeform -= 10; - if (OrgasmDeform < 0) + if (OrgasmDeform < 0) { OrgasmDeform = 0; } @@ -341,12 +338,12 @@ public static IEnumerator OrgasmAnimator() Main.logger.Log($"Orgasm animator has finished: {s.Elapsed}"); #endif } - private static IEnumerator UpdateOrgasmKeys() + private static IEnumerator UpdateOrgasmKeys() { - while (IsOrgasming) + while (IsOrgasming) { RunAllBackground - + (); yield return new WaitForSecondsRealtime(.5f); @@ -354,4 +351,4 @@ private static IEnumerator UpdateOrgasmKeys() yield break; }*/ } -} +} \ No newline at end of file diff --git a/YotogiShapekeys/1Old/HarmonyPatchers.cs b/YotogiShapekeys/1Old/HarmonyPatchers.cs index f4f81ed..c726b44 100644 --- a/YotogiShapekeys/1Old/HarmonyPatchers.cs +++ b/YotogiShapekeys/1Old/HarmonyPatchers.cs @@ -14,7 +14,6 @@ private static void NotifyOfLoad2(ref TMorph __1) ("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. @@ -55,7 +54,7 @@ private static void Intercede1(ref TMorph __instance) ShapekeyFetcherSetter.RegisterMaid(maid); } - //Patches the setter of the FPS value to run below code afterwards + //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) @@ -79,4 +78,4 @@ public static void OnOrgasm(string __0) Main.logger.Log($"Somebody seems to be having an orgasm!"); }*/ } -} +} \ No newline at end of file diff --git a/YotogiShapekeys/1Old/ShapekeyFetcherSetter.cs b/YotogiShapekeys/1Old/ShapekeyFetcherSetter.cs index 9260011..33a6bb1 100644 --- a/YotogiShapekeys/1Old/ShapekeyFetcherSetter.cs +++ b/YotogiShapekeys/1Old/ShapekeyFetcherSetter.cs @@ -74,7 +74,6 @@ public static void RunSingleMaid(Maid maid) } public static void RunSingleEntry(ShapeKeyEntry sk) { - #if (DEBUG) Stopwatch stop = new Stopwatch(); stop.Start(); @@ -162,12 +161,11 @@ public static List GetTMorphChangeForm(TMorph m) //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 (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}"); @@ -223,7 +221,6 @@ public static List GetTMorphChangeForm(TMorph m) //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 @@ -240,7 +237,6 @@ public static void ProcessChanges(IEnumerable changes) } public static IEnumerator RunShapekeyChange() { - CorouteRunning = true; #if (DEBUG) @@ -251,16 +247,15 @@ public static IEnumerator RunShapekeyChange() while (ChangeList.Count > 0) { - #if (DEBUG) Main.logger.LogDebug($"Running the while..."); #endif - ShapekeyChangeForm nextKey = + 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 (nextKey == null) { #if (DEBUG) Main.logger.LogDebug($"It seems no keys were ready to be changed. Waiting for next frame..."); @@ -324,7 +319,6 @@ public static IEnumerator RunShapekeyChange() } public static void RunShapekeyChangeNormal() { - #if (DEBUG) Main.logger.LogDebug($"Started Changer Normal..."); #endif @@ -391,4 +385,4 @@ public static void RunShapekeyChangeNormal() #endif } } -} +} \ No newline at end of file diff --git a/YotogiShapekeys/HarmonyPatchers.cs b/YotogiShapekeys/HarmonyPatchers.cs index 0cb13e0..4446d7f 100644 --- a/YotogiShapekeys/HarmonyPatchers.cs +++ b/YotogiShapekeys/HarmonyPatchers.cs @@ -1,30 +1,34 @@ -using HarmonyLib; +using BepInEx; +using HarmonyLib; using System; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Text; +using System.Reflection.Emit; using UnityEngine.SceneManagement; using static ShapekeyMaster.SMEventsAndArgs; namespace ShapekeyMaster { - class HarmonyPatchers + internal class HarmonyPatchers { public static event EventHandler MorphEvent; + public static event EventHandler ExcitementChange; + public static event EventHandler ClothingMaskChange; private static readonly List YotogiLvls = new List() { "SceneYotogi", "SceneYotogiOld" }; private static int SlowCounter = 0; + private static float[] PreviousBlends; + [HarmonyPatch(typeof(TMorph), MethodType.Constructor, new Type[] { typeof(TBodySkin) })] [HarmonyPostfix] private static void NotifyOfLoad(ref TMorph __instance) { #if (DEBUG) - Main.logger.LogDebug("ShapekeyMaster picked up a morph creation!"); + Main.logger.LogDebug($"Morph Creation Event @ {__instance.bodyskin.body.maid.status.fullNameJpStyle} :: {__instance.Category}"); #endif ShapekeyUpdate.ListOfActiveMorphs.Add(__instance); if (MorphEvent != null) @@ -40,12 +44,12 @@ private static void NotifyOfLoad(ref TMorph __instance) private static void NotifyOfUnLoad(ref TMorph __instance) { #if (DEBUG) - Main.logger.LogDebug("ShapekeyMaster picked up a morph deletion!"); + Main.logger.LogDebug($"Morph Deletion Event @ {__instance.Category}"); #endif ShapekeyUpdate.ListOfActiveMorphs.Remove(__instance); if (MorphEvent != null) - { + { MorphEvent.Invoke(null, new MorphEventArgs(__instance, false)); } } @@ -56,7 +60,7 @@ private static void NotifyOfUnLoad(ref TMorph __instance) private static void NotifyOfMenuLoad(ref Maid __instance) { #if (DEBUG) - Main.logger.LogDebug("ShapekeyMaster picked up a menu change!"); + Main.logger.LogDebug($"Menu Change Event @ {__instance.status.fullNameJpStyle}"); #endif ShapekeyUpdate.UpdateKeys(__instance.status.fullNameJpStyle); } @@ -66,7 +70,7 @@ private static void NotifyOfMenuLoad(ref Maid __instance) private static void NotifyOfClothesMask(ref TBody __instance) { #if (DEBUG) - Main.logger.LogDebug("ShapekeyMaster picked up mask change!"); + Main.logger.LogDebug($"Mask Change Event @ {__instance.maid.status.fullNameJpStyle}"); #endif if (ClothingMaskChange != null) { @@ -81,39 +85,32 @@ private static void NotifyOfClothesMask(ref TBody __instance) private static void VerifyBlendValuesBeforeSet(ref TMorph __instance) { #if (DEBUG) - Main.logger.LogDebug("Check morph dic for instance..."); + Main.logger.LogDebug($"Cheking Morph Dic @ {__instance.bodyskin.body.maid.status.fullNameJpStyle} :: {__instance.Category}\n{System.Environment.StackTrace}"); #endif + + PreviousBlends = __instance.BlendValues; + if (UI.SKDatabase.MorphShapekeyDictionary().ContainsKey(__instance)) { Stopwatch watch = new Stopwatch(); watch.Start(); #if (DEBUG) - Main.logger.LogDebug("Starting set check..."); + Main.logger.LogDebug($"Iterating Entries @ {__instance.bodyskin.body.maid.status.fullNameJpStyle} :: {__instance.Category}"); #endif foreach (ShapeKeyEntry shapeKeyEntry in UI.SKDatabase.ShapekeysByMorph(__instance)) { -#if (DEBUG) - Main.logger.LogDebug($"Checking hashset for key {shapeKeyEntry.ShapeKey}"); -#endif - if (!__instance.hash.ContainsKey(shapeKeyEntry.ShapeKey)) { continue; } -#if (DEBUG) - Main.logger.LogDebug("Getting key index..."); -#endif - var index = (int)__instance.hash[shapeKeyEntry.ShapeKey]; -#if (DEBUG) - Main.logger.LogDebug("Running actual checks..."); -#endif + var index = (int)__instance.hash[shapeKeyEntry.ShapeKey]; if (!shapeKeyEntry.Enabled) { #if (DEBUG) - Main.logger.LogDebug("Disabling key"); + Main.logger.LogDebug($"Disabling Key @ {__instance.bodyskin.body.maid.status.fullNameJpStyle} :: {__instance.Category} ::: {shapeKeyEntry.EntryName} :::: {shapeKeyEntry.ShapeKey}"); #endif __instance.BlendValues[index] = 0; __instance.BlendValuesBackup[index] = 0; @@ -121,7 +118,7 @@ private static void VerifyBlendValuesBeforeSet(ref TMorph __instance) else if (shapeKeyEntry.ConditionalsToggle && __instance.bodyskin != null && __instance.bodyskin.body && __instance.bodyskin.body.maid && SlotChecker.CheckIfSlotDisableApplies(shapeKeyEntry, __instance.bodyskin.body.maid)) { #if (DEBUG) - Main.logger.LogDebug("Checking conditionals."); + Main.logger.LogDebug($"Applying Conditional State @ {__instance.bodyskin.body.maid.status.fullNameJpStyle} :: {__instance.Category} ::: {shapeKeyEntry.EntryName} :::: {shapeKeyEntry.ShapeKey}"); #endif __instance.BlendValues[index] = shapeKeyEntry.DisabledDeform / 100; @@ -130,7 +127,7 @@ private static void VerifyBlendValuesBeforeSet(ref TMorph __instance) else if (shapeKeyEntry.AnimateWithExcitement && YotogiLvls.Contains(SceneManager.GetActiveScene().name)) { #if (DEBUG) - Main.logger.LogDebug("Calcing excitement deform"); + Main.logger.LogDebug($"Applying Excitement Deformation @ {__instance.bodyskin.body.maid.status.fullNameJpStyle} :: {__instance.Category} ::: {shapeKeyEntry.EntryName} :::: {shapeKeyEntry.ShapeKey}"); #endif var deform = HelperClasses.CalculateExcitementDeformation(shapeKeyEntry); @@ -141,7 +138,7 @@ private static void VerifyBlendValuesBeforeSet(ref TMorph __instance) else { #if (DEBUG) - Main.logger.LogDebug("Doing basic deform."); + Main.logger.LogDebug($"Applying Standard Deform @ {__instance.bodyskin.body.maid.status.fullNameJpStyle} :: {__instance.Category} ::: {shapeKeyEntry.EntryName} :::: {shapeKeyEntry.ShapeKey}"); #endif __instance.BlendValues[index] = shapeKeyEntry.Deform / 100; @@ -159,18 +156,34 @@ private static void VerifyBlendValuesBeforeSet(ref TMorph __instance) SlowCounter = 0; } } - else + else { SlowCounter = 0; } watch = null; } + + /* + if (ShapekeyUpdate.ShapekeyToPreview.IsNullOrWhiteSpace() == false && __instance.hash.ContainsKey(ShapekeyUpdate.ShapekeyToPreview)) + { + var index = (int)__instance.hash[ShapekeyUpdate.ShapekeyToPreview]; + __instance.BlendValues[index] = ShapekeyUpdate.PreviewValToSet / 100; + } + */ #if (DEBUG) - Main.logger.LogDebug("Update precheck done."); + Main.logger.LogDebug($"Update precheck done @ {__instance.bodyskin.body.maid.status.fullNameJpStyle} :: {__instance.Category}"); #endif } - //Patches the setter of the FPS value to run below code afterwards + [HarmonyPatch(typeof(TMorph), "FixBlendValues")] + [HarmonyPatch(typeof(TMorph), "FixFixBlendValues")] + [HarmonyPatch(typeof(TMorph), "FixBlendValues_Face")] + [HarmonyPostfix] + private static void ReturnBlendFiles(ref TMorph __instance) + { + __instance.BlendValues = PreviousBlends; + } + [HarmonyPatch(typeof(MaidStatus.Status), "currentExcite", MethodType.Setter)] [HarmonyPostfix] public static void OnExciteSet(ref MaidStatus.Status __instance, ref int __0) @@ -180,9 +193,21 @@ public static void OnExciteSet(ref MaidStatus.Status __instance, ref int __0) ExcitementChange.Invoke(null, new ExcitementChangeEvent(__instance.fullNameJpStyle, __0)); #if (DEBUG) - Main.logger.LogDebug($"{__instance.fullNameJpStyle }'s excitement changed to {__instance.currentExcite}! Making changes..."); + Main.logger.LogDebug($"{__instance.fullNameJpStyle}'s excitement changed to {__instance.currentExcite}! Making changes..."); #endif } } + + [HarmonyPatch(typeof(UltimateOrbitCamera), "Update")] + [HarmonyPrefix] + public static bool InputCheck() + { + if (MyGUI.Helpers.IsMouseOnGUI()) + { + return false; + } + + return true; + } } -} +} \ No newline at end of file diff --git a/YotogiShapekeys/HelperClasses.cs b/YotogiShapekeys/HelperClasses.cs index 5544edd..6793efa 100644 --- a/YotogiShapekeys/HelperClasses.cs +++ b/YotogiShapekeys/HelperClasses.cs @@ -1,4 +1,4 @@ -using HarmonyLib; +using BepInEx; using System; using System.Collections.Generic; using System.Linq; @@ -7,14 +7,34 @@ namespace ShapekeyMaster { - internal static class HelperClasses + public class Tuple { + public T1 First { get; private set; } + public T2 Second { get; private set; } - readonly static FieldInfo goSlotField = typeof(TBody).GetField("goSlot", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + internal Tuple(T1 first, T2 second) + { + First = first; + Second = second; + } + } - readonly static Type goSlotType = goSlotField.FieldType; + public static class Tuple + { + public static Tuple New(T1 first, T2 second) + { + var tuple = new Tuple(first, second); + return tuple; + } + } - readonly static MethodInfo goSlotMethod = goSlotType.GetMethod("GetListParents", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public) ?? null; + internal static class HelperClasses + { + private static readonly FieldInfo goSlotField = typeof(TBody).GetField("goSlot", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + private static readonly Type goSlotType = goSlotField.FieldType; + + private static readonly MethodInfo goSlotMethod = goSlotType.GetMethod("GetListParents", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public) ?? null; public static List FetchGoSlot(TBody body) { @@ -38,6 +58,7 @@ public static List FetchGoSlot(TBody body) return null; } + public static bool HasFlag(this Enum variable, Enum value) { // check if from the same type. @@ -52,12 +73,11 @@ public static bool HasFlag(this Enum variable, Enum value) return (num2 & num) == num; } + public static bool IsMaidActive(string name) { - if (name == "") { - bool result = GameMain.Instance.CharacterMgr .GetStockMaidList() @@ -75,9 +95,9 @@ public static bool IsMaidActive(string name) return GameMain.Instance.CharacterMgr .GetStockMaidList() - .Where(m => m != null && m.isActiveAndEnabled && m.status.fullNameJpStyle == name) - .Count() > 0; + .FirstOrDefault(m => m != null && m.isActiveAndEnabled && m.status.fullNameJpStyle == name) != null; } + public static Maid GetMaidByName(string name) { if (name == "") @@ -90,55 +110,106 @@ public static Maid GetMaidByName(string name) .GetStockMaidList() .FirstOrDefault(m => m != null && m.isActiveAndEnabled && m.status.fullNameJpStyle == name); } - public static IEnumerable GetAllMorphsFromMaidList(List list) + + public static IEnumerable> GetAllMorphsFromMaidList(List list) { return list - .Select(m => GetAllMorphsFromMaid(m)) - .SelectMany(tm => tm); + .SelectMany(m => GetAllMorphsFromMaid(m)) + .Select(r => new Tuple(r.First, r.Second)); } - public static IEnumerable GetAllMorphsFromMaid(Maid maid) + + public static IEnumerable> GetAllMorphsFromMaid(Maid maid) { return FetchGoSlot(maid .body0) - .Concat(new[] { maid.body0.Face }) - .Where(s => s != null) - .Select(s => s.morph) - .Where(o => o != null); + .Concat(maid.body0.goSlot) + .Where(s => s != null && s.morph != null) + .Select(r => new Tuple(r.Category, r.morph)); } - public static IEnumerable GetAllShapeKeysFromMaidList(List maids) + + public static bool DoesCategoryContainKey(this Maid maid, TBody.SlotID category, string shapekey) + { + return + maid.GetAllShapekeysInCategory(category) + .FirstOrDefault(r => r.Equals(shapekey)) + .IsNullOrWhiteSpace() == false; + } + + public static IEnumerable GetAllShapekeysInCategory(this Maid maid, TBody.SlotID category) + { + return + maid.GetAllMorphsInMaidOfCategory(category) + .Select(m => m.hash) + .SelectMany(r => r.Keys.Cast()); + } + + 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); + } + public static IEnumerable> GetAllShapeKeysFromMaidList(List maids) { return maids .Select(m => GetAllShapeKeysFromMaid(m)) - .SelectMany(skl => skl) - .Distinct(); + .SelectMany(r => r); } - public static IEnumerable GetAllShapeKeysFromMaid(Maid maid) + + public static IEnumerable> GetAllShapeKeysFromMaid(Maid maid) { if (maid == null) { return null; } - return - GetAllMorphsFromMaid(maid) - .Select(m => m.hash) - .Select(h => h.Keys) - .Select(k => k.Cast()) - .SelectMany(k => k) - .Distinct(); + List> result = new List>(); + + foreach (var keyPair in GetAllMorphsFromMaid(maid)) + { + var keyNameList = keyPair.Second.hash.Keys.Cast(); + + foreach (var stringKey in keyNameList) + { + result.Add(new Tuple(keyPair.First, stringKey)); + } + } + + result = result + .GroupBy(p => new { p.First, p.Second }) + .Select(g => g.First()) + .ToList(); + + return result; } - public static IEnumerable GetAllShapeKeysFromAllMaids() + + public static IEnumerable> GetAllShapeKeysFromAllMaids() { - var result = GetAllShapeKeysFromMaidList(GameMain.Instance.CharacterMgr - .GetStockMaidList().Where(m => m.isActiveAndEnabled).ToList()).ToList(); + var result = GetAllShapeKeysFromMaidList + (GameMain.Instance.CharacterMgr + .GetStockMaidList() + .Where(m => m.isActiveAndEnabled) + .ToList() + ); - result.Sort(); + result = result + .GroupBy(p => new { p.First, p.Second }) + .Select(g => g.First()) + .ToList(); return result; } + public static bool IsFaceKey(string Keyname) { return GameMain.Instance.CharacterMgr.GetStockMaidList() @@ -147,6 +218,7 @@ public static bool IsFaceKey(string Keyname) .Where(mr => mr.Contains(Keyname)) .Count() > 0; } + public static IEnumerable GetNameOfAllMaids() { var result = GameMain.Instance.CharacterMgr.GetStockMaidList().Select(m => m.status.fullNameJpStyle).ToList(); @@ -155,9 +227,9 @@ public static IEnumerable GetNameOfAllMaids() 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 @@ -182,6 +254,7 @@ public static IEnumerable GetAllBlendShapes(Mesh mesh) return res; } + public static float CalculateExcitementDeformation(ShapeKeyEntry sk) { float excitement = GetHighestExcitement(); @@ -205,6 +278,7 @@ public static float CalculateExcitementDeformation(ShapeKeyEntry sk) #endif return (result + sk.DeformMin); } + public static float GetHighestExcitement() { var maids = GameMain.instance.CharacterMgr.GetStockMaidList() @@ -224,5 +298,10 @@ public static float GetHighestExcitement() } return 0; } + + public static bool Contains(this string source, string cont, StringComparison compare) + { + return source.IndexOf(cont, compare) >= 0; + } } -} +} \ No newline at end of file diff --git a/YotogiShapekeys/Main.cs b/YotogiShapekeys/Main.cs index fcbf15b..4905fad 100644 --- a/YotogiShapekeys/Main.cs +++ b/YotogiShapekeys/Main.cs @@ -5,12 +5,12 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Security; using System.Security.Permissions; using System.Windows.Forms; using UnityEngine; + //using System.Threading.Tasks; [module: UnverifiableCode] @@ -18,7 +18,7 @@ namespace ShapekeyMaster { - [BepInPlugin("ShapekeyMaster", "ShapekeyMaster", "1.4.3")] + [BepInPlugin("ShapekeyMaster", "ShapekeyMaster", "1.4.4")] [BepInDependency("deathweasel.com3d2.api")] public class Main : BaseUnityPlugin { @@ -26,7 +26,7 @@ public class Main : BaseUnityPlugin internal static BepInEx.Logging.ManualLogSource logger; - private static bool enablegui = false; + public static bool enablegui { get; private set; } = false; private static SaveFileDialog FileSave = new SaveFileDialog(); @@ -34,6 +34,117 @@ public class Main : BaseUnityPlugin 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 SimpleMode; internal static ConfigEntry HideInactiveMaids; @@ -63,7 +174,9 @@ private void Awake() if (File.Exists(BepInEx.Paths.ConfigPath + "\\ShapekeyMaster.json")) { - UI.SKDatabase.AllShapekeyDictionary = LoadFromJson(BepInEx.Paths.ConfigPath + "\\ShapekeyMaster.json"); + var serDB = LoadFromJson(BepInEx.Paths.ConfigPath + "\\ShapekeyMaster.json"); + UI.SKDatabase.AllShapekeyDictionary = serDB.AllShapekeyDictionary; + UI.SKDatabase.BlacklistedShapekeys = serDB.BlacklistedShapekeys; } SystemShortcutAPI.AddButton("ShapekeyMaster", () => @@ -74,12 +187,11 @@ private void Awake() { SaveToJson(BepInEx.Paths.ConfigPath + "\\ShapekeyMaster.json", UI.SKDatabase); } - }, "Open/Close GUI", Convert.FromBase64String(iconBase64)); Logger.LogInfo("ShapekeyMaster is online!"); - } + private void Update() { if (HotkeyEnabled.Value && Hotkey.Value.IsDown()) @@ -87,6 +199,7 @@ private void Update() enablegui = !enablegui; } } + private void OnGUI() { if (enablegui) @@ -94,6 +207,7 @@ private void OnGUI() UI.Initialize(); } } + private void OnDestroy() { if (Autosave.Value) @@ -122,7 +236,7 @@ internal static void SaveToJson(string path, ShapekeyDatabase database, bool wit } } - internal static Dictionary LoadFromJson(string path, bool withPrompt = false) + internal static ShapekeyDatabase LoadFromJson(string path, bool withPrompt = false) { if (withPrompt) { @@ -140,12 +254,15 @@ internal static Dictionary LoadFromJson(string path, bool w { string mconfig = (File.ReadAllText(path)); - return JsonConvert.DeserializeObject( - mconfig).AllShapekeyDictionary; + var serializeset = new JsonSerializerSettings(); + serializeset.ObjectCreationHandling = ObjectCreationHandling.Replace; + + return JsonConvert.DeserializeObject(mconfig, serializeset); } return null; } + /* public static void SetBlendValues(int f_nIdx, float f_fValue, TMorph morph) { @@ -155,4 +272,4 @@ public static void SetBlendValues(int f_nIdx, float f_fValue, TMorph morph) } */ } -} +} \ No newline at end of file diff --git a/YotogiShapekeys/MyGUI/Helpers.cs b/YotogiShapekeys/MyGUI/Helpers.cs index bc04b7e..ca9c6ce 100644 --- a/YotogiShapekeys/MyGUI/Helpers.cs +++ b/YotogiShapekeys/MyGUI/Helpers.cs @@ -1,25 +1,34 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Text; using UnityEngine; namespace ShapekeyMaster.MyGUI { - class Helpers + internal class Helpers { + public static int LastMouseButtonUp { private set; get; } = -1; + public static void ChkMouseClick(Rect windowRect) { - if ((Input.mouseScrollDelta.y != 0 ||Input.GetMouseButtonUp(0)) && IsMouseOnGUI(windowRect)) + LastMouseButtonUp = Input.GetMouseButtonUp(0) ? 0 : Input.GetMouseButtonUp(1) ? 1 : Input.GetMouseButtonUp(2) ? 2 : -1; + + if ((Input.mouseScrollDelta.y != 0 || LastMouseButtonUp >= 0) && IsMouseOnGUI(windowRect)) { Input.ResetInputAxes(); } } - public static bool IsMouseOnGUI(Rect windowRect) + + public static bool IsMouseOnGUI(Rect? windowRect = null) { + if (windowRect.HasValue == false) + { + windowRect = UI.windowRect; + } + Vector2 point = new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y); - return windowRect.Contains(point); + return Main.enablegui && windowRect.Value.Contains(point); } + public static Texture2D MakeTex(int width, int height, Color col) { Color[] pix = new Color[width * height]; @@ -71,78 +80,138 @@ public static Texture2D MakeTexWithRoundedCorner(Color col) } } - public class P - { - public int x { get; set; } - public int y { get; set; } - public P(int x_, int y_) - { - x = x_; - y = y_; - } - } - - public static Texture2D MakeWindowTex(Color col, Color col2) - { - int x = 17; - int y = 27; - P[] nulls = new P[] { new P(0,0), new P(0,1), new P(0,2), new P(0,3), new P(0,4), - new P(1,0), new P(1,1), new P(1,2), new P(1,3), - new P(2,0), new P(2,1), new P(2,2), - new P(3,0), new P(3,1), - new P(4,0), - new P(x-1-0,0), new P(x-1-0,1), new P(x-1-0,2), new P(x-1-0,3), new P(x-1-0,4), - new P(x-1-1,0), new P(x-1-1,1), new P(x-1-1,2), new P(x-1-1,3), - new P(x-1-2,0), new P(x-1-2,1), new P(x-1-2,2), - new P(x-1-3,0), new P(x-1-3,1), - new P(x-1-4,0), - new P(0,y-1-0), new P(0,y-1-1), new P(0,y-1-2), new P(0,y-1-3), new P(0,y-1-4), - new P(1,y-1-0), new P(1,y-1-1), new P(1,y-1-2), new P(1,y-1-3), - new P(2,y-1-0), new P(2,y-1-1), new P(2,y-1-2), - new P(3,y-1-0), new P(3,y-1-1), - new P(4,y-1-0), - new P(x-1-0,y-1-0), new P(x-1-0,y-1-1), new P(x-1-0,y-1-2), new P(x-1-0,y-1-3), new P(x-1-0,y-1-4), - new P(x-1-1,y-1-0), new P(x-1-1,y-1-1), new P(x-1-1,y-1-2), new P(x-1-1,y-1-3), - new P(x-1-2,y-1-0), new P(x-1-2,y-1-1), new P(x-1-2,y-1-2), - new P(x-1-3,y-1-0), new P(x-1-3,y-1-1), - new P(x-1-4,y-1-0)}; - P[] brdrS = new P[] { new P(4,1), new P(3,2), new P(2,3), new P(1, 4), - new P(x-1-4,1), new P(x-1-3,2), new P(x-1-2,3), new P(x-1-1, 4), - new P(4,y-1-1), new P(3,y-1-2), new P(2,y-1-3), new P(1, y-1-4), - new P(x-1-4,y-1-1), new P(x-1-3,y-1-2), new P(x-1-2,y-1-3), new P(x-1-1, y-1-4)}; - - Texture2D result = new Texture2D(x, y); - for (int i = 0; i < x; i++) - { - for (int j = 0; j < y; j++) - { - //Border - if (i == 0 || j == 0 || i == (x - 1) || j == (y - 1) || brdrS.ToList().Exists(p => p.x == i && p.y == j)) - { - result.SetPixels(i, j, 1, 1, new Color[] { Color.black }); - } - else - { - if (j <= 10) - { - result.SetPixels(i, j, 1, 1, new Color[] { col }); - } - else - { - result.SetPixels(i, j, 1, 1, new Color[] { col2 }); - } - } - - //Corner - if (nulls.ToList().Exists(p => p.x == i && p.y == j)) - { - result.SetPixels(i, j, 1, 1, new Color[] { new Color(0, 0, 0, 0) }); - } - } - } - - result.Apply(); - return result; - } - } -} + public class P + { + public int x { get; set; } + public int y { get; set; } + + public P(int x_, int y_) + { + x = x_; + y = y_; + } + } + + public static Texture2D MakeWindowTex(Color col, Color col2) + { + int x = 17; + int y = 27; + P[] nulls = new P[] { new P(0,0), new P(0,1), new P(0,2), new P(0,3), new P(0,4), + new P(1,0), new P(1,1), new P(1,2), new P(1,3), + new P(2,0), new P(2,1), new P(2,2), + new P(3,0), new P(3,1), + new P(4,0), + new P(x-1-0,0), new P(x-1-0,1), new P(x-1-0,2), new P(x-1-0,3), new P(x-1-0,4), + new P(x-1-1,0), new P(x-1-1,1), new P(x-1-1,2), new P(x-1-1,3), + new P(x-1-2,0), new P(x-1-2,1), new P(x-1-2,2), + new P(x-1-3,0), new P(x-1-3,1), + new P(x-1-4,0), + new P(0,y-1-0), new P(0,y-1-1), new P(0,y-1-2), new P(0,y-1-3), new P(0,y-1-4), + new P(1,y-1-0), new P(1,y-1-1), new P(1,y-1-2), new P(1,y-1-3), + new P(2,y-1-0), new P(2,y-1-1), new P(2,y-1-2), + new P(3,y-1-0), new P(3,y-1-1), + new P(4,y-1-0), + new P(x-1-0,y-1-0), new P(x-1-0,y-1-1), new P(x-1-0,y-1-2), new P(x-1-0,y-1-3), new P(x-1-0,y-1-4), + new P(x-1-1,y-1-0), new P(x-1-1,y-1-1), new P(x-1-1,y-1-2), new P(x-1-1,y-1-3), + new P(x-1-2,y-1-0), new P(x-1-2,y-1-1), new P(x-1-2,y-1-2), + new P(x-1-3,y-1-0), new P(x-1-3,y-1-1), + new P(x-1-4,y-1-0)}; + P[] brdrS = new P[] { new P(4,1), new P(3,2), new P(2,3), new P(1, 4), + new P(x-1-4,1), new P(x-1-3,2), new P(x-1-2,3), new P(x-1-1, 4), + new P(4,y-1-1), new P(3,y-1-2), new P(2,y-1-3), new P(1, y-1-4), + new P(x-1-4,y-1-1), new P(x-1-3,y-1-2), new P(x-1-2,y-1-3), new P(x-1-1, y-1-4)}; + + Texture2D result = new Texture2D(x, y); + for (int i = 0; i < x; i++) + { + for (int j = 0; j < y; j++) + { + //Border + if (i == 0 || j == 0 || i == (x - 1) || j == (y - 1) || brdrS.ToList().Exists(p => p.x == i && p.y == j)) + { + result.SetPixels(i, j, 1, 1, new Color[] { Color.black }); + } + else + { + if (j <= 10) + { + result.SetPixels(i, j, 1, 1, new Color[] { col }); + } + else + { + result.SetPixels(i, j, 1, 1, new Color[] { col2 }); + } + } + + //Corner + if (nulls.ToList().Exists(p => p.x == i && p.y == j)) + { + result.SetPixels(i, j, 1, 1, new Color[] { new Color(0, 0, 0, 0) }); + } + } + } + + result.Apply(); + return result; + } + + public class ShapekeyEntryComparer : IComparer + { + public bool Ascending = true; + private int _Mode; + + //Mode 0, date of creation. + //Mode 1, entry name + //Mode 2, shapekey + public int Mode + { + get + { + return _Mode; + } + set + { + if (value > 2 || value < 0) + { + _Mode = 0; + } + else + { + _Mode = value; + } + } + } + + public int Compare(ShapeKeyEntry shapekeyThing1, ShapeKeyEntry shapekeyThing2) + { + int result = 0; + + switch (Mode) + { + case 0: + result = shapekeyThing1.CreationDate.CompareTo(shapekeyThing2.CreationDate); + break; + + case 1: + result = shapekeyThing1.EntryName.CompareTo(shapekeyThing2.EntryName); + break; + + case 2: + result = shapekeyThing1.ShapeKey.CompareTo(shapekeyThing2.ShapeKey); + break; + + default: + result = 0; + break; + } + + if (Ascending == false) + { + result *= -1; + } + + return result; + } + } + } +} \ No newline at end of file diff --git a/YotogiShapekeys/MyGUI/UI.cs b/YotogiShapekeys/MyGUI/UI.cs index c8abb8c..7dfbf32 100644 --- a/YotogiShapekeys/MyGUI/UI.cs +++ b/YotogiShapekeys/MyGUI/UI.cs @@ -1,47 +1,46 @@ -using System; +using BepInEx; +using System; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Text.RegularExpressions; using UnityEngine; +using static ShapekeyMaster.MyGUI.Helpers; namespace ShapekeyMaster { internal static class UI { - //public static SortedDictionary ShapeKeys = new SortedDictionary(); - //public static SortedDictionary FilteredShapeKeys = new SortedDictionary(); - //public static SortedDictionary> MaidFilteredShapeKeys = new SortedDictionary>(); + private static DateTime? TimeToKillNewKeyShine; + private static Guid? NewKeyToShine; - private static List ShapekeysNameList = new List(); + private static List> ShapekeysNameList = new List>(); private static List MaidNameList = new List(); private static Dictionary ThingsToExport = new Dictionary(); - //private static readonly List DeleteList = new List(); - internal static ShapekeyDatabase SKDatabase = new ShapekeyDatabase(); - private static readonly int WindowID = 777777; + public static readonly int WindowID = 777777; private static bool runonce = true; public static bool changewasmade = false; // Used for remembering old values when entering SKMenu private static string oldSKMenuFilter = ""; + private static Vector2 oldSKMenuScrollPosition = Vector2.zero; private static Vector2 oldPreSKMenuScrollPosition = Vector2.zero; private static string Filter = ""; private static int FilterMode = 0; private static int Page = 0; + private static bool FilterCommonKeys = true; + private static bool HideBlacklistedKeys = true; private static int TabSelection = 0; private static string MaidSelection = ""; - //Used for exporting... - //private static List MaidNamesWithKeys = new List(); + private static readonly ShapekeyEntryComparer entryComparer = new ShapekeyEntryComparer(); private static Vector2 scrollPosition = Vector2.zero; private static Vector2 scrollPosition1 = Vector2.zero; @@ -54,7 +53,7 @@ internal static class UI private static bool MaidGroupCreateOpen; private static bool ExportMenuOpen; - private static Rect windowRect = new Rect(Screen.width / 3, Screen.height / 4, Screen.width / 3f, Screen.height / 1.5f); + public static Rect windowRect = new Rect(Screen.width / 3, Screen.height / 4, Screen.width / 3f, Screen.height / 1.5f); private static int currentHeight = 0; private static int currentWidth = 0; @@ -63,8 +62,13 @@ internal static class UI private static GUIStyle Sections; private static GUIStyle Sections2; + private static GUIStyle ShineSections; + private static GUIStyle BlacklistedButton; + //private static GUIStyle PreviewButton; + public static void Initialize() { + //Setup some UI properties. if (runonce) { seperator = new GUIStyle(GUI.skin.horizontalSlider); @@ -85,10 +89,28 @@ public static void Initialize() Sections2 = new GUIStyle(GUI.skin.box); Sections2.normal.background = MyGUI.Helpers.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)); + + BlacklistedButton = new GUIStyle(GUI.skin.button); + BlacklistedButton.normal.textColor = Color.red; + BlacklistedButton.hover.textColor = Color.red; + BlacklistedButton.active.textColor = Color.red; + + /* + PreviewButton = new GUIStyle(GUI.skin.button); + PreviewButton.normal.textColor = Color.yellow; + PreviewButton.hover.textColor = Color.yellow; + PreviewButton.active.textColor = Color.yellow; + */ + + entryComparer.Mode = 0; + runonce = false; } - if (currentHeight != Screen.height || currentWidth != Screen.width) + //Sometimes the UI can be improperly sized, this sets it to some measurements. + if (currentHeight != Screen.height || currentWidth != Screen.width) { windowRect.height = Math.Max(Screen.height / 1.5f, 200); windowRect.width = Math.Max(Screen.width / 3f, 500); @@ -109,12 +131,8 @@ private static void GuiWindowControls(int windowID) { GUI.DragWindow(new Rect(0, 0, 10000, 20)); - //ToolbarSelection = ToolbarSelection = GUILayout.Toolbar(ToolbarSelection, ToolbarStrings); - scrollPosition = GUILayout.BeginScrollView(scrollPosition); - //if (ToolbarSelection == 0) - //{ if (ExportMenuOpen) { DisplayExportMenu(); @@ -145,6 +163,13 @@ private static void GuiWindowControls(int windowID) } else { + //This handles the shine of the UI. + if (NewKeyToShine.HasValue && TimeToKillNewKeyShine < DateTime.Now) + { + NewKeyToShine = null; + TimeToKillNewKeyShine = null; + } + DisplayHeaderMenu(); Main.SimpleMode.Value = GUILayout.Toggle(Main.SimpleMode.Value, "Simple"); @@ -155,41 +180,18 @@ private static void GuiWindowControls(int windowID) if (Main.SimpleMode.Value) { GUILayout.BeginVertical(Sections); - GUILayout.BeginHorizontal(Sections2); - if (GUILayout.Button("<<")) - { - Page = Math.Max(Page - Main.EntriesPerPage.Value, 0); - } - GUILayout.FlexibleSpace(); - GUILayout.Label($"Globals:{Page} ~ {Page + Main.EntriesPerPage.Value}"); - GUILayout.FlexibleSpace(); - if (GUILayout.Button(">>")) - { - Page = Math.Min(SKDatabase.GlobalShapekeyDictionary().Count - Main.EntriesPerPage.Value, Page + Main.EntriesPerPage.Value); - } - GUILayout.EndHorizontal(); + + DisplayPageManager(); SimpleDisplayShapeKeyEntriesMenu(SKDatabase.GlobalShapekeyDictionary()); + GUILayout.EndVertical(); } else { GUILayout.BeginVertical(Sections); - GUILayout.BeginHorizontal(Sections2); - GUILayout.FlexibleSpace(); - if (GUILayout.Button("<<")) - { - Page = Math.Max(Page - Main.EntriesPerPage.Value, 0); - } - GUILayout.FlexibleSpace(); - GUILayout.Label($"Globals:{Page} ~ {Page + Main.EntriesPerPage.Value}"); - GUILayout.FlexibleSpace(); - if (GUILayout.Button(">>")) - { - Page = Math.Min(SKDatabase.GlobalShapekeyDictionary().Count - Main.EntriesPerPage.Value, Page + Main.EntriesPerPage.Value); - } - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); + + DisplayPageManager(); DisplayShapeKeyEntriesMenu(SKDatabase.GlobalShapekeyDictionary()); @@ -201,6 +203,7 @@ private static void GuiWindowControls(int windowID) Main.HideInactiveMaids.Value = GUILayout.Toggle(Main.HideInactiveMaids.Value, "Hide Inactive Maids"); GUILayout.BeginVertical(Sections); + GUILayout.BeginHorizontal(Sections2); GUILayout.FlexibleSpace(); GUILayout.Label("Maids"); @@ -217,21 +220,8 @@ private static void GuiWindowControls(int windowID) if (Main.SimpleMode.Value) { GUILayout.BeginVertical(Sections); - GUILayout.BeginHorizontal(Sections2); - GUILayout.FlexibleSpace(); - if (GUILayout.Button("<<")) - { - Page = Math.Max(Page - Main.EntriesPerPage.Value, 0); - } - GUILayout.FlexibleSpace(); - GUILayout.Label($"All:{Page} ~ {Page + Main.EntriesPerPage.Value}"); - GUILayout.FlexibleSpace(); - if (GUILayout.Button(">>")) - { - Page = Math.Min(SKDatabase.AllShapekeyDictionary.Count - Main.EntriesPerPage.Value, Page + Main.EntriesPerPage.Value); - } - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); + + DisplayPageManager(); SimpleDisplayShapeKeyEntriesMenu(SKDatabase.AllShapekeyDictionary); @@ -240,21 +230,8 @@ private static void GuiWindowControls(int windowID) else { GUILayout.BeginVertical(Sections); - GUILayout.BeginHorizontal(Sections2); - GUILayout.FlexibleSpace(); - if (GUILayout.Button("<<")) - { - Page = Math.Max(Page - Main.EntriesPerPage.Value, 0); - } - GUILayout.FlexibleSpace(); - GUILayout.Label($"All:{Page} ~ {Page + Main.EntriesPerPage.Value}"); - GUILayout.FlexibleSpace(); - if (GUILayout.Button(">>")) - { - Page = Math.Min(SKDatabase.AllShapekeyDictionary.Count - Main.EntriesPerPage.Value, Page + Main.EntriesPerPage.Value); - } - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); + + DisplayPageManager(); DisplayShapeKeyEntriesMenu(SKDatabase.AllShapekeyDictionary); @@ -267,7 +244,6 @@ private static void GuiWindowControls(int windowID) GUILayout.EndScrollView(); DisplayFooter(); - ShapekeyMaster.MyGUI.Helpers.ChkMouseClick(windowRect); } @@ -275,6 +251,21 @@ private static void DisplayHeaderMenu() { GUILayout.BeginHorizontal(Sections2); + var modeLabel = entryComparer.Mode == 0 ? "Date" : entryComparer.Mode == 1 ? "Name" : "Shapekey"; + var ascendLabel = entryComparer.Ascending ? "↑" : "↓"; + + GUILayout.Label("Sort By:"); + if (GUILayout.Button(modeLabel)) + { + ++entryComparer.Mode; + } + if (GUILayout.Button(ascendLabel)) + { + entryComparer.Ascending = !entryComparer.Ascending; + } + + GUILayout.FlexibleSpace(); + if (GUILayout.Button("All")) { Page = 0; @@ -295,14 +286,22 @@ private static void DisplayHeaderMenu() DisplaySearchMenu(); } + private static void DisplaySearchMenu(bool NoModes = false) { GUILayout.BeginHorizontal(Sections2); - GUILayout.Label("Search by "); + if (OpenSKMenu != Guid.Empty) + { + FilterCommonKeys = GUILayout.Toggle(FilterCommonKeys, "Filter Common Keys"); + + HideBlacklistedKeys = GUILayout.Toggle(HideBlacklistedKeys, "Hide Blacklisted Keys"); + } GUILayout.FlexibleSpace(); + GUILayout.Label("Search by "); + if (NoModes == false) { if (FilterMode == 0) @@ -333,6 +332,47 @@ private static void DisplaySearchMenu(bool NoModes = false) GUILayout.EndHorizontal(); } + private static void DisplayPageManager(string MaidWithKey = null) + { + string headerString; + int applicantcount; + + switch (TabSelection) + { + case 1: + headerString = "Globals"; + applicantcount = SKDatabase.GlobalShapekeyDictionary().Count; + break; + + case 2: + headerString = MaidWithKey; + applicantcount = SKDatabase.ShapekeysByMaid(MaidWithKey).Count; + break; + + default: + headerString = "All"; + applicantcount = SKDatabase.AllShapekeyDictionary.Count; + break; + } + + GUILayout.BeginHorizontal(Sections2); + if (GUILayout.Button("<<")) + { + Page = Math.Max(Page - Main.EntriesPerPage.Value, 0); + } + GUILayout.FlexibleSpace(); + GUILayout.Label($"{headerString}:{Page} ~ {Page + Main.EntriesPerPage.Value}"); + GUILayout.FlexibleSpace(); + if (GUILayout.Button(">>")) + { + if (Page + Main.EntriesPerPage.Value < applicantcount) + { + Page = Page + Main.EntriesPerPage.Value; + } + } + GUILayout.EndHorizontal(); + } + private static void DisplayFooter() { GUILayout.BeginVertical(Sections2); @@ -353,7 +393,10 @@ private static void DisplayFooter() OpenRenameMenu = Guid.Empty; OpenSlotConditions = Guid.Empty; - SKDatabase.OverwriteDictionary(Main.LoadFromJson(BepInEx.Paths.ConfigPath + "\\ShapekeyMaster.json", false)); + var serDB = Main.LoadFromJson(BepInEx.Paths.ConfigPath + "\\ShapekeyMaster.json", false); + + SKDatabase.OverwriteDictionary(serDB.AllShapekeyDictionary); + SKDatabase.BlacklistedShapekeys = serDB.BlacklistedShapekeys; return; } @@ -373,7 +416,7 @@ private static void DisplayFooter() } if (GUILayout.Button("Import")) { - SKDatabase.ConcatenateDictionary(Main.LoadFromJson(null, true)); + SKDatabase.ConcatenateDictionary(Main.LoadFromJson(null, true).AllShapekeyDictionary); return; } @@ -407,7 +450,7 @@ private static void DisplayMaidOptions() } else if (FilterMode == 1) { - if (!Regex.IsMatch(MaidWithKey.ToLower(), $@".*{Filter.ToLower()}.*")) + if (MaidWithKey.Contains(Filter, StringComparison.OrdinalIgnoreCase) == false) { continue; } @@ -479,21 +522,7 @@ private static void DisplayMaidOptions() if (MaidSelection.Contains(MaidWithKey)) { - GUILayout.BeginHorizontal(Sections2); - GUILayout.FlexibleSpace(); - if (GUILayout.Button("<<")) - { - Page = Math.Max(Page - Main.EntriesPerPage.Value, 0); - } - GUILayout.FlexibleSpace(); - GUILayout.Label($"{Page} ~ {Page + Main.EntriesPerPage.Value}"); - GUILayout.FlexibleSpace(); - if (GUILayout.Button(">>")) - { - Page = Math.Min(SKDatabase.ShapekeysByMaid(MaidWithKey).Count - Main.EntriesPerPage.Value, Page + Main.EntriesPerPage.Value); - } - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); + DisplayPageManager(MaidWithKey); if (Main.SimpleMode.Value) { @@ -508,7 +537,10 @@ private static void DisplayMaidOptions() if (GUILayout.Button("+", GUILayout.Width(40))) { - SKDatabase.Add(new ShapeKeyEntry(Guid.NewGuid(), MaidWithKey)); + var id = Guid.NewGuid(); + SKDatabase.Add(new ShapeKeyEntry(id, MaidWithKey)); + + FocusToNewKey(id, SKDatabase.AllShapekeyDictionary, MaidWithKey); return; } @@ -521,7 +553,7 @@ private static void DisplayMaidOptions() GUILayout.EndVertical(); } - if (GUILayout.Button("New Maid")) + if (GUILayout.Button("New Maid Group")) { MaidNameList = HelperClasses.GetNameOfAllMaids().ToList(); @@ -533,150 +565,31 @@ private static void DisplayMaidOptions() GUILayout.EndVertical(); } - /*static bool DisplayGroups(string Maid, bool Filter = true) - { - bool CallForRefresh = true; - - GUILayout.BeginVertical(Sections); - foreach (KeyValuePair> GroupedShapekey in GroupedShapeKeys) - { - if (Filter && GroupedShapekey.Value.Where(tp => tp.Maid.Equals(Maid)).Count() == 0) - { - continue; - } - - GUILayout.BeginHorizontal(Sections); - GUILayout.Label(GroupedShapekey.Key); - - if (GUILayout.Button("I/O")) - { - bool targettoggle = !GroupedShapekey.Value.FirstOrDefault().Enabled; - - foreach (ShapeKeyEntry sk in GroupedShapekey.Value) - { - sk.Enabled = targettoggle; - } - } - - if (GUILayout.Button("Rename")) - { - GroupRenameMenu = GroupedShapekey.Key; - GroupRename = GroupedShapekey.Key; - } - - if (GUILayout.Button("Del")) - { - foreach (Guid skp in ShapeKeys.Where(kvp => kvp.Value.Group.Equals(GroupedShapekey.Key) && (kvp.Value.Maid.Equals(Maid) || Filter == false)).Select(kt => kt.Key)) - { - ShapeKeys.Remove(skp); - - return true; - } - - CallForRefresh = true; - } - - GUILayout.FlexibleSpace(); - - if (GUILayout.Button("☰")) - { - if (!GroupSelection.ContainsKey(Maid)) - { - GroupSelection[Maid] = new List(); - } - - if (!GroupSelection[Maid].Contains(GroupedShapekey.Key)) - { - GroupSelection[Maid].Add(GroupedShapekey.Key); - } - else - { - GroupSelection[Maid].Remove(GroupedShapekey.Key); - } - - CallForRefresh = true; - } - - GUILayout.EndHorizontal(); - - if (GroupSelection.Values.SelectMany(t => t).Contains(GroupedShapekey.Key) && (GroupSelection.ContainsKey(Maid) && GroupSelection[Maid].Contains(GroupedShapekey.Key)) || Filter == false) - { - var TempDic = new SortedDictionary(GroupedShapekey.Value.Where(tp => tp.Maid.Equals(Maid) || Filter == false).ToDictionary(ps => ps.Id, ps => ps)); - - if (SimpleMode) - { - SimpleDisplayShapeKeyEntriesMenu(TempDic); - } - else - { - DisplayShapeKeyEntriesMenu(TempDic); - } - - if (GUILayout.Button("+")) - { -#if (DEBUG) - Main.logger.LogDebug("I've been clicked! Oh the humanity!!"); -#endif - Guid newkey = Guid.NewGuid(); - - ShapeKeys.Add(newkey, new ShapeKeyEntry(newkey, GroupedShapekey.Key)); - - ShapeKeys[newkey].SetMaid(Maid); - - CallForRefresh = true; - } - } - } - - GUILayout.EndVertical(); - - if (GUILayout.Button("New Group")) - { -#if (DEBUG) - Main.logger.LogDebug("I've been clicked! Oh the humanity!!"); -#endif - int i = 0; - - for (i = 0; GroupedShapeKeys.Keys.Contains($"No Group {i}"); i++) ; - - Guid newkey = Guid.NewGuid(); - - ShapeKeys.Add(newkey, new ShapeKeyEntry(newkey, $"No Group {i}")); - - ShapeKeys[newkey].SetMaid(Maid); - - CallForRefresh = true; - } - - return CallForRefresh; - } - */ - private static void SimpleDisplayShapeKeyEntriesMenu(Dictionary GivenShapeKeys) { int i = 0; - foreach (ShapeKeyEntry s in GivenShapeKeys.Values.OrderBy(val => val.EntryName)) + foreach (ShapeKeyEntry s in GivenShapeKeys.Values.OrderBy(val => val, entryComparer)) { if (Filter != "") { if (FilterMode == 0) { - if (!Regex.IsMatch(s.EntryName.ToLower(), $@".*{Filter.ToLower()}.*")) + if (s.EntryName.Contains(Filter, StringComparison.OrdinalIgnoreCase) == false) { continue; } } else if (FilterMode == 1) { - if (!Regex.IsMatch(s.Maid.ToLower(), $@".*{Filter.ToLower()}.*")) + if (s.Maid.Contains(Filter, StringComparison.OrdinalIgnoreCase) == false) { continue; } } else if (FilterMode == 2) { - if (!Regex.IsMatch(s.ShapeKey.ToLower(), $@".*{Filter.ToLower()}.*")) + if (s.ShapeKey.Contains(Filter, StringComparison.OrdinalIgnoreCase) == false) { continue; } @@ -692,14 +605,15 @@ private static void SimpleDisplayShapeKeyEntriesMenu(Dictionary G int i = 0; - foreach (ShapeKeyEntry s in GivenShapeKeys.Values.OrderBy(val => val.EntryName)) + foreach (ShapeKeyEntry s in GivenShapeKeys.Values.OrderBy(val => val, entryComparer)) { if (Filter != "") { if (FilterMode == 0) { - if (!Regex.IsMatch(s.EntryName.ToLower(), $@".*{Filter.ToLower()}.*")) + if (s.EntryName.Contains(Filter, StringComparison.OrdinalIgnoreCase) == false) { continue; } } else if (FilterMode == 1) { - if (!Regex.IsMatch(s.Maid.ToLower(), $@".*{Filter.ToLower()}.*")) + if (s.Maid.Contains(Filter, StringComparison.OrdinalIgnoreCase) == false) { continue; } } else if (FilterMode == 2) { - if (!Regex.IsMatch(s.ShapeKey.ToLower(), $@".*{Filter.ToLower()}.*")) + if (s.ShapeKey.Contains(Filter, StringComparison.OrdinalIgnoreCase) == false) { continue; } @@ -829,11 +743,13 @@ private static void DisplayShapeKeyEntriesMenu(Dictionary G break; } - GUILayout.BeginVertical(Sections); + var Style = NewKeyToShine.HasValue && s.Id == NewKeyToShine ? ShineSections : Sections; + + GUILayout.BeginVertical(Style); if (s.Collapsed == false) { - GUILayout.BeginHorizontal(Sections); + GUILayout.BeginHorizontal(Style); GUILayout.Label(s.EntryName); GUILayout.FlexibleSpace(); if (GUILayout.Button("☰")) @@ -870,10 +786,12 @@ private static void DisplayShapeKeyEntriesMenu(Dictionary G ShapekeysNameList = HelperClasses.GetAllShapeKeysFromAllMaids().ToList(); } } + Filter = oldSKMenuFilter; oldPreSKMenuScrollPosition = scrollPosition; scrollPosition = oldSKMenuScrollPosition; - ShapekeysNameList.Sort(); + //ShapekeysNameList.Sort(); + return; } @@ -918,7 +836,6 @@ private static void DisplayShapeKeyEntriesMenu(Dictionary G } else if (s.Animate == false && s.AnimateWithExcitement) { - GUILayout.Label($"Max Excitement Threshold: {s.ExcitementMax}"); s.ExcitementMax = Mathf.RoundToInt(GUILayout.HorizontalSlider(s.ExcitementMax, s.ExcitementMin, 300.0F)); @@ -938,7 +855,7 @@ private static void DisplayShapeKeyEntriesMenu(Dictionary G s.Deform = (Mathf.RoundToInt(GUILayout.HorizontalSlider(s.Deform, 0, Main.MaxDeform.Value))); } - GUILayout.BeginHorizontal(Sections); + GUILayout.BeginHorizontal(Style); if (GUILayout.Button($"Open Slot Conditions Menu")) { @@ -980,14 +897,20 @@ private static void DisplayShapeKeyEntriesMenu(Dictionary G } //From here on down are submenus.... - private static void DisplayShapeKeySelectMenu(ShapeKeyEntry s) { - DisplaySearchMenu(true); + GUILayout.BeginHorizontal(); + GUILayout.Label($"{s.EntryName} Select ShapeKey"); + GUILayout.FlexibleSpace(); + + GUILayout.Label($"R-Click To Blacklist!"); + + GUILayout.EndHorizontal(); + if (GUILayout.Button("None")) { OpenSKMenu = Guid.Empty; @@ -999,65 +922,120 @@ private static void DisplayShapeKeySelectMenu(ShapeKeyEntry s) Filter = ""; } - GUILayout.BeginVertical(Sections); - GUILayout.BeginHorizontal(Sections2); - GUILayout.FlexibleSpace(); - GUILayout.Label("Body Keys"); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); + int columns = 0; + int totalGroupsWorked = 0; + + var groupedKeys = ShapekeysNameList + .GroupBy(r => r.First) + .OrderBy(r => r.Key); + + var bodyKeys = groupedKeys + .Where(r => r.Key.Equals("body")) + .SelectMany(r => r) + .Select(t => t.Second) + .ToList(); - foreach (string str in ShapekeysNameList.Where(key => !HelperClasses.IsFaceKey(key))) + var headKeys = groupedKeys + .Where(r => r.Key.Equals("head")) + .SelectMany(r => r) + .Select(t => t.Second) + .ToList(); + + foreach (var group in groupedKeys) { - if (Filter != "") + totalGroupsWorked++; + + var filteredList = group.ToList(); + + if (FilterCommonKeys) { - if (!Regex.IsMatch(str.ToLower(), $@".*{Filter.ToLower()}.*")) + if (group.Key.Equals("body") == false) { - continue; + filteredList = filteredList.Where(t => !bodyKeys.Contains(t.Second)).ToList(); + } + + if (group.Key.Equals("head") == false) + { + filteredList = filteredList.Where(t => !headKeys.Contains(t.Second)).ToList(); } } - if (GUILayout.Button(str)) + if (HideBlacklistedKeys) { - OpenSKMenu = Guid.Empty; - s.ShapeKey = str; - oldSKMenuFilter = Filter; - oldSKMenuScrollPosition = scrollPosition; - scrollPosition = oldPreSKMenuScrollPosition; - Filter = ""; + filteredList = filteredList.Where(t => SKDatabase.BlacklistedShapekeys.IsBlacklisted(t.Second) == false).ToList(); } - } - GUILayout.EndVertical(); + if (filteredList.Count > 0) + { + if (columns++ == 0) + { + //Columnar ordering + GUILayout.BeginHorizontal(); + } - GUILayout.BeginVertical(Sections); - GUILayout.BeginHorizontal(Sections2); - GUILayout.FlexibleSpace(); - GUILayout.Label("Face Keys"); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); + //Category vertical + GUILayout.BeginVertical(Sections); - foreach (string str in ShapekeysNameList.Where(key => HelperClasses.IsFaceKey(key))) - { - if (Filter != "") - { - if (!Regex.IsMatch(str.ToLower(), $@".*{Filter.ToLower()}.*")) + //Header for category + GUILayout.BeginHorizontal(Sections2); + GUILayout.FlexibleSpace(); + GUILayout.Label($"{group.Key}"); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + foreach (var str in filteredList.OrderBy(r => r.Second)) { - continue; + if (Filter != "") + { + if (str.Second.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)) + { + /* + if (LastMouseButtonUp == 2) + { + ShapekeyUpdate.PreviewKey(str.Second); + } + */ + if (LastMouseButtonUp == 1) + { + if (SKDatabase.BlacklistedShapekeys.IsBlacklisted(str.Second) == false) + { + SKDatabase.BlacklistedShapekeys.AddItem(str.Second); + } + else + { + SKDatabase.BlacklistedShapekeys.RemoveItem(str.Second); + } + } + else if (LastMouseButtonUp == 0) + { + OpenSKMenu = Guid.Empty; + s.ShapeKey = str.Second; + oldSKMenuFilter = Filter; + oldSKMenuScrollPosition = scrollPosition; + scrollPosition = oldPreSKMenuScrollPosition; + Filter = ""; + } + } } + + GUILayout.EndVertical(); } - if (GUILayout.Button(str)) + if (columns == 3 || totalGroupsWorked == groupedKeys.Count() && columns > 0) { - OpenSKMenu = Guid.Empty; - s.ShapeKey = str; - oldSKMenuFilter = Filter; - oldSKMenuScrollPosition = scrollPosition; - scrollPosition = oldPreSKMenuScrollPosition; - Filter = ""; + GUILayout.EndHorizontal(); + columns = 0; } } - GUILayout.EndHorizontal(); } + private static void DisplayMaidSelectMenu(ShapeKeyEntry s) { DisplaySearchMenu(true); @@ -1086,7 +1064,7 @@ private static void DisplayMaidSelectMenu(ShapeKeyEntry s) { if (Filter != "") { - if (!Regex.IsMatch(mn.ToLower(), $@".*{Filter.ToLower()}.*")) + if (mn.Contains(Filter, StringComparison.OrdinalIgnoreCase) == false) { continue; } @@ -1100,6 +1078,7 @@ private static void DisplayMaidSelectMenu(ShapeKeyEntry s) } } } + private static void DisplayMaidGroupCreateMenu(Dictionary GivenShapeKeys) { DisplaySearchMenu(true); @@ -1127,7 +1106,7 @@ private static void DisplayMaidGroupCreateMenu(Dictionary G { if (Filter != "") { - if (!Regex.IsMatch(mn.ToLower(), $@".*{Filter.ToLower()}.*")) + if (mn.Contains(Filter, StringComparison.OrdinalIgnoreCase) == false) { continue; } @@ -1147,6 +1126,7 @@ private static void DisplayMaidGroupCreateMenu(Dictionary G } } } + private static void DisplayRenameMenu(ShapeKeyEntry s) { GUILayout.Label($"Now renaming {s.EntryName}"); @@ -1158,6 +1138,7 @@ private static void DisplayRenameMenu(ShapeKeyEntry s) OpenRenameMenu = Guid.Empty; } } + private static void DisplaySlotConditionsMenu(ShapeKeyEntry s) { GUILayout.BeginVertical(Sections); @@ -1170,6 +1151,8 @@ private static void DisplaySlotConditionsMenu(ShapeKeyEntry s) s.ConditionalsToggle = GUILayout.Toggle(s.ConditionalsToggle, "Enable Conditionals"); + s.IgnoreCategoriesWithShapekey = GUILayout.Toggle(s.IgnoreCategoriesWithShapekey, "Ignore Categories With Shapekey"); + if (s.DisableWhen) { s.DisableWhen = GUILayout.Toggle(s.DisableWhen, "Set Shapekey if"); @@ -1205,7 +1188,6 @@ private static void DisplaySlotConditionsMenu(ShapeKeyEntry s) foreach (DisableWhenEquipped slot in Enum.GetValues(typeof(DisableWhenEquipped)).Cast()) { - if (i == 0) { GUILayout.BeginHorizontal(); @@ -1261,7 +1243,6 @@ private static void DisplaySlotConditionsMenu(ShapeKeyEntry s) s.MenuFileConditionals[menu] = GUILayout.TextField(s.MenuFileConditionals[menu]); GUILayout.EndHorizontal(); - } GUILayout.EndScrollView(); @@ -1278,6 +1259,7 @@ private static void DisplaySlotConditionsMenu(ShapeKeyEntry s) OpenSlotConditions = Guid.Empty; } } + private static void DisplayMaidRenameMenu(string s) { DisplaySearchMenu(true); @@ -1309,7 +1291,7 @@ private static void DisplayMaidRenameMenu(string s) { if (Filter != "") { - if (!Regex.IsMatch(mn.ToLower(), $@".*{Filter.ToLower()}.*")) + if (mn.Contains(Filter, StringComparison.OrdinalIgnoreCase) == false) { continue; } @@ -1331,6 +1313,7 @@ private static void DisplayMaidRenameMenu(string s) } } } + private static void DisplayExportMenu() { Main.HideInactiveMaids.Value = GUILayout.Toggle(Main.HideInactiveMaids.Value, "Hide Inactive Maids"); @@ -1395,11 +1378,14 @@ private static void DisplayExportMenu() } //UI Helper funcs - internal static void FocusToNewKey(Guid guid, Dictionary GivenShapeKeys) + internal static void FocusToNewKey(Guid guid, Dictionary GivenShapeKeys, string maid = null) { + NewKeyToShine = guid; + TimeToKillNewKeyShine = DateTime.Now.AddSeconds(3); + double pos = 0; - foreach (ShapeKeyEntry s in GivenShapeKeys.Values.OrderBy(val => val.EntryName)) + foreach (ShapeKeyEntry s in GivenShapeKeys.Values.Where(r => maid.IsNullOrWhiteSpace() || r.Maid.Equals(maid)).OrderBy(val => val, entryComparer)) { if (s.Id != guid) { @@ -1407,7 +1393,7 @@ internal static void FocusToNewKey(Guid guid, Dictionary Gi } else { - Page = ((int)Math.Floor(pos / 10)) * 10; + Page = ((int)Math.Floor(pos / Main.EntriesPerPage.Value)) * Main.EntriesPerPage.Value; } } } diff --git a/YotogiShapekeys/Properties/AssemblyInfo.cs b/YotogiShapekeys/Properties/AssemblyInfo.cs index a561db0..0c0ab4f 100644 --- a/YotogiShapekeys/Properties/AssemblyInfo.cs +++ b/YotogiShapekeys/Properties/AssemblyInfo.cs @@ -32,4 +32,4 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/YotogiShapekeys/SMEventsAndArgs.cs b/YotogiShapekeys/SMEventsAndArgs.cs index d65fe30..84d732f 100644 --- a/YotogiShapekeys/SMEventsAndArgs.cs +++ b/YotogiShapekeys/SMEventsAndArgs.cs @@ -1,11 +1,8 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace ShapekeyMaster { - class SMEventsAndArgs + internal class SMEventsAndArgs { //Cleaner for instancing. public class MorphEventArgs : EventArgs @@ -31,6 +28,7 @@ public ExcitementChangeEvent(string maid, int excite) Excitement = excite; } } + public class ClothingMaskChangeEvent : EventArgs { public string Maid { get; private set; } @@ -41,4 +39,4 @@ public ClothingMaskChangeEvent(string maid) } } } -} +} \ No newline at end of file diff --git a/YotogiShapekeys/ShapeKeyEntry.cs b/YotogiShapekeys/ShapeKeyEntry.cs index c61c1a8..d21aa5f 100644 --- a/YotogiShapekeys/ShapeKeyEntry.cs +++ b/YotogiShapekeys/ShapeKeyEntry.cs @@ -2,7 +2,6 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; -using UnityEngine.SceneManagement; namespace ShapekeyMaster { @@ -11,8 +10,10 @@ internal class ShapeKeyEntry private IEnumerator Animator; public Guid Id { get; set; } public string EntryName { get; set; } + public DateTime CreationDate { get; set; } private bool enabled; + public bool Enabled { set @@ -41,6 +42,7 @@ public bool Enabled } private bool animateWithExcitement; + public bool AnimateWithExcitement { set @@ -59,14 +61,15 @@ public bool AnimateWithExcitement } else { - HarmonyPatchers.ExcitementChange -= (s, e) => instance.RunUpdate(null, true); } } } get => animateWithExcitement; } + private float excitementMax; + public float ExcitementMax { get => excitementMax; @@ -79,7 +82,9 @@ public float ExcitementMax } } } + private float excitementMin; + public float ExcitementMin { get => excitementMin; @@ -93,7 +98,9 @@ public float ExcitementMin } } } + private bool animateWithOrgasm; + public bool AnimateWithOrgasm { get => false; @@ -106,7 +113,9 @@ public bool AnimateWithOrgasm } } } + private bool animate; + public bool Animate { set @@ -128,7 +137,9 @@ public bool Animate } get => animate; } + private string animationRate; + public string AnimationRate { get @@ -145,6 +156,7 @@ public string AnimationRate animationRate = value.ToString(); } } + public float AnimationRateFloat { get @@ -161,7 +173,9 @@ public float AnimationRateFloat animationRate = value.ToString(); } } + private string animationPoll; + public string AnimationPoll { get => animationPoll; @@ -170,6 +184,7 @@ public string AnimationPoll animationPoll = value; } } + public float AnimationPollFloat { get @@ -186,7 +201,9 @@ public float AnimationPollFloat animationPoll = value.ToString(); } } + private float animationMaximum; + public float AnimationMaximum { get => animationMaximum; @@ -195,7 +212,9 @@ public float AnimationMaximum animationMaximum = value; } } + private float animationMinimum; + public float AnimationMinimum { get => animationMinimum; @@ -204,7 +223,9 @@ public float AnimationMinimum animationMinimum = value; } } + private float deform; + public float Deform { get => deform; @@ -217,7 +238,9 @@ public float Deform } } } + private float disableddeform; + public float DisabledDeform { get => disableddeform; @@ -230,7 +253,9 @@ public float DisabledDeform } } } + private float deformMax; + public float DeformMax { get => deformMax; @@ -243,7 +268,9 @@ public float DeformMax } } } + private float deformMin; + public float DeformMin { get => deformMin; @@ -254,11 +281,11 @@ public float DeformMin deformMin = value; RunUpdate(); } - } } private string shapeKey; + public string ShapeKey { get => shapeKey; @@ -272,7 +299,9 @@ public string ShapeKey } } } + private string maid; + public string Maid { get => maid; @@ -287,8 +316,8 @@ public string Maid } } - private bool conditionalsToggle; + public bool ConditionalsToggle { get => conditionalsToggle; @@ -312,7 +341,24 @@ public bool ConditionalsToggle } } } + + private bool ignoreCategoriesWithShapekey; + + public bool IgnoreCategoriesWithShapekey + { + get => ignoreCategoriesWithShapekey; + set + { + if (value != ignoreCategoriesWithShapekey) + { + ignoreCategoriesWithShapekey = value; + RunUpdate(); + } + } + } + private bool disableWhen; + public bool DisableWhen { get => disableWhen; @@ -325,7 +371,9 @@ public bool DisableWhen } } } + private bool whenAll; + public bool WhenAll { get => whenAll; @@ -338,7 +386,9 @@ public bool WhenAll } } } + private DisableWhenEquipped slotFlags; + public DisableWhenEquipped SlotFlags { get => slotFlags; @@ -351,14 +401,17 @@ public DisableWhenEquipped SlotFlags } } } + public Dictionary MenuFileConditionals { get; set; } public bool Collapsed { get; set; } private readonly bool constructordone; + public ShapeKeyEntry(Guid id, string maid = "") { this.Id = id; EntryName = ""; + CreationDate = DateTime.Now; enabled = true; deform = 0; shapeKey = ""; @@ -393,6 +446,7 @@ public ShapeKeyEntry(Guid id, string maid = "") //Main.@this.StartCoroutine(Animator); } + private void RunUpdate(string maid = null, bool avoidWait = false) { #if (DEBUG) @@ -418,6 +472,7 @@ private void RunUpdate(string maid = null, bool avoidWait = false) #endif } } + private static IEnumerator AnimateCoRoute(ShapeKeyEntry key) { bool reverse = false; @@ -458,7 +513,7 @@ private static IEnumerator AnimateCoRoute(ShapeKeyEntry key) } #if (DEBUG) - Main.logger.LogDebug($"Changed deform value for shapekey entry {EntryName}"); + Main.logger.LogDebug($"Changed deform value for shapekey entry {key.EntryName}"); #endif ShapekeyUpdate.UpdateKeys(key, true); @@ -486,4 +541,4 @@ private static IEnumerator AnimateCoRoute(ShapeKeyEntry key) } } } -} +} \ No newline at end of file diff --git a/YotogiShapekeys/ShapekeyBlacklist.cs b/YotogiShapekeys/ShapekeyBlacklist.cs new file mode 100644 index 0000000..40caa30 --- /dev/null +++ b/YotogiShapekeys/ShapekeyBlacklist.cs @@ -0,0 +1,135 @@ +using Newtonsoft.Json; +using System.Collections.Generic; + +namespace ShapekeyMaster +{ + public class ShapekeyBlacklist + { + [JsonProperty] + public List Blacklist { get; private set; } = 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" + }; + + public void RemoveItem(string keyToUnlist) + { + Blacklist.Remove(keyToUnlist); + } + + public void AddItem(string keyToBlackList) + { + Blacklist.Add(keyToBlackList); + } + + public bool IsBlacklisted(string keyToCheck) + { + return Blacklist.Contains(keyToCheck); + } + } +} \ No newline at end of file diff --git a/YotogiShapekeys/ShapekeyDatabase.cs b/YotogiShapekeys/ShapekeyDatabase.cs index 92c8d82..8d1828e 100644 --- a/YotogiShapekeys/ShapekeyDatabase.cs +++ b/YotogiShapekeys/ShapekeyDatabase.cs @@ -1,29 +1,40 @@ -using System; +using Newtonsoft.Json; +using System; using System.Collections; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using UnityEngine; namespace ShapekeyMaster { - class ShapekeyDatabase + internal class ShapekeyDatabase { + [JsonIgnore] private Dictionary allShapekeyDictionary; + + [JsonIgnore] private Dictionary> maidShapekeyDictionary; + + [JsonIgnore] private Dictionary globalShapekeyDictionary; + + [JsonProperty] + public ShapekeyBlacklist BlacklistedShapekeys { get; internal set; } = new ShapekeyBlacklist(); + //These below handle morph specifics. They're important because they shorthand alot of the work involved tremendously. + [JsonIgnore] private List ListOfActiveMorphs = ShapekeyUpdate.ListOfActiveMorphs; + + [JsonIgnore] private Dictionary> morphShapekeyDictionary; - public Dictionary AllShapekeyDictionary + [JsonProperty] + public Dictionary AllShapekeyDictionary { - get + get { return allShapekeyDictionary; } - set + set { allShapekeyDictionary = value; RefreshSubDictionaries(); @@ -34,22 +45,26 @@ internal Dictionary GlobalShapekeyDictionary() { return globalShapekeyDictionary; } + internal Dictionary> MorphShapekeyDictionary() { return morphShapekeyDictionary; } - internal List ListOfMaidsWithKeys() + + internal List ListOfMaidsWithKeys() { return maidShapekeyDictionary.Keys.ToList(); } - internal ShapekeyDatabase() + + internal ShapekeyDatabase() { allShapekeyDictionary = new Dictionary(); morphShapekeyDictionary = new Dictionary>(); - HarmonyPatchers.MorphEvent += (s ,e) => Main.@this.StartCoroutine(UpdateMorphDic(e)); + HarmonyPatchers.MorphEvent += (s, e) => Main.@this.StartCoroutine(UpdateMorphDic(e)); RefreshSubDictionaries(); } + internal void RefreshSubDictionaries() { maidShapekeyDictionary = new Dictionary>(); @@ -73,7 +88,7 @@ internal void RefreshSubDictionaries() globalShapekeyDictionary = allShapekeyDictionary.Where(kv => String.IsNullOrEmpty(kv.Value.Maid)).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); - if (ListOfActiveMorphs.Count > 0) + if (ListOfActiveMorphs.Count > 0) { Main.@this.StartCoroutine(ReloadMorphDic()); } @@ -172,21 +187,28 @@ internal IEnumerator UpdateMorphDic(EventArgs args) internal bool DoesMaidPartialEntryName(string Maid, string Entry) { - return (maidShapekeyDictionary[Maid].Where(t => Regex.IsMatch(t.EntryName.ToLower(), $@".*{Entry.ToLower()}.*")).Count() > 0); + return maidShapekeyDictionary[Maid] + .Where(t => t.EntryName.Contains(Entry, StringComparison.OrdinalIgnoreCase)) + .Count() > 0; } + internal bool DoesMaidPartialShapekey(string Maid, string shapekey) { - return maidShapekeyDictionary[Maid].Where(t => Regex.IsMatch(t.ShapeKey.ToLower(), $@".*{shapekey.ToLower()}.*")).Count() > 0; + return maidShapekeyDictionary[Maid] + .Where(t => t.ShapeKey.Contains(shapekey, StringComparison.OrdinalIgnoreCase)) + .Count() > 0; } + internal Dictionary ShapekeysByMaid(string Maid) { - if (!maidShapekeyDictionary.ContainsKey(Maid)) + if (!maidShapekeyDictionary.ContainsKey(Maid)) { return new Dictionary(); } return new Dictionary(maidShapekeyDictionary[Maid].ToDictionary(sk => sk.Id, sk => sk)); } + internal HashSet ShapekeysByMorph(TMorph morph) { if (!morphShapekeyDictionary.ContainsKey(morph)) @@ -196,19 +218,22 @@ internal HashSet ShapekeysByMorph(TMorph morph) return morphShapekeyDictionary[morph]; } + internal void Add(ShapeKeyEntry newVal) { allShapekeyDictionary[newVal.Id] = newVal; RefreshSubDictionaries(); } + internal void Remove(ShapeKeyEntry newVal) { allShapekeyDictionary.Remove(newVal.Id); RefreshSubDictionaries(); } + internal void ConcatenateDictionary(Dictionary newDictionary, bool overwrite = false) { - if (!overwrite) + if (!overwrite) { allShapekeyDictionary = new Dictionary( allShapekeyDictionary @@ -217,7 +242,8 @@ internal void ConcatenateDictionary(Dictionary newDictionar .Where(kv => !allShapekeyDictionary.ContainsKey(kv.Key)) ) .ToDictionary(kvp => kvp.Key, kvp => kvp.Value)); - } else + } + else { allShapekeyDictionary = new Dictionary( newDictionary @@ -229,6 +255,7 @@ internal void ConcatenateDictionary(Dictionary newDictionar RefreshSubDictionaries(); } + internal void OverwriteDictionary(Dictionary newDictionary) { allShapekeyDictionary = newDictionary; diff --git a/YotogiShapekeys/ShapekeyMaster.csproj b/YotogiShapekeys/ShapekeyMaster.csproj index 4497e2b..3bbd5a9 100644 --- a/YotogiShapekeys/ShapekeyMaster.csproj +++ b/YotogiShapekeys/ShapekeyMaster.csproj @@ -36,6 +36,7 @@ OnBuildSuccess + @@ -58,23 +59,23 @@ - - ..\packages\HarmonyX.2.5.7\lib\net35\0Harmony.dll + + ..\packages\HarmonyX.2.10.1\lib\net35\0Harmony.dll - ..\packages\COM3D2.GameLibs.2.8.0-r.0\lib\net35\Assembly-CSharp.dll + ..\packages\COM3D2.GameLibs.2.24.0-r.1\lib\net35\Assembly-CSharp.dll - ..\packages\COM3D2.GameLibs.2.8.0-r.0\lib\net35\Assembly-CSharp-firstpass.dll + ..\packages\COM3D2.GameLibs.2.24.0-r.1\lib\net35\Assembly-CSharp-firstpass.dll - - ..\packages\BepInEx.BaseLib.5.4.16\lib\net35\BepInEx.dll + + ..\packages\BepInEx.BaseLib.5.4.21\lib\net35\BepInEx.dll ..\..\..\..\Desktop\Game Related Files\Meido Related Stuff\Meido Assemblies\COM Assemblies\Resources\COM3D2.API.dll - ..\packages\Newtonsoft.Json.13.0.1\lib\net35\Newtonsoft.Json.dll + ..\packages\Newtonsoft.Json.13.0.2\lib\net35\Newtonsoft.Json.dll @@ -82,7 +83,7 @@ ..\packages\UnityEngine.5.6.1\lib\net35\UnityEngine.dll - ..\packages\COM3D2.GameLibs.2.8.0-r.0\lib\net35\UnityEngine.UI.dll + ..\packages\COM3D2.GameLibs.2.24.0-r.1\lib\net35\UnityEngine.UI.dll diff --git a/YotogiShapekeys/ShapekeyUpdate.cs b/YotogiShapekeys/ShapekeyUpdate.cs index 41bddea..3c4ce2a 100644 --- a/YotogiShapekeys/ShapekeyUpdate.cs +++ b/YotogiShapekeys/ShapekeyUpdate.cs @@ -1,62 +1,101 @@ -using System; +using BepInEx; +using System; using System.Collections; using System.Collections.Generic; using System.Linq; -using System.Text; using UnityEngine; namespace ShapekeyMaster { - class ShapekeyUpdate + internal class ShapekeyUpdate { + + /* + internal static string ShapekeyToPreview; + internal static float PreviewValToSet { get; private set; } + private static DateTime? TimeToViewKey = null; + */ + internal static List ListOfActiveMorphs = new List(); + private static readonly Dictionary CoroutinesUpdatingMaid = new Dictionary(); + private static readonly Dictionary CoroutinesUpdatingMorph = new Dictionary(); private static IEnumerator UpdateAllCo; - private static IEnumerator UpdateSingleCo; - private static IEnumerator UpdateMorphCo; - internal static void UpdateKeys(bool avoidwait = false) + private static IEnumerator PreviewKeyCo; + + internal static void UpdateKeys(bool avoidwait = false) { if (UpdateAllCo != null) { Main.@this.StopCoroutine(UpdateAllCo); UpdateAllCo = null; } - if (UpdateSingleCo != null) + foreach (var kp in CoroutinesUpdatingMaid) { - Main.@this.StopCoroutine(UpdateSingleCo); - UpdateSingleCo = null; + Main.@this.StopCoroutine(kp.Value); } - if (UpdateMorphCo != null) + CoroutinesUpdatingMaid.Clear(); + + foreach (var kp in CoroutinesUpdatingMorph) { - Main.@this.StopCoroutine(UpdateMorphCo); - UpdateMorphCo = null; + Main.@this.StopCoroutine(kp.Value); } + CoroutinesUpdatingMorph.Clear(); UpdateAllCo = UpdateAll(avoidwait); Main.@this.StartCoroutine(UpdateAllCo); } - internal static void UpdateKeys(string maid, bool avoidwait = false) + + /* + internal static void PreviewKey(string key) + { + TimeToViewKey = DateTime.Now.AddSeconds(6); + ShapekeyToPreview = key; + PreviewValToSet = 0; + + if (!string.IsNullOrEmpty(key)) + { + if (PreviewKeyCo == null) + { + //Main.logger.LogMessage("Preview isn't running. Starting..."); + + PreviewKeyCo = PreviewKey(); + Main.@this.StartCoroutine(PreviewKeyCo); + } + } + } + */ + + internal static void UpdateKeys(string maid, bool avoidwait = false) { if (!string.IsNullOrEmpty(maid)) { - if (UpdateSingleCo != null) + if (CoroutinesUpdatingMaid.TryGetValue(maid, out var coroute) && coroute != null) { - Main.@this.StopCoroutine(UpdateSingleCo); + Main.@this.StopCoroutine(coroute); } - UpdateSingleCo = UpdateMaid(maid, avoidwait); - Main.@this.StartCoroutine(UpdateSingleCo); + CoroutinesUpdatingMaid[maid] = UpdateMaid(maid, avoidwait); + Main.@this.StartCoroutine(CoroutinesUpdatingMaid[maid]); } } + internal static void UpdateKeys(ShapeKeyEntry shapeKeyEntry, bool avoidwait = false) { if (shapeKeyEntry != null) { - Main.@this.StartCoroutine(UpdateMorph(shapeKeyEntry, avoidwait)); + if (CoroutinesUpdatingMorph.TryGetValue(shapeKeyEntry, out var coroute) && coroute != null) + { + Main.@this.StopCoroutine(coroute); + } + + CoroutinesUpdatingMorph[shapeKeyEntry] = UpdateMorph(shapeKeyEntry, avoidwait); + Main.@this.StartCoroutine(CoroutinesUpdatingMorph[shapeKeyEntry]); } } - private static IEnumerator UpdateAll(bool avoidwait = false) + + private static IEnumerator UpdateAll(bool avoidwait = false) { if (!avoidwait) { @@ -73,23 +112,27 @@ private static IEnumerator UpdateAll(bool avoidwait = false) morph.FixBlendValues_Face(); } } - catch - { - + catch + { } }); } + //Setters, loaders, etc,. - private static IEnumerator UpdateMaid(string Maid, bool avoidwait = false) + private static IEnumerator UpdateMaid(string maid, bool avoidwait = false) { - if (!avoidwait) { + if (!avoidwait) + { yield return new WaitForSeconds(0.10f); } try { - - UI.SKDatabase.MorphShapekeyDictionary().Keys.Where(m => m.bodyskin.body.maid.status.fullNameJpStyle.Equals(Maid)).ToList().ForEach(morph => + UI.SKDatabase.MorphShapekeyDictionary() + .Keys + .Where(m => m.bodyskin.body.maid.status.fullNameJpStyle.Equals(maid)) + .ToList() + .ForEach(morph => { morph.FixBlendValues(); @@ -102,15 +145,15 @@ private static IEnumerator UpdateMaid(string Maid, bool avoidwait = false) } catch { - } }); } - catch - { + catch + { //Sometimes a maid has a nullref somewhere in that recursive line of checking. Just catch the error and discard the operation if so... } } + private static IEnumerator UpdateMorph(ShapeKeyEntry shapeKeyEntry, bool avoidwait = false) { if (!avoidwait) @@ -131,9 +174,87 @@ private static IEnumerator UpdateMorph(ShapeKeyEntry shapeKeyEntry, bool avoidwa } catch { - } }); } + + /* + private static IEnumerator PreviewKey() + { + //Main.logger.LogMessage("Preview is starting!"); + + int ResetCount = 0; + + while (true) + { + if (ShapekeyToPreview.IsNullOrWhiteSpace() == false) + { + ResetCount = 0; + var keysToKick = ListOfActiveMorphs.Where(r => r.ContainsShapekey(ShapekeyToPreview)); + + foreach (var morph in keysToKick) + { + morph.FixBlendValues(); + + try + { + if (morph == morph.bodyskin.body.Face.morph) + { + morph.FixBlendValues_Face(); + } + } + catch + { + } + } + + if(TimeToViewKey.HasValue && TimeToViewKey < DateTime.Now) + { + PreviewValToSet = 0; + + ShapekeyToPreview = null; + TimeToViewKey = null; + + foreach (var morph in keysToKick) + { + morph.FixBlendValues(); + + try + { + if (morph == morph.bodyskin.body.Face.morph) + { + morph.FixBlendValues_Face(); + } + } + catch + { + } + } + } + else if (PreviewValToSet >= 100) + { + PreviewValToSet = 0; + } + else + { + PreviewValToSet += 33; + } + } + else + { + ResetCount++; + } + + if (ResetCount > 5) + { + //Main.logger.LogMessage("Preview is done!"); + PreviewKeyCo = null; + yield break; + } + + yield return new WaitForSecondsRealtime(0.5f); + } + } + */ } -} +} \ No newline at end of file diff --git a/YotogiShapekeys/SlotsFlags.cs b/YotogiShapekeys/SlotsFlags.cs index 672c138..b813ad4 100644 --- a/YotogiShapekeys/SlotsFlags.cs +++ b/YotogiShapekeys/SlotsFlags.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Text.RegularExpressions; namespace ShapekeyMaster { @@ -63,8 +61,15 @@ internal static bool CheckIfSlotDisableApplies(ShapeKeyEntry entry, Maid maid) #endif //If a maid has any clothing item of a type unequipped, we return false to disable. - if (entry.SlotFlags.HasFlag(slot) && !maid.body0.GetMask(SlotToSlotList[slot]) && maid.body0.GetSlotLoaded(SlotToSlotList[slot])) + if (entry.SlotFlags.HasFlag(slot) + && !maid.body0.GetMask(SlotToSlotList[slot]) + && maid.body0.GetSlotLoaded(SlotToSlotList[slot])) { + if (entry.IgnoreCategoriesWithShapekey && maid.DoesCategoryContainKey(SlotToSlotList[slot], entry.ShapeKey)) + { + continue; + } + return entry.DisableWhen; } } @@ -76,7 +81,10 @@ internal static bool CheckIfSlotDisableApplies(ShapeKeyEntry entry, Maid maid) #if (DEBUG) Main.logger.LogDebug($"Checking {menu}"); #endif - var TBodySkins = HelperClasses.FetchGoSlot(maid.body0).Select(tbody => tbody).Where(str => str.m_mp != null && Regex.IsMatch(str.m_mp.strFileName.ToLower(), menu, RegexOptions.IgnoreCase)); + var TBodySkins = HelperClasses + .FetchGoSlot(maid.body0) + .Select(tbody => tbody) + .Where(str => str.m_mp != null && str.m_mp.strFileName.Contains(menu, StringComparison.OrdinalIgnoreCase)); if (TBodySkins.Count() == 0) { @@ -107,7 +115,10 @@ internal static bool CheckIfSlotDisableApplies(ShapeKeyEntry entry, Maid maid) Main.logger.LogDebug($"Checking {slot}"); #endif //If a maid has any clothing item of a type equipped, we return true to disable. - if (entry.SlotFlags.HasFlag(slot) && maid.body0.GetMask(SlotToSlotList[slot]) && maid.body0.GetSlotLoaded(SlotToSlotList[slot])) + if (entry.SlotFlags.HasFlag(slot) + && maid.body0.GetMask(SlotToSlotList[slot]) + && maid.body0.GetSlotLoaded(SlotToSlotList[slot]) + && (entry.IgnoreCategoriesWithShapekey == false || maid.DoesCategoryContainKey(SlotToSlotList[slot], entry.ShapeKey) == false)) { return !entry.DisableWhen; } @@ -118,8 +129,10 @@ internal static bool CheckIfSlotDisableApplies(ShapeKeyEntry entry, Maid maid) #if (DEBUG) Main.logger.LogDebug($"Checking {menu}"); #endif - - var TBodySkins = HelperClasses.FetchGoSlot(maid.body0).Select(tbody => tbody).Where(str => str.m_mp != null && Regex.IsMatch(str.m_mp.strFileName.ToLower(), menu, RegexOptions.IgnoreCase)); + var TBodySkins = HelperClasses + .FetchGoSlot(maid.body0) + .Select(tbody => tbody) + .Where(str => str.m_mp != null && str.m_mp.strFileName.Contains(menu, StringComparison.OrdinalIgnoreCase)); foreach (TBodySkin skin in TBodySkins) { @@ -134,4 +147,4 @@ internal static bool CheckIfSlotDisableApplies(ShapeKeyEntry entry, Maid maid) } } } -} +} \ No newline at end of file diff --git a/YotogiShapekeys/packages.config b/YotogiShapekeys/packages.config index 693956a..2343511 100644 --- a/YotogiShapekeys/packages.config +++ b/YotogiShapekeys/packages.config @@ -1,8 +1,8 @@  - - - - + + + + \ No newline at end of file