From a388fe059ceb8e353ec0c3d65ae801639346188b Mon Sep 17 00:00:00 2001 From: Kaz Wolfe Date: Tue, 3 Oct 2023 01:04:00 -0700 Subject: [PATCH] Misc ClientStructs changes - Update HotbarSlotTypes accordingly - Crate translation layer between XIVDeck API names and CS names - Use spans properly --- .../Strategies/MinionStrategy.cs | 7 ++--- .../Strategies/OrnamentStrategy.cs | 11 +++---- FFXIVPlugin/Game/Managers/HotbarManager.cs | 2 +- FFXIVPlugin/Game/Watchers/HotbarWatcher.cs | 4 +-- .../Server/Controllers/ActionController.cs | 31 +++++++++++++++---- .../Server/Controllers/HotbarController.cs | 2 +- 6 files changed, 37 insertions(+), 20 deletions(-) diff --git a/FFXIVPlugin/ActionExecutor/Strategies/MinionStrategy.cs b/FFXIVPlugin/ActionExecutor/Strategies/MinionStrategy.cs index 2dfed31..61b596e 100644 --- a/FFXIVPlugin/ActionExecutor/Strategies/MinionStrategy.cs +++ b/FFXIVPlugin/ActionExecutor/Strategies/MinionStrategy.cs @@ -7,21 +7,20 @@ using XIVDeck.FFXIVPlugin.Base; using XIVDeck.FFXIVPlugin.Exceptions; using XIVDeck.FFXIVPlugin.Game; -using XIVDeck.FFXIVPlugin.Game.Chat; using XIVDeck.FFXIVPlugin.Game.Managers; using XIVDeck.FFXIVPlugin.Resources.Localization; using XIVDeck.FFXIVPlugin.Utils; namespace XIVDeck.FFXIVPlugin.ActionExecutor.Strategies; -[ActionStrategy(HotbarSlotType.Minion)] +[ActionStrategy(HotbarSlotType.Companion)] public class MinionStrategy : IActionStrategy { private static ExecutableAction GetExecutableAction(Companion minion) { return new ExecutableAction { ActionId = (int) minion.RowId, ActionName = minion.Singular.ToString(), IconId = minion.Icon, - HotbarSlotType = HotbarSlotType.Minion, + HotbarSlotType = HotbarSlotType.Companion, SortOrder = minion.Order }; } @@ -55,7 +54,7 @@ public void Execute(uint actionId, ActionPayload? _) { Injections.PluginLog.Debug($"Executing hotbar slot: Minion#{actionId} ({minion.Singular.ToTitleCase()})"); Injections.Framework.RunOnFrameworkThread(delegate { - HotbarManager.ExecuteHotbarAction(HotbarSlotType.Minion, actionId); + HotbarManager.ExecuteHotbarAction(HotbarSlotType.Companion, actionId); }); } diff --git a/FFXIVPlugin/ActionExecutor/Strategies/OrnamentStrategy.cs b/FFXIVPlugin/ActionExecutor/Strategies/OrnamentStrategy.cs index 0cfca34..e568f18 100644 --- a/FFXIVPlugin/ActionExecutor/Strategies/OrnamentStrategy.cs +++ b/FFXIVPlugin/ActionExecutor/Strategies/OrnamentStrategy.cs @@ -6,21 +6,20 @@ using XIVDeck.FFXIVPlugin.Base; using XIVDeck.FFXIVPlugin.Exceptions; using XIVDeck.FFXIVPlugin.Game; -using XIVDeck.FFXIVPlugin.Game.Chat; using XIVDeck.FFXIVPlugin.Game.Managers; using XIVDeck.FFXIVPlugin.Resources.Localization; using XIVDeck.FFXIVPlugin.Utils; namespace XIVDeck.FFXIVPlugin.ActionExecutor.Strategies; -[ActionStrategy(HotbarSlotType.FashionAccessory)] +[ActionStrategy(HotbarSlotType.Ornament)] public class OrnamentStrategy : IActionStrategy { private static ExecutableAction GetExecutableAction(Ornament ornament) { return new ExecutableAction { ActionId = (int) ornament.RowId, ActionName = ornament.Singular.ToString(), IconId = ornament.Icon, - HotbarSlotType = HotbarSlotType.FashionAccessory, + HotbarSlotType = HotbarSlotType.Ornament, SortOrder = ornament.Order }; } @@ -45,16 +44,16 @@ public void Execute(uint actionId, ActionPayload? _) { var ornament = GetOrnamentById(actionId); if (ornament == null) { - throw new ActionNotFoundException(HotbarSlotType.FashionAccessory, actionId); + throw new ActionNotFoundException(HotbarSlotType.Ornament, actionId); } if (!ornament.IsUnlocked()) { throw new ActionLockedException(string.Format(UIStrings.OrnamentStrategy_OrnamentLockedError, ornament.Singular)); } - Injections.PluginLog.Debug($"Executing hotbar slot: FashionAccessory#{ornament.RowId} ({ornament.Singular.ToTitleCase()})"); + Injections.PluginLog.Debug($"Executing hotbar slot: Ornament#{ornament.RowId} ({ornament.Singular.ToTitleCase()})"); Injections.Framework.RunOnFrameworkThread(delegate { - HotbarManager.ExecuteHotbarAction(HotbarSlotType.FashionAccessory, ornament.RowId); + HotbarManager.ExecuteHotbarAction(HotbarSlotType.Ornament, ornament.RowId); }); } diff --git a/FFXIVPlugin/Game/Managers/HotbarManager.cs b/FFXIVPlugin/Game/Managers/HotbarManager.cs index b468bb9..ba18edb 100644 --- a/FFXIVPlugin/Game/Managers/HotbarManager.cs +++ b/FFXIVPlugin/Game/Managers/HotbarManager.cs @@ -100,7 +100,7 @@ public static unsafe void CalcBForSlot(HotBarSlot* slot, out HotbarSlotType acti // Take in default values, just in case GetSlotAppearance fails for some reason var acType = slot->IconTypeB; var acId = slot->IconB; - ushort actionCost = slot->UNK_0xCA; + ushort actionCost = slot->CostType; RaptureHotbarModule.GetSlotAppearance(&acType, &acId, &actionCost, hotbarModule, slot); diff --git a/FFXIVPlugin/Game/Watchers/HotbarWatcher.cs b/FFXIVPlugin/Game/Watchers/HotbarWatcher.cs index dd2f26b..a6dc8c5 100644 --- a/FFXIVPlugin/Game/Watchers/HotbarWatcher.cs +++ b/FFXIVPlugin/Game/Watchers/HotbarWatcher.cs @@ -25,10 +25,10 @@ private unsafe void OnGameUpdate(IFramework framework) { List updatedSlots = new(); for (var hotbarId = 0; hotbarId < 17; hotbarId++) { - var hotbar = hotbarModule->HotBar[hotbarId]; + ref var hotbar = ref hotbarModule->HotBarsSpan[hotbarId]; for (var slotId = 0; slotId < 16; slotId++) { - var gameSlot = hotbar->Slot[slotId]; + var gameSlot = hotbar.GetHotbarSlot((uint) slotId); var cachedSlot = this._hotbarCache[hotbarId, slotId]; // We calculate IconB first so that we know what "appearance" the slot has. This allows us to optimize diff --git a/FFXIVPlugin/Server/Controllers/ActionController.cs b/FFXIVPlugin/Server/Controllers/ActionController.cs index 848fdc3..baa0e4d 100644 --- a/FFXIVPlugin/Server/Controllers/ActionController.cs +++ b/FFXIVPlugin/Server/Controllers/ActionController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using EmbedIO; @@ -18,15 +19,29 @@ namespace XIVDeck.FFXIVPlugin.Server.Controllers; [ApiController("/action")] public class ActionController : WebApiController { + /// + /// A lookup table of aliases for certain action types. Used for cases where an action type may have changed + /// names as a result of CS updates or similar. + /// + private static readonly Dictionary ActionTypeAliases = new() { + { "Minion", HotbarSlotType.Companion }, + { "FashionAccessory", HotbarSlotType.Ornament } + }; + + private static readonly Dictionary SlotTypeNames = ActionTypeAliases.Reverse() + .ToDictionary(v => v.Value, k => k.Key); + [Route(HttpVerbs.Get, "/")] - public Dictionary> GetActions() { - Dictionary> actions = new(); + public Dictionary> GetActions() { + Dictionary> actions = new(); foreach (var (type, strategy) in XIVDeckPlugin.Instance.ActionDispatcher.GetStrategies()) { var allowedItems = strategy.GetAllowedItems(); if (allowedItems == null || allowedItems.Count == 0) continue; - actions[type] = allowedItems; + var typeName = SlotTypeNames.GetValueOrDefault(type, type.ToString()); + + actions[typeName] = allowedItems; } return actions; @@ -34,7 +49,7 @@ public Dictionary> GetActions() { [Route(HttpVerbs.Get, "/{type}")] public List GetActionsByType(string type) { - if (!Enum.TryParse(type, out var slotType)) { + if (!TryGetSlotTypeByName(type, out var slotType)) { throw HttpException.NotFound(string.Format(UIStrings.ActionController_UnknownActionTypeError, type)); } @@ -44,7 +59,7 @@ public List GetActionsByType(string type) { [Route(HttpVerbs.Get, "/{type}/{id}")] public ExecutableAction GetAction(string type, int id) { - if (!Enum.TryParse(type, out var slotType)) { + if (!TryGetSlotTypeByName(type, out var slotType)) { throw HttpException.NotFound(string.Format(UIStrings.ActionController_UnknownActionTypeError, type)); } @@ -59,7 +74,7 @@ public ExecutableAction GetAction(string type, int id) { [Route(HttpVerbs.Post, "/{type}/{id}/execute")] public async Task ExecuteAction(string type, int id) { - if (!Enum.TryParse(type, out var slotType)) + if (!TryGetSlotTypeByName(type, out var slotType)) throw HttpException.NotFound(string.Format(UIStrings.ActionController_UnknownActionTypeError, type)); if (!Injections.ClientState.IsLoggedIn) @@ -79,4 +94,8 @@ public async Task ExecuteAction(string type, int id) { GameUtils.ResetAFKTimer(); strategy.Execute((uint) id, payload); } + + private static bool TryGetSlotTypeByName(string typeName, out HotbarSlotType slotType) { + return ActionTypeAliases.TryGetValue(typeName, out slotType) || Enum.TryParse(typeName, out slotType); + } } \ No newline at end of file diff --git a/FFXIVPlugin/Server/Controllers/HotbarController.cs b/FFXIVPlugin/Server/Controllers/HotbarController.cs index 5ee5aff..b057368 100644 --- a/FFXIVPlugin/Server/Controllers/HotbarController.cs +++ b/FFXIVPlugin/Server/Controllers/HotbarController.cs @@ -25,7 +25,7 @@ public unsafe SerializableHotbarSlot GetHotbarSlot(int hotbarId, int slotId) { throw HttpException.BadRequest(ex.Message); } - var hotbarItem = hotbarModule->HotBar[hotbarId]->Slot[slotId]; + var hotbarItem = hotbarModule->HotBarsSpan[hotbarId].GetHotbarSlot((uint) slotId); var iconId = HotbarManager.CalcIconForSlot(hotbarItem); return new SerializableHotbarSlot {