Cybertaur Posted May 17, 2021 Share Posted May 17, 2021 (edited) So, there are a few tricks to refresh/update menus without closing them. Let's start with the inventory menu. If this menu is open and, say, we equip an item through a script, the item doesn't show as equipped until we refresh the menu. We can close it and open it again through the script to get the update, but that's an ugly solution. A much better one is simply to add and remove an auxiliary item because the inventory menu will be updated by the game engine whenever the player's inventory is modified. The typical solution is to add and remove 1 unit of gold, which does the trick nicely in this case. The barter menu suffers from the same pathology. If this menu is open and we add an item through a script to the merchant providing the service, the item won't show until the menu is updated. The player can buy/sell something to get the update, but there's something better the script can do to get the update instantly. The skyui BarterMenu.as actionscript contains several functions that can be called through papyrus, one of which is the doTransaction(a_amount: Number) function. If we call this function in our script as: UI.InvokeNumber("BarterMenu", "_root.Menu_mc.doTransaction", 0.0) which simulates a transaction, the barter menu will be updated by the game engine and the item that we added will appear on the list. The training menu is another one, albeit in this case what we actually want to do is to reset it through the script. The number of training sessions that the player has used as shown in the menu can be simply reset through papyrus by increasing and then decreasing the player level with the Game.SetPlayerLevel() function. Now we come to the crux of this post, which is the crafting menu, in particular the Enchanting menu. Suppose this menu is open and we add an item that can be enchanted, or a filled soul gem, through a papyrus script. We want this item to show on the respective list without closing and opening the menu. Is there any way to achieve this? This particular menu is not updated by an inventory change. In addition, I've tried to run each function that appears in the CraftingMenu.as actionscript as described above but to no avail, the item still doesn't show on the enchanting lists. I've also tried to use the SetPlayerKnows() skse function to make the player forget/learn an enchantment, hoping that this would update the menu, but unfortunately it does not. To my knowledge, the only way to get the engine to update this menu (apart, of course, from closing and opening it again) is by actually enchanting something: after the confirmation that we want to enchant, the soul gem will get removed and the now enchanted weapon/armor will move from the list of items that can be enchanted to the "disenchant" list. If an item has been added through papyrus before the enchanting occurs, it will now appear on the lists. However, we don't want to force an enchanting of a weapon/armor just so our item shows up (there isn't even a way to do that with papyrus, it's an action that has to be performed by the player). So, if anyone has any ideas on how to achieve this, how to refresh/update the enchanting lists with papyrus without closing/opening the menu (and without an actual enchanting action), please drop a line, your help would be really appreciated. Edited May 17, 2021 by Cybertaur Link to comment Share on other sites More sharing options...
IsharaMeradin Posted May 17, 2021 Share Posted May 17, 2021 Instead of adding items after the crafting menu has opened, add them before opening the crafting menu. There is the perk entry point solution. Any number of mods can add a menu option, but only one can override the default action. Thus there is the chance that one or more mods may conflict. https://www.creationkit.com/index.php?title=Perk_Entry_Point Another option, requiring SKSE, is to utilize a key press with crosshair target to transfer the items and then activate the crafting station. Link to comment Share on other sites More sharing options...
Cybertaur Posted May 17, 2021 Author Share Posted May 17, 2021 Instead of adding items after the crafting menu has opened, add them before opening the crafting menu. There is the perk entry point solution. Any number of mods can add a menu option, but only one can override the default action. Thus there is the chance that one or more mods may conflict. https://www.creationkit.com/index.php?title=Perk_Entry_Point Another option, requiring SKSE, is to utilize a key press with crosshair target to transfer the items and then activate the crafting station.I wish it were that simple. The item, say, a filled soul gem, is added for use immediately after the player has performed a specific enchanting with the enchanting menu open. Think of it as the outcome of a specific enchanting act. Link to comment Share on other sites More sharing options...
IsharaMeradin Posted May 17, 2021 Share Posted May 17, 2021 When you tried the functions on CraftingMenu.as did you change the "invoke" function to match the parameter types required by the desired function? i.e. InvokeBool with UpdateItemList(abFullRebuild: Boolean) Link to comment Share on other sites More sharing options...
Cybertaur Posted May 17, 2021 Author Share Posted May 17, 2021 (edited) When you tried the functions on CraftingMenu.as did you change the "invoke" function to match the parameter types required by the desired function? i.e. InvokeBool with UpdateItemList(abFullRebuild: Boolean)Yes. I tried both the shortcut version: UI.InvokeBool("Crafting Menu", "_root.Menu.UpdateItemList", X) with X = True or False, as well as the true update function: UI.Invoke("Crafting Menu", "_root.Menu.InventoryLists.itemList.UpdateList") I really believe the only way is by calling some actionscript function from some actionscript file, but I can't seem to find which. I tried all from CraftingMenu.as, as well as from InventoryLists.as and a couple of others, but none worked so far. The game engine updates the Enchanting lists twice: when the enchanting menu is opened the first time and when an enchanting is performed (which does refresh the lists without closing/opening the menu because OnMenuClose and OnActivate events do not fire). I haven't figured out yet how to simulate an enchanting act. By looking at the actionscript files, they call a GameDelegate.call: private function onCraftButtonPress(): Void { if (bCanCraft) { GameDelegate.call("CraftButtonPress", []); } } but I can't replicate this through papyrus because OnCraftButtonPress is a private function, so I should not be able to call it with UI.Invoke(). Edited May 17, 2021 by Cybertaur Link to comment Share on other sites More sharing options...
Cybertaur Posted May 17, 2021 Author Share Posted May 17, 2021 When you tried the functions on CraftingMenu.as did you change the "invoke" function to match the parameter types required by the desired function? i.e. InvokeBool with UpdateItemList(abFullRebuild: Boolean)Yes. I tried both the shortcut version: UI.InvokeBool("Crafting Menu", "_root.Menu.UpdateItemList", X) with X = True or False, as well as the true update function: UI.Invoke("Crafting Menu", "_root.Menu.InventoryLists.itemList.UpdateList") I really believe the only way is by calling some actionscript function from some actionscript file, but I can't seem to find which. I tried all from CraftingMenu.as, as well as from InventoryLists.as and a couple of others, but none worked so far. The game engine updates the Enchanting lists twice: when the enchanting menu is opened the first time and when an enchanting is performed (which does refresh the lists without closing/opening the menu because OnMenuClose and OnActivate events do not fire). I haven't figured out yet how to simulate an enchanting act. By looking at the actionscript files, they call a GameDelegate.call: private function onCraftButtonPress(): Void { if (bCanCraft) { GameDelegate.call("CraftButtonPress", []); } } but I can't replicate this through papyrus because OnCraftButtonPress is a private function, so I should not be able to call it with UI.Invoke(). Wait, what?? I just tried and I CAN call private functions?? This changes everything! Give me a coupled of minutes. Link to comment Share on other sites More sharing options...
Cybertaur Posted May 18, 2021 Author Share Posted May 18, 2021 (edited) Just to drop an update since yesterday. Apart from the mcm, Skyui is a UI overhaul, it consists of an overhaul of the interface between the game engine and the user (essentially an overhaul of the native .swf flash interface files you can find in Data\skyrim - interface.bsa along with some papyrus scripts). If the game does not update the enchanting list with typical operations such as a modification of the inventory content, skyui by itself won't do it either. In the barter menu example I gave in the original post, we can get an update of the menu by performing a transaction (independently of skyui), so we just ask skyui to do one with that instruction. In the enchanting case, apparently we can only get the game to update the enchanting lists by either closing-opening the menu or by actually enchanting something, so all we can do is ask skyui to do one of those operations. We could try to do something else, for example, to close and open the enchanting panels through: UI.Invoke("Crafting Menu", "_root.Menu.CategoryList.hidePanel") Utility.WaitMenuMode(1.0) UI.Invoke("Crafting Menu", "_root.Menu.CategoryList.showPanel") but this is just a visual change, it doesn't truly update anything because the game itself still hasn't updated the enchanting list and sent that new information to skyui. So when the panels show up again, they still contain the old information. There are other instructions that we can try to run, for example we can run the public skyui function UpdateList() or UpdateItemList() as I indicated in my previous post, but again this is just a visual change. What this does is: given the info passed from the game to skyui, update the enchanting lists. If the content of the lists remains the same, there's no new information for skyui to show. The type of update we can get with such instruction is, say, an update to the name of the items that we modified through skyui. For example, as in the grimy craftinghotkey mod, if we change the skyui item name string with: UI.SetString("Crafting Menu", "_root.Menu.InventoryLists.itemList.selectedEntry.text","NewString") then we need to call a skyui update to get the new string to show: UI.InvokeBool("Crafting Menu", "_root.Menu.UpdateItemList", False) but the content of the enchanting list remains the same as that originally passed from the game to skyui. My original idea to get the game to update the enchanting list was to simulate an enchanting act. We could try to run the private skyui function onCraftButtonPress() in the CraftingMenu.as actionscript file: UI.Invoke("Crafting Menu", "_root.Menu.onCraftButtonPress") but this essentially just simulates a keypress of the crafting key (the 'R' key), and the game will tell you that you cannot craft if no triplet {item, enchanting, soul gem} has been chosen. We could choose such a triplet through papyrus by modifying the selected indices, say: UI.SetInt("Crafting Menu", "_root.Menu.InventoryLists.itemList.selectedIndex", 7) and once we have chosen an appropriate triplet, simulate a crafting keypress. But this is a really ugly solution just to get an update of the enchanting list. What I wanted but cannot do in this way is to simulate whatever happens right after we click 'yes' in that message box where the game asks you to confirm that you want to enchant; that's probably an internal process skyui doesn't have access to through its functions. So, the best (and only) solution I found so far is to call: UI.InvokeString("HUD Menu", "_global.skse.CloseMenu", "Crafting Menu") UI.InvokeString("HUD Menu", "_global.skse.OpenMenu", "Crafting Menu") With this, the Crafting Menu closes and opens again without the player leaving the enchanting table (to leave the arcane enchanter, we would use instead myEnchanterRef.Activate(PlayerRef, True)). Essentially, we see the enchanting panels going off and on again, somewhat similar to the hidePanel and showPanel above, but now the enchanting lists will be updated because asking to close the menu forces the game itself to update the lists. Unlike the hide/showPanel, this will trigger OnMenuClose and OnMenuOpen events (but not OnActivate events), which can be temporarily blocked by unregistering the corresponding forms. A curious thing I found with this is that, if we only close the menu this way, and then leave the arcane enchanter in-game by pressing some key, OnActivate events will trigger. It seems the game checks if the Crafting Menu is open when we leave an arcane enchanter; if it is, it doesn't send OnActivate events, otherwise it does. So there's that. If I eventually find any other way, I'll post it here. Edited May 18, 2021 by Cybertaur Link to comment Share on other sites More sharing options...
ItsAlways710 Posted July 26 Share Posted July 26 Has anyone found a better solution to this issue? Constructible Object Custom Keyword System replaces the smithing menu and opens faster than SkyUI's menu, I need a UI.Invoke that will refresh it and if I use the solution above it works, however you end up with the SkyUI Crafting Menu instead of the C.O.C.K.S. menu.... Link to comment Share on other sites More sharing options...
Recommended Posts