Skip to content

Commit

Permalink
In fixed window size mode, remove NPCs/characters that are out of ran…
Browse files Browse the repository at this point in the history
…ge. Fixes display bugs with GameServer/resoserv.
  • Loading branch information
ethanmoffat committed May 4, 2023
1 parent 323fb25 commit 239c61a
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 4 deletions.
2 changes: 1 addition & 1 deletion EndlessClient/HUD/Controls/HudControlsFactory.cs
Expand Up @@ -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()
Expand Down
74 changes: 71 additions & 3 deletions 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;
Expand Down Expand Up @@ -58,6 +71,8 @@ public override void Update(GameTime gameTime)
{
_lastRequestTime = DateTime.Now;
}

ClearOutOfRangeActors();
}

base.Update(gameTime);
Expand Down Expand Up @@ -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<int>();
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<NPC>();
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);
}
}
}
20 changes: 20 additions & 0 deletions EndlessClient/Rendering/NPC/NPCRendererUpdater.cs
Expand Up @@ -29,6 +29,7 @@ public class NPCRendererUpdater : INPCRendererUpdater
public void UpdateNPCs(GameTime gameTime)
{
CleanUpDeadNPCs();
CleanUpRemovedNPCs();
CreateAndCacheNPCRenderers();
UpdateNPCRenderers(gameTime);
}
Expand All @@ -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)
Expand Down

0 comments on commit 239c61a

Please sign in to comment.