From 239c61ab4796b5ecafd7dd316f55c62a7c8086c1 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Thu, 4 May 2023 11:29:44 -0700 Subject: [PATCH] In fixed window size mode, remove NPCs/characters that are out of range. Fixes display bugs with GameServer/resoserv. --- .../HUD/Controls/HudControlsFactory.cs | 2 +- .../Network/UnknownEntitiesRequester.cs | 74 ++++++++++++++++++- .../Rendering/NPC/NPCRendererUpdater.cs | 20 +++++ 3 files changed, 92 insertions(+), 4 deletions(-) diff --git a/EndlessClient/HUD/Controls/HudControlsFactory.cs b/EndlessClient/HUD/Controls/HudControlsFactory.cs index ee480b465..52548059e 100644 --- a/EndlessClient/HUD/Controls/HudControlsFactory.cs +++ b/EndlessClient/HUD/Controls/HudControlsFactory.cs @@ -533,7 +533,7 @@ private PeriodicStatUpdaterComponent CreatePeriodicStatUpdater() private UnknownEntitiesRequester CreateUnknownEntitiesRequester() { - return new UnknownEntitiesRequester(_endlessGameProvider, _currentMapStateRepository, _packetSendService); + return new UnknownEntitiesRequester(_endlessGameProvider, _clientWindowSizeRepository, (ICharacterProvider)_characterRepository, _currentMapStateRepository, _packetSendService); } private StatusBarLabel CreateStatusLabel() diff --git a/EndlessClient/Network/UnknownEntitiesRequester.cs b/EndlessClient/Network/UnknownEntitiesRequester.cs index 76d9edb8a..c2a2f02c3 100644 --- a/EndlessClient/Network/UnknownEntitiesRequester.cs +++ b/EndlessClient/Network/UnknownEntitiesRequester.cs @@ -1,25 +1,38 @@ using EndlessClient.GameExecution; +using EndlessClient.Rendering; +using EOLib.Domain.Character; using EOLib.Domain.Map; +using EOLib.Domain.NPC; using EOLib.Net; using EOLib.Net.Communication; using Microsoft.Xna.Framework; using System; +using System.Collections.Generic; namespace EndlessClient.Network { public class UnknownEntitiesRequester : GameComponent { + private const double REQUEST_INTERVAL_SECONDS = 1.0; + + private readonly IClientWindowSizeProvider _clientWindowSizeProvider; + private readonly ICharacterProvider _characterProvider; private readonly ICurrentMapStateRepository _currentMapStateRepository; private readonly IPacketSendService _packetSendService; + private DateTime _lastRequestTime; - private const double REQUEST_INTERVAL_SECONDS = 1; + // todo: create actions in EOLib.Domain for requesting unknown entities, instead of using packetsendservice directly public UnknownEntitiesRequester(IEndlessGameProvider gameProvider, - ICurrentMapStateRepository currentMapStateRepository, - IPacketSendService packetSendService) + IClientWindowSizeProvider clientWindowSizeProvider, + ICharacterProvider characterProvider, + ICurrentMapStateRepository currentMapStateRepository, + IPacketSendService packetSendService) : base((Game) gameProvider.Game) { + _clientWindowSizeProvider = clientWindowSizeProvider; + _characterProvider = characterProvider; _currentMapStateRepository = currentMapStateRepository; _packetSendService = packetSendService; _lastRequestTime = DateTime.Now; @@ -58,6 +71,8 @@ public override void Update(GameTime gameTime) { _lastRequestTime = DateTime.Now; } + + ClearOutOfRangeActors(); } base.Update(gameTime); @@ -101,5 +116,58 @@ private IPacket CreateRequestForPlayers() } return builder.Build(); } + + private void ClearOutOfRangeActors() + { + // todo: the server should communicate the "seedistance" to clients + // for now, disable auto remove of entities in Resizable mode + if (_clientWindowSizeProvider.Resizable) + { + return; + } + + var mc = _characterProvider.MainCharacter; + + var idsToRemove = new List(); + foreach (var id in _currentMapStateRepository.Characters.Keys) + { + var c = _currentMapStateRepository.Characters[id]; + + var xDiff = Math.Abs(mc.X - c.X); + var yDiff = Math.Abs(mc.Y - c.Y); + + if (c.X < mc.X || c.Y < mc.Y) + { + if (xDiff + yDiff > 11) + idsToRemove.Add(id); + } + else if (xDiff + yDiff > 14) + { + idsToRemove.Add(id); + } + } + + foreach (var id in idsToRemove) + _currentMapStateRepository.Characters.Remove(id); + + var npcsToRemove = new List(); + foreach (var npc in _currentMapStateRepository.NPCs) + { + var xDiff = Math.Abs(mc.X - npc.X); + var yDiff = Math.Abs(mc.Y - npc.Y); + + if (npc.X < mc.X || npc.Y < mc.Y) + { + if (xDiff + yDiff > 11) + npcsToRemove.Add(npc); + } + else if (xDiff + yDiff > 14) + { + npcsToRemove.Add(npc); + } + } + + _currentMapStateRepository.NPCs.RemoveWhere(npcsToRemove.Contains); + } } } diff --git a/EndlessClient/Rendering/NPC/NPCRendererUpdater.cs b/EndlessClient/Rendering/NPC/NPCRendererUpdater.cs index fadd24275..ead7a9d82 100644 --- a/EndlessClient/Rendering/NPC/NPCRendererUpdater.cs +++ b/EndlessClient/Rendering/NPC/NPCRendererUpdater.cs @@ -29,6 +29,7 @@ public class NPCRendererUpdater : INPCRendererUpdater public void UpdateNPCs(GameTime gameTime) { CleanUpDeadNPCs(); + CleanUpRemovedNPCs(); CreateAndCacheNPCRenderers(); UpdateNPCRenderers(gameTime); } @@ -47,6 +48,25 @@ private void CleanUpDeadNPCs() } } + private void CleanUpRemovedNPCs() + { + var removedNPCs = _npcRendererRepository.NPCRenderers.Values + .Where(x => x.IsAlive) + .Select(x => x.NPC.Index) + .Where(x => !_currentMapStateProvider.NPCs.Select(y => y.Index).Any(y => y == x)) + .ToList(); + + foreach (var index in removedNPCs) + { + if (!_npcRendererRepository.NPCRenderers.TryGetValue(index, out var renderer)) + continue; + + renderer.Dispose(); + _npcRendererRepository.NPCRenderers.Remove(index); + _npcStateCache.RemoveStateByIndex(index); + } + } + private void CreateAndCacheNPCRenderers() { foreach (var npc in _currentMapStateProvider.NPCs)