From ebcb528e7524410fcb6e2ee1bc8aad936d4f56dc Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Thu, 4 May 2023 17:02:52 -0700 Subject: [PATCH] Update algorithm for AFK timer to be accurate to EO main --- EOLib.Localization/EOResourceID.cs | 4 + .../HUD/Controls/HudControlsFactory.cs | 8 +- .../HUD/Controls/IHudControlsFactory.cs | 2 +- .../EndlessClientInitializer.cs | 2 +- .../Character/PeriodicEmoteHandler.cs | 100 ++++++++++++++---- 5 files changed, 94 insertions(+), 22 deletions(-) diff --git a/EOLib.Localization/EOResourceID.cs b/EOLib.Localization/EOResourceID.cs index ecbc3ffcd..72e003583 100644 --- a/EOLib.Localization/EOResourceID.cs +++ b/EOLib.Localization/EOResourceID.cs @@ -177,6 +177,10 @@ public enum EOResourceID DIALOG_PERFORMANCE_BEST_KILL = 293, DIALOG_PERFORMANCE_LAST_KILL = 294, + IDLE_TOO_LONG = 295, + IDLE_PLEASE_START_MOVING = 296, + + SKILLMASTER_WORD_SPELL = 297, SKILLMASTER_WORD_SKILL = 298, SPELL_WAS_SELECTED = 299, diff --git a/EndlessClient/HUD/Controls/HudControlsFactory.cs b/EndlessClient/HUD/Controls/HudControlsFactory.cs index 52548059e..5fedb29a2 100644 --- a/EndlessClient/HUD/Controls/HudControlsFactory.cs +++ b/EndlessClient/HUD/Controls/HudControlsFactory.cs @@ -67,7 +67,9 @@ public class HudControlsFactory : IHudControlsFactory private readonly INewsProvider _newsProvider; private readonly IFixedTimeStepRepository _fixedTimeStepRepository; private readonly IClickDispatcherFactory _clickDispatcherFactory; + private IChatController _chatController; + private IMainButtonController _mainButtonController; public HudControlsFactory(IHudButtonController hudButtonController, IHudPanelFactory hudPanelFactory, @@ -130,9 +132,11 @@ public HudControlsFactory(IHudButtonController hudButtonController, _clickDispatcherFactory = clickDispatcherFactory; } - public void InjectChatController(IChatController chatController) + public void InjectChatController(IChatController chatController, + IMainButtonController mainButtonController) { _chatController = chatController; + _mainButtonController = mainButtonController; } public IReadOnlyDictionary CreateHud() @@ -567,7 +571,7 @@ private INPCAnimator CreateNPCAnimator() private IPeriodicEmoteHandler CreatePeriodicEmoteHandler(ICharacterAnimator characterAnimator) { - return new PeriodicEmoteHandler(_endlessGameProvider, _characterActions, _userInputTimeProvider, _characterRepository, characterAnimator); + return new PeriodicEmoteHandler(_endlessGameProvider, _characterActions, _userInputTimeProvider, _characterRepository, characterAnimator, _statusLabelSetter, _mainButtonController); } private PreviousUserInputTracker CreatePreviousUserInputTracker() diff --git a/EndlessClient/HUD/Controls/IHudControlsFactory.cs b/EndlessClient/HUD/Controls/IHudControlsFactory.cs index 0778480e2..2b7c2d115 100644 --- a/EndlessClient/HUD/Controls/IHudControlsFactory.cs +++ b/EndlessClient/HUD/Controls/IHudControlsFactory.cs @@ -6,7 +6,7 @@ namespace EndlessClient.HUD.Controls { public interface IHudControlsFactory { - void InjectChatController(IChatController chatController); + void InjectChatController(IChatController chatController, IMainButtonController mainButtonController); IReadOnlyDictionary CreateHud(); } diff --git a/EndlessClient/Initialization/EndlessClientInitializer.cs b/EndlessClient/Initialization/EndlessClientInitializer.cs index e6b0f9e2a..4bd7b6e21 100644 --- a/EndlessClient/Initialization/EndlessClientInitializer.cs +++ b/EndlessClient/Initialization/EndlessClientInitializer.cs @@ -92,7 +92,7 @@ public void Initialize() _characterManagementController); _characterInfoPanelFactory.InjectCharacterManagementController(_characterManagementController); _characterInfoPanelFactory.InjectLoginController(_loginController); - _hudControlsFactory.InjectChatController(_chatController); + _hudControlsFactory.InjectChatController(_chatController, _mainButtonController); _paperdollDialogFactory.InjectInventoryController(_inventoryController); } } diff --git a/EndlessClient/Rendering/Character/PeriodicEmoteHandler.cs b/EndlessClient/Rendering/Character/PeriodicEmoteHandler.cs index fd1bb2b0c..286dcf8d8 100644 --- a/EndlessClient/Rendering/Character/PeriodicEmoteHandler.cs +++ b/EndlessClient/Rendering/Character/PeriodicEmoteHandler.cs @@ -1,6 +1,9 @@ -using EndlessClient.GameExecution; +using EndlessClient.Controllers; +using EndlessClient.GameExecution; +using EndlessClient.HUD; using EndlessClient.Input; using EOLib.Domain.Character; +using EOLib.Localization; using Microsoft.Xna.Framework; using Optional; using System; @@ -10,13 +13,24 @@ namespace EndlessClient.Rendering.Character { public class PeriodicEmoteHandler : GameComponent, IPeriodicEmoteHandler { - private const int AFK_TIME_MINUTES = 5; - private const int AFK_TIME_BETWEEN_EMOTES_MINUTES = 1; + // Time before periodic AFK emotes start firing (5 minutes) + private const int AFK_TIME_MS = 300000; + // Time between each emote once period emotes start firing (30 seconds) + private const int AFK_TIME_BETWEEN_EMOTES_MS = 30000; + + // Time before periodic alert messages start firing (30 minutes) + private const int AFK_TIME_ALERT_MS = 1800000; + // Time between each periodic alert message fires (60 seconds) + private const int AFK_TIME_BETWEEN_ALERTS_MS = 60000; + // Time between first alert and alternate alert (3.6 seconds) + private const int AFK_TIME_ALT_ALERT_MS = 3600; private readonly ICharacterActions _characterActions; private readonly IUserInputTimeProvider _userInputTimeProvider; private readonly ICharacterRepository _characterRepository; private readonly ICharacterAnimator _animator; + private readonly IStatusLabelSetter _statusLabelSetter; + private readonly IMainButtonController _mainButtonController; private readonly Random _random; @@ -26,19 +40,24 @@ public class PeriodicEmoteHandler : GameComponent, IPeriodicEmoteHandler private double _drunkTimeoutSeconds; private Option _afkTimeSinceLastEmote; + private Option _afkTimeSinceLastAlert; + private bool _altAlert; public PeriodicEmoteHandler(IEndlessGameProvider endlessGameProvider, ICharacterActions characterActions, IUserInputTimeProvider userInputTimeProvider, ICharacterRepository characterRepository, - ICharacterAnimator animator) + ICharacterAnimator animator, + IStatusLabelSetter statusLabelSetter, + IMainButtonController mainButtonController) : base((Game)endlessGameProvider.Game) { _characterActions = characterActions; _userInputTimeProvider = userInputTimeProvider; _characterRepository = characterRepository; _animator = animator; - + _statusLabelSetter = statusLabelSetter; + _mainButtonController = mainButtonController; _random = new Random(); } @@ -84,24 +103,69 @@ public override void Update(GameTime gameTime) } }); - if ((DateTime.Now - _userInputTimeProvider.LastInputTime).TotalMinutes >= AFK_TIME_MINUTES) + var now = DateTime.Now; + + if ((now - _userInputTimeProvider.LastInputTime).TotalMilliseconds >= AFK_TIME_MS) { - _afkTimeSinceLastEmote.Match( - some: at => - { - if (at.Elapsed.TotalMinutes >= AFK_TIME_BETWEEN_EMOTES_MINUTES) + if ((now - _userInputTimeProvider.LastInputTime).TotalMilliseconds >= AFK_TIME_MS + AFK_TIME_ALERT_MS) + { + _mainButtonController.GoToInitialStateAndDisconnect(); + } + else + { + _afkTimeSinceLastEmote.Match( + some: at => { - if (_animator.Emote(_characterRepository.MainCharacter.ID, Emote.Moon)) + if (at.ElapsedMilliseconds >= AFK_TIME_BETWEEN_EMOTES_MS) + { + _animator.Emote(_characterRepository.MainCharacter.ID, Emote.Moon); _characterActions.Emote(Emote.Moon); + _afkTimeSinceLastEmote = Option.Some(Stopwatch.StartNew()); + } + }, + none: () => + { + _animator.Emote(_characterRepository.MainCharacter.ID, Emote.Moon); + _characterActions.Emote(Emote.Moon); _afkTimeSinceLastEmote = Option.Some(Stopwatch.StartNew()); - } - }, - none: () => + }); + + if ((DateTime.Now - _userInputTimeProvider.LastInputTime).TotalMilliseconds >= AFK_TIME_ALERT_MS) { - if (_animator.Emote(_characterRepository.MainCharacter.ID, Emote.Moon)) - _characterActions.Emote(Emote.Moon); - _afkTimeSinceLastEmote = Option.Some(Stopwatch.StartNew()); - }); + _afkTimeSinceLastAlert.Match( + some: at => + { + if (at.ElapsedMilliseconds >= AFK_TIME_BETWEEN_ALERTS_MS) + { + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_WARNING, EOResourceID.IDLE_TOO_LONG); + _afkTimeSinceLastAlert = Option.Some(Stopwatch.StartNew()); + _altAlert = false; + } + }, + none: () => + { + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_WARNING, EOResourceID.IDLE_TOO_LONG); + _afkTimeSinceLastAlert = Option.Some(Stopwatch.StartNew()); + _altAlert = false; + }); + + _afkTimeSinceLastAlert.Match( + some: at => + { + if (at.ElapsedMilliseconds >= AFK_TIME_ALT_ALERT_MS && !_altAlert) + { + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_WARNING, EOResourceID.IDLE_PLEASE_START_MOVING); + _altAlert = true; + } + }, + none: () => _altAlert = false); + } + } + } + else + { + _afkTimeSinceLastEmote = Option.None(); + _afkTimeSinceLastAlert = Option.None(); } base.Update(gameTime);