From ceae1656e1fba25b24f7189f1cec9f6d55c6aac8 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Fri, 27 May 2022 15:15:03 -0700 Subject: [PATCH 1/3] Refactor handling for INIT packets that are received after transitioning to in-game state. Refactor online player list and friend/ignore list dialogs to update their UI based on a repository similarly to how other panels do it --- EOLib/Domain/Online/OnlineListData.cs | 12 ---- EOLib/Domain/Online/OnlinePlayerActions.cs | 16 ++--- EOLib/Domain/Online/OnlinePlayerRepository.cs | 33 +++++++++ EOLib/Net/Handlers/PacketHandlingActions.cs | 34 ++++++--- .../Translators/OnlineListPacketTranslator.cs | 70 ------------------- .../Init/BasePlayersListHandler.cs | 36 ++++++++++ .../Init/FriendIgnoreListHandler.cs | 24 +++++++ .../Init/IInGameInitPacketHandler.cs | 12 ++++ .../Init/InGameInitPacketHandler.cs | 34 +++++++++ .../Init/OnlinePlayerListHandler.cs | 52 ++++++++++++++ .../Dialogs/Actions/InGameDialogActions.cs | 4 +- .../Dialogs/ActiveDialogRepository.cs | 8 +-- .../FriendIgnoreListDialogFactory.cs | 15 ++-- .../Dialogs/FriendIgnoreListDialog.cs | 38 ++++++++++ EndlessClient/Dialogs/ListDialogItem.cs | 6 ++ EndlessClient/Dialogs/ScrollingListDialog.cs | 6 ++ .../HUD/Controls/HudControlsFactory.cs | 12 ++-- EndlessClient/HUD/HudButtonController.cs | 33 ++------- EndlessClient/HUD/IHudButtonController.cs | 10 ++- EndlessClient/HUD/Panels/HudPanelFactory.cs | 6 +- EndlessClient/HUD/Panels/OnlineListPanel.cs | 68 ++++++++++++------ 21 files changed, 350 insertions(+), 179 deletions(-) delete mode 100644 EOLib/Domain/Online/OnlineListData.cs create mode 100644 EOLib/Domain/Online/OnlinePlayerRepository.cs delete mode 100644 EOLib/Net/Translators/OnlineListPacketTranslator.cs create mode 100644 EOLib/PacketHandlers/Init/BasePlayersListHandler.cs create mode 100644 EOLib/PacketHandlers/Init/FriendIgnoreListHandler.cs create mode 100644 EOLib/PacketHandlers/Init/IInGameInitPacketHandler.cs create mode 100644 EOLib/PacketHandlers/Init/InGameInitPacketHandler.cs create mode 100644 EOLib/PacketHandlers/Init/OnlinePlayerListHandler.cs create mode 100644 EndlessClient/Dialogs/FriendIgnoreListDialog.cs diff --git a/EOLib/Domain/Online/OnlineListData.cs b/EOLib/Domain/Online/OnlineListData.cs deleted file mode 100644 index 94696e040..000000000 --- a/EOLib/Domain/Online/OnlineListData.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Amadevus.RecordGenerator; -using EOLib.Net.Translators; -using System.Collections.Generic; - -namespace EOLib.Domain.Online -{ - [Record(Features.ObjectEquals | Features.Constructor)] - public sealed partial class OnlineListData : ITranslatedData - { - public IReadOnlyList OnlineList { get; } - } -} diff --git a/EOLib/Domain/Online/OnlinePlayerActions.cs b/EOLib/Domain/Online/OnlinePlayerActions.cs index 2afe767dd..93b1accf3 100644 --- a/EOLib/Domain/Online/OnlinePlayerActions.cs +++ b/EOLib/Domain/Online/OnlinePlayerActions.cs @@ -1,9 +1,6 @@ using AutomaticTypeMapper; using EOLib.Net; using EOLib.Net.Communication; -using EOLib.Net.Translators; -using System.Collections.Generic; -using System.Threading.Tasks; namespace EOLib.Domain.Online { @@ -11,26 +8,21 @@ namespace EOLib.Domain.Online public class OnlinePlayerActions : IOnlinePlayerActions { private readonly IPacketSendService _packetSendService; - private readonly IPacketTranslator _onlineListPacketTranslator; - public OnlinePlayerActions(IPacketSendService packetSendService, - IPacketTranslator onlineListPacketTranslator) + public OnlinePlayerActions(IPacketSendService packetSendService) { _packetSendService = packetSendService; - _onlineListPacketTranslator = onlineListPacketTranslator; } - public async Task> GetOnlinePlayersAsync(bool fullList) + public void RequestOnlinePlayers(bool fullList) { var packet = new PacketBuilder(PacketFamily.Players, fullList ? PacketAction.Request : PacketAction.List).Build(); - var response = await _packetSendService.SendEncodedPacketAndWaitAsync(packet); - - return _onlineListPacketTranslator.TranslatePacket(response).OnlineList; + _packetSendService.SendPacket(packet); } } public interface IOnlinePlayerActions { - Task> GetOnlinePlayersAsync(bool fullList); + void RequestOnlinePlayers(bool fullList); } } diff --git a/EOLib/Domain/Online/OnlinePlayerRepository.cs b/EOLib/Domain/Online/OnlinePlayerRepository.cs new file mode 100644 index 000000000..89d7ac302 --- /dev/null +++ b/EOLib/Domain/Online/OnlinePlayerRepository.cs @@ -0,0 +1,33 @@ +using AutomaticTypeMapper; +using System.Collections.Generic; + +namespace EOLib.Domain.Online +{ + public interface IOnlinePlayerRepository : IResettable + { + HashSet OnlinePlayers { get; } + } + + public interface IOnlinePlayerProvider + { + IReadOnlyCollection OnlinePlayers { get; } + } + + [AutoMappedType(IsSingleton = true)] + public class OnlinePlayerRepository : IOnlinePlayerRepository, IOnlinePlayerProvider + { + public HashSet OnlinePlayers { get; private set; } + + IReadOnlyCollection IOnlinePlayerProvider.OnlinePlayers => OnlinePlayers; + + public OnlinePlayerRepository() + { + ResetState(); + } + + public void ResetState() + { + OnlinePlayers = new HashSet(); + } + } +} diff --git a/EOLib/Net/Handlers/PacketHandlingActions.cs b/EOLib/Net/Handlers/PacketHandlingActions.cs index ccc448592..765b37ab0 100644 --- a/EOLib/Net/Handlers/PacketHandlingActions.cs +++ b/EOLib/Net/Handlers/PacketHandlingActions.cs @@ -1,4 +1,5 @@ using AutomaticTypeMapper; +using EOLib.Domain.Login; using EOLib.Net.Communication; namespace EOLib.Net.Handlers @@ -8,27 +9,38 @@ public class PacketHandlingActions : IPacketHandlingActions { private readonly IPacketQueueProvider _packetQueueProvider; private readonly IPacketHandlingTypeFinder _packetHandlingTypeFinder; + private readonly IPlayerInfoProvider _playerInfoProvider; public PacketHandlingActions(IPacketQueueProvider packetQueueProvider, - IPacketHandlingTypeFinder packetHandlingTypeFinder) + IPacketHandlingTypeFinder packetHandlingTypeFinder, + IPlayerInfoProvider playerInfoProvider) { _packetQueueProvider = packetQueueProvider; _packetHandlingTypeFinder = packetHandlingTypeFinder; + _playerInfoProvider = playerInfoProvider; } public void EnqueuePacketForHandling(IPacket packet) { - var handleType = _packetHandlingTypeFinder.FindHandlingType(packet.Family, packet.Action); - - switch (handleType) + if (_playerInfoProvider.PlayerIsInGame) + { + // all in-game packets should be handled in-band + _packetQueueProvider.HandleOutOfBandPacketQueue.EnqueuePacketForHandling(packet); + } + else { - case PacketHandlingType.InBand: - _packetQueueProvider.HandleInBandPacketQueue.EnqueuePacketAndSignalConsumer(packet); - break; - case PacketHandlingType.OutOfBand: - _packetQueueProvider.HandleOutOfBandPacketQueue.EnqueuePacketForHandling(packet); - break; - /*default: don't handle the received packet*/ + var handleType = _packetHandlingTypeFinder.FindHandlingType(packet.Family, packet.Action); + + switch (handleType) + { + case PacketHandlingType.InBand: + _packetQueueProvider.HandleInBandPacketQueue.EnqueuePacketAndSignalConsumer(packet); + break; + case PacketHandlingType.OutOfBand: + _packetQueueProvider.HandleOutOfBandPacketQueue.EnqueuePacketForHandling(packet); + break; + /*default: don't handle the received packet*/ + } } } } diff --git a/EOLib/Net/Translators/OnlineListPacketTranslator.cs b/EOLib/Net/Translators/OnlineListPacketTranslator.cs deleted file mode 100644 index c10412190..000000000 --- a/EOLib/Net/Translators/OnlineListPacketTranslator.cs +++ /dev/null @@ -1,70 +0,0 @@ -using AutomaticTypeMapper; -using EOLib.Domain.Online; -using EOLib.Domain.Protocol; -using EOLib.IO.Repositories; -using System.Collections.Generic; - -namespace EOLib.Net.Translators -{ - [AutoMappedType] - public class OnlineListPacketTranslator : IPacketTranslator - { - private readonly IECFFileProvider _classFileProvider; - - public OnlineListPacketTranslator(IECFFileProvider classFileProvider) - { - _classFileProvider = classFileProvider; - } - - public OnlineListData TranslatePacket(IPacket packet) - { - var reply = (InitReply)packet.ReadByte(); - - if (reply != InitReply.AllPlayersList && reply != InitReply.FriendPlayersList) - throw new MalformedPacketException($"Expected online list or friend list init data, but was {reply}", packet); - - short numTotal = packet.ReadShort(); - if (packet.ReadByte() != 255) - throw new MalformedPacketException("Expected break byte after number of entries", packet); - - var retList = new List(numTotal); - for (int i = 0; i < numTotal; ++i) - { - string name = packet.ReadBreakString(); - - if (reply == InitReply.AllPlayersList) - { - var title = packet.ReadBreakString(); - if (packet.ReadChar() != 0) - throw new MalformedPacketException("Expected 0 char after online entry title", packet); - - var iconType = (OnlineIcon)packet.ReadChar(); - int clsId = packet.ReadChar(); - var guild = packet.ReadBreakString(); - - name = char.ToUpper(name[0]) + name.Substring(1); - - if (string.IsNullOrWhiteSpace(title)) - title = "-"; - else - title = char.ToUpper(title[0]) + title.Substring(1); - - var className = _classFileProvider.ECFFile.Length >= clsId - ? _classFileProvider.ECFFile[clsId].Name - : "-"; - - if (string.IsNullOrWhiteSpace(guild)) - guild = "-"; - - retList.Add(new OnlinePlayerInfo(name, title, guild, className, iconType)); - } - else - { - retList.Add(new OnlinePlayerInfo(name)); - } - } - - return new OnlineListData(retList); - } - } -} diff --git a/EOLib/PacketHandlers/Init/BasePlayersListHandler.cs b/EOLib/PacketHandlers/Init/BasePlayersListHandler.cs new file mode 100644 index 000000000..01ac250eb --- /dev/null +++ b/EOLib/PacketHandlers/Init/BasePlayersListHandler.cs @@ -0,0 +1,36 @@ +using EOLib.Domain.Online; +using EOLib.Domain.Protocol; +using EOLib.Net; + +namespace EOLib.PacketHandlers.Init +{ + public abstract class BasePlayersListHandler : IInitPacketHandler + { + private readonly IOnlinePlayerRepository _onlinePlayerRepository; + + public abstract InitReply Reply { get; } + + protected BasePlayersListHandler(IOnlinePlayerRepository onlinePlayerRepository) + { + _onlinePlayerRepository = onlinePlayerRepository; + } + + public bool HandlePacket(IPacket packet) + { + var numTotal = packet.ReadShort(); + + if (packet.ReadByte() != 255) + return false; + + _onlinePlayerRepository.OnlinePlayers.Clear(); + for (int i = 0; i < numTotal; ++i) + { + _onlinePlayerRepository.OnlinePlayers.Add(GetNextRecord(packet)); + } + + return true; + } + + protected abstract OnlinePlayerInfo GetNextRecord(IPacket packet); + } +} diff --git a/EOLib/PacketHandlers/Init/FriendIgnoreListHandler.cs b/EOLib/PacketHandlers/Init/FriendIgnoreListHandler.cs new file mode 100644 index 000000000..7895bcd5a --- /dev/null +++ b/EOLib/PacketHandlers/Init/FriendIgnoreListHandler.cs @@ -0,0 +1,24 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Online; +using EOLib.Domain.Protocol; +using EOLib.Net; + +namespace EOLib.PacketHandlers.Init +{ + [AutoMappedType] + public class FriendIgnoreListHandler : BasePlayersListHandler + { + public override InitReply Reply => InitReply.FriendPlayersList; + + public FriendIgnoreListHandler(IOnlinePlayerRepository onlinePlayerRepository) + : base(onlinePlayerRepository) + { + } + + protected override OnlinePlayerInfo GetNextRecord(IPacket packet) + { + string name = packet.ReadBreakString(); + return new OnlinePlayerInfo(name); + } + } +} diff --git a/EOLib/PacketHandlers/Init/IInGameInitPacketHandler.cs b/EOLib/PacketHandlers/Init/IInGameInitPacketHandler.cs new file mode 100644 index 000000000..5e58644f7 --- /dev/null +++ b/EOLib/PacketHandlers/Init/IInGameInitPacketHandler.cs @@ -0,0 +1,12 @@ +using EOLib.Domain.Protocol; +using EOLib.Net; + +namespace EOLib.PacketHandlers.Init +{ + public interface IInitPacketHandler + { + InitReply Reply { get; } + + bool HandlePacket(IPacket packet); + } +} diff --git a/EOLib/PacketHandlers/Init/InGameInitPacketHandler.cs b/EOLib/PacketHandlers/Init/InGameInitPacketHandler.cs new file mode 100644 index 000000000..fd79cf219 --- /dev/null +++ b/EOLib/PacketHandlers/Init/InGameInitPacketHandler.cs @@ -0,0 +1,34 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Login; +using EOLib.Domain.Protocol; +using EOLib.Net; +using EOLib.Net.Handlers; +using Optional.Collections; +using System.Collections.Generic; + +namespace EOLib.PacketHandlers.Init +{ + [AutoMappedType] + public class InGameInitPacketHandler : InGameOnlyPacketHandler + { + private readonly IEnumerable _initPacketHandlers; + + public override PacketFamily Family => PacketFamily.Init; + + public override PacketAction Action => PacketAction.Init; + + public InGameInitPacketHandler(IPlayerInfoProvider playerInfoProvider, + IEnumerable initPacketHandlers) + : base(playerInfoProvider) + { + _initPacketHandlers = initPacketHandlers; + } + + public override bool HandlePacket(IPacket packet) + { + var reply = (InitReply)packet.ReadByte(); + return _initPacketHandlers.SingleOrNone(x => x.Reply == reply) + .Match(x => x.HandlePacket(packet), () => false); + } + } +} diff --git a/EOLib/PacketHandlers/Init/OnlinePlayerListHandler.cs b/EOLib/PacketHandlers/Init/OnlinePlayerListHandler.cs new file mode 100644 index 000000000..8e70a4236 --- /dev/null +++ b/EOLib/PacketHandlers/Init/OnlinePlayerListHandler.cs @@ -0,0 +1,52 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Online; +using EOLib.Domain.Protocol; +using EOLib.IO.Repositories; +using EOLib.Net; + +namespace EOLib.PacketHandlers.Init +{ + [AutoMappedType] + public class OnlinePlayerListHandler : BasePlayersListHandler + { + private readonly IECFFileProvider _classFileProvider; + + public override InitReply Reply => InitReply.AllPlayersList; + + public OnlinePlayerListHandler(IOnlinePlayerRepository onlinePlayerRepository, + IECFFileProvider classFileProvider) + : base(onlinePlayerRepository) + { + _classFileProvider = classFileProvider; + } + + protected override OnlinePlayerInfo GetNextRecord(IPacket packet) + { + string name = packet.ReadBreakString(); + + var title = packet.ReadBreakString(); + if (packet.ReadChar() != 0) + throw new MalformedPacketException("Expected 0 char after online entry title", packet); + + var iconType = (OnlineIcon)packet.ReadChar(); + int clsId = packet.ReadChar(); + var guild = packet.ReadBreakString(); + + name = char.ToUpper(name[0]) + name.Substring(1); + + if (string.IsNullOrWhiteSpace(title)) + title = "-"; + else + title = char.ToUpper(title[0]) + title.Substring(1); + + var className = _classFileProvider.ECFFile.Length >= clsId + ? _classFileProvider.ECFFile[clsId].Name + : "-"; + + if (string.IsNullOrWhiteSpace(guild)) + guild = "-"; + + return new OnlinePlayerInfo(name, title, guild, className, iconType); + } + } +} diff --git a/EndlessClient/Dialogs/Actions/InGameDialogActions.cs b/EndlessClient/Dialogs/Actions/InGameDialogActions.cs index 898b337f6..083c46e00 100644 --- a/EndlessClient/Dialogs/Actions/InGameDialogActions.cs +++ b/EndlessClient/Dialogs/Actions/InGameDialogActions.cs @@ -70,7 +70,7 @@ public void ShowFriendListDialog() _activeDialogRepository.FriendIgnoreDialog.MatchNone(() => { var dlg = _friendIgnoreListDialogFactory.Create(isFriendList: true); - dlg.DialogClosed += (_, _) => _activeDialogRepository.FriendIgnoreDialog = Option.None(); + dlg.DialogClosed += (_, _) => _activeDialogRepository.FriendIgnoreDialog = Option.None(); _activeDialogRepository.FriendIgnoreDialog = Option.Some(dlg); UseDefaultDialogSounds(dlg); @@ -84,7 +84,7 @@ public void ShowIgnoreListDialog() _activeDialogRepository.FriendIgnoreDialog.MatchNone(() => { var dlg = _friendIgnoreListDialogFactory.Create(isFriendList: false); - dlg.DialogClosed += (_, _) => _activeDialogRepository.FriendIgnoreDialog = Option.None(); + dlg.DialogClosed += (_, _) => _activeDialogRepository.FriendIgnoreDialog = Option.None(); _activeDialogRepository.FriendIgnoreDialog = Option.Some(dlg); UseDefaultDialogSounds(dlg); diff --git a/EndlessClient/Dialogs/ActiveDialogRepository.cs b/EndlessClient/Dialogs/ActiveDialogRepository.cs index babf4ea77..7b2405386 100644 --- a/EndlessClient/Dialogs/ActiveDialogRepository.cs +++ b/EndlessClient/Dialogs/ActiveDialogRepository.cs @@ -9,7 +9,7 @@ namespace EndlessClient.Dialogs { public interface IActiveDialogProvider : IDisposable { - Option FriendIgnoreDialog { get; } + Option FriendIgnoreDialog { get; } Option SessionExpDialog { get; } @@ -36,7 +36,7 @@ public interface IActiveDialogProvider : IDisposable public interface IActiveDialogRepository : IDisposable { - Option FriendIgnoreDialog { get; set; } + Option FriendIgnoreDialog { get; set; } Option SessionExpDialog { get; set; } @@ -64,7 +64,7 @@ public interface IActiveDialogRepository : IDisposable [AutoMappedType(IsSingleton = true)] public class ActiveDialogRepository : IActiveDialogRepository, IActiveDialogProvider { - public Option FriendIgnoreDialog { get; set; } + public Option FriendIgnoreDialog { get; set; } public Option SessionExpDialog { get; set; } @@ -116,7 +116,7 @@ public void Dispose() foreach (var dlg in ActiveDialogs) dlg.MatchSome(d => d.Dispose()); - FriendIgnoreDialog = Option.None(); + FriendIgnoreDialog = Option.None(); SessionExpDialog = Option.None(); QuestStatusDialog = Option.None(); PaperdollDialog = Option.None(); diff --git a/EndlessClient/Dialogs/Factories/FriendIgnoreListDialogFactory.cs b/EndlessClient/Dialogs/Factories/FriendIgnoreListDialogFactory.cs index 215377f7e..1e212c732 100644 --- a/EndlessClient/Dialogs/Factories/FriendIgnoreListDialogFactory.cs +++ b/EndlessClient/Dialogs/Factories/FriendIgnoreListDialogFactory.cs @@ -7,6 +7,7 @@ using EndlessClient.UIControls; using EOLib; using EOLib.Domain.Character; +using EOLib.Domain.Online; using EOLib.Graphics; using EOLib.Localization; using System; @@ -18,42 +19,42 @@ namespace EndlessClient.Dialogs.Factories [AutoMappedType] public class FriendIgnoreListDialogFactory : IFriendIgnoreListDialogFactory { - private readonly IGameStateProvider _gameStateProvider; private readonly INativeGraphicsManager _nativeGraphicsManager; private readonly IEODialogButtonService _dialogButtonService; private readonly ILocalizedStringFinder _localizedStringFinder; private readonly ICharacterProvider _characterProvider; private readonly IHudControlProvider _hudControlProvider; + private readonly IOnlinePlayerProvider _onlinePlayerProvider; private readonly ITextInputDialogFactory _textInputDialogFactory; private readonly IEOMessageBoxFactory _eoMessageBoxFactory; private readonly IFriendIgnoreListService _friendIgnoreListService; - public FriendIgnoreListDialogFactory(IGameStateProvider gameStateProvider, - INativeGraphicsManager nativeGraphicsManager, + public FriendIgnoreListDialogFactory(INativeGraphicsManager nativeGraphicsManager, IEODialogButtonService dialogButtonService, ILocalizedStringFinder localizedStringFinder, ICharacterProvider characterProvider, IHudControlProvider hudControlProvider, + IOnlinePlayerProvider onlinePlayerProvider, ITextInputDialogFactory textInputDialogFactory, IEOMessageBoxFactory eoMessageBoxFactory, IFriendIgnoreListService friendIgnoreListService) { - _gameStateProvider = gameStateProvider; _nativeGraphicsManager = nativeGraphicsManager; _dialogButtonService = dialogButtonService; _localizedStringFinder = localizedStringFinder; _characterProvider = characterProvider; _hudControlProvider = hudControlProvider; + _onlinePlayerProvider = onlinePlayerProvider; _textInputDialogFactory = textInputDialogFactory; _eoMessageBoxFactory = eoMessageBoxFactory; _friendIgnoreListService = friendIgnoreListService; } - public ScrollingListDialog Create(bool isFriendList) + public FriendIgnoreListDialog Create(bool isFriendList) { var textFileLines = _friendIgnoreListService.LoadList(isFriendList ? Constants.FriendListFile : Constants.IgnoreListFile); - var dialog = new ScrollingListDialog(_nativeGraphicsManager, _dialogButtonService) + var dialog = new FriendIgnoreListDialog(_nativeGraphicsManager, _dialogButtonService, _onlinePlayerProvider) { Buttons = ScrollingListDialogButtons.AddCancel, ListItemType = ListDialogItem.ListItemStyle.Small, @@ -134,6 +135,6 @@ private string GetDialogTitle(ScrollingListDialog dialog, bool isFriendList) public interface IFriendIgnoreListDialogFactory { - ScrollingListDialog Create(bool isFriendList); + FriendIgnoreListDialog Create(bool isFriendList); } } diff --git a/EndlessClient/Dialogs/FriendIgnoreListDialog.cs b/EndlessClient/Dialogs/FriendIgnoreListDialog.cs new file mode 100644 index 000000000..3c4e0c4b1 --- /dev/null +++ b/EndlessClient/Dialogs/FriendIgnoreListDialog.cs @@ -0,0 +1,38 @@ +using EndlessClient.Dialogs.Services; +using EOLib.Domain.Online; +using EOLib.Graphics; +using Microsoft.Xna.Framework; +using System.Collections.Generic; +using System.Linq; + +namespace EndlessClient.Dialogs +{ + public class FriendIgnoreListDialog : ScrollingListDialog + { + private readonly IOnlinePlayerProvider _onlinePlayerProvider; + + private HashSet _cachedOnlinePlayers; + + public FriendIgnoreListDialog(INativeGraphicsManager nativeGraphicsManager, + IEODialogButtonService dialogButtonService, + IOnlinePlayerProvider onlinePlayerProvider) + : base(nativeGraphicsManager, dialogButtonService, ScrollingListDialogSize.Large) + { + _onlinePlayerProvider = onlinePlayerProvider; + _cachedOnlinePlayers = new HashSet(); + } + + protected override void OnUpdateControl(GameTime gameTime) + { + if (!_cachedOnlinePlayers.SetEquals(_onlinePlayerProvider.OnlinePlayers)) + { + _cachedOnlinePlayers = _onlinePlayerProvider.OnlinePlayers.ToHashSet(); + + ClearHighlightedText(); + HighlightTextByLabel(_cachedOnlinePlayers.Select(x => x.Name).ToList()); + } + + base.OnUpdateControl(gameTime); + } + } +} diff --git a/EndlessClient/Dialogs/ListDialogItem.cs b/EndlessClient/Dialogs/ListDialogItem.cs index 939b9bfbb..7c02667c4 100644 --- a/EndlessClient/Dialogs/ListDialogItem.cs +++ b/EndlessClient/Dialogs/ListDialogItem.cs @@ -206,6 +206,12 @@ public void Highlight() _primaryText.ForeColor = Color.FromNonPremultiplied(0xf0, 0xf0, 0xf0, 0xff); } + public void ClearHighlight() + { + int colorFactor = Style == ListItemStyle.Large ? 0xc8 : 0xb4; + _primaryText.ForeColor = Color.FromNonPremultiplied(colorFactor, colorFactor, colorFactor, 0xff); + } + protected override void OnUpdateControl(GameTime gameTime) { base.OnUpdateControl(gameTime); diff --git a/EndlessClient/Dialogs/ScrollingListDialog.cs b/EndlessClient/Dialogs/ScrollingListDialog.cs index c4901c2cf..6a6886d66 100644 --- a/EndlessClient/Dialogs/ScrollingListDialog.cs +++ b/EndlessClient/Dialogs/ScrollingListDialog.cs @@ -338,6 +338,12 @@ public void HighlightTextByLabel(IReadOnlyList activeLabels) } } + public void ClearHighlightedText() + { + foreach (var item in _listItems) + item.ClearHighlight(); + } + public void ClearItemList() { foreach (var item in _listItems) diff --git a/EndlessClient/HUD/Controls/HudControlsFactory.cs b/EndlessClient/HUD/Controls/HudControlsFactory.cs index 1bbfe8282..ced76b532 100644 --- a/EndlessClient/HUD/Controls/HudControlsFactory.cs +++ b/EndlessClient/HUD/Controls/HudControlsFactory.cs @@ -214,8 +214,8 @@ private IXNAButton CreateStateChangeButton(InGameStates whichState) { DrawOrder = HUD_CONTROL_LAYER }; - retButton.OnClick += async (o, e) => await DoHudStateChangeClick(whichState); - retButton.OnMouseEnter += (o, e) => _statusLabelSetter.SetStatusLabel( + retButton.OnClick += (_, _) => DoHudStateChangeClick(whichState); + retButton.OnMouseEnter += (_, _) => _statusLabelSetter.SetStatusLabel( EOResourceID.STATUS_LABEL_TYPE_BUTTON, EOResourceID.STATUS_LABEL_HUD_BUTTON_HOVER_FIRST + buttonIndex); return retButton; @@ -231,7 +231,7 @@ private IXNAButton CreateFriendListButton() { DrawOrder = HUD_CONTROL_LAYER }; - button.OnClick += async (o, e) => await _hudButtonController.ClickFriendList(); + button.OnClick += (_, _) => _hudButtonController.ClickFriendList(); button.OnClick += (_, _) => _sfxPlayer.PlaySfx(SoundEffectID.ButtonClick); button.OnMouseOver += (o, e) => _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_BUTTON, EOResourceID.STATUS_LABEL_FRIEND_LIST); @@ -248,14 +248,14 @@ private IXNAButton CreateIgnoreListButton() { DrawOrder = HUD_CONTROL_LAYER }; - button.OnClick += async (o, e) => await _hudButtonController.ClickIgnoreList(); + button.OnClick += (_, _) => _hudButtonController.ClickIgnoreList(); button.OnClick += (_, _) => _sfxPlayer.PlaySfx(SoundEffectID.ButtonClick); button.OnMouseOver += (o, e) => _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_BUTTON, EOResourceID.STATUS_LABEL_IGNORE_LIST); return button; } - private async Task DoHudStateChangeClick(InGameStates whichState) + private void DoHudStateChangeClick(InGameStates whichState) { switch (whichState) { @@ -272,7 +272,7 @@ private async Task DoHudStateChangeClick(InGameStates whichState) _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_STATS_PANEL_NOW_VIEWED); break; case InGameStates.OnlineList: - await _hudButtonController.ClickOnlineList(); + _hudButtonController.ClickOnlineList(); _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_ONLINE_PLAYERS_NOW_VIEWED); break; case InGameStates.Party: _hudButtonController.ClickParty(); break; diff --git a/EndlessClient/HUD/HudButtonController.cs b/EndlessClient/HUD/HudButtonController.cs index 73cb03522..876b73d5a 100644 --- a/EndlessClient/HUD/HudButtonController.cs +++ b/EndlessClient/HUD/HudButtonController.cs @@ -1,14 +1,8 @@ using AutomaticTypeMapper; -using EndlessClient.ControlSets; -using EndlessClient.Dialogs; using EndlessClient.Dialogs.Actions; -using EndlessClient.HUD.Controls; -using EndlessClient.HUD.Panels; using EOLib.Domain.Interact.Quest; using EOLib.Domain.Online; using EOLib.Localization; -using System.Linq; -using System.Threading.Tasks; namespace EndlessClient.HUD { @@ -19,28 +13,22 @@ public class HudButtonController : IHudButtonController private readonly IOnlinePlayerActions _onlinePlayerActions; private readonly IInGameDialogActions _inGameDialogActions; private readonly IQuestActions _questActions; - private readonly IHudControlProvider _hudControlProvider; private readonly IStatusLabelSetter _statusLabelSetter; private readonly ILocalizedStringFinder _localizedStringFinder; - private readonly IActiveDialogProvider _activeDialogProvider; public HudButtonController(IHudStateActions hudStateActions, IOnlinePlayerActions onlinePlayerActions, IInGameDialogActions inGameDialogActions, IQuestActions questActions, - IHudControlProvider hudControlProvider, IStatusLabelSetter statusLabelSetter, - ILocalizedStringFinder localizedStringFinder, - IActiveDialogProvider activeDialogProvider) + ILocalizedStringFinder localizedStringFinder) { _hudStateActions = hudStateActions; _onlinePlayerActions = onlinePlayerActions; _inGameDialogActions = inGameDialogActions; _questActions = questActions; - _hudControlProvider = hudControlProvider; _statusLabelSetter = statusLabelSetter; _localizedStringFinder = localizedStringFinder; - _activeDialogProvider = activeDialogProvider; } public void ClickInventory() @@ -73,13 +61,10 @@ public void ClickStats() _hudStateActions.SwitchToState(InGameStates.Stats); } - public async Task ClickOnlineList() + public void ClickOnlineList() { - var onlinePlayers = await _onlinePlayerActions.GetOnlinePlayersAsync(fullList: true); + _onlinePlayerActions.RequestOnlinePlayers(fullList: true); _hudStateActions.SwitchToState(InGameStates.OnlineList); - - _hudControlProvider.GetComponent(HudControlIdentifier.OnlineListPanel) - .UpdateOnlinePlayers(onlinePlayers); } public void ClickParty() @@ -97,24 +82,20 @@ public void ClickHelp() _hudStateActions.SwitchToState(InGameStates.Help); } - public async Task ClickFriendList() + public void ClickFriendList() { _inGameDialogActions.ShowFriendListDialog(); - - var onlinePlayers = await _onlinePlayerActions.GetOnlinePlayersAsync(fullList: false); - _activeDialogProvider.FriendIgnoreDialog.MatchSome(dlg => dlg.HighlightTextByLabel(onlinePlayers.Select(x => x.Name).ToList())); + _onlinePlayerActions.RequestOnlinePlayers(fullList: false); _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_FRIEND_LIST, _localizedStringFinder.GetString(EOResourceID.STATUS_LABEL_USE_RIGHT_MOUSE_CLICK_DELETE)); } - public async Task ClickIgnoreList() + public void ClickIgnoreList() { _inGameDialogActions.ShowIgnoreListDialog(); - - var onlinePlayers = await _onlinePlayerActions.GetOnlinePlayersAsync(fullList: false); - _activeDialogProvider.FriendIgnoreDialog.MatchSome(dlg => dlg.HighlightTextByLabel(onlinePlayers.Select(x => x.Name).ToList())); + _onlinePlayerActions.RequestOnlinePlayers(fullList: false); _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_IGNORE_LIST, diff --git a/EndlessClient/HUD/IHudButtonController.cs b/EndlessClient/HUD/IHudButtonController.cs index ecc327ee1..34c8a875c 100644 --- a/EndlessClient/HUD/IHudButtonController.cs +++ b/EndlessClient/HUD/IHudButtonController.cs @@ -1,6 +1,4 @@ -using System.Threading.Tasks; - -namespace EndlessClient.HUD +namespace EndlessClient.HUD { public interface IHudButtonController { @@ -16,7 +14,7 @@ public interface IHudButtonController void ClickStats(); - Task ClickOnlineList(); + void ClickOnlineList(); void ClickParty(); @@ -24,9 +22,9 @@ public interface IHudButtonController void ClickHelp(); - Task ClickFriendList(); + void ClickFriendList(); - Task ClickIgnoreList(); + void ClickIgnoreList(); void ClickSessionExp(); diff --git a/EndlessClient/HUD/Panels/HudPanelFactory.cs b/EndlessClient/HUD/Panels/HudPanelFactory.cs index 066a0af72..dfa57ae53 100644 --- a/EndlessClient/HUD/Panels/HudPanelFactory.cs +++ b/EndlessClient/HUD/Panels/HudPanelFactory.cs @@ -15,6 +15,7 @@ using EOLib.Domain.Chat; using EOLib.Domain.Item; using EOLib.Domain.Login; +using EOLib.Domain.Online; using EOLib.Graphics; using EOLib.IO.Repositories; using EOLib.Localization; @@ -49,6 +50,7 @@ public class HudPanelFactory : IHudPanelFactory private readonly IActiveDialogProvider _activeDialogProvider; private readonly ISpellSlotDataRepository _spellSlotDataRepository; private readonly IConfigurationRepository _configurationRepository; + private readonly IOnlinePlayerProvider _onlinePlayerProvider; private readonly ILocalizedStringFinder _localizedStringFinder; private readonly IAudioActions _audioActions; private readonly ISfxPlayer _sfxPlayer; @@ -76,6 +78,7 @@ public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, IActiveDialogProvider activeDialogProvider, ISpellSlotDataRepository spellSlotDataRepository, IConfigurationRepository configurationRepository, + IOnlinePlayerProvider onlinePlayerProvider, ILocalizedStringFinder localizedStringFinder, IAudioActions audioActions, ISfxPlayer sfxPlayer) @@ -103,6 +106,7 @@ public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, _activeDialogProvider = activeDialogProvider; _spellSlotDataRepository = spellSlotDataRepository; _configurationRepository = configurationRepository; + _onlinePlayerProvider = onlinePlayerProvider; _localizedStringFinder = localizedStringFinder; _audioActions = audioActions; _sfxPlayer = sfxPlayer; @@ -180,7 +184,7 @@ public StatsPanel CreateStatsPanel() public OnlineListPanel CreateOnlineListPanel() { var chatFont = _contentProvider.Fonts[Constants.FontSize08]; - return new OnlineListPanel(_nativeGraphicsManager, _hudControlProvider, _friendIgnoreListService, _sfxPlayer, chatFont) { DrawOrder = HUD_CONTROL_LAYER }; + return new OnlineListPanel(_nativeGraphicsManager, _hudControlProvider, _onlinePlayerProvider, _friendIgnoreListService, _sfxPlayer, chatFont) { DrawOrder = HUD_CONTROL_LAYER }; } public PartyPanel CreatePartyPanel() diff --git a/EndlessClient/HUD/Panels/OnlineListPanel.cs b/EndlessClient/HUD/Panels/OnlineListPanel.cs index ac236e13e..15a9512f0 100644 --- a/EndlessClient/HUD/Panels/OnlineListPanel.cs +++ b/EndlessClient/HUD/Panels/OnlineListPanel.cs @@ -34,6 +34,7 @@ private enum Filter private readonly INativeGraphicsManager _nativeGraphicsManager; private readonly IHudControlProvider _hudControlProvider; + private readonly IOnlinePlayerProvider _onlinePlayerProvider; private readonly IFriendIgnoreListService _friendIgnoreListService; private readonly ISfxPlayer _sfxPlayer; @@ -47,18 +48,22 @@ private enum Filter private readonly Texture2D _weirdOffsetTextureSheet, _chatIconsTexture; private readonly Rectangle[] _filterTextureSources; + private HashSet _cachedList; + private Filter _filter; private List _filteredList; private IReadOnlyList _friendList; public OnlineListPanel(INativeGraphicsManager nativeGraphicsManager, IHudControlProvider hudControlProvider, + IOnlinePlayerProvider onlinePlayerProvider, IFriendIgnoreListService friendIgnoreListService, ISfxPlayer sfxPlayer, SpriteFont chatFont) { _nativeGraphicsManager = nativeGraphicsManager; _hudControlProvider = hudControlProvider; + _onlinePlayerProvider = onlinePlayerProvider; _friendIgnoreListService = friendIgnoreListService; _sfxPlayer = sfxPlayer; _chatFont = chatFont; @@ -93,6 +98,7 @@ public OnlineListPanel(INativeGraphicsManager nativeGraphicsManager, for (int i = 0; i < _filterTextureSources.Length; ++i) _filterTextureSources[i] = new Rectangle(i % 2 == 0 ? 0 : 12, i >= 2 ? 246 : 233, 12, 13); + _cachedList = new HashSet(); _filter = Filter.All; _filteredList = new List(); } @@ -107,21 +113,34 @@ public override void Initialize() public void UpdateOnlinePlayers(IReadOnlyList onlinePlayers) { - _onlineList.Clear(); - _onlineList.AddRange(onlinePlayers); - - _onlineList.Sort((a, b) => a.Name.CompareTo(b.Name)); - _filteredList = new List(_onlineList); - - _totalNumberOfPlayers.Text = $"{_onlineList.Count}"; - _scrollBar.UpdateDimensions(_onlineList.Count); - _scrollBar.ScrollToTop(); - - _friendList = _friendIgnoreListService.LoadList(Constants.FriendListFile); } protected override void OnUpdateControl(GameTime gameTime) { + if (!_cachedList.SetEquals(_onlinePlayerProvider.OnlinePlayers)) + { + _cachedList = _onlinePlayerProvider.OnlinePlayers.ToHashSet(); + + // keep the friends list data from overriding the displayed data in this panel + // it will be friends list data if all titles (or any field other than name) are empty + if (!_cachedList.All(x => x.Title == string.Empty)) + { + _onlineList.Clear(); + _onlineList.AddRange(_cachedList); + + _onlineList.Sort((a, b) => a.Name.CompareTo(b.Name)); + _filteredList = new List(_onlineList); + + _totalNumberOfPlayers.Text = $"{_onlineList.Count}"; + _scrollBar.UpdateDimensions(_onlineList.Count); + _scrollBar.ScrollToTop(); + + _friendList = _friendIgnoreListService.LoadList(Constants.FriendListFile); + + ApplyFilter(); + } + } + if (_filterClickArea.ContainsPoint(CurrentMouseState.X, CurrentMouseState.Y) && CurrentMouseState.LeftButton == ButtonState.Released && PreviousMouseState.LeftButton == ButtonState.Pressed) @@ -134,17 +153,7 @@ protected override void OnUpdateControl(GameTime gameTime) _scrollBar.ScrollToTop(); - switch (_filter) - { - case Filter.Friends: _filteredList = _onlineList.Where(x => _friendList.Contains(x.Name, StringComparer.InvariantCultureIgnoreCase)).ToList(); break; - case Filter.Admins: _filteredList = _onlineList.Where(IsAdminIcon).ToList(); break; - // todo: implement for party/guild - case Filter.Party: _filteredList.Clear(); break; - case Filter.All: - default: _filteredList = new List(_onlineList); break; - } - - _scrollBar.UpdateDimensions(_filteredList.Count); + ApplyFilter(); } else if (CurrentMouseState.RightButton == ButtonState.Released && PreviousMouseState.RightButton == ButtonState.Pressed) @@ -193,6 +202,21 @@ protected override void OnDrawControl(GameTime gameTime) _spriteBatch.End(); } + private void ApplyFilter() + { + switch (_filter) + { + case Filter.Friends: _filteredList = _onlineList.Where(x => _friendList.Contains(x.Name, StringComparer.InvariantCultureIgnoreCase)).ToList(); break; + case Filter.Admins: _filteredList = _onlineList.Where(IsAdminIcon).ToList(); break; + // todo: implement for party/guild + case Filter.Party: _filteredList.Clear(); break; + case Filter.All: + default: _filteredList = new List(_onlineList); break; + } + + _scrollBar.UpdateDimensions(_filteredList.Count); + } + private static bool IsAdminIcon(OnlinePlayerInfo onlineInfo) { switch (onlineInfo.Icon) From 718c2dcda6163a835ca7a35a40fd3135d0e7cf97 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Fri, 27 May 2022 15:15:17 -0700 Subject: [PATCH 2/3] Prevent crash when someone is emoting while logging in --- .../Rendering/Character/CharacterAnimationActions.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/EndlessClient/Rendering/Character/CharacterAnimationActions.cs b/EndlessClient/Rendering/Character/CharacterAnimationActions.cs index 68f3206a9..3dfe9a378 100644 --- a/EndlessClient/Rendering/Character/CharacterAnimationActions.cs +++ b/EndlessClient/Rendering/Character/CharacterAnimationActions.cs @@ -254,7 +254,14 @@ public void NotifyMapEffect(MapEffect effect, byte strength = 0) public void NotifyEmote(short playerId, Emote emote) { - Animator.Emote(playerId, emote); + try + { + Animator.Emote(playerId, emote); + } + catch (InvalidOperationException) + { + // if still transitioning to in-game state, the game will crash because the in-game control set is not completely set up yet + } } public void MakeMainPlayerDrunk() From 3cb7441e7651388efdb439119f9a2531e88dbcb8 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Fri, 27 May 2022 19:07:46 -0700 Subject: [PATCH 3/3] Implement map mutation --- EOLib/Domain/Notifiers/IMapChangedNotifier.cs | 4 + EOLib/Net/API/Init.cs | 109 ------------------ EOLib/Net/API/PacketAPI.cs | 8 -- .../PacketHandlers/Init/MapMutationHandler.cs | 57 +++++++++ EndlessClient/Audio/SoundEffectID.cs | 1 + EndlessClient/Old/OldWorld.cs | 37 ------ EndlessClient/Old/PacketAPICallbackManager.cs | 18 --- .../Rendering/Map/MapChangedActions.cs | 23 ++++ 8 files changed, 85 insertions(+), 172 deletions(-) delete mode 100644 EOLib/Net/API/Init.cs create mode 100644 EOLib/PacketHandlers/Init/MapMutationHandler.cs diff --git a/EOLib/Domain/Notifiers/IMapChangedNotifier.cs b/EOLib/Domain/Notifiers/IMapChangedNotifier.cs index cbc9094e4..24ffad95e 100644 --- a/EOLib/Domain/Notifiers/IMapChangedNotifier.cs +++ b/EOLib/Domain/Notifiers/IMapChangedNotifier.cs @@ -6,11 +6,15 @@ namespace EOLib.Domain.Notifiers public interface IMapChangedNotifier { void NotifyMapChanged(WarpAnimation warpAnimation, bool differentMapID); + + void NotifyMapMutation(); } [AutoMappedType] public class NoOpMapChangedNotifier : IMapChangedNotifier { public void NotifyMapChanged(WarpAnimation warpAnimation, bool differentMapID) { } + + public void NotifyMapMutation() { } } } diff --git a/EOLib/Net/API/Init.cs b/EOLib/Net/API/Init.cs deleted file mode 100644 index 43151a7bf..000000000 --- a/EOLib/Net/API/Init.cs +++ /dev/null @@ -1,109 +0,0 @@ -using EOLib.Net.Handlers; -using System; -using System.IO; -using System.Threading; - -namespace EOLib.Net.API -{ - public enum InitReply : byte - { - INIT_OUT_OF_DATE = 1, - INIT_OK = 2, - INIT_BANNED = 3, - INIT_FILE_MAP = 4, - INIT_FILE_EIF = 5, - INIT_FILE_ENF = 6, - INIT_FILE_ESF = 7, - INIT_PLAYERS = 8, - INIT_MAP_MUTATION = 9, - INIT_FRIEND_LIST_PLAYERS = 10, - INIT_FILE_ECF = 11, - THIS_IS_WRONG = 0 - } - - public enum PaperdollIconType - { - Normal = 0, - GM = 4, - HGM = 5, - Party = 6, - GMParty = 9, - HGMParty = 10, - SLNBot = 20 - } - - public partial class PacketAPI - { - private AutoResetEvent m_init_responseEvent; - - //shared between API calls and response handler - private int m_init_requestedMap; - - public event Action OnMapMutation; - - private void _createInitMembers() - { - m_init_responseEvent = new AutoResetEvent(false); - - m_init_requestedMap = 0; - - m_client.AddPacketHandler(new FamilyActionPair(PacketFamily.Init, PacketAction.Init), _handleInitInit, false); - } - - private void _disposeInitMembers() - { - if (m_init_responseEvent != null) - { - m_init_responseEvent.Dispose(); - m_init_responseEvent = null; - } - } - - private void _handleInitInit(OldPacket pkt) - { - InitReply response = (InitReply)pkt.GetByte(); - switch (response) - { - case InitReply.INIT_MAP_MUTATION: - { - string localDir = response == InitReply.INIT_FILE_MAP || response == InitReply.INIT_MAP_MUTATION ? "maps" : "pub"; - - if (response == InitReply.INIT_MAP_MUTATION) - m_init_requestedMap = 0; - - if (!Directory.Exists(localDir)) - Directory.CreateDirectory(localDir); - - string filename; - if (response == InitReply.INIT_FILE_EIF) - filename = "dat001.eif"; - else if (response == InitReply.INIT_FILE_ENF) - filename = "dtn001.enf"; - else if (response == InitReply.INIT_FILE_ESF) - filename = "dsl001.esf"; - else if (response == InitReply.INIT_FILE_ECF) - filename = "dat001.ecf"; - else - filename = $"{m_init_requestedMap,5:D5}.emf"; - - using (FileStream fs = File.Create(Path.Combine(localDir, filename))) - { - int dataLen = pkt.Length - 3; - if (dataLen == 0) - return; //trigger error by not setting response event - fs.Write(pkt.GetBytes(dataLen), 0, dataLen); - } - - if (response == InitReply.INIT_MAP_MUTATION && OnMapMutation != null) - { - OnMapMutation(); - } - } - break; - } - - m_client.ExpectingFile = false; - m_init_responseEvent.Set(); //packet was handled - } - } -} diff --git a/EOLib/Net/API/PacketAPI.cs b/EOLib/Net/API/PacketAPI.cs index d8af20ad0..33ed558fd 100644 --- a/EOLib/Net/API/PacketAPI.cs +++ b/EOLib/Net/API/PacketAPI.cs @@ -20,7 +20,6 @@ public PacketAPI(EOClient client) m_client = client; //each of these sets up members of the partial PacketAPI class relevant to a particular packet family - _createInitMembers(); _createPartyMembers(); _createNPCMembers(); _createSpellMembers(); @@ -29,13 +28,6 @@ public PacketAPI(EOClient client) public void Dispose() { - Dispose(true); - } - - private void Dispose(bool disposing) - { - if (disposing) - _disposeInitMembers(); } } } diff --git a/EOLib/PacketHandlers/Init/MapMutationHandler.cs b/EOLib/PacketHandlers/Init/MapMutationHandler.cs new file mode 100644 index 000000000..1870f979e --- /dev/null +++ b/EOLib/PacketHandlers/Init/MapMutationHandler.cs @@ -0,0 +1,57 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Character; +using EOLib.Domain.Map; +using EOLib.Domain.Notifiers; +using EOLib.Domain.Protocol; +using EOLib.IO.Map; +using EOLib.IO.Repositories; +using EOLib.IO.Services; +using EOLib.IO.Services.Serializers; +using EOLib.Net; +using System.Collections.Generic; +using System.Linq; + +namespace EOLib.PacketHandlers.Init +{ + [AutoMappedType] + public class MapMutationHandler : IInitPacketHandler + { + private readonly IMapFileRepository _mapFileRepository; + private readonly IMapDeserializer _mapFileDeserializer; + private readonly IMapFileSaveService _mapFileSaveService; + private readonly ICharacterProvider _characterProvider; + private readonly IEnumerable _mapChangedNotifiers; + + public InitReply Reply => InitReply.MapMutation; + + public MapMutationHandler(IMapFileRepository mapFileRepository, + IMapDeserializer mapFileDeserializer, + IMapFileSaveService mapFileSaveService, + ICharacterProvider characterProvider, + IEnumerable mapChangedNotifiers) + { + _mapFileRepository = mapFileRepository; + _mapFileDeserializer = mapFileDeserializer; + _mapFileSaveService = mapFileSaveService; + _characterProvider = characterProvider; + _mapChangedNotifiers = mapChangedNotifiers; + } + + public bool HandlePacket(IPacket packet) + { + var mapID = _characterProvider.MainCharacter.MapID; + var fileData = packet.ReadBytes(packet.Length - packet.ReadPosition); + var mapFile = _mapFileDeserializer + .DeserializeFromByteArray(fileData.ToArray()) + .WithMapID(mapID); + + _mapFileRepository.MapFiles[mapID] = mapFile; + _mapFileSaveService.SaveFileToDefaultDirectory(mapFile, rewriteChecksum: false); + + foreach (var notifier in _mapChangedNotifiers) + notifier.NotifyMapMutation(); + + return true; + } + } +} diff --git a/EndlessClient/Audio/SoundEffectID.cs b/EndlessClient/Audio/SoundEffectID.cs index 23d0a7b0d..435e0d299 100644 --- a/EndlessClient/Audio/SoundEffectID.cs +++ b/EndlessClient/Audio/SoundEffectID.cs @@ -15,6 +15,7 @@ public enum SoundEffectID Login = 4, ServerMessage = Login, DeleteCharacter, + MapMutation = DeleteCharacter, UnknownStaticSound, ScreenCapture, PrivateMessageReceived = 8, diff --git a/EndlessClient/Old/OldWorld.cs b/EndlessClient/Old/OldWorld.cs index 5430928b5..633848024 100644 --- a/EndlessClient/Old/OldWorld.cs +++ b/EndlessClient/Old/OldWorld.cs @@ -143,9 +143,6 @@ public EOLanguage Language public short JailMap { get; private set; } - //this is an int for the map id since there are multiple maps - public int NeedMap { get; private set; } - public IPubFile EIF { get; private set; } public IPubFile ENF { get; private set; } @@ -222,13 +219,6 @@ public OldCharacterRenderer ActiveCharacterRenderer public ClientBase Client => m_client; /*** Functions for loading/checking the different pub/map files ***/ - - //tries to load the map that MainPlayer.ActiveCharacter is hanging out on - private bool _tryLoadMap(int mapID, bool forceReload) - { - return true; - } - public void ResetGameElements() { if (m_mapRender != null) @@ -266,36 +256,9 @@ private void Dispose(bool disposing) } } - public void Remap() - { - MapCache.Remove(MainPlayer.ActiveCharacter.CurrentMap); - if (!_tryLoadMap(-1, true)) - { - EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); - return; - } - - //EOGame.Instance.Hud.AddChat(ChatTab.Local, GetString(EOResourceID.STRING_SERVER), GetString(EOResourceID.SERVER_MESSAGE_MAP_MUTATION), ChatIcon.Exclamation, ChatColor.Server); - //EOGame.Instance.Hud.AddChat(ChatTab.System, GetString(EOResourceID.STRING_SERVER), GetString(EOResourceID.SERVER_MESSAGE_MAP_MUTATION), ChatIcon.Exclamation, ChatColor.Server); - - ActiveMapRenderer.SetActiveMap(MapCache[MainPlayer.ActiveCharacter.CurrentMap]); - } - public static void IgnoreDialogs(XNAControl control) { control.IgnoreDialog(typeof(TradeDialog)); } - - public static Texture2D GetSpellIcon(short icon, bool hover) - { - Texture2D fullTexture = EOGame.Instance.GFXManager.TextureFromResource(GFXTypes.SpellIcons, icon); - Texture2D ret = new Texture2D(fullTexture.GraphicsDevice, fullTexture.Width / 2, fullTexture.Height); - - Color[] data = new Color[ret.Width * ret.Height]; - fullTexture.GetData(0, new Rectangle(hover ? ret.Width : 0, 0, ret.Width, ret.Height), data, 0, data.Length); - ret.SetData(data); - - return ret; - } } } diff --git a/EndlessClient/Old/PacketAPICallbackManager.cs b/EndlessClient/Old/PacketAPICallbackManager.cs index 27bcdaac7..22dda09f3 100644 --- a/EndlessClient/Old/PacketAPICallbackManager.cs +++ b/EndlessClient/Old/PacketAPICallbackManager.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.IO; -using EndlessClient.Audio; using EndlessClient.Dialogs; using EndlessClient.Dialogs.Old; using EOLib.Domain.Character; @@ -24,8 +22,6 @@ public PacketAPICallbackManager(PacketAPI apiObj, EOGame game) public void AssignCallbacks() { - m_packetAPI.OnMapMutation += _mapMutate; - //npc related m_packetAPI.OnRemoveChildNPCs += _removeChildNPCs; @@ -49,20 +45,6 @@ public void AssignCallbacks() m_packetAPI.OnCastSpellTargetGroup += _playerCastGroupSpell; } - private void _mapMutate() - { - if (File.Exists("maps\\00000.emf")) - { - string fmt = $"maps\\{OldWorld.Instance.MainPlayer.ActiveCharacter.CurrentMap,5:D5}.emf"; - if (File.Exists(fmt)) - File.Delete(fmt); - File.Move("maps\\00000.emf", fmt); - OldWorld.Instance.Remap(); - } - else - throw new FileNotFoundException("Unable to remap the file, something broke"); - } - private void _removeChildNPCs(short childNPCID) { OldWorld.Instance.ActiveMapRenderer.RemoveNPCsWhere(x => x.NPC.Data.ID == childNPCID); diff --git a/EndlessClient/Rendering/Map/MapChangedActions.cs b/EndlessClient/Rendering/Map/MapChangedActions.cs index 1dee65e00..f9334a410 100644 --- a/EndlessClient/Rendering/Map/MapChangedActions.cs +++ b/EndlessClient/Rendering/Map/MapChangedActions.cs @@ -84,6 +84,24 @@ public void NotifyMapChanged(WarpAnimation warpAnimation, bool differentMapID) RedrawGroundLayer(); } + public void NotifyMapMutation() + { + ClearOpenDoors(); + ClearSpikeTraps(); + + ShowMapTransition(showMapTransition: true); + + AddSpikeTraps(); + RedrawGroundLayer(); + + var localChatData = new ChatData(ChatTab.Local, _localizedStringFinder.GetString(EOResourceID.STRING_SERVER), _localizedStringFinder.GetString(EOResourceID.SERVER_MESSAGE_MAP_MUTATION), ChatIcon.Exclamation, ChatColor.Server); + var systemChatData = new ChatData(ChatTab.System, _localizedStringFinder.GetString(EOResourceID.STRING_SERVER), _localizedStringFinder.GetString(EOResourceID.SERVER_MESSAGE_MAP_MUTATION), ChatIcon.Exclamation, ChatColor.Server); + _chatRepository.AllChat[ChatTab.Local].Add(localChatData); + _chatRepository.AllChat[ChatTab.System].Add(systemChatData); + + _sfxPlayer.PlaySfx(SoundEffectID.MapMutation); + } + private void StopAllAnimations() { var characterAnimator = _hudControlProvider.GetComponent(HudControlIdentifier.CharacterAnimator); @@ -116,6 +134,11 @@ private void ClearOpenDoors() _currentMapStateRepository.OpenDoors.Clear(); } + private void ClearSpikeTraps() + { + _currentMapStateRepository.VisibleSpikeTraps.Clear(); + } + private void ShowMapNameIfAvailable(bool differentMapID) { if (!differentMapID || string.IsNullOrWhiteSpace(_currentMapProvider.CurrentMap.Properties.Name))