diff --git a/EOLib/Domain/Map/CurrentMapStateRepository.cs b/EOLib/Domain/Map/CurrentMapStateRepository.cs index 2649d825a..6e46a3ad5 100644 --- a/EOLib/Domain/Map/CurrentMapStateRepository.cs +++ b/EOLib/Domain/Map/CurrentMapStateRepository.cs @@ -1,4 +1,5 @@ using AutomaticTypeMapper; +using Optional; using System.Collections.Generic; namespace EOLib.Domain.Map @@ -25,6 +26,10 @@ public interface ICurrentMapStateRepository WarpState MapWarpState { get; set; } + Option MapWarpSession { get; set; } + + Option MapWarpID { get; set; } + HashSet UnknownPlayerIDs { get; set; } HashSet UnknownNPCIndexes { get; set; } @@ -52,6 +57,10 @@ public interface ICurrentMapStateProvider WarpState MapWarpState { get; } + Option MapWarpSession { get; } + + Option MapWarpID { get; } + HashSet UnknownPlayerIDs { get; } HashSet UnknownNPCIndexes { get; } @@ -80,6 +89,10 @@ public class CurrentMapStateRepository : ICurrentMapStateRepository, ICurrentMap public WarpState MapWarpState { get; set; } + public Option MapWarpSession { get; set; } + + public Option MapWarpID { get; set; } + public HashSet UnknownPlayerIDs { get; set; } public HashSet UnknownNPCIndexes { get; set; } @@ -117,6 +130,8 @@ public void ResetState() UnknownNPCIndexes = new HashSet(); MapWarpState = WarpState.None; + MapWarpSession = Option.None(); + MapWarpID = Option.None(); } } } diff --git a/EOLib/Net/API/NPC.cs b/EOLib/Net/API/NPC.cs deleted file mode 100644 index 7328d8458..000000000 --- a/EOLib/Net/API/NPC.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using EOLib.Net.Handlers; - -namespace EOLib.Net.API -{ - partial class PacketAPI - { - public event Action OnRemoveChildNPCs; - - private void _createNPCMembers() - { - m_client.AddPacketHandler(new FamilyActionPair(PacketFamily.NPC, PacketAction.Junk), _handleNPCJunk, true); - } - - private void _handleNPCJunk(OldPacket pkt) - { - if (OnRemoveChildNPCs != null) - OnRemoveChildNPCs(pkt.GetShort()); - } - } -} diff --git a/EOLib/Net/API/PacketAPI.cs b/EOLib/Net/API/PacketAPI.cs index 33ed558fd..03880045b 100644 --- a/EOLib/Net/API/PacketAPI.cs +++ b/EOLib/Net/API/PacketAPI.cs @@ -21,7 +21,6 @@ public PacketAPI(EOClient client) //each of these sets up members of the partial PacketAPI class relevant to a particular packet family _createPartyMembers(); - _createNPCMembers(); _createSpellMembers(); _createTradeMembers(); } diff --git a/EOLib/Net/FileTransfer/FileRequestActions.cs b/EOLib/Net/FileTransfer/FileRequestActions.cs index f67a23208..8a5a70b99 100644 --- a/EOLib/Net/FileTransfer/FileRequestActions.cs +++ b/EOLib/Net/FileTransfer/FileRequestActions.cs @@ -1,13 +1,14 @@ -using System; -using System.Threading.Tasks; using AutomaticTypeMapper; using EOLib.Domain.Login; +using EOLib.Domain.Map; using EOLib.Domain.Protocol; using EOLib.IO; -using EOLib.IO.Map; using EOLib.IO.Pub; using EOLib.IO.Repositories; using EOLib.IO.Services; +using Optional; +using System; +using System.Threading.Tasks; namespace EOLib.Net.FileTransfer { @@ -21,6 +22,7 @@ public class FileRequestActions : IFileRequestActions private readonly ILoginFileChecksumProvider _loginFileChecksumProvider; private readonly IPubFileRepository _pubFileRepository; private readonly IMapFileRepository _mapFileRepository; + private readonly ICurrentMapStateRepository _currentMapStateRepository; private readonly IPlayerInfoProvider _playerInfoProvider; public FileRequestActions(INumberEncoderService numberEncoderService, @@ -30,6 +32,7 @@ public FileRequestActions(INumberEncoderService numberEncoderService, ILoginFileChecksumProvider loginFileChecksumProvider, IPubFileRepository pubFileRepository, IMapFileRepository mapFileRepository, + ICurrentMapStateRepository currentMapStateRepository, IPlayerInfoProvider playerInfoProvider) { _numberEncoderService = numberEncoderService; @@ -39,6 +42,7 @@ public FileRequestActions(INumberEncoderService numberEncoderService, _loginFileChecksumProvider = loginFileChecksumProvider; _pubFileRepository = pubFileRepository; _mapFileRepository = mapFileRepository; + _currentMapStateRepository = currentMapStateRepository; _playerInfoProvider = playerInfoProvider; } @@ -58,16 +62,22 @@ public bool NeedsMapForWarp(short mapID, byte[] mapRid, int fileSize) return NeedMap(mapID, expectedChecksum, fileSize); } - public async Task GetMapForWarp(short mapID, short sessionID) + public void RequestMapForWarp(short mapID, short sessionID) { - var mapFile = await _fileRequestService.RequestMapFileForWarp(mapID, sessionID); - SaveAndCacheMapFile(mapID, mapFile); + _fileRequestService.RequestMapFileForWarp(mapID, sessionID); + _currentMapStateRepository.MapWarpSession = Option.Some(sessionID); + _currentMapStateRepository.MapWarpID = Option.Some(mapID); } public async Task GetMapFromServer(short mapID, short sessionID) { var mapFile = await _fileRequestService.RequestMapFile(mapID, sessionID); - SaveAndCacheMapFile(mapID, mapFile); + _mapFileSaveService.SaveFileToDefaultDirectory(mapFile, rewriteChecksum: false); + + if (_mapFileRepository.MapFiles.ContainsKey(mapID)) + _mapFileRepository.MapFiles[mapID] = mapFile; + else + _mapFileRepository.MapFiles.Add(mapID, mapFile); } public async Task GetItemFileFromServer(short sessionID) @@ -133,16 +143,6 @@ private bool NeedPub(InitFileType fileType) throw new ArgumentOutOfRangeException(nameof(fileType), fileType, null); } } - - private void SaveAndCacheMapFile(short mapID, IMapFile mapFile) - { - _mapFileSaveService.SaveFileToDefaultDirectory(mapFile, rewriteChecksum: false); - - if (_mapFileRepository.MapFiles.ContainsKey(mapID)) - _mapFileRepository.MapFiles[mapID] = mapFile; - else - _mapFileRepository.MapFiles.Add(mapID, mapFile); - } } public interface IFileRequestActions @@ -151,7 +151,7 @@ public interface IFileRequestActions bool NeedsMapForWarp(short mapID, byte[] mapRid, int fileSize); - Task GetMapForWarp(short mapID, short sessionID); + void RequestMapForWarp(short mapID, short sessionID); Task GetMapFromServer(short mapID, short sessionID); diff --git a/EOLib/Net/FileTransfer/FileRequestService.cs b/EOLib/Net/FileTransfer/FileRequestService.cs index 5b8ae1a1c..b2fb4145e 100644 --- a/EOLib/Net/FileTransfer/FileRequestService.cs +++ b/EOLib/Net/FileTransfer/FileRequestService.cs @@ -37,14 +37,14 @@ public async Task RequestMapFile(short mapID, short sessionID) return await GetMapFile(request, mapID); } - public async Task RequestMapFileForWarp(short mapID, short sessionID) + public void RequestMapFileForWarp(short mapID, short sessionID) { var request = new PacketBuilder(PacketFamily.Warp, PacketAction.Take) .AddShort(mapID) .AddShort(sessionID) .Build(); - return await GetMapFile(request, mapID); + _packetSendService.SendPacket(request); } public async Task> RequestFile(InitFileType fileType, short sessionID) @@ -112,7 +112,7 @@ public interface IFileRequestService { Task RequestMapFile(short mapID, short sessionID); - Task RequestMapFileForWarp(short mapID, short sessionID); + void RequestMapFileForWarp(short mapID, short sessionID); Task> RequestFile(InitFileType fileType, short sessionID) where TRecord : class, IPubRecord, new(); diff --git a/EOLib/PacketHandlers/BeginPlayerWarpHandler.cs b/EOLib/PacketHandlers/BeginPlayerWarpHandler.cs index c836f13fc..a725afc19 100644 --- a/EOLib/PacketHandlers/BeginPlayerWarpHandler.cs +++ b/EOLib/PacketHandlers/BeginPlayerWarpHandler.cs @@ -1,7 +1,4 @@ -using System; -using System.IO; -using System.Linq; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.IO.Actions; @@ -10,6 +7,9 @@ using EOLib.Net.Communication; using EOLib.Net.FileTransfer; using EOLib.Net.Handlers; +using System; +using System.IO; +using System.Linq; namespace EOLib.PacketHandlers { @@ -47,34 +47,43 @@ public override bool HandlePacket(IPacket packet) { if (_mapStateRepository.MapWarpState != WarpState.None) throw new InvalidOperationException("Attempted to warp while another warp was in progress"); + _mapStateRepository.MapWarpState = WarpState.WarpStarted; var warpType = packet.ReadChar(); var mapID = packet.ReadShort(); - short sessionID; + switch (warpType) { case WARP_SAME_MAP: - sessionID = packet.ReadShort(); - SendWarpAcceptToServer(mapID, sessionID); + { + var sessionID = packet.ReadShort(); + SendWarpAcceptToServer(mapID, sessionID); + } break; case WARP_NEW_MAP: - var mapRid = packet.ReadBytes(4).ToArray(); - var fileSize = packet.ReadThree(); - sessionID = packet.ReadShort(); - - var mapIsDownloaded = true; - try { - if (!_mapFileProvider.MapFiles.ContainsKey(mapID)) - _mapFileLoadActions.LoadMapFileByID(mapID); - } - catch (IOException) { mapIsDownloaded = false; } + var mapRid = packet.ReadBytes(4).ToArray(); + var fileSize = packet.ReadThree(); + var sessionID = packet.ReadShort(); - if (!mapIsDownloaded || _fileRequestActions.NeedsMapForWarp(mapID, mapRid, fileSize)) - _fileRequestActions.GetMapForWarp(mapID, sessionID).Wait(5000); + var mapIsDownloaded = true; + try + { + if (!_mapFileProvider.MapFiles.ContainsKey(mapID)) + _mapFileLoadActions.LoadMapFileByID(mapID); + } + catch (IOException) { mapIsDownloaded = false; } - SendWarpAcceptToServer(mapID, sessionID); + if (!mapIsDownloaded || _fileRequestActions.NeedsMapForWarp(mapID, mapRid, fileSize)) + { + _fileRequestActions.RequestMapForWarp(mapID, sessionID); + } + else + { + SendWarpAcceptToServer(mapID, sessionID); + } + } break; default: _mapStateRepository.MapWarpState = WarpState.None; diff --git a/EOLib/PacketHandlers/Init/MapWarpFileDownloadHandler.cs b/EOLib/PacketHandlers/Init/MapWarpFileDownloadHandler.cs new file mode 100644 index 000000000..8ccd03573 --- /dev/null +++ b/EOLib/PacketHandlers/Init/MapWarpFileDownloadHandler.cs @@ -0,0 +1,76 @@ +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 EOLib.Net.Communication; +using System.Collections.Generic; +using System.Linq; + +namespace EOLib.PacketHandlers.Init +{ + [AutoMappedType] + public class MapWarpFileDownloadHandler : IInitPacketHandler + { + private readonly IMapFileRepository _mapFileRepository; + private readonly IMapDeserializer _mapFileDeserializer; + private readonly IMapFileSaveService _mapFileSaveService; + private readonly ICurrentMapStateProvider _currentMapStateProvider; + private readonly IPacketSendService _packetSendService; + + public InitReply Reply => InitReply.WarpMap; + + public MapWarpFileDownloadHandler(IMapFileRepository mapFileRepository, + IMapDeserializer mapFileDeserializer, + IMapFileSaveService mapFileSaveService, + ICurrentMapStateProvider currentMapStateProvider, + IPacketSendService packetSendService) + { + _mapFileRepository = mapFileRepository; + _mapFileDeserializer = mapFileDeserializer; + _mapFileSaveService = mapFileSaveService; + _currentMapStateProvider = currentMapStateProvider; + _packetSendService = packetSendService; + } + + public bool HandlePacket(IPacket packet) + { + if (_currentMapStateProvider.MapWarpState != WarpState.WarpStarted) + return false; + + if (!_currentMapStateProvider.MapWarpID.HasValue || + !_currentMapStateProvider.MapWarpSession.HasValue) + return false; + + _currentMapStateProvider.MapWarpID.MatchSome( + 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); + + _currentMapStateProvider.MapWarpSession.MatchSome(sessionID => SendWarpAcceptToServer(mapID, sessionID)); + }); + + return true; + } + + private void SendWarpAcceptToServer(short mapID, short sessionID) + { + var response = new PacketBuilder(PacketFamily.Warp, PacketAction.Accept) + .AddShort(mapID) + .AddShort(sessionID) + .Build(); + _packetSendService.SendPacket(response); + } + } +} diff --git a/EOLib/PacketHandlers/NPCChildDespawnHandler.cs b/EOLib/PacketHandlers/NPCChildDespawnHandler.cs new file mode 100644 index 000000000..24a1cd5da --- /dev/null +++ b/EOLib/PacketHandlers/NPCChildDespawnHandler.cs @@ -0,0 +1,58 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Character; +using EOLib.Domain.Login; +using EOLib.Domain.Map; +using EOLib.Domain.Notifiers; +using EOLib.Net; +using EOLib.Net.Handlers; +using Optional; +using System.Collections.Generic; +using System.Linq; + +namespace EOLib.PacketHandlers +{ + [AutoMappedType] + public class NPCChildDespawnHandler : InGameOnlyPacketHandler + { + private readonly ICharacterProvider _characterProvider; + private readonly ICurrentMapStateRepository _currentMapStateRepository; + private readonly IEnumerable _npcActionNotifiers; + + public override PacketFamily Family => PacketFamily.NPC; + + public override PacketAction Action => PacketAction.Junk; + + public NPCChildDespawnHandler(IPlayerInfoProvider playerInfoProvider, + ICharacterProvider characterProvider, + ICurrentMapStateRepository currentMapStateRepository, + IEnumerable npcActionNotifiers) + : base(playerInfoProvider) + { + _characterProvider = characterProvider; + _currentMapStateRepository = currentMapStateRepository; + _npcActionNotifiers = npcActionNotifiers; + } + + public override bool HandlePacket(IPacket packet) + { + var childNpcId = packet.ReadShort(); + + var indexes = _currentMapStateRepository.NPCs.Where(npc => npc.ID == childNpcId).Select(x => x.Index).ToList(); + foreach (var notifier in _npcActionNotifiers) + { + foreach (var index in indexes) + { + notifier.RemoveNPCFromView(index, + _characterProvider.MainCharacter.ID, + spellId: Option.None(), + damage: Option.None(), + showDeathAnimation: true); + } + } + + _currentMapStateRepository.NPCs.RemoveWhere(npc => npc.ID == childNpcId); + + return true; + } + } +} diff --git a/EndlessClient/Old/PacketAPICallbackManager.cs b/EndlessClient/Old/PacketAPICallbackManager.cs index 22dda09f3..3e01549f4 100644 --- a/EndlessClient/Old/PacketAPICallbackManager.cs +++ b/EndlessClient/Old/PacketAPICallbackManager.cs @@ -22,9 +22,6 @@ public PacketAPICallbackManager(PacketAPI apiObj, EOGame game) public void AssignCallbacks() { - //npc related - m_packetAPI.OnRemoveChildNPCs += _removeChildNPCs; - //party m_packetAPI.OnPartyClose += _partyClose; m_packetAPI.OnPartyDataRefresh += _partyDataRefresh; @@ -45,11 +42,6 @@ public void AssignCallbacks() m_packetAPI.OnCastSpellTargetGroup += _playerCastGroupSpell; } - private void _removeChildNPCs(short childNPCID) - { - OldWorld.Instance.ActiveMapRenderer.RemoveNPCsWhere(x => x.NPC.Data.ID == childNPCID); - } - private void _partyClose() { m_game.Hud.CloseParty();