From a5b17e3147b6533ddf2fb11cfecc9a06be9fcbe7 Mon Sep 17 00:00:00 2001 From: Californium-251 Date: Wed, 6 Nov 2024 01:20:35 -0800 Subject: [PATCH 1/3] Made armor set calculations run on separate thread --- ItemCatalogueUI.cs | 15 +++++-- UIElements/UIArmorSetCatalogueItemSlot.cs | 55 ++++++++++++++++++----- 2 files changed, 54 insertions(+), 16 deletions(-) diff --git a/ItemCatalogueUI.cs b/ItemCatalogueUI.cs index 1ab555b..6797e46 100644 --- a/ItemCatalogueUI.cs +++ b/ItemCatalogueUI.cs @@ -11,6 +11,7 @@ using Terraria.ID; using Terraria.ModLoader; using Terraria.UI; +using System.Threading.Tasks; namespace RecipeBrowser { @@ -243,7 +244,7 @@ private void ValidateItemDescription() updateNeeded = true; } - internal void Update() + internal async void Update() { // TODO: investigate why this Update is slower than RecipeCatalogueUI @@ -296,9 +297,15 @@ internal void Update() List slotsToUse = itemSlots; if (SharedUI.instance.SelectedCategory.name == ArmorSetFeatureHelper.ArmorSetsHoverTest) { - if (ArmorSetFeatureHelper.armorSetSlots == null) - ArmorSetFeatureHelper.CalculateArmorSets(); - slotsToUse = ArmorSetFeatureHelper.armorSetSlots.Cast().ToList(); + if (ArmorSetFeatureHelper.hasCalculated == false && ArmorSetFeatureHelper.hasStarted != true) + await Task.Run(() => ArmorSetFeatureHelper.CalculateArmorSets()); //TODO: make this run on a separate thread + if (ArmorSetFeatureHelper.hasCalculated && ArmorSetFeatureHelper.armorSetSlotsMutex.WaitOne(10)) + { + slotsToUse = ArmorSetFeatureHelper.armorSetSlots.Cast().ToList(); + ArmorSetFeatureHelper.armorSetSlotsMutex.ReleaseMutex(); + } + else + slotsToUse = new List(); //empty ArmorSetFeatureHelper.AppendSpecialUI(itemGrid); } diff --git a/UIElements/UIArmorSetCatalogueItemSlot.cs b/UIElements/UIArmorSetCatalogueItemSlot.cs index 6578a61..e30fae4 100644 --- a/UIElements/UIArmorSetCatalogueItemSlot.cs +++ b/UIElements/UIArmorSetCatalogueItemSlot.cs @@ -7,6 +7,8 @@ using Terraria.ModLoader; using Terraria.ModLoader.UI; using Terraria.UI; +using Terraria.ID; +using System.Threading; namespace RecipeBrowser.UIElements { @@ -76,7 +78,7 @@ public override void Update(GameTime gameTime) { this.Height.Set(defaultBackgroundTexture.Height() * 4.6f * scale, 0f); // 50 heigh else this.Height.Set(defaultBackgroundTexture.Height() * 1.6f * scale, 0f); - + needsUpdate = false; } @@ -197,11 +199,20 @@ internal static class ArmorSetFeatureHelper { internal static List> sets; internal static List armorSetSlots; + internal static Mutex armorSetSlotsMutex = new Mutex(); + internal static bool hasCalculated = false; + internal static bool hasStarted = false; internal const string ArmorSetsHoverTest = "Armor Sets\n(Warning: May take many seconds to calculate)"; internal static void Unload() { sets = null; + + while (!armorSetSlotsMutex.WaitOne(100)) { } armorSetSlots = null; + armorSetSlotsMutex.ReleaseMutex(); + + hasCalculated = false; + hasStarted = false; UIArmorSetCatalogueItemSlot.drawPlayer = null; } @@ -214,10 +225,16 @@ internal static void AppendSpecialUI(UIGrid itemGrid) { var showItemsCheckbox = new UICheckbox("Show Items", "Display the items that make up the set"); showItemsCheckbox.Selected = UIArmorSetCatalogueItemSlot.showItems; - showItemsCheckbox.OnSelectedChanged += (s, e) => { + showItemsCheckbox.OnSelectedChanged += (s, e) => + { UIArmorSetCatalogueItemSlot.showItems = showItemsCheckbox.Selected; - foreach (var item in armorSetSlots) { - item.needsUpdate = true; + if (armorSetSlots != null && armorSetSlotsMutex.WaitOne(10)) //we can't be clogging up main thread waiting for this + { + foreach (var item in armorSetSlots) + { + item.needsUpdate = true; + } + armorSetSlotsMutex.ReleaseMutex(); } }; showItemsCheckbox.Left.Set(0, 0); @@ -255,6 +272,7 @@ internal static void AppendSpecialUI(UIGrid itemGrid) { } internal static void CalculateArmorSets() { + hasStarted = true; //new Category("Head", x => x.headSlot != -1, smallHead), //new Category("Body", x => x.bodySlot != -1, smallBody), //new Category("Legs", x => x.legSlot != -1, smallLegs), @@ -263,23 +281,29 @@ internal static void CalculateArmorSets() { List Heads = new List(); List Bodys = new List(); List Legs = new List(); + + // go thru all items and get all the armor pieces into their respective arrays for (int type = 1; type < ItemLoader.ItemCount; type++) { Item item = new Item(); item.SetDefaults(type, false); - if (item.type == 0) - continue; - if (item.headSlot != -1) + + if (item.type == ItemID.None) // Case where we get a gap in item id's? + continue; + + if (item.headSlot != -1) // if item is a helmet Heads.Add(item); - if (item.bodySlot != -1) + if (item.bodySlot != -1) // if item is a chestplate Bodys.Add(item); - if (item.legSlot != -1) + if (item.legSlot != -1) // if item is leggings Legs.Add(item); } - sets = new List>(); + + sets = new List>(); // tuple is (helmet, chestplate, leggings, set Bonus, total defense [incl any from set bonus]) foreach (var head in Heads) { foreach (var body in Bodys) { foreach (var leg in Legs) { + // TODO: thread this shit to hell and back to speed up efficiency. testPlayer.statDefense = Player.DefenseStat.Default; testPlayer.head = head.headSlot; testPlayer.body = body.bodySlot; @@ -348,12 +372,19 @@ internal static void CalculateArmorSets() { // Check Head/Body, Head/Legs, etc? armorSetSlots = new List(); - if (armorSetSlots.Count == 0) { - foreach (var set in sets) { + while (!armorSetSlotsMutex.WaitOne(1000)) { } //acquire mutex + + if (armorSetSlots.Count == 0) + { + foreach (var set in sets) + { var slot = new UIArmorSetCatalogueItemSlot(set); armorSetSlots.Add(slot); } } + armorSetSlotsMutex.ReleaseMutex(); //release mutex + hasCalculated = true; + } } } \ No newline at end of file From 2c332c2ffbe4524fade89a8fdb619af5700ee1a7 Mon Sep 17 00:00:00 2001 From: Californium-251 Date: Wed, 6 Nov 2024 01:51:17 -0800 Subject: [PATCH 2/3] Removed Todos and some of the comments I added to understand the code --- ItemCatalogueUI.cs | 2 +- UIElements/UIArmorSetCatalogueItemSlot.cs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ItemCatalogueUI.cs b/ItemCatalogueUI.cs index 6797e46..023a736 100644 --- a/ItemCatalogueUI.cs +++ b/ItemCatalogueUI.cs @@ -298,7 +298,7 @@ internal async void Update() if (SharedUI.instance.SelectedCategory.name == ArmorSetFeatureHelper.ArmorSetsHoverTest) { if (ArmorSetFeatureHelper.hasCalculated == false && ArmorSetFeatureHelper.hasStarted != true) - await Task.Run(() => ArmorSetFeatureHelper.CalculateArmorSets()); //TODO: make this run on a separate thread + await Task.Run(() => ArmorSetFeatureHelper.CalculateArmorSets()); if (ArmorSetFeatureHelper.hasCalculated && ArmorSetFeatureHelper.armorSetSlotsMutex.WaitOne(10)) { slotsToUse = ArmorSetFeatureHelper.armorSetSlots.Cast().ToList(); diff --git a/UIElements/UIArmorSetCatalogueItemSlot.cs b/UIElements/UIArmorSetCatalogueItemSlot.cs index e30fae4..84bfad5 100644 --- a/UIElements/UIArmorSetCatalogueItemSlot.cs +++ b/UIElements/UIArmorSetCatalogueItemSlot.cs @@ -288,22 +288,22 @@ internal static void CalculateArmorSets() { item.SetDefaults(type, false); - if (item.type == ItemID.None) // Case where we get a gap in item id's? + if (item.type == ItemID.None) continue; - if (item.headSlot != -1) // if item is a helmet + if (item.headSlot != -1) Heads.Add(item); - if (item.bodySlot != -1) // if item is a chestplate + if (item.bodySlot != -1) Bodys.Add(item); - if (item.legSlot != -1) // if item is leggings + if (item.legSlot != -1) Legs.Add(item); } - sets = new List>(); // tuple is (helmet, chestplate, leggings, set Bonus, total defense [incl any from set bonus]) + sets = new List>(); foreach (var head in Heads) { foreach (var body in Bodys) { foreach (var leg in Legs) { - // TODO: thread this shit to hell and back to speed up efficiency. + testPlayer.statDefense = Player.DefenseStat.Default; testPlayer.head = head.headSlot; testPlayer.body = body.bodySlot; @@ -382,7 +382,7 @@ internal static void CalculateArmorSets() { armorSetSlots.Add(slot); } } - armorSetSlotsMutex.ReleaseMutex(); //release mutex + armorSetSlotsMutex.ReleaseMutex(); //release mutex hasCalculated = true; } From 00fa863c0f156fd8c936f5841743b7c08e97675d Mon Sep 17 00:00:00 2001 From: Californium-251 Date: Thu, 7 Nov 2024 00:37:28 -0800 Subject: [PATCH 3/3] code simplification and minor corrections --- ItemCatalogueUI.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ItemCatalogueUI.cs b/ItemCatalogueUI.cs index 023a736..ee127a4 100644 --- a/ItemCatalogueUI.cs +++ b/ItemCatalogueUI.cs @@ -297,16 +297,18 @@ internal async void Update() List slotsToUse = itemSlots; if (SharedUI.instance.SelectedCategory.name == ArmorSetFeatureHelper.ArmorSetsHoverTest) { - if (ArmorSetFeatureHelper.hasCalculated == false && ArmorSetFeatureHelper.hasStarted != true) + if (!(ArmorSetFeatureHelper.hasCalculated) && !(ArmorSetFeatureHelper.hasStarted)) await Task.Run(() => ArmorSetFeatureHelper.CalculateArmorSets()); if (ArmorSetFeatureHelper.hasCalculated && ArmorSetFeatureHelper.armorSetSlotsMutex.WaitOne(10)) { slotsToUse = ArmorSetFeatureHelper.armorSetSlots.Cast().ToList(); ArmorSetFeatureHelper.armorSetSlotsMutex.ReleaseMutex(); - } + + ArmorSetFeatureHelper.AppendSpecialUI(itemGrid); + } else slotsToUse = new List(); //empty - ArmorSetFeatureHelper.AppendSpecialUI(itemGrid); + } foreach (var slot in slotsToUse)