From 927c60ddc9baabdcb500cc75efa04f42233e4bfe Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Tue, 5 Apr 2022 23:47:25 -0700 Subject: [PATCH] Don't show empty dialogs if there is no response from the server when interacting with an NPC --- .../Interact/INPCInteractionNotifier.cs | 16 +++++++++++++ EOLib/Domain/Interact/MapNPCActions.cs | 23 ++++++++++++------- .../Interact/Quest/QuestDataRepository.cs | 7 ++++++ .../Interact/Shop/ShopOpenHandler.cs | 9 +++++++- .../Quest/QuestDialogHandler.cs | 9 +++++++- .../Controllers/NPCInteractionController.cs | 10 ++------ .../Dialogs/Actions/InGameDialogActions.cs | 23 +++++++++++++++---- .../Dialogs/Factories/QuestDialogFactory.cs | 8 +++---- EndlessClient/Dialogs/QuestDialog.cs | 7 ++---- 9 files changed, 80 insertions(+), 32 deletions(-) create mode 100644 EOLib/Domain/Interact/INPCInteractionNotifier.cs diff --git a/EOLib/Domain/Interact/INPCInteractionNotifier.cs b/EOLib/Domain/Interact/INPCInteractionNotifier.cs new file mode 100644 index 000000000..90132af19 --- /dev/null +++ b/EOLib/Domain/Interact/INPCInteractionNotifier.cs @@ -0,0 +1,16 @@ +using AutomaticTypeMapper; +using EOLib.IO; + +namespace EOLib.Domain.Interact +{ + public interface INPCInteractionNotifier + { + void NotifyInteractionFromNPC(NPCType npcType); + } + + [AutoMappedType] + public class NoOpNPCInteractionNotifier : INPCInteractionNotifier + { + public void NotifyInteractionFromNPC(NPCType npcType) { } + } +} diff --git a/EOLib/Domain/Interact/MapNPCActions.cs b/EOLib/Domain/Interact/MapNPCActions.cs index b1a5ecf90..4eafbf762 100644 --- a/EOLib/Domain/Interact/MapNPCActions.cs +++ b/EOLib/Domain/Interact/MapNPCActions.cs @@ -1,4 +1,6 @@ using AutomaticTypeMapper; +using EOLib.Domain.NPC; +using EOLib.IO.Repositories; using EOLib.Net; using EOLib.Net.Communication; @@ -8,26 +10,31 @@ namespace EOLib.Domain.Interact public class MapNPCActions : IMapNPCActions { private readonly IPacketSendService _packetSendService; + private readonly IENFFileProvider _enfFileProvider; - public MapNPCActions(IPacketSendService packetSendService) + public MapNPCActions(IPacketSendService packetSendService, + IENFFileProvider enfFileProvider) { _packetSendService = packetSendService; + _enfFileProvider = enfFileProvider; } - public void RequestShop(byte index) + public void RequestShop(INPC npc) { var packet = new PacketBuilder(PacketFamily.Shop, PacketAction.Open) - .AddShort(index) + .AddShort(npc.Index) .Build(); _packetSendService.SendPacket(packet); } - public void RequestQuest(short index, short vendorId) + public void RequestQuest(INPC npc) { + var data = _enfFileProvider.ENFFile[npc.ID]; + var packet = new PacketBuilder(PacketFamily.Quest, PacketAction.Use) - .AddShort(index) - .AddShort(vendorId) + .AddShort(npc.Index) + .AddShort(data.VendorID) .Build(); _packetSendService.SendPacket(packet); @@ -36,8 +43,8 @@ public void RequestQuest(short index, short vendorId) public interface IMapNPCActions { - void RequestShop(byte index); + void RequestShop(INPC npc); - void RequestQuest(short index, short vendorId); + void RequestQuest(INPC npc); } } diff --git a/EOLib/Domain/Interact/Quest/QuestDataRepository.cs b/EOLib/Domain/Interact/Quest/QuestDataRepository.cs index 96548e827..e6ae8083f 100644 --- a/EOLib/Domain/Interact/Quest/QuestDataRepository.cs +++ b/EOLib/Domain/Interact/Quest/QuestDataRepository.cs @@ -1,21 +1,28 @@ using AutomaticTypeMapper; +using EOLib.Domain.NPC; using Optional; namespace EOLib.Domain.Interact.Quest { public interface IQuestDataRepository : IResettable { + INPC RequestedNPC { get; set; } + Option QuestDialogData { get; set; } } public interface IQuestDataProvider : IResettable { + INPC RequestedNPC { get; } + Option QuestDialogData { get; } } [AutoMappedType(IsSingleton = true)] public class QuestDataRepository : IQuestDataProvider, IQuestDataRepository { + public INPC RequestedNPC { get; set; } + public Option QuestDialogData { get; set; } public QuestDataRepository() diff --git a/EOLib/PacketHandlers/Interact/Shop/ShopOpenHandler.cs b/EOLib/PacketHandlers/Interact/Shop/ShopOpenHandler.cs index 79e250ad7..66d9eb0d4 100644 --- a/EOLib/PacketHandlers/Interact/Shop/ShopOpenHandler.cs +++ b/EOLib/PacketHandlers/Interact/Shop/ShopOpenHandler.cs @@ -1,4 +1,5 @@ using AutomaticTypeMapper; +using EOLib.Domain.Interact; using EOLib.Domain.Interact.Shop; using EOLib.Domain.Login; using EOLib.Net; @@ -11,16 +12,19 @@ namespace EOLib.PacketHandlers.Interact.Shop public class ShopOpenHandler : InGameOnlyPacketHandler { private readonly IShopDataRepository _shopDataRepository; + private readonly IEnumerable _npcInteractionNotifiers; public override PacketFamily Family => PacketFamily.Shop; public override PacketAction Action => PacketAction.Open; public ShopOpenHandler(IPlayerInfoProvider playerInfoProvider, - IShopDataRepository shopDataRepository) + IShopDataRepository shopDataRepository, + IEnumerable npcInteractionNotifiers) : base(playerInfoProvider) { _shopDataRepository = shopDataRepository; + _npcInteractionNotifiers = npcInteractionNotifiers; } public override bool HandlePacket(IPacket packet) @@ -62,6 +66,9 @@ public override bool HandlePacket(IPacket packet) _shopDataRepository.CraftItems = craftItems; + foreach (var notifier in _npcInteractionNotifiers) + notifier.NotifyInteractionFromNPC(IO.NPCType.Shop); + return true; } } diff --git a/EOLib/PacketHandlers/Quest/QuestDialogHandler.cs b/EOLib/PacketHandlers/Quest/QuestDialogHandler.cs index 245bb6d79..97ddaa08d 100644 --- a/EOLib/PacketHandlers/Quest/QuestDialogHandler.cs +++ b/EOLib/PacketHandlers/Quest/QuestDialogHandler.cs @@ -1,4 +1,5 @@ using AutomaticTypeMapper; +using EOLib.Domain.Interact; using EOLib.Domain.Interact.Quest; using EOLib.Domain.Login; using EOLib.Net; @@ -12,6 +13,7 @@ namespace EOLib.PacketHandlers.Quest public class QuestDialogHandler : InGameOnlyPacketHandler { private readonly IQuestDataRepository _questDataRepository; + private readonly IEnumerable _npcInteractionNotifiers; private enum DialogEntryType : byte { @@ -24,10 +26,12 @@ private enum DialogEntryType : byte public override PacketAction Action => PacketAction.Dialog; public QuestDialogHandler(IPlayerInfoProvider playerInfoProvider, - IQuestDataRepository questDataRepository) + IQuestDataRepository questDataRepository, + IEnumerable npcInteractionNotifiers) : base(playerInfoProvider) { _questDataRepository = questDataRepository; + _npcInteractionNotifiers = npcInteractionNotifiers; } public override bool HandlePacket(IPacket packet) @@ -70,6 +74,9 @@ public override bool HandlePacket(IPacket packet) _questDataRepository.QuestDialogData = Option.Some(questData); + foreach (var notifier in _npcInteractionNotifiers) + notifier.NotifyInteractionFromNPC(IO.NPCType.Quest); + return true; } } diff --git a/EndlessClient/Controllers/NPCInteractionController.cs b/EndlessClient/Controllers/NPCInteractionController.cs index c100374ba..43d27f8fa 100644 --- a/EndlessClient/Controllers/NPCInteractionController.cs +++ b/EndlessClient/Controllers/NPCInteractionController.cs @@ -1,5 +1,4 @@ using AutomaticTypeMapper; -using EndlessClient.Dialogs.Actions; using EOLib.Domain.Interact; using EOLib.Domain.NPC; using EOLib.IO.Repositories; @@ -10,15 +9,12 @@ namespace EndlessClient.Controllers public class NPCInteractionController : INPCInteractionController { private readonly IMapNPCActions _mapNpcActions; - private readonly IInGameDialogActions _inGameDialogActions; private readonly IENFFileProvider _enfFileProvider; public NPCInteractionController(IMapNPCActions mapNpcActions, - IInGameDialogActions inGameDialogActions, IENFFileProvider enfFileProvider) { _mapNpcActions = mapNpcActions; - _inGameDialogActions = inGameDialogActions; _enfFileProvider = enfFileProvider; } @@ -29,12 +25,10 @@ public void ShowNPCDialog(INPC npc) switch(data.Type) { case EOLib.IO.NPCType.Shop: - _mapNpcActions.RequestShop(npc.Index); - _inGameDialogActions.ShowShopDialog(); + _mapNpcActions.RequestShop(npc); break; case EOLib.IO.NPCType.Quest: - _mapNpcActions.RequestQuest(npc.Index, data.VendorID); - _inGameDialogActions.ShowQuestDialog(npc); + _mapNpcActions.RequestQuest(npc); break; } } diff --git a/EndlessClient/Dialogs/Actions/InGameDialogActions.cs b/EndlessClient/Dialogs/Actions/InGameDialogActions.cs index cbc26599d..20382a4e9 100644 --- a/EndlessClient/Dialogs/Actions/InGameDialogActions.cs +++ b/EndlessClient/Dialogs/Actions/InGameDialogActions.cs @@ -1,15 +1,17 @@ using AutomaticTypeMapper; using EndlessClient.Dialogs.Factories; using EOLib.Domain.Character; +using EOLib.Domain.Interact; using EOLib.Domain.Interact.Quest; using EOLib.Domain.Interact.Shop; using EOLib.Domain.NPC; +using EOLib.IO; using Optional; namespace EndlessClient.Dialogs.Actions { [AutoMappedType] - public class InGameDialogActions : IInGameDialogActions + public class InGameDialogActions : IInGameDialogActions, INPCInteractionNotifier { private readonly IFriendIgnoreListDialogFactory _friendIgnoreListDialogFactory; private readonly IPaperdollDialogFactory _paperdollDialogFactory; @@ -72,6 +74,19 @@ public void ShowPaperdollDialog(ICharacter character, bool isMainCharacter) }); } + public void NotifyInteractionFromNPC(NPCType npcType) + { + // originally, these methods were called directly from NPCInteractionController + // however, this resulted in empty responses (e.g. no shop or quest) showing an empty dialog + // instead, wait for the response packet to notify this class and then show the dialog + // once data has been received from the server + switch (npcType) + { + case NPCType.Shop: ShowShopDialog(); break; + case NPCType.Quest: ShowQuestDialog(); break; + } + } + public void ShowShopDialog() { _activeDialogRepository.ShopDialog.MatchNone(() => @@ -88,11 +103,11 @@ public void ShowShopDialog() }); } - public void ShowQuestDialog(INPC npc) + public void ShowQuestDialog() { _activeDialogRepository.QuestDialog.MatchNone(() => { - var dlg = _questDialogFactory.Create(npc); + var dlg = _questDialogFactory.Create(); dlg.DialogClosed += (_, _) => { _activeDialogRepository.QuestDialog = Option.None(); @@ -115,6 +130,6 @@ public interface IInGameDialogActions void ShowShopDialog(); - void ShowQuestDialog(INPC npc); + void ShowQuestDialog(); } } diff --git a/EndlessClient/Dialogs/Factories/QuestDialogFactory.cs b/EndlessClient/Dialogs/Factories/QuestDialogFactory.cs index b07fab734..0fdc86289 100644 --- a/EndlessClient/Dialogs/Factories/QuestDialogFactory.cs +++ b/EndlessClient/Dialogs/Factories/QuestDialogFactory.cs @@ -2,7 +2,6 @@ using EndlessClient.Content; using EndlessClient.Dialogs.Services; using EOLib.Domain.Interact.Quest; -using EOLib.Domain.NPC; using EOLib.Graphics; using EOLib.IO.Repositories; @@ -33,20 +32,19 @@ public class QuestDialogFactory : IQuestDialogFactory _contentProvider = contentProvider; } - public QuestDialog Create(INPC npc) + public QuestDialog Create() { return new QuestDialog(_nativeGraphicsManager, _questActions, _dialogButtonService, _questDataProvider, _enfFileProvider, - _contentProvider, - npc); + _contentProvider); } } public interface IQuestDialogFactory { - QuestDialog Create(INPC npc); + QuestDialog Create(); } } diff --git a/EndlessClient/Dialogs/QuestDialog.cs b/EndlessClient/Dialogs/QuestDialog.cs index 47d712fa9..fa5ddabd2 100644 --- a/EndlessClient/Dialogs/QuestDialog.cs +++ b/EndlessClient/Dialogs/QuestDialog.cs @@ -19,7 +19,6 @@ public class QuestDialog : ScrollingListDialog private readonly IQuestDataProvider _questDataProvider; private readonly IENFFileProvider _enfFileProvider; private readonly IContentProvider _contentProvider; - private readonly INPC _questNpc; private Option _cachedData; @@ -30,15 +29,13 @@ public class QuestDialog : ScrollingListDialog IEODialogButtonService dialogButtonService, IQuestDataProvider questDataProvider, IENFFileProvider enfFileProvider, - IContentProvider contentProvider, - INPC questNpc) + IContentProvider contentProvider) : base(nativeGraphicsManager, dialogButtonService, dialogSize: ScrollingListDialogSize.SmallDialog) { _questActions = questActions; _questDataProvider = questDataProvider; _enfFileProvider = enfFileProvider; _contentProvider = contentProvider; - _questNpc = questNpc; _cachedData = Option.None(); @@ -86,7 +83,7 @@ private void UpdateDialogControls(IQuestDialogData repoData) private void UpdateTitle(IQuestDialogData repoData) { - var npcName = _enfFileProvider.ENFFile[_questNpc.ID].Name; + var npcName = _enfFileProvider.ENFFile[_questDataProvider.RequestedNPC.ID].Name; var titleText = npcName; if (!repoData.DialogTitles.ContainsKey(repoData.VendorID) && repoData.DialogTitles.Count == 1) titleText += $" - {repoData.DialogTitles[0]}";