diff --git a/EOBot/BotBase.cs b/EOBot/BotBase.cs index fe4aee83d..0ec336dd2 100644 --- a/EOBot/BotBase.cs +++ b/EOBot/BotBase.cs @@ -1,11 +1,14 @@ using System; using System.Threading; using System.Threading.Tasks; +using EOLib; using EOLib.Config; using EOLib.Domain.Protocol; using EOLib.Net.Communication; using EOLib.Net.Connection; using EOLib.Net.PacketProcessing; +using Moffat.EndlessOnline.SDK.Packet; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOBot { @@ -17,9 +20,12 @@ public abstract class BotBase : IBot public event Action WorkCompleted; + protected Random _random; + protected BotBase(int botIndex) { _index = botIndex; + _random = new Random(); } //all bots are going to want to do the init handshake with the server @@ -52,17 +58,16 @@ public virtual async Task InitializeAsync(string host, int port) connectionActions.DisconnectFromServer(); }; - var handshakeResult = await connectionActions.BeginHandshake(); + var handshakeResult = await connectionActions.BeginHandshake(_random.Next(Constants.MaxChallenge)); - if (handshakeResult.Response != InitReply.Success) + if (handshakeResult.ReplyCode != InitReply.Ok) throw new InvalidOperationException(string.Format("Bot {0}: Invalid response from server or connection failed! Must receive an OK reply.", _index)); - var packetProcessActions = c.Resolve(); + var handshakeData = (InitInitServerPacket.ReplyCodeDataOk)handshakeResult.ReplyCodeData; - packetProcessActions.SetInitialSequenceNumber(handshakeResult[InitializationDataKey.SequenceByte1], - handshakeResult[InitializationDataKey.SequenceByte2]); - packetProcessActions.SetEncodeMultiples(handshakeResult[InitializationDataKey.ReceiveMultiple], - handshakeResult[InitializationDataKey.SendMultiple]); + var packetProcessActions = c.Resolve(); + packetProcessActions.SetSequenceStart(InitSequenceStart.FromInitValues(handshakeData.Seq1, handshakeData.Seq2)); + packetProcessActions.SetEncodeMultiples(handshakeData.ServerEncryptionMultiple, handshakeData.ClientEncryptionMultiple); connectionActions.CompleteHandshake(handshakeResult); diff --git a/EOBot/BotHelper.cs b/EOBot/BotHelper.cs index 8201dfca9..991567de6 100644 --- a/EOBot/BotHelper.cs +++ b/EOBot/BotHelper.cs @@ -2,9 +2,10 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Domain.Protocol; using EOLib.IO.Actions; using EOLib.Net.FileTransfer; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional.Collections; using System; using System.IO; @@ -29,7 +30,7 @@ public async Task CreateAccountAsync(string name, string password) var accountActions = DependencyMaster.TypeRegistry[_botIndex].Resolve(); var accParams = new CreateAccountParameters(name, password, password, name, name, name + "@eobot.net"); var nameResult = await accountActions.CheckAccountNameWithServer(name); - return nameResult >= AccountReply.OK_CodeRange + return nameResult >= (AccountReply)10 ? await accountActions.CreateAccount(accParams, (int)nameResult) : nameResult; } @@ -73,19 +74,19 @@ public async Task LoginToCharacterAsync(string name) } var fileRequestActions = DependencyMaster.TypeRegistry[_botIndex].Resolve(); - if (unableToLoadMap || fileRequestActions.NeedsFileForLogin(InitFileType.Map, mapStateProvider.CurrentMapID)) + if (unableToLoadMap || fileRequestActions.NeedsFileForLogin(FileType.Emf, mapStateProvider.CurrentMapID)) await fileRequestActions.GetMapFromServer(mapStateProvider.CurrentMapID, sessionID); - if (fileRequestActions.NeedsFileForLogin(InitFileType.Item)) + if (fileRequestActions.NeedsFileForLogin(FileType.Eif)) await fileRequestActions.GetItemFileFromServer(sessionID); - if (fileRequestActions.NeedsFileForLogin(InitFileType.Npc)) + if (fileRequestActions.NeedsFileForLogin(FileType.Enf)) await fileRequestActions.GetNPCFileFromServer(sessionID); - if (fileRequestActions.NeedsFileForLogin(InitFileType.Spell)) + if (fileRequestActions.NeedsFileForLogin(FileType.Esf)) await fileRequestActions.GetSpellFileFromServer(sessionID); - if (fileRequestActions.NeedsFileForLogin(InitFileType.Class)) + if (fileRequestActions.NeedsFileForLogin(FileType.Ecf)) await fileRequestActions.GetClassFileFromServer(sessionID); await loginActions.CompleteCharacterLogin(sessionID); @@ -106,7 +107,7 @@ public async Task DeleteCharacterAsync(string name, bool force) if (!characterSelectorRepository.CharacterForDelete.HasValue) { ConsoleHelper.WriteMessage(ConsoleHelper.Type.Warning, $"Character {name} could not be deleted / does not exist"); - return CharacterReply.THIS_IS_WRONG; + return (CharacterReply)255; } var characterActions = DependencyMaster.TypeRegistry[_botIndex].Resolve(); diff --git a/EOBot/Interpreter/BuiltInIdentifierConfigurator.cs b/EOBot/Interpreter/BuiltInIdentifierConfigurator.cs index c96701f1a..ae946eaf9 100644 --- a/EOBot/Interpreter/BuiltInIdentifierConfigurator.cs +++ b/EOBot/Interpreter/BuiltInIdentifierConfigurator.cs @@ -1,18 +1,20 @@ using EOBot.Interpreter.States; using EOBot.Interpreter.Variables; +using EOLib; using EOLib.Config; -using EOLib.Domain.Account; using EOLib.Domain.Character; using EOLib.Domain.Chat; using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.NPC; using EOLib.Domain.Party; -using EOLib.Domain.Protocol; using EOLib.IO.Repositories; using EOLib.Net.Communication; using EOLib.Net.Connection; using EOLib.Net.PacketProcessing; +using Moffat.EndlessOnline.SDK.Packet; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System; using System.Collections.Generic; using System.Linq; @@ -27,6 +29,7 @@ public class BuiltInIdentifierConfigurator private readonly int _botIndex; private readonly ArgumentsParser _parsedArgs; private readonly BotHelper _botHelper; + private readonly Random _random; public BuiltInIdentifierConfigurator(ProgramState state, int botIndex, ArgumentsParser parsedArgs) { @@ -34,6 +37,7 @@ public BuiltInIdentifierConfigurator(ProgramState state, int botIndex, Arguments _botIndex = botIndex; _parsedArgs = parsedArgs; _botHelper = new BotHelper(_botIndex); + _random = new Random(); } public void SetupBuiltInFunctions() @@ -119,17 +123,16 @@ private async Task ConnectAsync(string host, int port) var backgroundReceiveActions = c.Resolve(); backgroundReceiveActions.RunBackgroundReceiveLoop(); - var handshakeResult = await connectionActions.BeginHandshake(); + var handshakeResult = await connectionActions.BeginHandshake(_random.Next(Constants.MaxChallenge)); - if (handshakeResult.Response != InitReply.Success) + if (handshakeResult.ReplyCode != InitReply.Ok) throw new InvalidOperationException($"Bot {_botIndex}: Invalid response from server or connection failed! Must receive an OK reply."); - var packetProcessActions = c.Resolve(); + var handshakeData = (InitInitServerPacket.ReplyCodeDataOk)handshakeResult.ReplyCodeData; - packetProcessActions.SetInitialSequenceNumber(handshakeResult[InitializationDataKey.SequenceByte1], - handshakeResult[InitializationDataKey.SequenceByte2]); - packetProcessActions.SetEncodeMultiples(handshakeResult[InitializationDataKey.ReceiveMultiple], - handshakeResult[InitializationDataKey.SendMultiple]); + var packetProcessActions = c.Resolve(); + packetProcessActions.SetSequenceStart(InitSequenceStart.FromInitValues(handshakeData.Seq1, handshakeData.Seq2)); + packetProcessActions.SetEncodeMultiples(handshakeData.ServerEncryptionMultiple, handshakeData.ClientEncryptionMultiple); connectionActions.CompleteHandshake(handshakeResult); } diff --git a/EOBot/TrainerBot.cs b/EOBot/TrainerBot.cs index 4b953bf1b..b33a01262 100644 --- a/EOBot/TrainerBot.cs +++ b/EOBot/TrainerBot.cs @@ -11,6 +11,7 @@ using EOLib.IO.Repositories; using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System; using System.Collections.Generic; using System.Linq; @@ -377,9 +378,9 @@ private async Task UseHealItem(IEnumerable healItems) private async Task ToggleSit() { var renderProps = _characterRepository.MainCharacter.RenderProperties; - var nextState = renderProps.SitState == SitState.Standing ? "Floor" : "Stand"; - ConsoleHelper.WriteMessage(ConsoleHelper.Type.Sit, $"{nextState,7} - Toggling from: {Enum.GetName(typeof(SitState), renderProps.SitState)}"); - await TrySend(_characterActions.ToggleSit); + var nextState = renderProps.SitState == EOLib.Domain.Character.SitState.Standing ? "Floor" : "Stand"; + ConsoleHelper.WriteMessage(ConsoleHelper.Type.Sit, $"{nextState,7} - Toggling from: {Enum.GetName(typeof(EOLib.Domain.Character.SitState), renderProps.SitState)}"); + await TrySend(() => _characterActions.Sit(MapCoordinate.Zero)); } private async Task TrySend(Action action, uint attempts = 3) diff --git a/EOLib.Graphics.Test/NativeGraphicsManagerTest.cs b/EOLib.Graphics.Test/NativeGraphicsManagerTest.cs index 14c2ffeb6..69d24a3e7 100644 --- a/EOLib.Graphics.Test/NativeGraphicsManagerTest.cs +++ b/EOLib.Graphics.Test/NativeGraphicsManagerTest.cs @@ -155,7 +155,7 @@ public void WhenLoadTexture_MaleHat_Transparent_SetsSpecialColorToTransparent() Texture2D resultTexture; var bmp = LoadGFXReturnsBitmap(GFXTypes.MaleHat, requestedResource); - FillBitmapWithColor(bmp, new Color(0x08, 0x00, 0x00, 0xff)); + FillBitmapWithColor(bmp, new Color(0xff000008)); resultTexture = _nativeGraphicsManager.TextureFromResource(GFXTypes.MaleHat, requestedResource, true); var data = new Microsoft.Xna.Framework.Color[resultTexture.Width * resultTexture.Height]; @@ -171,7 +171,7 @@ public void WhenLoadTexture_FemaleHat_Transparent_SetsSpecialColorToTransparent( Texture2D resultTexture; var bmp = LoadGFXReturnsBitmap(GFXTypes.FemaleHat, requestedResource); - FillBitmapWithColor(bmp, new Color(0x08, 0x00, 0x00, 0xff)); + FillBitmapWithColor(bmp, new Color(0xff000008)); resultTexture = _nativeGraphicsManager.TextureFromResource(GFXTypes.FemaleHat, requestedResource, true); var data = new Color[resultTexture.Width * resultTexture.Height]; @@ -221,9 +221,9 @@ private static void FillBitmapWithColor(Memory image, Color color) { for (int i = 54; i < image.Length; i+=4) { - image.Span[i] = color.R; + image.Span[i] = color.B; image.Span[i + 1] = color.G; - image.Span[i + 2] = color.B; + image.Span[i + 2] = color.R; image.Span[i + 3] = color.A; } } diff --git a/EOLib.Graphics/NativeGraphicsManager.cs b/EOLib.Graphics/NativeGraphicsManager.cs index a6abbbaab..4cbcef2d2 100644 --- a/EOLib.Graphics/NativeGraphicsManager.cs +++ b/EOLib.Graphics/NativeGraphicsManager.cs @@ -61,23 +61,15 @@ private Texture2D LoadTexture(GFXTypes file, int resourceVal, bool transparent, if (transparent) { - // for all gfx: 0x000000 is transparent - processAction = data => CrossPlatformMakeTransparent(data, Color.Black); + processAction = data => CrossPlatformMakeTransparent(data); - // for hats: R=8 G=0 B=0 is transparent - // some default gfx use R=0 G=8 B=0 as black - // 0,0,0 clips pixels below it - if (file == GFXTypes.FemaleHat || file == GFXTypes.MaleHat) + if (fullTransparent) { - processAction = data => CrossPlatformMakeTransparent(data, new Color(0xff000008)); + processAction = data => CrossPlatformMakeTransparent(data, isHat: true); } - - // for hats: some hat gfx use multiple masking colors but don't have clipping behavior - if (fullTransparent) + else if (file == GFXTypes.FemaleHat || file == GFXTypes.MaleHat) { - processAction = data => CrossPlatformMakeTransparent(data, - new Color(0xff000000), - new Color(0xff000008)); + processAction = data => CrossPlatformMakeTransparent(data, checkClip: true, isHat: true); } } @@ -87,8 +79,39 @@ private Texture2D LoadTexture(GFXTypes file, int resourceVal, bool transparent, return ret; } - private static unsafe void CrossPlatformMakeTransparent(byte[] data, params Color[] transparentColors) + private static unsafe void CrossPlatformMakeTransparent(byte[] data, bool isHat = false, bool checkClip = false) { + var shouldClip = false; + if (checkClip) + { + fixed (byte* ptr = data) + { + for (int i = 0; i < data.Length; i += 4) + { + uint* addr = (uint*)(ptr + i); + if (*addr == 0xff000008) + { + shouldClip = true; + break; + } + } + } + } + + // for all gfx: 0,0,0 is transparent + + // for some hats: 8,0,0 and 0,0,0 are both transparent + + // for hats: R=8 G=0 B=0 is transparent + // some default gfx use R=0 G=8 B=0 as black + // 0,0,0 clips pixels below it if 8,0,0 is present on the frame + + var transparentColors = isHat + ? shouldClip + ? new Color[] { new Color(0xff000008) } // check clip: make ff000008 transparent only, use black for clipping if present + : new Color[] { Color.Black, new Color(0xff000008) } // isHat: make both colors transparent + : new Color[] { Color.Black }; // default: make only black transparent + fixed (byte* ptr = data) { for (int i = 0; i < data.Length; i += 4) diff --git a/EOLib.IO.Test/Map/MapFilePropertiesTest.cs b/EOLib.IO.Test/Map/MapFilePropertiesTest.cs index a01e5021a..49cfbe460 100644 --- a/EOLib.IO.Test/Map/MapFilePropertiesTest.cs +++ b/EOLib.IO.Test/Map/MapFilePropertiesTest.cs @@ -93,7 +93,7 @@ public void MapFileProperties_DeserializeFromByteArray_ThrowsExceptionWhenNotEMF private static IMapFileProperties CreateMapPropertiesWithSomeTestData(IMapFileProperties props) { - return props.WithChecksum(new byte[] {1, 2, 3, 4}) + return props.WithChecksum(new List {1, 2}) .WithName("Some test name") .WithWidth(200) .WithHeight(100) @@ -117,7 +117,7 @@ private static byte[] CreateExpectedBytes(IMapFileProperties props) var ret = new List(); ret.AddRange(Encoding.ASCII.GetBytes(props.FileType)); - ret.AddRange(props.Checksum); + ret.AddRange(props.Checksum.SelectMany(x => numberEncoderService.EncodeNumber(x, 2))); var fullName = Enumerable.Repeat((byte)0xFF, 24).ToArray(); var encodedName = mapStringEncoderService.EncodeMapString(props.Name, props.Name.Length); diff --git a/EOLib.IO.Test/Services/Serializers/PubFileSerializerTest.cs b/EOLib.IO.Test/Services/Serializers/PubFileSerializerTest.cs index 0f917146c..9119c8a7f 100644 --- a/EOLib.IO.Test/Services/Serializers/PubFileSerializerTest.cs +++ b/EOLib.IO.Test/Services/Serializers/PubFileSerializerTest.cs @@ -30,9 +30,12 @@ public abstract class PubFileSerializerTest [Test] public void DeserializeFromByteArray_WrongLength_Throws() { - const int ExpectedChecksum = 1234567890; + const int ExpectedChecksum1 = 12345; + const int ExpectedChecksum2 = 6789; const int ExpectedLength = 4; + var expectedChecksum = new List { ExpectedChecksum1, ExpectedChecksum2 }; + var records = new[] { new U().WithID(1).WithName("Rec_1"), @@ -41,16 +44,19 @@ public void DeserializeFromByteArray_WrongLength_Throws() new U().WithID(4).WithName("Rec_4"), }; - var pubBytesShort = MakePubFileBytes(ExpectedChecksum, ExpectedLength - 1, records); + var pubBytesShort = MakePubFileBytes(expectedChecksum, ExpectedLength - 1, records); Assert.That(() => CreateSerializer().DeserializeFromByteArray(1, pubBytesShort, () => new T()), Throws.InstanceOf()); } [Test] public void DeserializeFromByteArray_HasExpectedHeader() { - const int ExpectedChecksum = 1234567890; + const int ExpectedChecksum1 = 12345; + const int ExpectedChecksum2 = 6789; const int ExpectedLength = 4; + var expectedChecksum = new List { ExpectedChecksum1, ExpectedChecksum2 }; + var records = new[] { new U().WithID(1).WithName("Rec_1"), @@ -59,17 +65,17 @@ public void DeserializeFromByteArray_HasExpectedHeader() new U().WithID(4).WithName("Rec_4"), }; - var pubBytes = MakePubFileBytes(ExpectedChecksum, ExpectedLength, records); + var pubBytes = MakePubFileBytes(expectedChecksum, ExpectedLength, records); var file = CreateSerializer().DeserializeFromByteArray(1, pubBytes, () => new T()); - Assert.That(file.CheckSum, Is.EqualTo(ExpectedChecksum)); + Assert.That(file.CheckSum, Is.EqualTo(expectedChecksum)); Assert.That(file.Length, Is.EqualTo(ExpectedLength)); } [Test] public void SerializeToByteArray_ReturnsExpectedBytes() { - var expectedBytes = MakePubFileBytes(55565554, + var expectedBytes = MakePubFileBytes(new List { 5556, 5554 }, 9, new U().WithID(1).WithName("TestFixture"), new U().WithID(2).WithName("Test2"), @@ -104,7 +110,7 @@ public void DeserializeFromByteArray_HasExpectedIDAndNames() new U().WithID(8).WithName("Test8"), new U().WithID(9).WithName("eof") }; - var bytes = MakePubFileBytes(55565554, 9, records); + var bytes = MakePubFileBytes(new List { 5556, 5554 }, 9, records); var serializer = CreateSerializer(); var file = serializer.DeserializeFromByteArray(1, bytes, () => new T()); @@ -113,14 +119,14 @@ public void DeserializeFromByteArray_HasExpectedIDAndNames() file.Select(x => new { x.ID, x.Name }).ToList()); } - private byte[] MakePubFileBytes(int checksum, int length, params IPubRecord[] records) + private byte[] MakePubFileBytes(List checksum, int length, params IPubRecord[] records) { var numberEncoderService = new NumberEncoderService(); var recordSerializer = new PubRecordSerializer(numberEncoderService); var bytes = new List(); bytes.AddRange(Encoding.ASCII.GetBytes(new T().FileType)); - bytes.AddRange(numberEncoderService.EncodeNumber(checksum, 4)); + bytes.AddRange(checksum.SelectMany(x => numberEncoderService.EncodeNumber(x, 2))); bytes.AddRange(numberEncoderService.EncodeNumber(length, 2)); bytes.Add(numberEncoderService.EncodeNumber(1, 1)[0]); foreach (var record in records) diff --git a/EOLib.IO/EOLib.IO.csproj b/EOLib.IO/EOLib.IO.csproj index 62f69d7ca..bc088c1f8 100644 --- a/EOLib.IO/EOLib.IO.csproj +++ b/EOLib.IO/EOLib.IO.csproj @@ -14,5 +14,7 @@ + + \ No newline at end of file diff --git a/EOLib.IO/Extensions/TileSpecExtensions.cs b/EOLib.IO/Extensions/TileSpecExtensions.cs index acdb35ef5..b81c00924 100644 --- a/EOLib.IO/Extensions/TileSpecExtensions.cs +++ b/EOLib.IO/Extensions/TileSpecExtensions.cs @@ -6,14 +6,12 @@ public static class TileSpecExtensions { public static bool IsBoard(this TileSpec tileSpec) { - return tileSpec == TileSpec.Board1 || - tileSpec == TileSpec.Board2 || - tileSpec == TileSpec.Board3 || - tileSpec == TileSpec.Board4 || - tileSpec == TileSpec.Board5 || - tileSpec == TileSpec.Board6 || - tileSpec == TileSpec.Board7 || - tileSpec == TileSpec.Board8; + return tileSpec >= (TileSpec)20 && tileSpec <= (TileSpec)27; + } + + public static bool IsChair(this TileSpec tileSpec) + { + return tileSpec >= (TileSpec)1 && tileSpec <= (TileSpec)7; } } } diff --git a/EOLib.IO/Map/IMapFileProperties.cs b/EOLib.IO/Map/IMapFileProperties.cs index fd8af1b13..9fbd89109 100644 --- a/EOLib.IO/Map/IMapFileProperties.cs +++ b/EOLib.IO/Map/IMapFileProperties.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; + namespace EOLib.IO.Map { public interface IMapFileProperties @@ -6,8 +8,7 @@ public interface IMapFileProperties int MapID { get; } int FileSize { get; } - byte[] Checksum { get; } - int ChecksumInt { get; } + IReadOnlyList Checksum { get; } string Name { get; } int Width { get; } int Height { get; } @@ -27,7 +28,7 @@ public interface IMapFileProperties IMapFileProperties WithMapID(int id); IMapFileProperties WithFileSize(int fileSize); - IMapFileProperties WithChecksum(byte[] checksum); + IMapFileProperties WithChecksum(IReadOnlyList checksum); IMapFileProperties WithName(string name); IMapFileProperties WithWidth(int width); IMapFileProperties WithHeight(int height); diff --git a/EOLib.IO/Map/MapFileProperties.cs b/EOLib.IO/Map/MapFileProperties.cs index 40c79ee2c..94d9a4fdf 100644 --- a/EOLib.IO/Map/MapFileProperties.cs +++ b/EOLib.IO/Map/MapFileProperties.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace EOLib.IO.Map { @@ -10,8 +11,7 @@ public class MapFileProperties : IMapFileProperties public int MapID { get; private set; } public int FileSize { get; private set; } - public byte[] Checksum { get; private set; } - public int ChecksumInt { get; private set; } + public IReadOnlyList Checksum { get; private set; } public string Name { get; private set; } public int Width { get; private set; } @@ -37,7 +37,7 @@ public class MapFileProperties : IMapFileProperties public MapFileProperties() { Name = ""; - Checksum = new byte[4]; + Checksum = new List { 0, 0 }; } public IMapFileProperties WithMapID(int id) @@ -54,11 +54,13 @@ public IMapFileProperties WithFileSize(int fileSize) return clone; } - public IMapFileProperties WithChecksum(byte[] checksum) + public IMapFileProperties WithChecksum(IReadOnlyList checksum) { + if (checksum.Count != 2) + throw new ArgumentException("Checksum should be 2 eo 'short' values", nameof(checksum)); + var clone = Clone(); - clone.Checksum = checksum; - clone.ChecksumInt = BitConverter.ToInt32(checksum, 0); + clone.Checksum = new List(checksum); return clone; } @@ -169,12 +171,11 @@ public IMapFileProperties WithHasTimedSpikes(bool hasTimedSpikes) private MapFileProperties Clone() { - var props = new MapFileProperties + return new MapFileProperties { MapID = MapID, FileSize = FileSize, - Checksum = new byte[Checksum.Length], - ChecksumInt = ChecksumInt, + Checksum = new List(Checksum), Name = Name, Width = Width, Height = Height, @@ -191,9 +192,6 @@ private MapFileProperties Clone() PKAvailable = PKAvailable, HasTimedSpikes = HasTimedSpikes }; - Array.Copy(Checksum, props.Checksum, props.Checksum.Length); - - return props; } } } diff --git a/EOLib.IO/Pub/BasePubFile.cs b/EOLib.IO/Pub/BasePubFile.cs index 28d7225b7..18c9d5f9d 100644 --- a/EOLib.IO/Pub/BasePubFile.cs +++ b/EOLib.IO/Pub/BasePubFile.cs @@ -17,7 +17,7 @@ public abstract class BasePubFile : IPubFile public int ID { get; private set; } /// - public int CheckSum { get; private set; } + public IReadOnlyList CheckSum { get; private set; } /// public int Length => _data.Count; @@ -33,8 +33,11 @@ protected BasePubFile() _data = new List(); } - protected BasePubFile(int id, int checksum, int totalLength, List data) + protected BasePubFile(int id, IReadOnlyList checksum, int totalLength, List data) { + if (checksum.Count != 2) + throw new ArgumentException("Checksum should be 2 eo 'short' values", nameof(checksum)); + ID = id; CheckSum = checksum; TotalLength = totalLength; @@ -49,8 +52,11 @@ public IPubFile WithID(int id) } /// - public IPubFile WithCheckSum(int checksum) + public IPubFile WithCheckSum(IReadOnlyList checksum) { + if (checksum.Count != 2) + throw new ArgumentException("Checksum should be 2 eo 'short' values", nameof(checksum)); + var copy = MakeCopy(); copy.CheckSum = checksum; return copy; diff --git a/EOLib.IO/Pub/ECFFile.cs b/EOLib.IO/Pub/ECFFile.cs index 61b5cc30a..b5fabf506 100644 --- a/EOLib.IO/Pub/ECFFile.cs +++ b/EOLib.IO/Pub/ECFFile.cs @@ -7,10 +7,11 @@ public class ECFFile : BasePubFile public override string FileType => "ECF"; public ECFFile() + : this(0, new List { 0, 0 }, 0, new List()) { } - public ECFFile(int id, int checksum, int totalLength, List data) + public ECFFile(int id, IReadOnlyList checksum, int totalLength, List data) : base(id, checksum, totalLength, data) { } diff --git a/EOLib.IO/Pub/EIFFile.cs b/EOLib.IO/Pub/EIFFile.cs index a441301be..499a3c644 100644 --- a/EOLib.IO/Pub/EIFFile.cs +++ b/EOLib.IO/Pub/EIFFile.cs @@ -7,10 +7,11 @@ public class EIFFile : BasePubFile public override string FileType => "EIF"; public EIFFile() + : this(0, new List { 0, 0 }, 0, new List()) { } - public EIFFile(int id, int checksum, int totalLength, List data) + public EIFFile(int id, IReadOnlyList checksum, int totalLength, List data) : base (id, checksum, totalLength, data) { } diff --git a/EOLib.IO/Pub/ENFFile.cs b/EOLib.IO/Pub/ENFFile.cs index 9c2e44c5b..a6f9dcc23 100644 --- a/EOLib.IO/Pub/ENFFile.cs +++ b/EOLib.IO/Pub/ENFFile.cs @@ -7,10 +7,11 @@ public class ENFFile : BasePubFile public override string FileType => "ENF"; public ENFFile() + : this(0, new List { 0, 0 }, 0, new List()) { } - public ENFFile(int id, int checksum, int totalLength, List data) + public ENFFile(int id, IReadOnlyList checksum, int totalLength, List data) : base(id, checksum, totalLength, data) { } diff --git a/EOLib.IO/Pub/ESFFile.cs b/EOLib.IO/Pub/ESFFile.cs index b1cb1419b..e49601565 100644 --- a/EOLib.IO/Pub/ESFFile.cs +++ b/EOLib.IO/Pub/ESFFile.cs @@ -7,10 +7,11 @@ public class ESFFile : BasePubFile public override string FileType => "ESF"; public ESFFile() + : this(0, new List { 0, 0 }, 0, new List()) { } - public ESFFile(int id, int checksum, int totalLength, List data) + public ESFFile(int id, IReadOnlyList checksum, int totalLength, List data) : base(id, checksum, totalLength, data) { } diff --git a/EOLib.IO/Pub/IPubFile.cs b/EOLib.IO/Pub/IPubFile.cs index cd4ffba0c..15cd71368 100644 --- a/EOLib.IO/Pub/IPubFile.cs +++ b/EOLib.IO/Pub/IPubFile.cs @@ -55,9 +55,9 @@ public interface IPubFile string FileType { get; } /// - /// The file checksum. This is really two shorts encoded next to each other but is represented as an int. + /// The file checksum; two EO shorts /// - int CheckSum { get; } + IReadOnlyList CheckSum { get; } /// /// The length of the file (number of records) @@ -82,7 +82,7 @@ public interface IPubFile /// /// The new checksum. /// The updated pub file. - IPubFile WithCheckSum(int checkSum); + IPubFile WithCheckSum(IReadOnlyList checkSum); /// /// Create a copy of this pub file with the specified total length. diff --git a/EOLib.IO/Services/DataEncoderService.cs b/EOLib.IO/Services/DataEncoderService.cs deleted file mode 100644 index 11e94582b..000000000 --- a/EOLib.IO/Services/DataEncoderService.cs +++ /dev/null @@ -1,106 +0,0 @@ -using AutomaticTypeMapper; -using System.Collections.Generic; -using System.Linq; - -namespace EOLib.IO.Services -{ - [AutoMappedType] - public class DataEncoderService : IDataEncoderService - { - public List Interleave(IReadOnlyList data) - { - var numArray = new byte[data.Count]; - var index1 = 0; - var num = 0; - - while (index1 < data.Count) - { - numArray[index1] = data[num++]; - index1 += 2; - } - - var index2 = index1 - 1; - if (data.Count % 2 != 0) - index2 -= 2; - - while (index2 >= 0) - { - numArray[index2] = data[num++]; - index2 -= 2; - } - - return numArray.ToList(); - } - - public List Deinterleave(IReadOnlyList data) - { - var numArray = new byte[data.Count]; - var index1 = 0; - var num = 0; - - while (index1 < data.Count) - { - numArray[num++] = data[index1]; - index1 += 2; - } - - var index2 = index1 - 1; - if (data.Count % 2 != 0) - index2 -= 2; - - while (index2 >= 0) - { - numArray[num++] = data[index2]; - index2 -= 2; - } - - return numArray.ToList(); - } - - public List FlipMSB(IReadOnlyList data) - { - return data.Select(x => (byte)(x == 128 || x == 0 ? x : x ^ 0x80u)).ToList(); - } - - public List SwapMultiples(IReadOnlyList data, int multi) - { - int num1 = 0; - - var result = data.ToArray(); - - for (int index1 = 0; index1 <= data.Count; ++index1) - { - if (index1 != data.Count && data[index1] % multi == 0) - { - ++num1; - } - else - { - if (num1 > 1) - { - for (int index2 = 0; index2 < num1 / 2; ++index2) - { - byte num2 = data[index1 - num1 + index2]; - result[index1 - num1 + index2] = data[index1 - index2 - 1]; - result[index1 - index2 - 1] = num2; - } - } - num1 = 0; - } - } - - return result.ToList(); - } - } - - public interface IDataEncoderService - { - List Interleave(IReadOnlyList data); - - List Deinterleave(IReadOnlyList data); - - List FlipMSB(IReadOnlyList data); - - List SwapMultiples(IReadOnlyList data, int multi); - } -} diff --git a/EOLib.IO/Services/NumberEncoderService.cs b/EOLib.IO/Services/NumberEncoderService.cs index 7138ef08c..83d915bf7 100644 --- a/EOLib.IO/Services/NumberEncoderService.cs +++ b/EOLib.IO/Services/NumberEncoderService.cs @@ -1,62 +1,14 @@ using AutomaticTypeMapper; -using System.Linq; +using Moffat.EndlessOnline.SDK.Data; +using System; namespace EOLib.IO.Services { [MappedType(BaseType = typeof(INumberEncoderService))] public class NumberEncoderService : INumberEncoderService { - public byte[] EncodeNumber(int number, int size) - { - var unsigned = (uint) number; - var numArray = Enumerable.Repeat((uint)254, 4).ToArray(); - var original = unsigned; + public byte[] EncodeNumber(int number, int size) => new ReadOnlySpan(NumberEncoder.EncodeNumber(number), 0, size).ToArray(); - if (original >= NumericConstants.THREE_BYTE_MAX) - { - numArray[3] = unsigned / NumericConstants.THREE_BYTE_MAX + 1; - unsigned = unsigned % NumericConstants.THREE_BYTE_MAX; - } - - if (original >= NumericConstants.TWO_BYTE_MAX) - { - numArray[2] = unsigned / NumericConstants.TWO_BYTE_MAX + 1; - unsigned = unsigned % NumericConstants.TWO_BYTE_MAX; - } - - if (original >= NumericConstants.ONE_BYTE_MAX) - { - numArray[1] = unsigned / NumericConstants.ONE_BYTE_MAX + 1; - unsigned = unsigned % NumericConstants.ONE_BYTE_MAX; - } - - numArray[0] = unsigned + 1; - - return numArray.Select(x => (byte)x) - .Take(size) - .ToArray(); - } - - public int DecodeNumber(params byte[] b) - { - for (int index = 0; index < b.Length; ++index) - { - if (b[index] == 254) - b[index] = 1; - else if (b[index] == 0) - b[index] = 128; - --b[index]; - } - - var retNum = 0; - if (b.Length > 3) - retNum += b[3]*(int)NumericConstants.THREE_BYTE_MAX; - if (b.Length > 2) - retNum += b[2]*(int)NumericConstants.TWO_BYTE_MAX; - if (b.Length > 1) - retNum += b[1]*(int)NumericConstants.ONE_BYTE_MAX; - - return retNum + b[0]; - } + public int DecodeNumber(params byte[] b) => NumberEncoder.DecodeNumber(b); } } diff --git a/EOLib.IO/Services/Serializers/MapPropertiesSerializer.cs b/EOLib.IO/Services/Serializers/MapPropertiesSerializer.cs index fbfd63bb4..51c92c8f0 100644 --- a/EOLib.IO/Services/Serializers/MapPropertiesSerializer.cs +++ b/EOLib.IO/Services/Serializers/MapPropertiesSerializer.cs @@ -4,6 +4,7 @@ using System.Text; using AutomaticTypeMapper; using EOLib.IO.Map; +using Moffat.EndlessOnline.SDK.Data; namespace EOLib.IO.Services.Serializers { @@ -26,7 +27,8 @@ public byte[] SerializeToByteArray(IMapFileProperties mapEntity) var ret = new List(); ret.AddRange(Encoding.ASCII.GetBytes(mapEntity.FileType)); - ret.AddRange(mapEntity.Checksum); + foreach (int value in mapEntity.Checksum) + ret.AddRange(_numberEncoderService.EncodeNumber(value, 2)); var mapNameBytes = EncodeMapName(mapEntity); ret.AddRange(mapNameBytes); @@ -58,7 +60,11 @@ public IMapFileProperties DeserializeFromByteArray(byte[] data) if (typeString != properties.FileType) throw new FormatException("Data is not correctly formatted! Must be an EMF file header"); - var checksumArray = data.Skip(3).Take(4).ToArray(); + var checksumArray = new List + { + _numberEncoderService.DecodeNumber(data[3], data[4]), + _numberEncoderService.DecodeNumber(data[5], data[6]), + }; var mapNameArray = data.Skip(7).Take(24).ToArray(); var mapName = _mapStringEncoderService.DecodeMapString(mapNameArray); diff --git a/EOLib.IO/Services/Serializers/PubFileSerializer.cs b/EOLib.IO/Services/Serializers/PubFileSerializer.cs index 37897d744..2817711f1 100644 --- a/EOLib.IO/Services/Serializers/PubFileSerializer.cs +++ b/EOLib.IO/Services/Serializers/PubFileSerializer.cs @@ -1,6 +1,7 @@ using AutomaticTypeMapper; using EOLib.IO.Pub; using System; +using System.Collections.Generic; using System.IO; using System.Text; @@ -28,7 +29,11 @@ public IPubFile DeserializeFromByteArray(int id, byte[] data, var checksumBytes = new byte[4]; mem.Read(checksumBytes, 0, 4); - var checksum = _numberEncoderService.DecodeNumber(checksumBytes); + var checksum = new List + { + _numberEncoderService.DecodeNumber(checksumBytes[0], checksumBytes[1]), + _numberEncoderService.DecodeNumber(checksumBytes[2], checksumBytes[3]) + }; var lenBytes = new byte[2]; mem.Read(lenBytes, 0, 2); @@ -87,14 +92,17 @@ public byte[] SerializeToByteArray(IPubFile file, bool rewrite fileBytes = mem.ToArray(); } - var checksumBytes = _numberEncoderService.EncodeNumber(file.CheckSum, 4); + var checksumBytes = new List(); + for (int i = 0; i < file.CheckSum.Count; i++) + checksumBytes.AddRange(_numberEncoderService.EncodeNumber(file.CheckSum[i], 2)); + if (rewriteChecksum) { var checksum = CRC32.Check(fileBytes); - checksumBytes = _numberEncoderService.EncodeNumber((int)checksum, 4); + checksumBytes = new List(_numberEncoderService.EncodeNumber((int)checksum, 4)); } - Array.Copy(checksumBytes, 0, fileBytes, 3, 4); + Array.Copy(checksumBytes.ToArray(), 0, fileBytes, 3, 4); return fileBytes; } } diff --git a/EOLib.Localization.Test/DataFileLoadActionsTest.cs b/EOLib.Localization.Test/DataFileLoadActionsTest.cs index 60cf8600f..dd79760b1 100644 --- a/EOLib.Localization.Test/DataFileLoadActionsTest.cs +++ b/EOLib.Localization.Test/DataFileLoadActionsTest.cs @@ -1,7 +1,6 @@ -using System.Diagnostics.CodeAnalysis; +using NUnit.Framework; +using System.Diagnostics.CodeAnalysis; using System.IO; -using EOLib.IO.Services; -using NUnit.Framework; namespace EOLib.Localization.Test { @@ -16,7 +15,7 @@ public class DataFileLoadActionsTest public void SetUp() { _dataFileRepository = new DataFileRepository(); - _edfLoaderService = new EDFLoaderService(new DataEncoderService()); + _edfLoaderService = new EDFLoaderService(); _actions = new DataFileLoadActions(_dataFileRepository, _edfLoaderService); } diff --git a/EOLib.Localization.Test/EDFLoaderServiceTest.cs b/EOLib.Localization.Test/EDFLoaderServiceTest.cs index 5483e2768..9c7a12a0a 100644 --- a/EOLib.Localization.Test/EDFLoaderServiceTest.cs +++ b/EOLib.Localization.Test/EDFLoaderServiceTest.cs @@ -1,10 +1,9 @@ -using System; +using NUnit.Framework; +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; -using EOLib.IO.Services; -using NUnit.Framework; namespace EOLib.Localization.Test { @@ -18,7 +17,7 @@ public class EDFLoaderServiceTest [SetUp] public void SetUp() { - _edfLoaderService = new EDFLoaderService(new DataEncoderService()); + _edfLoaderService = new EDFLoaderService(); } public void TearDown() diff --git a/EOLib.Localization/EOLib.Localization.csproj b/EOLib.Localization/EOLib.Localization.csproj index a48bf6040..925f964e3 100644 --- a/EOLib.Localization/EOLib.Localization.csproj +++ b/EOLib.Localization/EOLib.Localization.csproj @@ -14,9 +14,9 @@ - + \ No newline at end of file diff --git a/EOLib.Localization/Services/EDFLoaderService.cs b/EOLib.Localization/Services/EDFLoaderService.cs index 43c44c986..e51fa2fd1 100644 --- a/EOLib.Localization/Services/EDFLoaderService.cs +++ b/EOLib.Localization/Services/EDFLoaderService.cs @@ -1,5 +1,5 @@ using AutomaticTypeMapper; -using EOLib.IO.Services; +using Moffat.EndlessOnline.SDK.Data; using System; using System.Collections.Generic; using System.IO; @@ -11,13 +11,6 @@ namespace EOLib.Localization [AutoMappedType] public class EDFLoaderService : IEDFLoaderService { - private readonly IDataEncoderService _dataEncoderService; - - public EDFLoaderService(IDataEncoderService dataEncoderService) - { - _dataEncoderService = dataEncoderService; - } - public IEDFFile LoadFile(string fileName, DataFiles whichFile) { switch (whichFile) @@ -103,24 +96,24 @@ private IEDFFile LoadUnencodedFile(string fileName, DataFiles whichFile) private string DecodeDatString(string content, DataFiles whichFile) { - var res = _dataEncoderService.Deinterleave(Encoding.ASCII.GetBytes(content)); + var res = DataEncrypter.Deinterleave(Encoding.ASCII.GetBytes(content)); if (whichFile != DataFiles.CurseFilter) - res = _dataEncoderService.SwapMultiples(res, 7); + res = DataEncrypter.SwapMultiples(res, 7); return Encoding.ASCII.GetString(res.ToArray()); } private string EncodeDatString(string content, DataFiles whichFile) { - List res = null; + byte[] res = null; if (whichFile != DataFiles.CurseFilter) - res = _dataEncoderService.SwapMultiples(Encoding.ASCII.GetBytes(content).ToList(), 7); + res = DataEncrypter.SwapMultiples(Encoding.ASCII.GetBytes(content), 7); - res = _dataEncoderService.Interleave(res ?? Encoding.ASCII.GetBytes(content).ToList()); + res = DataEncrypter.Interleave(res ?? Encoding.ASCII.GetBytes(content)); - return Encoding.ASCII.GetString(res.ToArray()); + return Encoding.ASCII.GetString(res); } } } diff --git a/EOLib.Test/Net/FileTransfer/FileRequestServiceTest.cs b/EOLib.Test/Net/FileTransfer/FileRequestServiceTest.cs index 3ddd8bfec..5a2ce8a44 100644 --- a/EOLib.Test/Net/FileTransfer/FileRequestServiceTest.cs +++ b/EOLib.Test/Net/FileTransfer/FileRequestServiceTest.cs @@ -13,6 +13,11 @@ using NUnit.Framework; using Moq; using System.Collections.Generic; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Text; +using Moffat.EndlessOnline.SDK.Data; namespace EOLib.Test.Net.FileTransfer { @@ -44,21 +49,21 @@ public void SetUp() [Test] public void RequestFile_ResponsePacketHasInvalidHeader_ThrowsEmptyPacketReceivedException() { - Mock.Get(_packetSendService).SetupReceivedPacketHasHeader(PacketFamily.Account, PacketAction.Accept); - Assert.ThrowsAsync(async () => await _fileRequestService.RequestFile(InitFileType.Item, 1)); + Mock.Get(_packetSendService).SetupReceivedPacketHasHeader(); + Assert.ThrowsAsync(async () => await _fileRequestService.RequestFile(FileType.Eif, 1)); } [Test] public void RequestFile_ResponsePacketInvalidExtraByte_ThrowsMalformedPacketException() { - Mock.Get(_packetSendService).SetupReceivedPacketHasHeader(PacketFamily.Init, PacketAction.Init, (byte)InitReply.ItemFile, 33); - Assert.ThrowsAsync(async () => await _fileRequestService.RequestFile(InitFileType.Item, 1)); + Mock.Get(_packetSendService).SetupReceivedPacketHasHeader((byte)InitReply.FileEif, 33); + Assert.ThrowsAsync(async () => await _fileRequestService.RequestFile(FileType.Eif, 1)); } [Test] public void RequestFile_SendsPacket_BasedOnSpecifiedType() { - var types = new[] { InitFileType.Item, InitFileType.Npc, InitFileType.Spell, InitFileType.Class }; + var types = new[] { FileType.Eif, FileType.Enf, FileType.Esf, FileType.Ecf }; foreach (var type in types) { var packetIsCorrect = false; @@ -75,33 +80,33 @@ public void RequestFile_SendsPacket_BasedOnSpecifiedType() [Test] public void RequestFile_CorrectResponse_ExecutesWithoutFault() { - var types = new[] { InitFileType.Item, InitFileType.Npc, InitFileType.Spell, InitFileType.Class }; + var types = new[] { FileType.Eif, FileType.Enf, FileType.Esf, FileType.Ecf }; foreach (var type in types) { - Mock.Get(_packetSendService).SetupReceivedPacketHasHeader(PacketFamily.Init, PacketAction.Init, CreateFilePacket(type)); + Mock.Get(_packetSendService).SetupReceivedPacketHasHeader(CreateFilePacket(type)); AggregateException aggEx = null; switch (type) { - case InitFileType.Item: + case FileType.Eif: Mock.Get(_pubFileDeserializer) .Setup(x => x.DeserializeFromByteArray(1, It.IsAny(), It.IsAny>>())) .Returns(new EIFFile()); aggEx = _fileRequestService.RequestFile(type, 1).Exception; break; - case InitFileType.Npc: + case FileType.Enf: Mock.Get(_pubFileDeserializer) .Setup(x => x.DeserializeFromByteArray(1, It.IsAny(), It.IsAny>>())) .Returns(new ENFFile()); aggEx = _fileRequestService.RequestFile(type, 1).Exception; break; - case InitFileType.Spell: + case FileType.Esf: Mock.Get(_pubFileDeserializer) .Setup(x => x.DeserializeFromByteArray(1, It.IsAny(), It.IsAny>>())) .Returns(new ESFFile()); aggEx = _fileRequestService.RequestFile(type, 1).Exception; break; - case InitFileType.Class: + case FileType.Ecf: Mock.Get(_pubFileDeserializer) .Setup(x => x.DeserializeFromByteArray(1, It.IsAny(), It.IsAny>>())) .Returns(new ECFFile()); @@ -121,22 +126,22 @@ public void RequestFile_CorrectResponse_ExecutesWithoutFault() [Test] public void RequestMapFile_ResponsePacketHasInvalidHeader_ThrowsEmptyPacketReceivedException() { - Mock.Get(_packetSendService).SetupReceivedPacketHasHeader(PacketFamily.Account, PacketAction.Accept); + Mock.Get(_packetSendService).SetupReceivedPacketHasHeader(); Assert.ThrowsAsync(async () => await _fileRequestService.RequestMapFile(1, 1)); } [Test] public void RequestMapFile_ResponsePacketHasIncorrectFileType_ThrowsMalformedPacketException() { - Mock.Get(_packetSendService).SetupReceivedPacketHasHeader(PacketFamily.Init, PacketAction.Init, (byte) InitReply.SpellFile, 33); - Assert.ThrowsAsync(async () => await _fileRequestService.RequestMapFile(1, 1)); + Mock.Get(_packetSendService).SetupReceivedPacketHasHeader((byte) InitReply.FileEsf, 33); + Assert.ThrowsAsync(async () => await _fileRequestService.RequestMapFile(1, 1)); } [Test] public void RequestMapFile_SendsPacket_BasedOnSpecifiedMap() { var packetIsCorrect = false; - Mock.Get(_packetSendService).Setup(x => x.SendEncodedPacketAndWaitAsync(It.IsAny())).Callback((IPacket packet) => packetIsCorrect = IsCorrectFileRequestPacket(packet, InitFileType.Map)); + Mock.Get(_packetSendService).Setup(x => x.SendEncodedPacketAndWaitAsync(It.IsAny())).Callback((IPacket packet) => packetIsCorrect = IsCorrectFileRequestPacket(packet, FileType.Emf)); _fileRequestService.RequestMapFile(1, 1); @@ -152,7 +157,7 @@ public void RequestMapFile_HasPlayerAndMapID() var packetIsCorrect = false; Mock.Get(_packetSendService) .Setup(x => x.SendEncodedPacketAndWaitAsync(It.IsAny())) - .Callback((IPacket p) => packetIsCorrect = IsCorrectFileRequestPacket(p, InitFileType.Map, PlayerID, MapID)); + .Callback((IPacket p) => packetIsCorrect = IsCorrectFileRequestPacket(p, FileType.Emf, PlayerID, MapID)); _fileRequestService.RequestMapFile(MapID, PlayerID); @@ -163,67 +168,112 @@ public void RequestMapFile_HasPlayerAndMapID() #region Helper Methods - private static bool IsCorrectFileRequestPacket(IPacket packet, InitFileType type, short playerId = 0, short mapId = 0) + private static bool IsCorrectFileRequestPacket(IPacket packet, FileType type, short sessionId = 0, short mapId = 0) { - var correctTyping = packet.Family == PacketFamily.Welcome && packet.Action == PacketAction.Agree && packet.ReadChar() == (byte) type; + var waPacket = packet as WelcomeAgreeClientPacket; + var correctTyping = waPacket.FileType == type; var correctData = true; - if (mapId > 0 && playerId > 0) + if (mapId > 0 && sessionId > 0) { - correctData = packet.ReadShort() == playerId && packet.ReadShort() == mapId; + var emfData = waPacket.FileTypeData as WelcomeAgreeClientPacket.FileTypeDataEmf; + correctData = emfData.FileId == mapId && waPacket.SessionId == sessionId; } return correctTyping && correctData; } - private static byte[] CreateFilePacket(InitFileType type) + private static byte[] CreateFilePacket(FileType type) { - IPacketBuilder packetBuilder = new PacketBuilder(); + var ret = new InitInitServerPacket(); var nes = new NumberEncoderService(); var rs = new PubRecordSerializer(nes); + var eoWriter = new EoWriter(); switch (type) { - case InitFileType.Item: - packetBuilder = packetBuilder - .AddByte((byte) InitReply.ItemFile).AddChar(1) //spacer - .AddString("EIF").AddInt(1) //RID - .AddShort(2) //Len - .AddByte(1) //filler byte - .AddBytes(rs.SerializeToByteArray(new EIFRecord().WithID(1).WithName("Test1"))) - .AddBytes(rs.SerializeToByteArray(new EIFRecord().WithID(2).WithName("eof"))); + case FileType.Eif: + ret.ReplyCode = InitReply.FileEif; + + eoWriter.AddString("EIF"); + eoWriter.AddInt(1); // RID + eoWriter.AddShort(2); // length + eoWriter.AddByte(1); // version + eoWriter.AddBytes(rs.SerializeToByteArray(new EIFRecord().WithID(1).WithName("Test1"))); + eoWriter.AddBytes(rs.SerializeToByteArray(new EIFRecord().WithID(2).WithName("eof"))); + + ret.ReplyCodeData = new InitInitServerPacket.ReplyCodeDataFileEif + { + PubFile = new PubFile + { + FileId = 1, + Content = eoWriter.ToByteArray() + } + }; break; - case InitFileType.Npc: - packetBuilder = packetBuilder - .AddByte((byte) InitReply.NpcFile).AddChar(1) //spacer - .AddString("ENF").AddInt(1) //RID - .AddShort(2) //Len - .AddByte(1) //filler byte - .AddBytes(rs.SerializeToByteArray(new ENFRecord().WithID(1).WithName("Test1"))) - .AddBytes(rs.SerializeToByteArray(new ENFRecord().WithID(2).WithName("eof"))); + case FileType.Enf: + ret.ReplyCode = InitReply.FileEnf; + + eoWriter.AddString("ENF"); + eoWriter.AddInt(1); // RID + eoWriter.AddShort(2); // length + eoWriter.AddByte(1); // version + eoWriter.AddBytes(rs.SerializeToByteArray(new ENFRecord().WithID(1).WithName("Test1"))); + eoWriter.AddBytes(rs.SerializeToByteArray(new ENFRecord().WithID(2).WithName("eof"))); + + ret.ReplyCodeData = new InitInitServerPacket.ReplyCodeDataFileEnf + { + PubFile = new PubFile + { + FileId = 1, + Content = eoWriter.ToByteArray() + } + }; break; - case InitFileType.Spell: - packetBuilder = packetBuilder - .AddByte((byte) InitReply.SpellFile).AddChar(1) //spacer - .AddString("ESF").AddInt(1) //RID - .AddShort(2) //Len - .AddByte(1) //filler byte - .AddBytes(rs.SerializeToByteArray(new ESFRecord().WithID(1).WithNames(new List { "Test1", "" }))) - .AddBytes(rs.SerializeToByteArray(new ESFRecord().WithID(2).WithNames(new List { "eof", "" }))); + case FileType.Esf: + ret.ReplyCode = InitReply.FileEsf; + + eoWriter.AddString("ESF"); + eoWriter.AddInt(1); // RID + eoWriter.AddShort(2); // length + eoWriter.AddByte(1); // version + eoWriter.AddBytes(rs.SerializeToByteArray(new ESFRecord().WithID(1).WithName("Test1"))); + eoWriter.AddBytes(rs.SerializeToByteArray(new ESFRecord().WithID(2).WithName("eof"))); + + ret.ReplyCodeData = new InitInitServerPacket.ReplyCodeDataFileEsf + { + PubFile = new PubFile + { + FileId = 1, + Content = eoWriter.ToByteArray() + } + }; break; - case InitFileType.Class: - packetBuilder = packetBuilder - .AddByte((byte) InitReply.ClassFile).AddChar(1) //spacer - .AddString("ECF").AddInt(1) //RID - .AddShort(2) //Len - .AddByte(1) //filler byte - .AddBytes(rs.SerializeToByteArray(new ECFRecord().WithID(1).WithName("Test1"))) - .AddBytes(rs.SerializeToByteArray(new ECFRecord().WithID(2).WithName("eof"))); + case FileType.Ecf: + ret.ReplyCode = InitReply.FileEcf; + + eoWriter.AddString("ECF"); + eoWriter.AddInt(1); // RID + eoWriter.AddShort(2); // length + eoWriter.AddByte(1); // version + eoWriter.AddBytes(rs.SerializeToByteArray(new ECFRecord().WithID(1).WithName("Test1"))); + eoWriter.AddBytes(rs.SerializeToByteArray(new ECFRecord().WithID(2).WithName("eof"))); + + ret.ReplyCodeData = new InitInitServerPacket.ReplyCodeDataFileEcf + { + PubFile = new PubFile + { + FileId = 1, + Content = eoWriter.ToByteArray() + } + }; break; } - return packetBuilder.Build().RawData.ToArray(); + eoWriter = new EoWriter(); + ret.Serialize(eoWriter); + return eoWriter.ToByteArray(); } #endregion diff --git a/EOLib.Test/Net/PacketEncoderServiceTest.cs b/EOLib.Test/Net/PacketEncoderServiceTest.cs deleted file mode 100644 index 585238a30..000000000 --- a/EOLib.Test/Net/PacketEncoderServiceTest.cs +++ /dev/null @@ -1,45 +0,0 @@ -using EOLib.Domain.Interact.Quest; -using EOLib.IO.Services; -using EOLib.Net; -using EOLib.Net.PacketProcessing; -using NUnit.Framework; - -namespace EOLib.IO.Test.Services -{ - [TestFixture] - public class PacketEncoderServiceTest - { - [Test] - public void PacketEncoderService_Encode_127Byte_DoesNotProduceAny0ValueBytes() - { - var svc = new PacketEncoderService(new NumberEncoderService(), new DataEncoderService()); - - var packet = new PacketBuilder(PacketFamily.Quest, PacketAction.Accept) - .AddShort(0) - .AddShort(0) - .AddShort(111) - .AddShort(127) - .AddChar((int)DialogReply.Link) - .AddChar(1) - .Build(); - - var encoded = svc.Encode(packet, 5); - - Assert.That(encoded, Has.All.Not.EqualTo(0)); - } - - [Test] - public void PacketEncoderService_Encode_0Byte_DoesNotProduceAny128ValueBytes() - { - var svc = new PacketEncoderService(new NumberEncoderService(), new DataEncoderService()); - - var packet = new PacketBuilder(PacketFamily.Quest, PacketAction.Accept) - .AddByte(0) - .Build(); - - var encoded = svc.Encode(packet, 5); - - Assert.That(encoded, Has.All.Not.EqualTo(128)); - } - } -} diff --git a/EOLib.Test/TestHelpers/PacketSendServiceHelpers.cs b/EOLib.Test/TestHelpers/PacketSendServiceHelpers.cs index cb5a5978e..4a0629c98 100644 --- a/EOLib.Test/TestHelpers/PacketSendServiceHelpers.cs +++ b/EOLib.Test/TestHelpers/PacketSendServiceHelpers.cs @@ -1,8 +1,10 @@ -using System.Diagnostics.CodeAnalysis; -using System.Threading.Tasks; -using EOLib.Net; -using EOLib.Net.Communication; +using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Data; +using Moffat.EndlessOnline.SDK.Protocol.Net; using Moq; +using System; +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; namespace EOLib.Test.TestHelpers { @@ -13,18 +15,12 @@ internal static class PacketSendServiceHelpers /// Setup the PacketSendService mock to return a packet with the specified family/action/data from SendEncodedPacketAndWaitAsync /// /// The mocked packet send service - /// Packet family for the "received" packet - /// Packet action for the "received" packet /// Packet data payload (any additional data that should be in the packet) - internal static void SetupReceivedPacketHasHeader(this Mock packetSendServiceMock, - PacketFamily family, - PacketAction action, - params byte[] data) + internal static void SetupReceivedPacketHasHeader(this Mock packetSendServiceMock, params byte[] data) + where T : IPacket { - var receivedPacket = new PacketBuilder(family, action) - .AddBytes(data) - .Build(); - + IPacket receivedPacket = (IPacket)Activator.CreateInstance(typeof(T)); + receivedPacket.Deserialize(new EoReader(data)); packetSendServiceMock.Setup(x => x.SendEncodedPacketAndWaitAsync(It.IsAny())) .Returns(Task.FromResult(receivedPacket)); } diff --git a/EOLib/Domain/Account/AccountActions.cs b/EOLib/Domain/Account/AccountActions.cs index 2b4acf988..0a34a1c5a 100644 --- a/EOLib/Domain/Account/AccountActions.cs +++ b/EOLib/Domain/Account/AccountActions.cs @@ -4,6 +4,10 @@ using EOLib.Net; using EOLib.Net.Communication; using EOLib.Net.PacketProcessing; +using Moffat.EndlessOnline.SDK.Packet; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Linq; using System.Net; using System.Threading.Tasks; @@ -60,68 +64,56 @@ public CreateAccountParameterResult CheckAccountCreateParameters(ICreateAccountP public async Task CheckAccountNameWithServer(string accountName) { - var nameCheckPacket = new PacketBuilder(PacketFamily.Account, PacketAction.Request) - .AddString(accountName) - .Build(); + var nameCheckPacket = new AccountRequestClientPacket { Username = accountName }; var response = await _packetSendService.SendEncodedPacketAndWaitAsync(nameCheckPacket); - if (IsInvalidResponse(response)) + if (IsInvalidResponse(response, out var responsePacket)) throw new EmptyPacketReceivedException(); - var reply = (AccountReply)response.ReadShort(); - if (reply >= AccountReply.OK_CodeRange) + if (responsePacket.ReplyCode > (AccountReply)9) { - // Based on patch: https://github.com/eoserv/eoserv/commit/80dde6d4e7f440a93503aeec79f4a2f5931dc13d - // Account may change sequence start depending on the eoserv build being used - // Official software always updates sequence number - var hasNewSequence = response.Length == 7; - if (hasNewSequence) - { - var newSequenceStart = response.ReadChar(); - _sequenceRepository.SequenceStart = newSequenceStart; - } - - if (response.ReadEndString() != "OK") - reply = AccountReply.NotApproved; + var defaultData = (AccountReplyServerPacket.ReplyCodeDataDefault)responsePacket.ReplyCodeData; + _sequenceRepository.Sequencer = _sequenceRepository.Sequencer.WithSequenceStart(AccountReplySequenceStart.FromValue(defaultData.SequenceStart)); } - return reply; + return responsePacket.ReplyCode; } public async Task CreateAccount(ICreateAccountParameters parameters, int sessionID) { - var createAccountPacket = new PacketBuilder(PacketFamily.Account, PacketAction.Create) - .AddShort(sessionID) - .AddByte(255) - .AddBreakString(parameters.AccountName) - .AddBreakString(parameters.Password) - .AddBreakString(parameters.RealName) - .AddBreakString(parameters.Location) - .AddBreakString(parameters.Email) - .AddBreakString(Dns.GetHostName()) - .AddBreakString(_hdSerialNumberService.GetHDSerialNumber()) - .Build(); + var createAccountPacket = new AccountCreateClientPacket + { + SessionId = sessionID, + Username = parameters.AccountName, + Password = parameters.Password, + FullName = parameters.RealName, + Location = parameters.Location, + Email = parameters.Email, + Computer = Dns.GetHostName(), + Hdid = _hdSerialNumberService.GetHDSerialNumber(), + }; var response = await _packetSendService.SendEncodedPacketAndWaitAsync(createAccountPacket); - if (IsInvalidResponse(response)) + if (IsInvalidResponse(response, out var responsePacket)) throw new EmptyPacketReceivedException(); - return (AccountReply) response.ReadShort(); + return responsePacket.ReplyCode; } public async Task ChangePassword(IChangePasswordParameters parameters) { - var changePasswordPacket = new PacketBuilder(PacketFamily.Account, PacketAction.Agree) - .AddBreakString(parameters.AccountName) - .AddBreakString(parameters.OldPassword) - .AddBreakString(parameters.NewPassword) - .Build(); + var changePasswordPacket = new AccountAgreeClientPacket + { + Username = parameters.AccountName, + OldPassword = parameters.OldPassword, + NewPassword = parameters.NewPassword, + }; var response = await _packetSendService.SendEncodedPacketAndWaitAsync(changePasswordPacket); - if (IsInvalidResponse(response)) + if (IsInvalidResponse(response, out var responsePacket)) throw new EmptyPacketReceivedException(); - return (AccountReply) response.ReadShort(); + return responsePacket.ReplyCode; } private bool AnyFieldsStillEmpty(ICreateAccountParameters parameters) @@ -134,12 +126,13 @@ private bool AnyFieldsStillEmpty(ICreateAccountParameters parameters) parameters.RealName, parameters.Location, parameters.Email - }.Any(x => x.Length == 0); + }.Any(string.IsNullOrWhiteSpace); } - private bool IsInvalidResponse(IPacket response) + private bool IsInvalidResponse(IPacket response, out AccountReplyServerPacket responsePacket) { - return response.Family != PacketFamily.Account || response.Action != PacketAction.Reply; + responsePacket = response as AccountReplyServerPacket; + return responsePacket != null && response.Family != PacketFamily.Account || response.Action != PacketAction.Reply; } } diff --git a/EOLib/Domain/Account/AccountReply.cs b/EOLib/Domain/Account/AccountReply.cs deleted file mode 100644 index 2c32ea9a0..000000000 --- a/EOLib/Domain/Account/AccountReply.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace EOLib.Domain.Account -{ - public enum AccountReply : ushort - { - THIS_IS_WRONG = 0, - Exists = 1, - NotApproved = 2, - Created = 3, - ChangeFailed = 5, - ChangeSuccess = 6, - /// - /// Anything greater or equal to this value means the account was approved - /// - OK_CodeRange = 10, - } -} \ No newline at end of file diff --git a/EOLib/Domain/Character/AdminLevel.cs b/EOLib/Domain/Character/AdminLevel.cs deleted file mode 100644 index 4575be0e5..000000000 --- a/EOLib/Domain/Character/AdminLevel.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace EOLib.Domain.Character -{ - public enum AdminLevel - { - Player, - Spy, - Guide, - Guardian, - GM, - HGM - } -} \ No newline at end of file diff --git a/EOLib/Domain/Character/AvatarSlot.cs b/EOLib/Domain/Character/AvatarSlot.cs deleted file mode 100644 index d188e5372..000000000 --- a/EOLib/Domain/Character/AvatarSlot.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace EOLib.Domain.Character -{ - public enum AvatarSlot : byte - { - Clothes = 1, - Hair = 2, - HairColor = 3 - }; -} diff --git a/EOLib/Domain/Character/Character.cs b/EOLib/Domain/Character/Character.cs index 14e4af9ac..a78bf49cf 100644 --- a/EOLib/Domain/Character/Character.cs +++ b/EOLib/Domain/Character/Character.cs @@ -1,6 +1,8 @@ using Amadevus.RecordGenerator; using EOLib.Domain.Extensions; using EOLib.Domain.Spells; +using Moffat.EndlessOnline.SDK.Protocol; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.Domain.Character { @@ -48,5 +50,43 @@ public sealed partial class Character : ISpellTargetable public int MapID { get; } public bool NoWall { get; } + + public static Character FromCharacterSelectionListEntry(CharacterSelectionListEntry selectionListEntry) + { + return new Builder + { + Name = selectionListEntry.Name, + ID = selectionListEntry.Id, + Stats = new CharacterStats() + .WithNewStat(CharacterStat.Level, selectionListEntry.Level), + RenderProperties = new CharacterRenderProperties.Builder + { + Gender = (int)selectionListEntry.Gender, + HairStyle = selectionListEntry.HairStyle, + HairColor = selectionListEntry.HairColor, + Race = selectionListEntry.Skin, + BootsGraphic = selectionListEntry.Equipment.Boots, + ArmorGraphic = selectionListEntry.Equipment.Armor, + HatGraphic = selectionListEntry.Equipment.Hat, + ShieldGraphic = selectionListEntry.Equipment.Shield, + WeaponGraphic = selectionListEntry.Equipment.Weapon, + }.ToImmutable(), + AdminLevel = selectionListEntry.Admin, + }.ToImmutable(); + } + + public static Character FromNearby(CharacterMapInfo characterMapInfo) + { + return new Builder + { + Name = char.ToUpper(characterMapInfo.Name[0]) + characterMapInfo.Name.Substring(1), + ID = characterMapInfo.PlayerId, + ClassID = characterMapInfo.ClassId, + MapID = characterMapInfo.MapId, + GuildTag = characterMapInfo.GuildTag, + Stats = CharacterStats.FromCharacterMapInfo(characterMapInfo), + RenderProperties = CharacterRenderProperties.FromCharacterMapInfo(characterMapInfo), + }.ToImmutable(); + } } } \ No newline at end of file diff --git a/EOLib/Domain/Character/CharacterActions.cs b/EOLib/Domain/Character/CharacterActions.cs index e01db6ac9..0cb2aad89 100644 --- a/EOLib/Domain/Character/CharacterActions.cs +++ b/EOLib/Domain/Character/CharacterActions.cs @@ -1,12 +1,15 @@ -using System; -using System.Linq; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EOLib.Domain.Extensions; -using EOLib.Domain.NPC; +using EOLib.Domain.Map; using EOLib.Domain.Spells; using EOLib.IO.Repositories; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Data; +using Moffat.EndlessOnline.SDK.Protocol; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; +using System; +using System.Linq; namespace EOLib.Domain.Character { @@ -31,10 +34,7 @@ public CharacterActions(IPacketSendService packetSendService, public void Face(EODirection direction) { - var packet = new PacketBuilder(PacketFamily.Face, PacketAction.Player) - .AddChar((int)direction) - .Build(); - + var packet = new FacePlayerClientPacket { Direction = (Direction)direction }; _packetSendService.SendPacket(packet); } @@ -43,14 +43,20 @@ public void Walk() var admin = _characterRepository.MainCharacter.NoWall && _characterRepository.MainCharacter.AdminLevel != AdminLevel.Player; var renderProperties = _characterRepository.MainCharacter.RenderProperties; + var walkAction = new WalkAction + { + Direction = (Direction)renderProperties.Direction, + Timestamp = (int)_fixedTimeStepRepository.TickCount, + Coords = new Coords + { + X = renderProperties.GetDestinationX(), + Y = renderProperties.GetDestinationY() + } + }; - var packet = new PacketBuilder(PacketFamily.Walk, admin ? PacketAction.Admin : PacketAction.Player) - .AddChar((int)renderProperties.Direction) - .AddThree((int)_fixedTimeStepRepository.TickCount) - .AddChar(renderProperties.GetDestinationX()) - .AddChar(renderProperties.GetDestinationY()) - .Build(); - + var packet = admin + ? (IPacket)new WalkAdminClientPacket { WalkAction = walkAction } + : (IPacket)new WalkPlayerClientPacket { WalkAction = walkAction }; _packetSendService.SendPacket(packet); } @@ -60,52 +66,56 @@ public void Attack() var sp = Math.Max(0, c.Stats[CharacterStat.SP] - 1); _characterRepository.MainCharacter = c.WithStats(c.Stats.WithNewStat(CharacterStat.SP, sp)); - var packet = new PacketBuilder(PacketFamily.Attack, PacketAction.Use) - .AddChar((int) _characterRepository.MainCharacter.RenderProperties.Direction) - .AddThree((int)_fixedTimeStepRepository.TickCount) - .Build(); - + var packet = new AttackUseClientPacket + { + Direction = (Direction)_characterRepository.MainCharacter.RenderProperties.Direction, + Timestamp = (int)_fixedTimeStepRepository.TickCount + }; _packetSendService.SendPacket(packet); } - public void ToggleSit() + /// + public void Sit(MapCoordinate coords, bool isChair = false) { + if (coords.X < 0 || coords.Y < 0) + coords = MapCoordinate.Zero; + var renderProperties = _characterRepository.MainCharacter.RenderProperties; var sitAction = renderProperties.SitState == SitState.Standing ? SitAction.Sit : SitAction.Stand; - var packetFamily = renderProperties.SitState == SitState.Chair - ? PacketFamily.Chair - : PacketFamily.Sit; - - var packet = new PacketBuilder(packetFamily, PacketAction.Request) - .AddChar((int)sitAction) - .Build(); - - _packetSendService.SendPacket(packet); - } - - public void SitInChair() - { - var rp = _characterRepository.MainCharacter.RenderProperties; - var action = rp.SitState == SitState.Chair ? SitAction.Stand : SitAction.Sit; - var packet = new PacketBuilder(PacketFamily.Chair, PacketAction.Request) - .AddChar((int)action) - .AddChar(rp.GetDestinationX()) - .AddChar(rp.GetDestinationY()) - .Build(); - + IPacket packet = isChair || renderProperties.SitState == SitState.Chair + ? new ChairRequestClientPacket + { + SitAction = sitAction, + SitActionData = sitAction == SitAction.Sit + ? new ChairRequestClientPacket.SitActionDataSit + { + Coords = new Coords { X = coords.X, Y = coords.Y }, + } + : null + } + : (IPacket)new SitRequestClientPacket + { + SitAction = sitAction, + SitActionData = sitAction == SitAction.Sit + ? new SitRequestClientPacket.SitActionDataSit + { + CursorCoords = new Coords { X = coords.X, Y = coords.Y }, + } + : null + }; _packetSendService.SendPacket(packet); } public void PrepareCastSpell(int spellId) { - var packet = new PacketBuilder(PacketFamily.Spell, PacketAction.Request) - .AddShort(spellId) - .AddThree((int)_fixedTimeStepRepository.TickCount) - .Build(); - + var packet = new SpellRequestClientPacket + { + SpellId = spellId, + Timestamp = (int)_fixedTimeStepRepository.TickCount + }; _packetSendService.SendPacket(packet); } @@ -117,57 +127,40 @@ public void CastSpell(int spellId, ISpellTargetable target) var sp = Math.Max(0, c.Stats[CharacterStat.SP] - data.SP); _characterRepository.MainCharacter = c.WithStats(c.Stats.WithNewStat(CharacterStat.SP, sp)); - var action = data.Target == IO.SpellTarget.Self - ? PacketAction.TargetSelf - : data.Target == IO.SpellTarget.Normal - ? PacketAction.TargetOther - : data.Target == IO.SpellTarget.Group - ? PacketAction.TargetGroup - : throw new InvalidOperationException("Spell ID has unknown spell target"); - - IPacketBuilder builder = new PacketBuilder(PacketFamily.Spell, action); - - if (data.Target == IO.SpellTarget.Group) + IPacket packet = data.Target switch { - builder = builder - .AddShort(spellId) - .AddThree((int)_fixedTimeStepRepository.TickCount); - } - else - { - var spellTargetType = target is NPC.NPC - ? SpellTargetType.NPC - : target is Character - ? SpellTargetType.Player - : throw new InvalidOperationException("Invalid spell target specified, must be player or character"); - builder = builder.AddChar((int)spellTargetType); - - if (data.Target == IO.SpellTarget.Normal) + IO.SpellTarget.Self => new SpellTargetSelfClientPacket { - builder = builder - .AddChar(1) // unknown - .AddShort(1) // unknown - .AddShort(spellId) - .AddShort(target.Index) - .AddThree((int)_fixedTimeStepRepository.TickCount); - } - else + SpellId = spellId, + Direction = (Direction)c.RenderProperties.Direction, + Timestamp = (int)_fixedTimeStepRepository.TickCount, + }, + IO.SpellTarget.Normal => new SpellTargetOtherClientPacket { - builder = builder - .AddShort(spellId) - .AddInt((int)_fixedTimeStepRepository.TickCount); - } - } - - _packetSendService.SendPacket(builder.Build()); + SpellId = spellId, + VictimId = target.Index, + TargetType = target is NPC.NPC + ? SpellTargetType.Npc + : target is Character + ? SpellTargetType.Player + : throw new InvalidOperationException("Unknown SpellTargetType (must be character or NPC)"), + // todo: previous time stamp tracking. this was previously sent to eoserv as a char(1) and short (1) + PreviousTimestamp = NumberEncoder.DecodeNumber(new byte[] { 2, 2, 254 }), + Timestamp = (int)_fixedTimeStepRepository.TickCount, + }, + IO.SpellTarget.Group => new SpellTargetGroupClientPacket + { + SpellId = spellId, + Timestamp = (int)_fixedTimeStepRepository.TickCount, + }, + _ => throw new ArgumentOutOfRangeException("Unknown spell target (should be Self, Normal, or Group)") + }; + _packetSendService.SendPacket(packet); } public void Emote(Emote whichEmote) { - var packet = new PacketBuilder(PacketFamily.Emote, PacketAction.Report) - .AddChar((int)whichEmote) - .Build(); - + var packet = new EmoteReportClientPacket { Emote = (Moffat.EndlessOnline.SDK.Protocol.Emote)whichEmote }; _packetSendService.SendPacket(packet); } } @@ -180,9 +173,12 @@ public interface ICharacterActions void Attack(); - void ToggleSit(); - - void SitInChair(); + /// + /// Request sit action + /// + /// The chair coordinate for sitting in a chair, the mouse cursor coordinates for floor sit. + /// True if the sit action is for a chair. + void Sit(MapCoordinate coord, bool isChair = false); void PrepareCastSpell(int spellId); diff --git a/EOLib/Domain/Character/CharacterCreateData.cs b/EOLib/Domain/Character/CharacterCreateData.cs deleted file mode 100644 index 55138251c..000000000 --- a/EOLib/Domain/Character/CharacterCreateData.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Collections.Generic; -using EOLib.Net.Translators; - -namespace EOLib.Domain.Character -{ - public class CharacterCreateData : ICharacterCreateData - { - public CharacterReply Response { get; } - - private readonly List _characters; - public IReadOnlyList Characters => _characters; - - public CharacterCreateData(CharacterReply response, List characters) - { - Response = response; - _characters = characters; - } - } - - public interface ICharacterCreateData : ITranslatedData - { - CharacterReply Response { get; } - - IReadOnlyList Characters { get; } - } -} \ No newline at end of file diff --git a/EOLib/Domain/Character/CharacterManagementActions.cs b/EOLib/Domain/Character/CharacterManagementActions.cs index 98aa6f042..7a352a40a 100644 --- a/EOLib/Domain/Character/CharacterManagementActions.cs +++ b/EOLib/Domain/Character/CharacterManagementActions.cs @@ -1,11 +1,12 @@ -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Net; using EOLib.Net.Communication; -using EOLib.Net.Translators; +using Moffat.EndlessOnline.SDK.Protocol; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Linq; +using System.Threading.Tasks; namespace EOLib.Domain.Character { @@ -13,69 +14,85 @@ namespace EOLib.Domain.Character public class CharacterManagementActions : ICharacterManagementActions { private readonly IPacketSendService _packetSendService; - private readonly IPacketTranslator _characterCreatePacketTranslator; private readonly ICharacterSelectorRepository _characterSelectorRepository; public CharacterManagementActions(IPacketSendService packetSendService, - IPacketTranslator characterCreatePacketTranslator, ICharacterSelectorRepository characterSelectorRepository) { _packetSendService = packetSendService; - _characterCreatePacketTranslator = characterCreatePacketTranslator; _characterSelectorRepository = characterSelectorRepository; } public async Task RequestCharacterCreation() { - var packet = new PacketBuilder(PacketFamily.Character, PacketAction.Request) - .AddBreakString("NEW") - .Build(); - var responsePacket = await _packetSendService.SendEncodedPacketAndWaitAsync(packet); - return responsePacket.ReadShort(); + var packet = new CharacterRequestClientPacket(); + var response = await _packetSendService.SendEncodedPacketAndWaitAsync(packet); + + if (response is CharacterReplyServerPacket responsePacket) + return (int)responsePacket.ReplyCode; + + throw new EmptyPacketReceivedException(); } public async Task CreateCharacter(ICharacterCreateParameters parameters, int createID) { - var packet = new PacketBuilder(PacketFamily.Character, PacketAction.Create) - .AddShort(createID) - .AddShort(parameters.Gender) - .AddShort(parameters.HairStyle) - .AddShort(parameters.HairColor) - .AddShort(parameters.Race) - .AddByte(255) - .AddBreakString(parameters.Name) - .Build(); - var responsePacket = await _packetSendService.SendEncodedPacketAndWaitAsync(packet); + var packet = new CharacterCreateClientPacket + { + SessionId = createID, + Gender = (Gender)parameters.Gender, + HairStyle = parameters.HairStyle, + HairColor = parameters.HairColor, + Skin = parameters.Race, + Name = parameters.Name, + }; + + var response = await _packetSendService.SendEncodedPacketAndWaitAsync(packet); + if (!(response is CharacterReplyServerPacket responsePacket)) + throw new EmptyPacketReceivedException(); - var translatedData = _characterCreatePacketTranslator.TranslatePacket(responsePacket); - if (translatedData.Characters.Any()) - _characterSelectorRepository.Characters = translatedData.Characters; - return translatedData.Response; + if (responsePacket.ReplyCodeData is CharacterReplyServerPacket.ReplyCodeDataOk dataOk && dataOk.Characters.Any()) + { + _characterSelectorRepository.Characters = dataOk.Characters + .Select(Character.FromCharacterSelectionListEntry).ToList(); + } + + return responsePacket.ReplyCode; } public async Task RequestCharacterDelete() { - var packet = _characterSelectorRepository.CharacterForDelete.Match( - some: c => new PacketBuilder(PacketFamily.Character, PacketAction.Take).AddInt(c.ID).Build(), - none: () => new EmptyPacket()); - - var responsePacket = await _packetSendService.SendEncodedPacketAndWaitAsync(packet); - var deleteRequestId = responsePacket.ReadShort(); + var clientPacket = _characterSelectorRepository.CharacterForDelete.Match( + c => new CharacterTakeClientPacket { CharacterId = c.ID }, + () => null) ?? throw new NoDataSentException(); - return deleteRequestId; + var response = await _packetSendService.SendEncodedPacketAndWaitAsync(clientPacket); + if (!(response is CharacterPlayerServerPacket responsePacket)) + throw new EmptyPacketReceivedException(); + + return responsePacket.SessionId; } public async Task DeleteCharacter(int deleteRequestID) { - var packet = _characterSelectorRepository.CharacterForDelete.Match( - some: c => new PacketBuilder(PacketFamily.Character, PacketAction.Remove).AddShort(deleteRequestID).AddInt(c.ID).Build(), - none: () => new EmptyPacket()); + var clientPacket = _characterSelectorRepository.CharacterForDelete.Match( + c => new CharacterRemoveClientPacket + { + SessionId = deleteRequestID, + CharacterId = c.ID + }, + () => null) ?? throw new NoDataSentException(); + + var response = await _packetSendService.SendEncodedPacketAndWaitAsync(clientPacket); + if (!(response is CharacterReplyServerPacket responsePacket)) + throw new EmptyPacketReceivedException(); - var responsePacket = await _packetSendService.SendEncodedPacketAndWaitAsync(packet); + if (responsePacket.ReplyCodeData is CharacterReplyServerPacket.ReplyCodeDataDeleted dataDeleted) + { + _characterSelectorRepository.Characters = dataDeleted.Characters + .Select(Character.FromCharacterSelectionListEntry).ToList(); + } - var translatedData = _characterCreatePacketTranslator.TranslatePacket(responsePacket); - _characterSelectorRepository.Characters = translatedData.Characters; - return translatedData.Response; + return responsePacket.ReplyCode; } } diff --git a/EOLib/Domain/Character/CharacterRenderProperties.cs b/EOLib/Domain/Character/CharacterRenderProperties.cs index 419ad3ff6..f01a1f734 100644 --- a/EOLib/Domain/Character/CharacterRenderProperties.cs +++ b/EOLib/Domain/Character/CharacterRenderProperties.cs @@ -1,4 +1,6 @@ using Amadevus.RecordGenerator; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using NetSitState = Moffat.EndlessOnline.SDK.Protocol.Net.Server.SitState; namespace EOLib.Domain.Character { @@ -40,5 +42,29 @@ public sealed partial class CharacterRenderProperties public bool IsHidden { get; } public bool IsDead { get; } public bool IsDrunk { get; } + + public static CharacterRenderProperties FromCharacterMapInfo(CharacterMapInfo characterMapInfo) + { + return new Builder + { + Direction = (EODirection)characterMapInfo.Direction, + Gender = (int)characterMapInfo.Gender, + HairStyle = characterMapInfo.HairStyle, + HairColor = characterMapInfo.HairColor, + Race = characterMapInfo.Skin, + BootsGraphic = characterMapInfo.Equipment.Boots, + ArmorGraphic = characterMapInfo.Equipment.Armor, + HatGraphic = characterMapInfo.Equipment.Hat, + ShieldGraphic = characterMapInfo.Equipment.Shield, + WeaponGraphic = characterMapInfo.Equipment.Weapon, + SitState = (SitState)characterMapInfo.SitState, + CurrentAction = characterMapInfo.SitState == NetSitState.Stand + ? CharacterActionState.Standing + : CharacterActionState.Sitting, + IsHidden = characterMapInfo.Invisible, + MapX = characterMapInfo.Coords.X, + MapY = characterMapInfo.Coords.Y + }.ToImmutable(); + } } } diff --git a/EOLib/Domain/Character/CharacterReply.cs b/EOLib/Domain/Character/CharacterReply.cs deleted file mode 100644 index c2bc3b049..000000000 --- a/EOLib/Domain/Character/CharacterReply.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace EOLib.Domain.Character -{ - public enum CharacterReply : short - { - Exists = 1, - Full = 2, - NotApproved = 4, - Ok = 5, - Deleted = 6, - THIS_IS_WRONG = 255 - } -} \ No newline at end of file diff --git a/EOLib/Domain/Character/CharacterStats.cs b/EOLib/Domain/Character/CharacterStats.cs index 674485d95..506718e28 100644 --- a/EOLib/Domain/Character/CharacterStats.cs +++ b/EOLib/Domain/Character/CharacterStats.cs @@ -1,4 +1,5 @@ using Amadevus.RecordGenerator; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System; using System.Collections.Generic; using System.Linq; @@ -21,5 +22,105 @@ public CharacterStats WithNewStat(CharacterStat whichStat, int statValue) newStats[whichStat] = statValue; return new CharacterStats(newStats); } + + public CharacterStats Apply(CharacterStats other) + { + var dict = Stats.ToDictionary(k => k.Key, v => v.Value); + foreach (var pair in other.Stats) + dict[pair.Key] = pair.Value; + return new CharacterStats(dict); + } + + public static CharacterStats FromSelectCharacterData(WelcomeReplyServerPacket.WelcomeCodeDataSelectCharacter selectCharacterData) + { + var characterStatsWelcome = selectCharacterData.Stats; + var characterStats = new Dictionary + { + [CharacterStat.Level] = selectCharacterData.Level, + [CharacterStat.Experience] = selectCharacterData.Experience, + [CharacterStat.Usage] = selectCharacterData.Usage, + [CharacterStat.HP] = characterStatsWelcome.Hp, + [CharacterStat.MaxHP] = characterStatsWelcome.MaxHp, + [CharacterStat.TP] = characterStatsWelcome.Tp, + [CharacterStat.MaxTP] = characterStatsWelcome.MaxTp, + [CharacterStat.SP] = characterStatsWelcome.MaxSp, + [CharacterStat.MaxSP] = characterStatsWelcome.MaxSp, + [CharacterStat.StatPoints] = characterStatsWelcome.StatPoints, + [CharacterStat.SkillPoints] = characterStatsWelcome.SkillPoints, + [CharacterStat.Karma] = characterStatsWelcome.Karma, + [CharacterStat.Strength] = characterStatsWelcome.Base.Str, + [CharacterStat.Intelligence] = characterStatsWelcome.Base.Intl, + [CharacterStat.Wisdom] = characterStatsWelcome.Base.Wis, + [CharacterStat.Agility] = characterStatsWelcome.Base.Agi, + [CharacterStat.Constitution] = characterStatsWelcome.Base.Con, + [CharacterStat.Charisma] = characterStatsWelcome.Base.Cha, + [CharacterStat.MinDam] = characterStatsWelcome.Secondary.MinDamage, + [CharacterStat.MaxDam] = characterStatsWelcome.Secondary.MaxDamage, + [CharacterStat.Accuracy] = characterStatsWelcome.Secondary.Accuracy, + [CharacterStat.Evade] = characterStatsWelcome.Secondary.Evade, + [CharacterStat.Armor] = characterStatsWelcome.Secondary.Armor, + }; + + return new CharacterStats(characterStats); + } + + public static CharacterStats FromCharacterMapInfo(CharacterMapInfo characterMapInfo) + { + return new CharacterStats(new Dictionary + { + [CharacterStat.Level] = characterMapInfo.Level, + [CharacterStat.HP] = characterMapInfo.Hp, + [CharacterStat.MaxHP] = characterMapInfo.MaxHp, + [CharacterStat.TP] = characterMapInfo.Tp, + [CharacterStat.MaxTP] = characterMapInfo.MaxTp, + }); + } + + public static CharacterStats FromStatUpdate(CharacterStatsUpdate characterStatsUpdate) + { + return new CharacterStats(new Dictionary + { + [CharacterStat.MaxHP] = characterStatsUpdate.MaxHp, + [CharacterStat.MaxTP] = characterStatsUpdate.MaxTp, + [CharacterStat.MaxSP] = characterStatsUpdate.MaxSp, + [CharacterStat.Strength] = characterStatsUpdate.BaseStats.Str, + [CharacterStat.Intelligence] = characterStatsUpdate.BaseStats.Intl, + [CharacterStat.Wisdom] = characterStatsUpdate.BaseStats.Wis, + [CharacterStat.Agility] = characterStatsUpdate.BaseStats.Agi, + [CharacterStat.Constitution] = characterStatsUpdate.BaseStats.Con, + [CharacterStat.Charisma] = characterStatsUpdate.BaseStats.Cha, + [CharacterStat.MaxWeight] = characterStatsUpdate.MaxWeight, + [CharacterStat.MinDam] = characterStatsUpdate.SecondaryStats.MinDamage, + [CharacterStat.MaxDam] = characterStatsUpdate.SecondaryStats.MaxDamage, + [CharacterStat.Accuracy] = characterStatsUpdate.SecondaryStats.Accuracy, + [CharacterStat.Evade] = characterStatsUpdate.SecondaryStats.Evade, + [CharacterStat.Armor] = characterStatsUpdate.SecondaryStats.Armor, + }); + } + + public static CharacterStats FromStatReset(CharacterStatsReset characterStatsUpdate) + { + return new CharacterStats(new Dictionary + { + [CharacterStat.StatPoints] = characterStatsUpdate.StatPoints, + [CharacterStat.SkillPoints] = characterStatsUpdate.SkillPoints, + [CharacterStat.HP] = characterStatsUpdate.Hp, + [CharacterStat.MaxHP] = characterStatsUpdate.MaxHp, + [CharacterStat.TP] = characterStatsUpdate.Tp, + [CharacterStat.MaxTP] = characterStatsUpdate.MaxTp, + [CharacterStat.MaxSP] = characterStatsUpdate.MaxSp, + [CharacterStat.Strength] = characterStatsUpdate.Base.Str, + [CharacterStat.Intelligence] = characterStatsUpdate.Base.Intl, + [CharacterStat.Wisdom] = characterStatsUpdate.Base.Wis, + [CharacterStat.Agility] = characterStatsUpdate.Base.Agi, + [CharacterStat.Constitution] = characterStatsUpdate.Base.Con, + [CharacterStat.Charisma] = characterStatsUpdate.Base.Cha, + [CharacterStat.MinDam] = characterStatsUpdate.Secondary.MinDamage, + [CharacterStat.MaxDam] = characterStatsUpdate.Secondary.MaxDamage, + [CharacterStat.Accuracy] = characterStatsUpdate.Secondary.Accuracy, + [CharacterStat.Evade] = characterStatsUpdate.Secondary.Evade, + [CharacterStat.Armor] = characterStatsUpdate.Secondary.Armor, + }); + } } } diff --git a/EOLib/Domain/Character/IPlayerInfoData.cs b/EOLib/Domain/Character/IPlayerInfoData.cs index 8da2e5525..ae162a5d1 100644 --- a/EOLib/Domain/Character/IPlayerInfoData.cs +++ b/EOLib/Domain/Character/IPlayerInfoData.cs @@ -1,4 +1,4 @@ -using EOLib.Domain.Online; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.Domain.Character { @@ -22,6 +22,6 @@ public interface IPlayerInfoData int Gender { get; } - OnlineIcon Icon { get; } + CharacterIcon Icon { get; } } } diff --git a/EOLib/Domain/Character/InventoryItem.cs b/EOLib/Domain/Character/InventoryItem.cs index 22003aeed..cb5b26e9c 100644 --- a/EOLib/Domain/Character/InventoryItem.cs +++ b/EOLib/Domain/Character/InventoryItem.cs @@ -1,4 +1,7 @@ using Amadevus.RecordGenerator; +using System; + +using NetItem = Moffat.EndlessOnline.SDK.Protocol.Net.Item; namespace EOLib.Domain.Character { @@ -8,5 +11,7 @@ public sealed partial class InventoryItem public int ItemID { get; } public int Amount { get; } + + public static InventoryItem FromNet(NetItem source) => new InventoryItem(source.Id, source.Amount); } } \ No newline at end of file diff --git a/EOLib/Domain/Character/InventorySpell.cs b/EOLib/Domain/Character/InventorySpell.cs index d5bc2f136..4cb14e21b 100644 --- a/EOLib/Domain/Character/InventorySpell.cs +++ b/EOLib/Domain/Character/InventorySpell.cs @@ -1,4 +1,5 @@ using Amadevus.RecordGenerator; +using Moffat.EndlessOnline.SDK.Protocol.Net; namespace EOLib.Domain.Character { @@ -8,5 +9,7 @@ public sealed partial class InventorySpell public int ID { get; } public int Level { get; } + + public static InventorySpell FromNet(Spell source) => new InventorySpell(source.Id, source.Level); } } \ No newline at end of file diff --git a/EOLib/Domain/Character/PaperdollData.cs b/EOLib/Domain/Character/PaperdollData.cs index fa7c891d7..3ded396da 100644 --- a/EOLib/Domain/Character/PaperdollData.cs +++ b/EOLib/Domain/Character/PaperdollData.cs @@ -1,6 +1,7 @@ using Amadevus.RecordGenerator; -using EOLib.Domain.Online; using EOLib.IO; +using Moffat.EndlessOnline.SDK.Protocol; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.Domain.Character @@ -32,7 +33,7 @@ public sealed partial class PaperdollData public IReadOnlyList QuestNames { get; } - public OnlineIcon Icon { get; } + public CharacterIcon Icon { get; } public PaperdollData() { diff --git a/EOLib/Domain/Character/SitAction.cs b/EOLib/Domain/Character/SitAction.cs deleted file mode 100644 index 91727e477..000000000 --- a/EOLib/Domain/Character/SitAction.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace EOLib.Domain.Character -{ - public enum SitAction - { - Sit = 1, - Stand = 2 - } -} diff --git a/EOLib/Domain/Character/TrainType.cs b/EOLib/Domain/Character/TrainType.cs deleted file mode 100644 index b74c552e5..000000000 --- a/EOLib/Domain/Character/TrainType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace EOLib.Domain.Character -{ - internal enum TrainType - { - Stat = 1, - Skill = 2 - } -} diff --git a/EOLib/Domain/Character/TrainingActions.cs b/EOLib/Domain/Character/TrainingActions.cs index 3bd9e7439..6d4014ba2 100644 --- a/EOLib/Domain/Character/TrainingActions.cs +++ b/EOLib/Domain/Character/TrainingActions.cs @@ -1,7 +1,7 @@ -using System; -using AutomaticTypeMapper; -using EOLib.Net; +using AutomaticTypeMapper; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; +using System; namespace EOLib.Domain.Character { @@ -20,21 +20,27 @@ public void LevelUpStat(CharacterStat whichStat) if (InvalidStat(whichStat)) return; - var packet = new PacketBuilder(PacketFamily.StatSkill, PacketAction.Add) - .AddChar((int) TrainType.Stat) - .AddShort(GetStatIndex(whichStat)) - .Build(); - + var packet = new StatSkillAddClientPacket + { + ActionType = TrainType.Stat, + ActionTypeData = new StatSkillAddClientPacket.ActionTypeDataStat + { + StatId = (StatId)GetStatIndex(whichStat) + } + }; _packetSendService.SendPacket(packet); } public void LevelUpSkill(int spellId) { - var packet = new PacketBuilder(PacketFamily.StatSkill, PacketAction.Add) - .AddChar((int)TrainType.Skill) - .AddShort(spellId) - .Build(); - + var packet = new StatSkillAddClientPacket + { + ActionType = TrainType.Skill, + ActionTypeData = new StatSkillAddClientPacket.ActionTypeDataSkill + { + SpellId = spellId + } + }; _packetSendService.SendPacket(packet); } @@ -54,17 +60,16 @@ private static bool InvalidStat(CharacterStat whichStat) private static int GetStatIndex(CharacterStat whichStat) { - switch (whichStat) + return whichStat switch { - case CharacterStat.Strength: return 1; - case CharacterStat.Intelligence: return 2; - case CharacterStat.Wisdom: return 3; - case CharacterStat.Agility: return 4; - case CharacterStat.Constitution: return 5; - case CharacterStat.Charisma: return 6; - } - - throw new ArgumentOutOfRangeException(nameof(whichStat)); + CharacterStat.Strength => 1, + CharacterStat.Intelligence => 2, + CharacterStat.Wisdom => 3, + CharacterStat.Agility => 4, + CharacterStat.Constitution => 5, + CharacterStat.Charisma => 6, + _ => throw new ArgumentOutOfRangeException(nameof(whichStat)), + }; } } diff --git a/EOLib/Domain/Chat/Builders/ChatPacketBuilder.cs b/EOLib/Domain/Chat/Builders/ChatPacketBuilder.cs new file mode 100644 index 000000000..ff643914f --- /dev/null +++ b/EOLib/Domain/Chat/Builders/ChatPacketBuilder.cs @@ -0,0 +1,34 @@ +using System; +using AutomaticTypeMapper; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; + +namespace EOLib.Domain.Chat.Builders +{ + [AutoMappedType] + public class ChatPacketBuilder : IChatPacketBuilder + { + public IPacket BuildChatPacket(ChatType chatType, string chat, string targetCharacter) + { + IPacket packet; + switch (chatType) + { + case ChatType.Local: packet = new TalkReportClientPacket { Message = chat }; break; + case ChatType.PM: + if (string.IsNullOrEmpty(targetCharacter)) + { + throw new ArgumentException("Target character must be specified for PM messages", nameof(targetCharacter)); + } + packet = new TalkTellClientPacket { Message = chat, Name = targetCharacter }; + break; + case ChatType.Global: packet = new TalkMsgClientPacket { Message = chat }; break; + case ChatType.Guild: packet = new TalkRequestClientPacket { Message = chat }; break; + case ChatType.Party: packet = new TalkOpenClientPacket { Message = chat }; break; + case ChatType.Admin: packet = new TalkAdminClientPacket { Message = chat }; break; + case ChatType.Announce: packet = new TalkAnnounceClientPacket { Message = chat }; break; + default: throw new ArgumentOutOfRangeException(nameof(chatType)); + } + return packet; + } + } +} diff --git a/EOLib/Domain/Chat/Builders/IChatPacketBuilder.cs b/EOLib/Domain/Chat/Builders/IChatPacketBuilder.cs new file mode 100644 index 000000000..8768ed773 --- /dev/null +++ b/EOLib/Domain/Chat/Builders/IChatPacketBuilder.cs @@ -0,0 +1,9 @@ +using Moffat.EndlessOnline.SDK.Protocol.Net; + +namespace EOLib.Domain.Chat.Builders +{ + public interface IChatPacketBuilder + { + IPacket BuildChatPacket(ChatType chatType, string chat, string targetCharacter); + } +} diff --git a/EOLib/Domain/Chat/ChatActions.cs b/EOLib/Domain/Chat/ChatActions.cs index e2de5c0de..adeb17eea 100644 --- a/EOLib/Domain/Chat/ChatActions.cs +++ b/EOLib/Domain/Chat/ChatActions.cs @@ -1,10 +1,11 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; +using EOLib.Domain.Chat.Builders; using EOLib.Domain.Map; using EOLib.Domain.Party; -using EOLib.Net; -using EOLib.Net.Builders; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; using System; using System.Linq; @@ -107,18 +108,13 @@ public ChatActions(IChatRepository chatRepository, public void SetHearWhispers(bool whispersEnabled) { - // GLOBAL_REMOVE with 'n' enables whispers...? - var packet = new PacketBuilder(PacketFamily.Global, whispersEnabled ? PacketAction.Remove : PacketAction.Player) - .AddChar(whispersEnabled ? 'n' : 'y') - .Build(); + var packet = whispersEnabled ? (IPacket)new GlobalRemoveClientPacket() : new GlobalPlayerClientPacket(); _packetSendService.SendPacket(packet); } public void SetGlobalActive(bool active) { - var packet = new PacketBuilder(PacketFamily.Global, active ? PacketAction.Open : PacketAction.Close) - .AddChar(active ? 'y' : 'n') - .Build(); + var packet = active ? (IPacket)new GlobalOpenClientPacket() : new GlobalCloseClientPacket(); _packetSendService.SendPacket(packet); } diff --git a/EOLib/Domain/Chat/ChatTypeCalculator.cs b/EOLib/Domain/Chat/ChatTypeCalculator.cs index 28bcf107c..4bfea9423 100644 --- a/EOLib/Domain/Chat/ChatTypeCalculator.cs +++ b/EOLib/Domain/Chat/ChatTypeCalculator.cs @@ -1,6 +1,6 @@ -using System; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EOLib.Domain.Character; +using Moffat.EndlessOnline.SDK.Protocol; namespace EOLib.Domain.Chat { @@ -22,17 +22,17 @@ public ChatType CalculateChatType(string input) if(!CharacterIsAdmin && (input[0] == '+' || input[0] == '@')) return ChatType.Local; - switch (input[0]) + return input[0] switch { - case '+': return ChatType.Admin; - case '@': return ChatType.Announce; - case '\'': return ChatType.Party; - case '&': return ChatType.Guild; - case '~': return ChatType.Global; - case '!': return ChatType.PM; - case '#': return ChatType.Command; - default: return ChatType.Local; - } + '+' => ChatType.Admin, + '@' => ChatType.Announce, + '\'' => ChatType.Party, + '&' => ChatType.Guild, + '~' => ChatType.Global, + '!' => ChatType.PM, + '#' => ChatType.Command, + _ => ChatType.Local, + }; } private bool CharacterIsAdmin => _characterProvider.MainCharacter.AdminLevel != AdminLevel.Player; diff --git a/EOLib/Domain/Chat/Commands/FindCommand.cs b/EOLib/Domain/Chat/Commands/FindCommand.cs index 199dc29b6..8a8e116e7 100644 --- a/EOLib/Domain/Chat/Commands/FindCommand.cs +++ b/EOLib/Domain/Chat/Commands/FindCommand.cs @@ -1,6 +1,6 @@ using AutomaticTypeMapper; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Chat.Commands { @@ -20,11 +20,8 @@ public bool Execute(string parameter) if (string.IsNullOrEmpty(parameter)) return false; - var packet = new PacketBuilder(PacketFamily.Players, PacketAction.Accept) - .AddString(parameter) - .Build(); + _packetSendService.SendPacketAsync(new PlayersAcceptClientPacket { Name = parameter }); - _packetSendService.SendPacketAsync(packet); return true; } } diff --git a/EOLib/Domain/Chat/Commands/NoWallCommand.cs b/EOLib/Domain/Chat/Commands/NoWallCommand.cs index c792a58c8..1a29ee7a0 100644 --- a/EOLib/Domain/Chat/Commands/NoWallCommand.cs +++ b/EOLib/Domain/Chat/Commands/NoWallCommand.cs @@ -1,5 +1,6 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; +using Moffat.EndlessOnline.SDK.Protocol; namespace EOLib.Domain.Chat.Commands { diff --git a/EOLib/Domain/Chat/Commands/PingCommand.cs b/EOLib/Domain/Chat/Commands/PingCommand.cs index 998e5255e..53b2be141 100644 --- a/EOLib/Domain/Chat/Commands/PingCommand.cs +++ b/EOLib/Domain/Chat/Commands/PingCommand.cs @@ -1,8 +1,7 @@ -using System; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EOLib.Domain.Protocol; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Chat.Commands { @@ -11,7 +10,6 @@ public class PingCommand : IPlayerCommand { private readonly IPacketSendService _packetSendService; private readonly IPingTimeRepository _pingTimeRepository; - private readonly Random _random; public const string Text = "ping"; @@ -22,24 +20,12 @@ public PingCommand(IPacketSendService packetSendService, { _packetSendService = packetSendService; _pingTimeRepository = pingTimeRepository; - _random = new Random(); } public bool Execute(string parameter) { - int requestID; - do - { - requestID = _random.Next(0, short.MaxValue - 1); - } while (_pingTimeRepository.PingRequests.ContainsKey(requestID)); - - _pingTimeRepository.PingRequests.Add(requestID, DateTime.Now); - - var packet = new PacketBuilder(PacketFamily.Message, PacketAction.Ping) - .AddShort(requestID) - .Build(); - - _packetSendService.SendPacketAsync(packet); + _packetSendService.SendPacket(new MessagePingClientPacket()); + _pingTimeRepository.RequestTimer.Start(); return true; } } diff --git a/EOLib/Domain/Extensions/NPCExtensions.cs b/EOLib/Domain/Extensions/NPCExtensions.cs index 83b19b9a9..566735522 100644 --- a/EOLib/Domain/Extensions/NPCExtensions.cs +++ b/EOLib/Domain/Extensions/NPCExtensions.cs @@ -38,6 +38,9 @@ public static int GetWalkFrame(this NPC.NPC npc) public static NPC.NPC WithNextWalkFrame(this NPC.NPC npc) { + if (npc.IsActing(NPCActionState.Attacking)) + return npc; + if (npc.Frame == NPCFrame.WalkFrame4) { return npc.WithFrame(NPCFrame.Standing); @@ -52,6 +55,9 @@ public static NPC.NPC WithNextWalkFrame(this NPC.NPC npc) public static NPC.NPC WithNextAttackFrame(this NPC.NPC npc) { + if (npc.IsActing(NPCActionState.Walking)) + return npc; + var retNpc = npc.WithActualAttackFrame((npc.ActualAttackFrame + 1) % 5); if (npc.ActualAttackFrame == 0) diff --git a/EOLib/Domain/Extensions/PaperdollExtensions.cs b/EOLib/Domain/Extensions/PaperdollExtensions.cs new file mode 100644 index 000000000..59bd16f3b --- /dev/null +++ b/EOLib/Domain/Extensions/PaperdollExtensions.cs @@ -0,0 +1,53 @@ +using EOLib.IO; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Collections.Generic; + +namespace EOLib.Domain.Extensions +{ + public static class PaperdollExtensions + { + public static IReadOnlyDictionary GetPaperdoll(this EquipmentWelcome equipment) + { + return new Dictionary + { + [EquipLocation.Boots] = equipment.Boots, + [EquipLocation.Accessory] = equipment.Accessory, + [EquipLocation.Gloves] = equipment.Gloves, + [EquipLocation.Belt] = equipment.Belt, + [EquipLocation.Armor] = equipment.Armor, + [EquipLocation.Necklace] = equipment.Necklace, + [EquipLocation.Hat] = equipment.Hat, + [EquipLocation.Shield] = equipment.Shield, + [EquipLocation.Weapon] = equipment.Weapon, + [EquipLocation.Ring1] = equipment.Ring[0], + [EquipLocation.Ring2] = equipment.Ring[1], + [EquipLocation.Armlet1] = equipment.Armlet[0], + [EquipLocation.Armlet2] = equipment.Armlet[1], + [EquipLocation.Bracer1] = equipment.Bracer[0], + [EquipLocation.Bracer2] = equipment.Bracer[1], + }; + } + + public static IReadOnlyDictionary GetPaperdoll(this EquipmentPaperdoll equipment) + { + return new Dictionary + { + [EquipLocation.Boots] = equipment.Boots, + [EquipLocation.Accessory] = equipment.Accessory, + [EquipLocation.Gloves] = equipment.Gloves, + [EquipLocation.Belt] = equipment.Belt, + [EquipLocation.Armor] = equipment.Armor, + [EquipLocation.Necklace] = equipment.Necklace, + [EquipLocation.Hat] = equipment.Hat, + [EquipLocation.Shield] = equipment.Shield, + [EquipLocation.Weapon] = equipment.Weapon, + [EquipLocation.Ring1] = equipment.Ring[0], + [EquipLocation.Ring2] = equipment.Ring[1], + [EquipLocation.Armlet1] = equipment.Armlet[0], + [EquipLocation.Armlet2] = equipment.Armlet[1], + [EquipLocation.Bracer1] = equipment.Bracer[0], + [EquipLocation.Bracer2] = equipment.Bracer[1], + }; + } + } +} diff --git a/EOLib/Domain/Interact/Bank/BankActions.cs b/EOLib/Domain/Interact/Bank/BankActions.cs index fb3a6ea2f..fd221e1d5 100644 --- a/EOLib/Domain/Interact/Bank/BankActions.cs +++ b/EOLib/Domain/Interact/Bank/BankActions.cs @@ -1,6 +1,7 @@ using AutomaticTypeMapper; using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Interact.Bank { @@ -8,37 +9,28 @@ namespace EOLib.Domain.Interact.Bank public class BankActions : IBankActions { private readonly IPacketSendService _packetSendService; + private readonly IBankDataProvider _bankDataProvider; - public BankActions(IPacketSendService packetSendService) + public BankActions(IPacketSendService packetSendService, + IBankDataProvider bankDataProvider) { _packetSendService = packetSendService; + _bankDataProvider = bankDataProvider; } public void Deposit(int amount) { - var packet = new PacketBuilder(PacketFamily.Bank, PacketAction.Add) - .AddInt(amount) - .Build(); - + var packet = new BankAddClientPacket { Amount = amount, SessionId = _bankDataProvider.SessionID }; _packetSendService.SendPacket(packet); } public void Withdraw(int amount) { - var packet = new PacketBuilder(PacketFamily.Bank, PacketAction.Take) - .AddInt(amount) - .Build(); - + var packet = new BankTakeClientPacket { Amount = amount, SessionId = _bankDataProvider.SessionID }; _packetSendService.SendPacket(packet); } - public void BuyStorageUpgrade() - { - var packet = new PacketBuilder(PacketFamily.Locker, PacketAction.Buy) - .Build(); - - _packetSendService.SendPacket(packet); - } + public void BuyStorageUpgrade() => _packetSendService.SendPacket(new LockerBuyClientPacket()); } public interface IBankActions diff --git a/EOLib/Domain/Interact/Barber/BarberActions.cs b/EOLib/Domain/Interact/Barber/BarberActions.cs index ac7415a3d..9624ca394 100644 --- a/EOLib/Domain/Interact/Barber/BarberActions.cs +++ b/EOLib/Domain/Interact/Barber/BarberActions.cs @@ -1,8 +1,6 @@ using AutomaticTypeMapper; -using EOLib.Net; using EOLib.Net.Communication; -using System.Diagnostics; -using EOLib.Domain.Character; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Interact.Barber { [AutoMappedType] @@ -20,13 +18,12 @@ public BarberActions(IPacketSendService packetSendService, public void Purchase(int hairStyle, int hairColor) { - var packet = new PacketBuilder(PacketFamily.Barber, PacketAction.Buy) - .AddChar((char)hairStyle) - .AddChar((char)hairColor) - .AddInt(_barberDataRepository.SessionID) - .Build(); - - _packetSendService.SendPacket(packet); + _packetSendService.SendPacket(new BarberBuyClientPacket + { + SessionId = _barberDataRepository.SessionID, + HairStyle = hairStyle, + HairColor = hairColor, + }); } } @@ -34,4 +31,4 @@ public interface IBarberActions { void Purchase(int hairStyle, int hairColor); } -} \ No newline at end of file +} diff --git a/EOLib/Domain/Interact/Board/BoardActions.cs b/EOLib/Domain/Interact/Board/BoardActions.cs index d333fa35a..42802b0ad 100644 --- a/EOLib/Domain/Interact/Board/BoardActions.cs +++ b/EOLib/Domain/Interact/Board/BoardActions.cs @@ -1,6 +1,6 @@ using AutomaticTypeMapper; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Interact.Board { @@ -21,13 +21,13 @@ public void AddPost(string subject, string body) { _boardProvider.BoardId.MatchSome(boardId => { - var packet = new PacketBuilder(PacketFamily.Board, PacketAction.Create) - .AddShort(boardId) - .AddByte(255) - .AddBreakString(subject.Replace('y', (char)255)) // this is in EOSERV for some reason. Probably due to chunking (see Sanitization here: https://github.com/Cirras/eo-protocol/blob/master/docs/chunks.md) - .AddBreakString(body.Replace('\n', '\r')) // original EO client uses \r as newline separator. XNAControls uses \n. - .Build(); - + var packet = new BoardCreateClientPacket + { + BoardId = boardId, + PostSubject = subject, + // original EO client uses \r as newline separator. XNAControls uses \n. + PostBody = body.Replace('\n', '\r') + }; _packetSendService.SendPacket(packet); }); } @@ -36,11 +36,11 @@ public void DeletePost(int postId) { _boardProvider.BoardId.MatchSome(boardId => { - var packet = new PacketBuilder(PacketFamily.Board, PacketAction.Remove) - .AddShort(boardId) - .AddShort(postId) - .Build(); - + var packet = new BoardRemoveClientPacket + { + BoardId = boardId, + PostId = postId + }; _packetSendService.SendPacket(packet); }); } @@ -49,11 +49,11 @@ public void ViewPost(int postId) { _boardProvider.BoardId.MatchSome(boardId => { - var packet = new PacketBuilder(PacketFamily.Board, PacketAction.Take) - .AddShort(boardId) - .AddShort(postId) - .Build(); - + var packet = new BoardTakeClientPacket + { + BoardId = boardId, + PostId = postId + }; _packetSendService.SendPacket(packet); }); } diff --git a/EOLib/Domain/Interact/BookActions.cs b/EOLib/Domain/Interact/BookActions.cs index 76f75d14f..3108ac140 100644 --- a/EOLib/Domain/Interact/BookActions.cs +++ b/EOLib/Domain/Interact/BookActions.cs @@ -1,6 +1,6 @@ using AutomaticTypeMapper; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Interact { @@ -16,9 +16,7 @@ public BookActions(IPacketSendService packetSendService) public void RequestBook(int characterId) { - var packet = new PacketBuilder(PacketFamily.Book, PacketAction.Request) - .AddShort(characterId) - .Build(); + var packet = new BookRequestClientPacket { PlayerId = characterId }; _packetSendService.SendPacket(packet); } } diff --git a/EOLib/Domain/Interact/Citizen/CitizenActions.cs b/EOLib/Domain/Interact/Citizen/CitizenActions.cs index 8ac765df6..c2d769932 100644 --- a/EOLib/Domain/Interact/Citizen/CitizenActions.cs +++ b/EOLib/Domain/Interact/Citizen/CitizenActions.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Map; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; using System.Collections.Generic; +using System.Linq; namespace EOLib.Domain.Interact.Citizen { @@ -24,46 +25,42 @@ public CitizenActions(IPacketSendService packetSendService, public void RequestSleep() { - var packet = new PacketBuilder(PacketFamily.Citizen, PacketAction.Request) - .AddShort(_currentMapStateProvider.MapWarpSession.ValueOr(0)) - .AddShort(_citizenDataProvider.BehaviorID.ValueOr(0)) - .Build(); - + var packet = new CitizenRequestClientPacket + { + SessionId = _currentMapStateProvider.MapWarpSession.ValueOr(0), + BehaviorId = _citizenDataProvider.BehaviorID.ValueOr(0), + }; _packetSendService.SendPacket(packet); } public void ConfirmSleep() { - var packet = new PacketBuilder(PacketFamily.Citizen, PacketAction.Accept) - .AddShort(_currentMapStateProvider.MapWarpSession.ValueOr(0)) - .AddShort(_citizenDataProvider.BehaviorID.ValueOr(0)) - .Build(); - + var packet = new CitizenAcceptClientPacket + { + SessionId = _currentMapStateProvider.MapWarpSession.ValueOr(0), + BehaviorId = _citizenDataProvider.BehaviorID.ValueOr(0), + }; _packetSendService.SendPacket(packet); } public void SignUp(IReadOnlyList answers) { - var packet = new PacketBuilder(PacketFamily.Citizen, PacketAction.Reply) - .AddShort(_currentMapStateProvider.MapWarpSession.ValueOr(0)) - .AddByte(255) - .AddShort(_citizenDataProvider.BehaviorID.ValueOr(0)) - .AddByte(255) - .AddBreakString(answers[0]) - .AddBreakString(answers[1]) - .AddString(answers[2]) - .Build(); - + var packet = new CitizenReplyClientPacket + { + SessionId = _currentMapStateProvider.MapWarpSession.ValueOr(0), + BehaviorId = _citizenDataProvider.BehaviorID.ValueOr(0), + Answers = answers.ToList(), + }; _packetSendService.SendPacket(packet); } public void Unsubscribe() { - var packet = new PacketBuilder(PacketFamily.Citizen, PacketAction.Remove) - .AddShort(_citizenDataProvider.BehaviorID.ValueOr(0)) - .Build(); - + var packet = new CitizenRemoveClientPacket + { + BehaviorId = _citizenDataProvider.BehaviorID.ValueOr(0) + }; _packetSendService.SendPacket(packet); } } diff --git a/EOLib/Domain/Interact/Citizen/CitizenUnsubscribeReply.cs b/EOLib/Domain/Interact/Citizen/CitizenUnsubscribeReply.cs deleted file mode 100644 index 18dac7a74..000000000 --- a/EOLib/Domain/Interact/Citizen/CitizenUnsubscribeReply.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace EOLib.Domain.Interact.Citizen -{ - public enum CitizenUnsubscribeReply - { - NotACitizen = 0, - Unsubscribed = 1 - } -} diff --git a/EOLib/Domain/Interact/INPCInteractionNotifier.cs b/EOLib/Domain/Interact/INPCInteractionNotifier.cs index fba6595cc..b340b801a 100644 --- a/EOLib/Domain/Interact/INPCInteractionNotifier.cs +++ b/EOLib/Domain/Interact/INPCInteractionNotifier.cs @@ -1,9 +1,7 @@ using AutomaticTypeMapper; -using EOLib.Domain.Interact.Citizen; -using EOLib.Domain.Interact.Law; -using EOLib.Domain.Interact.Priest; using EOLib.Domain.Interact.Skill; using EOLib.IO; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.Domain.Interact { @@ -19,7 +17,7 @@ public interface INPCInteractionNotifier void NotifyStatReset(); - void NotifyCitizenUnsubscribe(CitizenUnsubscribeReply reply); + void NotifyCitizenUnsubscribe(InnUnsubscribeReply reply); void NotifyCitizenSignUp(int questionsWrong); @@ -45,7 +43,7 @@ public void NotifySkillForget() { } public void NotifyStatReset() { } - public void NotifyCitizenUnsubscribe(CitizenUnsubscribeReply reply) { } + public void NotifyCitizenUnsubscribe(InnUnsubscribeReply reply) { } public void NotifyCitizenSignUp(int questionsWrong) { } diff --git a/EOLib/Domain/Interact/Jukebox/JukeboxActions.cs b/EOLib/Domain/Interact/Jukebox/JukeboxActions.cs index efdde2ddf..2aa3c265b 100644 --- a/EOLib/Domain/Interact/Jukebox/JukeboxActions.cs +++ b/EOLib/Domain/Interact/Jukebox/JukeboxActions.cs @@ -1,10 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; -using EOLib.Domain.Map; using EOLib.IO; using EOLib.IO.Repositories; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; using Optional.Collections; using System; @@ -35,23 +34,19 @@ public void PlayNote(int noteIndex) _eifFileProvider.EIFFile.SingleOrNone(x => x.Type == ItemType.Weapon && x.DollGraphic == weapon) .MatchSome(rec => { - var packet = new PacketBuilder(PacketFamily.JukeBox, PacketAction.Use) - .AddChar(rec.DollGraphic) // todo: determine what GameServer expects; eoserv sends DollGraphic as a response in Character::PlayBard - .AddChar(noteIndex + 1) - .Build(); - + // todo: determine what GameServer expects; eoserv sends DollGraphic as a response in Character::PlayBard + var packet = new JukeboxUseClientPacket + { + InstrumentId = rec.DollGraphic, + NoteId = noteIndex + 1, + }; _packetSendService.SendPacket(packet); }); } - public void RequestSong(MapCoordinate coordinate, int songIndex) + public void RequestSong(int songIndex) { - var packet = new PacketBuilder(PacketFamily.JukeBox, PacketAction.Message) - .AddChar(coordinate.X) - .AddChar(coordinate.Y) - .AddShort(songIndex) - .Build(); - + var packet = new JukeboxMsgClientPacket { TrackId = songIndex }; _packetSendService.SendPacket(packet); } } @@ -60,6 +55,6 @@ public interface IJukeboxActions { void PlayNote(int noteIndex); - void RequestSong(MapCoordinate coordinate, int songIndex); + void RequestSong(int songIndex); } } diff --git a/EOLib/Domain/Interact/Law/LawActions.cs b/EOLib/Domain/Interact/Law/LawActions.cs index b5e3b3d99..61f0ba62b 100644 --- a/EOLib/Domain/Interact/Law/LawActions.cs +++ b/EOLib/Domain/Interact/Law/LawActions.cs @@ -1,6 +1,6 @@ using AutomaticTypeMapper; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Interact.Law { @@ -19,7 +19,7 @@ public LawActions(ILawSessionProvider lawSessionProvider, public void RequestMarriage(string partner) { - SendShared(MarriageRequestType.Marriage, partner); + SendShared(MarriageRequestType.MarriageApproval, partner); } public void RequestDivorce(string partner) @@ -29,13 +29,12 @@ public void RequestDivorce(string partner) private void SendShared(MarriageRequestType requestType, string partner) { - var packet = new PacketBuilder(PacketFamily.Marriage, PacketAction.Request) - .AddChar((int)requestType) - .AddInt(_lawSessionProvider.SessionID) - .AddByte(255) - .AddString(partner) - .Build(); - + var packet = new MarriageRequestClientPacket + { + RequestType = requestType, + SessionId = _lawSessionProvider.SessionID, + Name = partner + }; _packetSendService.SendPacket(packet); } } diff --git a/EOLib/Domain/Interact/Law/MarriageReply.cs b/EOLib/Domain/Interact/Law/MarriageReply.cs deleted file mode 100644 index cd608af69..000000000 --- a/EOLib/Domain/Interact/Law/MarriageReply.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace EOLib.Domain.Interact.Law -{ - public enum MarriageReply - { - AlreadyMarried = 1, - NotMarried = 2, - Success = 3, - NotEnoughGold = 4, - WrongName = 5, - ServiceBusy = 6, - DivorceNotification = 7 - } -} diff --git a/EOLib/Domain/Interact/Law/MarriageRequestType.cs b/EOLib/Domain/Interact/Law/MarriageRequestType.cs deleted file mode 100644 index 072ec4209..000000000 --- a/EOLib/Domain/Interact/Law/MarriageRequestType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace EOLib.Domain.Interact.Law -{ - public enum MarriageRequestType - { - Marriage = 1, - Divorce = 2 - } -} diff --git a/EOLib/Domain/Interact/MapNPCActions.cs b/EOLib/Domain/Interact/MapNPCActions.cs index 64971f16a..2a80472f3 100644 --- a/EOLib/Domain/Interact/MapNPCActions.cs +++ b/EOLib/Domain/Interact/MapNPCActions.cs @@ -1,9 +1,8 @@ using AutomaticTypeMapper; using EOLib.Domain.Interact.Quest; -using EOLib.Domain.NPC; using EOLib.IO.Repositories; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Interact { @@ -25,10 +24,7 @@ public MapNPCActions(IPacketSendService packetSendService, public void RequestShop(NPC.NPC npc) { - var packet = new PacketBuilder(PacketFamily.Shop, PacketAction.Open) - .AddShort(npc.Index) - .Build(); - + var packet = new ShopOpenClientPacket { NpcIndex = npc.Index }; _packetSendService.SendPacket(packet); } @@ -36,67 +32,47 @@ public void RequestQuest(NPC.NPC npc) { _questDataRepository.RequestedNPC = npc; - var data = _enfFileProvider.ENFFile[npc.ID]; - - var packet = new PacketBuilder(PacketFamily.Quest, PacketAction.Use) - .AddShort(npc.Index) - .AddShort(data.VendorID) - .Build(); - + var packet = new QuestUseClientPacket + { + NpcIndex = npc.Index, + QuestId = _enfFileProvider.ENFFile[npc.ID].VendorID + }; _packetSendService.SendPacket(packet); } public void RequestBank(NPC.NPC npc) { - var packet = new PacketBuilder(PacketFamily.Bank, PacketAction.Open) - .AddShort(npc.Index) - .Build(); - + var packet = new BankOpenClientPacket { NpcIndex = npc.Index }; _packetSendService.SendPacket(packet); } public void RequestSkillmaster(NPC.NPC npc) { - var packet = new PacketBuilder(PacketFamily.StatSkill, PacketAction.Open) - .AddShort(npc.Index) - .Build(); - + var packet = new StatSkillOpenClientPacket { NpcIndex = npc.Index }; _packetSendService.SendPacket(packet); } public void RequestInnkeeper(NPC.NPC npc) { - var packet = new PacketBuilder(PacketFamily.Citizen, PacketAction.Open) - .AddShort(npc.Index) - .Build(); - + var packet = new CitizenOpenClientPacket { NpcIndex = npc.Index }; _packetSendService.SendPacket(packet); } public void RequestLaw(NPC.NPC npc) { - var packet = new PacketBuilder(PacketFamily.Marriage, PacketAction.Open) - .AddShort(npc.Index) - .Build(); - + var packet = new MarriageOpenClientPacket { NpcIndex = npc.Index }; _packetSendService.SendPacket(packet); } public void RequestPriest(NPC.NPC npc) { - var packet = new PacketBuilder(PacketFamily.Priest, PacketAction.Open) - .AddInt(npc.Index) - .Build(); - + var packet = new PriestOpenClientPacket { NpcIndex = npc.Index }; _packetSendService.SendPacket(packet); } public void RequestBarber(NPC.NPC npc) { - var packet = new PacketBuilder(PacketFamily.Barber, PacketAction.Open) - .AddInt(npc.Index) - .Build(); - + var packet = new BarberOpenClientPacket { NpcIndex = npc.Index }; _packetSendService.SendPacket(packet); } } @@ -110,7 +86,7 @@ public interface IMapNPCActions void RequestInnkeeper(NPC.NPC npc); void RequestLaw(NPC.NPC npc); void RequestPriest(NPC.NPC npc); - void RequestBarber(NPC.NPC npc); // Corrected here + void RequestBarber(NPC.NPC npc); } } diff --git a/EOLib/Domain/Interact/PaperdollActions.cs b/EOLib/Domain/Interact/PaperdollActions.cs index ae1384327..f510dac80 100644 --- a/EOLib/Domain/Interact/PaperdollActions.cs +++ b/EOLib/Domain/Interact/PaperdollActions.cs @@ -1,6 +1,6 @@ using AutomaticTypeMapper; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Interact { @@ -16,9 +16,7 @@ public PaperdollActions(IPacketSendService packetSendService) public void RequestPaperdoll(int characterId) { - var packet = new PacketBuilder(PacketFamily.PaperDoll, PacketAction.Request) - .AddShort(characterId) - .Build(); + var packet = new PaperdollRequestClientPacket { PlayerId = characterId }; _packetSendService.SendPacket(packet); } } diff --git a/EOLib/Domain/Interact/Priest/PriestActions.cs b/EOLib/Domain/Interact/Priest/PriestActions.cs index b806a2fcc..d9d0e195d 100644 --- a/EOLib/Domain/Interact/Priest/PriestActions.cs +++ b/EOLib/Domain/Interact/Priest/PriestActions.cs @@ -1,6 +1,6 @@ using AutomaticTypeMapper; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Interact.Priest { @@ -19,30 +19,19 @@ public PriestActions(IPriestSessionProvider priestSessionProvider, public void AcceptRequest() { - var packet = new PacketBuilder(PacketFamily.Priest, PacketAction.Accept) - .AddShort(_priestSessionProvider.SessionID) - .Build(); - + var packet = new PriestAcceptClientPacket { SessionId = _priestSessionProvider.SessionID }; _packetSendService.SendPacket(packet); } public void RequestMarriage(string partner) { - var packet = new PacketBuilder(PacketFamily.Priest, PacketAction.Request) - .AddInt(_priestSessionProvider.SessionID) - .AddByte(255) - .AddString(partner) - .Build(); - + var packet = new PriestRequestClientPacket { SessionId = _priestSessionProvider.SessionID, Name = partner }; _packetSendService.SendPacket(packet); } public void ConfirmMarriage() { - var packet = new PacketBuilder(PacketFamily.Priest, PacketAction.Use) - .AddInt(_priestSessionProvider.SessionID) - .Build(); - + var packet = new PriestUseClientPacket { SessionId = _priestSessionProvider.SessionID }; _packetSendService.SendPacket(packet); } } diff --git a/EOLib/Domain/Interact/Priest/PriestReply.cs b/EOLib/Domain/Interact/Priest/PriestReply.cs deleted file mode 100644 index 3d51d8b60..000000000 --- a/EOLib/Domain/Interact/Priest/PriestReply.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace EOLib.Domain.Interact.Priest -{ - public enum PriestReply - { - NotDressed = 1, - LowLevel = 2, - PartnerNotPresent = 3, - PartnerNotDressed = 4, - Busy = 5, - DoYou = 6, - PartnerAlreadyMarried = 7, - NoPermission = 8 - } -} diff --git a/EOLib/Domain/Interact/Quest/BookIcon.cs b/EOLib/Domain/Interact/Quest/BookIcon.cs deleted file mode 100644 index 3b97ae8da..000000000 --- a/EOLib/Domain/Interact/Quest/BookIcon.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace EOLib.Domain.Interact.Quest -{ - public enum BookIcon : byte - { - Item = 3, - Talk = 5, - Kill = 8, - Step = 10 - } -} diff --git a/EOLib/Domain/Interact/Quest/DialogReply.cs b/EOLib/Domain/Interact/Quest/DialogReply.cs deleted file mode 100644 index ed8e668a0..000000000 --- a/EOLib/Domain/Interact/Quest/DialogReply.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace EOLib.Domain.Interact.Quest -{ - public enum DialogReply - { - Ok = 1, - Link - } -} diff --git a/EOLib/Domain/Interact/Quest/QuestActions.cs b/EOLib/Domain/Interact/Quest/QuestActions.cs index 59d04c350..a483a982a 100644 --- a/EOLib/Domain/Interact/Quest/QuestActions.cs +++ b/EOLib/Domain/Interact/Quest/QuestActions.cs @@ -1,6 +1,7 @@ using AutomaticTypeMapper; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Interact.Quest { @@ -21,27 +22,27 @@ public void RespondToQuestDialog(DialogReply reply, int linkId = 0) { _questDataProvider.QuestDialogData.MatchSome(data => { - var builder = new PacketBuilder(PacketFamily.Quest, PacketAction.Accept) - .AddShort(data.SessionID) // ignored by eoserv - .AddShort(data.DialogID) // ignored by eoserv - .AddShort(data.QuestID) - .AddShort(data.VendorID) // ignored by eoserv - .AddChar((int)reply); - - if (reply == DialogReply.Link) - builder = builder.AddChar(linkId); - - var packet = builder.Build(); + var packet = new QuestAcceptClientPacket + { + SessionId = data.SessionID, + DialogId = data.DialogID, + QuestId = data.QuestID, + NpcIndex = data.VendorID, + ReplyType = reply, + ReplyTypeData = reply == DialogReply.Link + ? new QuestAcceptClientPacket.ReplyTypeDataLink { Action = linkId } + : null + }; _packetSendService.SendPacket(packet); }); } public void RequestQuestHistory(QuestPage page) { - var packet = new PacketBuilder(PacketFamily.Quest, PacketAction.List) - .AddChar((int)page) - .Build(); - + var packet = new QuestListClientPacket + { + Page = page + }; _packetSendService.SendPacket(packet); } } diff --git a/EOLib/Domain/Interact/Quest/QuestPage.cs b/EOLib/Domain/Interact/Quest/QuestPage.cs deleted file mode 100644 index ea47fc00f..000000000 --- a/EOLib/Domain/Interact/Quest/QuestPage.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace EOLib.Domain.Interact.Quest -{ - public enum QuestPage - { - Progress = 1, - History - } -} diff --git a/EOLib/Domain/Interact/Quest/QuestProgressData.cs b/EOLib/Domain/Interact/Quest/QuestProgressData.cs index 9b18c2ba0..d1cffcc24 100644 --- a/EOLib/Domain/Interact/Quest/QuestProgressData.cs +++ b/EOLib/Domain/Interact/Quest/QuestProgressData.cs @@ -1,4 +1,5 @@ using Amadevus.RecordGenerator; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System; namespace EOLib.Domain.Interact.Quest @@ -10,28 +11,18 @@ public sealed partial class QuestProgressData public string Description { get; } - public BookIcon Icon { get; } + public QuestRequirementIcon Icon { get; } - public int IconIndex - { - get - { - //these are probably wrong. can't really tell what it's supposed to be from original - switch (Icon) + //these are probably wrong. can't really tell what it's supposed to be from original + public int IconIndex => + Icon switch { - case BookIcon.Item: - return 2; - case BookIcon.Talk: - return 1; - case BookIcon.Kill: - return 3; - case BookIcon.Step: - return 4; - default: - throw new ArgumentOutOfRangeException(); - } - } - } + QuestRequirementIcon.Item => 2, + QuestRequirementIcon.Talk => 1, + QuestRequirementIcon.Kill => 3, + QuestRequirementIcon.Step => 4, + _ => 1, + }; public int Progress { get; } diff --git a/EOLib/Domain/Interact/Shop/ShopActions.cs b/EOLib/Domain/Interact/Shop/ShopActions.cs index c39a6cc67..1df130e86 100644 --- a/EOLib/Domain/Interact/Shop/ShopActions.cs +++ b/EOLib/Domain/Interact/Shop/ShopActions.cs @@ -1,6 +1,6 @@ using AutomaticTypeMapper; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Interact.Shop { @@ -8,38 +8,50 @@ namespace EOLib.Domain.Interact.Shop public class ShopActions : IShopActions { private readonly IPacketSendService _packetSendService; + private readonly IShopDataProvider _shopDataProvider; - public ShopActions(IPacketSendService packetSendService) + public ShopActions(IPacketSendService packetSendService, + IShopDataProvider shopDataProvider) { _packetSendService = packetSendService; + _shopDataProvider = shopDataProvider; } public void BuyItem(int itemId, int amount) { - var packet = new PacketBuilder(PacketFamily.Shop, PacketAction.Buy) - .AddShort(itemId) - .AddInt(amount) - .Build(); - + var packet = new ShopBuyClientPacket + { + SessionId = _shopDataProvider.SessionID, + BuyItem = new Moffat.EndlessOnline.SDK.Protocol.Net.Item + { + Id = itemId, + Amount = amount + } + }; _packetSendService.SendPacket(packet); } public void SellItem(int itemId, int amount) { - var packet = new PacketBuilder(PacketFamily.Shop, PacketAction.Sell) - .AddShort(itemId) - .AddInt(amount) - .Build(); - + var packet = new ShopSellClientPacket + { + SessionId = _shopDataProvider.SessionID, + SellItem = new Moffat.EndlessOnline.SDK.Protocol.Net.Item + { + Id = itemId, + Amount = amount + } + }; _packetSendService.SendPacket(packet); } public void CraftItem(int itemId) { - var packet = new PacketBuilder(PacketFamily.Shop, PacketAction.Create) - .AddShort(itemId) - .Build(); - + var packet = new ShopCreateClientPacket + { + SessionId = _shopDataProvider.SessionID, + CraftItemId = itemId + }; _packetSendService.SendPacket(packet); } } diff --git a/EOLib/Domain/Interact/Shop/ShopDataRepository.cs b/EOLib/Domain/Interact/Shop/ShopDataRepository.cs index c7b024d13..fc4b5d047 100644 --- a/EOLib/Domain/Interact/Shop/ShopDataRepository.cs +++ b/EOLib/Domain/Interact/Shop/ShopDataRepository.cs @@ -5,7 +5,7 @@ namespace EOLib.Domain.Interact.Shop { public interface IShopDataRepository : IResettable { - int ShopID { get; set; } + int SessionID { get; set; } string ShopName { get; set; } @@ -16,7 +16,7 @@ public interface IShopDataRepository : IResettable public interface IShopDataProvider : IResettable { - int ShopID { get; } + int SessionID { get; } string ShopName { get; } @@ -28,7 +28,7 @@ public interface IShopDataProvider : IResettable [AutoMappedType(IsSingleton = true)] public class ShopDataRepository : IShopDataProvider, IShopDataRepository { - public int ShopID { get; set; } + public int SessionID { get; set; } public string ShopName { get; set; } public List TradeItems { get; set; } @@ -46,7 +46,7 @@ public ShopDataRepository() public void ResetState() { - ShopID = 0; + SessionID = 0; ShopName = string.Empty; TradeItems = new List(); CraftItems = new List(); diff --git a/EOLib/Domain/Interact/Skill/SkillmasterActions.cs b/EOLib/Domain/Interact/Skill/SkillmasterActions.cs index 6f29e7a24..2eac1fa5d 100644 --- a/EOLib/Domain/Interact/Skill/SkillmasterActions.cs +++ b/EOLib/Domain/Interact/Skill/SkillmasterActions.cs @@ -1,6 +1,6 @@ using AutomaticTypeMapper; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Interact.Skill { @@ -19,30 +19,30 @@ public SkillmasterActions(IPacketSendService packetSendService, public void LearnSkill(int spellId) { - var packet = new PacketBuilder(PacketFamily.StatSkill, PacketAction.Take) - .AddInt(_skillDataProvider.ID) - .AddShort(spellId) - .Build(); - + var packet = new StatSkillTakeClientPacket + { + SessionId = _skillDataProvider.ID, + SpellId = spellId + }; _packetSendService.SendPacket(packet); } public void ForgetSkill(int spellId) { - var packet = new PacketBuilder(PacketFamily.StatSkill, PacketAction.Remove) - .AddInt(_skillDataProvider.ID) - .AddShort(spellId) - .Build(); - + var packet = new StatSkillRemoveClientPacket + { + SessionId = _skillDataProvider.ID, + SpellId = spellId + }; _packetSendService.SendPacket(packet); } public void ResetCharacter() { - var packet = new PacketBuilder(PacketFamily.StatSkill, PacketAction.Junk) - .AddInt(_skillDataProvider.ID) - .Build(); - + var packet = new StatSkillJunkClientPacket + { + SessionId = _skillDataProvider.ID, + }; _packetSendService.SendPacket(packet); } } diff --git a/EOLib/Domain/Item/ItemActions.cs b/EOLib/Domain/Item/ItemActions.cs index 8e0e452a0..784011137 100644 --- a/EOLib/Domain/Item/ItemActions.cs +++ b/EOLib/Domain/Item/ItemActions.cs @@ -1,7 +1,10 @@ using AutomaticTypeMapper; using EOLib.Domain.Map; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Data; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; +using System.IO; namespace EOLib.Domain.Item { @@ -17,51 +20,58 @@ public ItemActions(IPacketSendService packetSendService) public void UseItem(int itemId) { - var packet = new PacketBuilder(PacketFamily.Item, PacketAction.Use) - .AddShort(itemId) - .Build(); - + var packet = new ItemUseClientPacket { ItemId = itemId }; _packetSendService.SendPacket(packet); } public void EquipItem(int itemId, bool alternateLocation) { - var packet = new PacketBuilder(PacketFamily.PaperDoll, PacketAction.Add) - .AddShort(itemId) - .AddChar(alternateLocation ? 1 : 0) - .Build(); - + var packet = new PaperdollAddClientPacket + { + ItemId = itemId, + SubLoc = alternateLocation ? 1 : 0, + }; _packetSendService.SendPacket(packet); } public void UnequipItem(int itemId, bool alternateLocation) { - var packet = new PacketBuilder(PacketFamily.PaperDoll, PacketAction.Remove) - .AddShort(itemId) - .AddChar(alternateLocation ? 1 : 0) - .Build(); - + var packet = new PaperdollRemoveClientPacket + { + ItemId = itemId, + SubLoc = alternateLocation ? 1 : 0, + }; _packetSendService.SendPacket(packet); } public void DropItem(int itemId, int amount, MapCoordinate dropPoint) { - var packet = new PacketBuilder(PacketFamily.Item, PacketAction.Drop) - .AddShort(itemId) - .AddInt(amount) - .AddChar(dropPoint.X) - .AddChar(dropPoint.Y) - .Build(); + // The drop point coordinates are extra encoded. See ItemDropClientPacket::Coords. + var dropX = dropPoint.X == 255 ? dropPoint.X : NumberEncoder.EncodeNumber(dropPoint.X)[0]; + var dropY = dropPoint.Y == 255 ? dropPoint.Y : NumberEncoder.EncodeNumber(dropPoint.Y)[0]; + + var packet = new ItemDropClientPacket + { + Item = new ThreeItem + { + Id = itemId, + Amount = amount, + }, + Coords = new ByteCoords { X = dropX, Y = dropY }, + }; _packetSendService.SendPacket(packet); } public void JunkItem(int itemId, int amount) { - var packet = new PacketBuilder(PacketFamily.Item, PacketAction.Junk) - .AddShort(itemId) - .AddInt(amount) - .Build(); - + var packet = new ItemJunkClientPacket + { + Item = new Moffat.EndlessOnline.SDK.Protocol.Net.Item + { + Id = itemId, + Amount = amount, + } + }; _packetSendService.SendPacket(packet); } } diff --git a/EOLib/Domain/Item/ItemDropValidator.cs b/EOLib/Domain/Item/ItemDropValidator.cs index 2e3d0746c..d131479e4 100644 --- a/EOLib/Domain/Item/ItemDropValidator.cs +++ b/EOLib/Domain/Item/ItemDropValidator.cs @@ -40,7 +40,7 @@ public ItemDropResult ValidateItemDrop(Character.Character mainCharacter, Invent return ItemDropResult.Jail; var rp = mainCharacter.RenderProperties; - if (Math.Max(Math.Abs(rp.MapX - dropPoint.X), Math.Abs(rp.MapY - dropPoint.Y)) > 2) + if (dropPoint != MapCoordinate.Max && Math.Max(Math.Abs(rp.MapX - dropPoint.X), Math.Abs(rp.MapY - dropPoint.Y)) > 2) return ItemDropResult.TooFar; return ItemDropResult.Ok; diff --git a/EOLib/Domain/Login/AccountLoginData.cs b/EOLib/Domain/Login/AccountLoginData.cs deleted file mode 100644 index 7a4478140..000000000 --- a/EOLib/Domain/Login/AccountLoginData.cs +++ /dev/null @@ -1,26 +0,0 @@ -using EOLib.Net.Translators; -using System.Collections.Generic; - -namespace EOLib.Domain.Login -{ - public class AccountLoginData : IAccountLoginData - { - public LoginReply Response { get; } - - private readonly List _characters; - public IReadOnlyList Characters => _characters; - - public AccountLoginData(LoginReply reply, List characters) - { - Response = reply; - _characters = characters; - } - } - - public interface IAccountLoginData : ITranslatedData - { - LoginReply Response { get; } - - IReadOnlyList Characters { get; } - } -} diff --git a/EOLib/Domain/Login/CharacterLoginReply.cs b/EOLib/Domain/Login/CharacterLoginReply.cs deleted file mode 100644 index 0e1f48e7f..000000000 --- a/EOLib/Domain/Login/CharacterLoginReply.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace EOLib.Domain.Login -{ - public enum CharacterLoginReply : short - { - RequestGranted = 1, // response from welcome_request - RequestCompleted = 2, // response from welcome_message - RequestDenied = 3, // response from welcome_message if the client sends invalid player ID - } -} \ No newline at end of file diff --git a/EOLib/Domain/Login/LoginActions.cs b/EOLib/Domain/Login/LoginActions.cs index 3af287c6a..7a4593d91 100644 --- a/EOLib/Domain/Login/LoginActions.cs +++ b/EOLib/Domain/Login/LoginActions.cs @@ -1,15 +1,18 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EOLib.Domain.Character; +using EOLib.Domain.Extensions; using EOLib.Domain.Map; -using EOLib.Domain.NPC; -using EOLib.Domain.Protocol; +using EOLib.IO; using EOLib.Net; using EOLib.Net.Communication; using EOLib.Net.FileTransfer; -using EOLib.Net.Translators; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; namespace EOLib.Domain.Login { @@ -17,9 +20,6 @@ namespace EOLib.Domain.Login public class LoginActions : ILoginActions { private readonly IPacketSendService _packetSendService; - private readonly IPacketTranslator _loginPacketTranslator; - private readonly IPacketTranslator _loginRequestGrantedPacketTranslator; - private readonly IPacketTranslator _loginRequestCompletedPacketTranslator; private readonly ICharacterSelectorRepository _characterSelectorRepository; private readonly IPlayerInfoRepository _playerInfoRepository; private readonly ICharacterRepository _characterRepository; @@ -31,9 +31,6 @@ public class LoginActions : ILoginActions private readonly ICharacterSessionRepository _characterSessionRepository; public LoginActions(IPacketSendService packetSendService, - IPacketTranslator loginPacketTranslator, - IPacketTranslator loginRequestGrantedPacketTranslator, - IPacketTranslator loginRequestCompletedPacketTranslator, ICharacterSelectorRepository characterSelectorRepository, IPlayerInfoRepository playerInfoRepository, ICharacterRepository characterRepository, @@ -45,9 +42,6 @@ public LoginActions(IPacketSendService packetSendService, ICharacterSessionRepository characterSessionRepository) { _packetSendService = packetSendService; - _loginPacketTranslator = loginPacketTranslator; - _loginRequestGrantedPacketTranslator = loginRequestGrantedPacketTranslator; - _loginRequestCompletedPacketTranslator = loginRequestCompletedPacketTranslator; _characterSelectorRepository = characterSelectorRepository; _playerInfoRepository = playerInfoRepository; _characterRepository = characterRepository; @@ -67,142 +61,170 @@ public bool LoginParametersAreValid(ILoginParameters parameters) public async Task LoginToServer(ILoginParameters parameters) { - var packet = new PacketBuilder(PacketFamily.Login, PacketAction.Request) - .AddBreakString(parameters.Username) - .AddBreakString(parameters.Password) - .Build(); + var packet = new LoginRequestClientPacket + { + Username = parameters.Username, + Password = parameters.Password, + }; var response = await _packetSendService.SendEncodedPacketAndWaitAsync(packet); - if (IsInvalidResponse(response)) + if (IsInvalidResponse(response, out var responsePacket)) throw new EmptyPacketReceivedException(); - var data = _loginPacketTranslator.TranslatePacket(response); - _characterSelectorRepository.Characters = data.Characters; - - if (data.Response == LoginReply.Ok) + if (responsePacket.ReplyCode == LoginReply.Ok) { + _characterSelectorRepository.Characters = ((LoginReplyServerPacket.ReplyCodeDataOk)responsePacket.ReplyCodeData) + .Characters.Select(Character.Character.FromCharacterSelectionListEntry).ToList(); _playerInfoRepository.LoggedInAccountName = parameters.Username; _playerInfoRepository.PlayerPassword = parameters.Password; } - return data.Response; + return responsePacket.ReplyCode; } public async Task RequestCharacterLogin(Character.Character character) { - var packet = new PacketBuilder(PacketFamily.Welcome, PacketAction.Request) - .AddInt(character.ID) - .Build(); + var packet = new WelcomeRequestClientPacket { CharacterId = character.ID }; var response = await _packetSendService.SendEncodedPacketAndWaitAsync(packet); - if (IsInvalidWelcome(response)) + if (IsInvalidWelcome(response, out var responsePacket) || responsePacket.WelcomeCode != WelcomeCode.SelectCharacter) throw new EmptyPacketReceivedException(); - var data = _loginRequestGrantedPacketTranslator.TranslatePacket(response); + var data = (WelcomeReplyServerPacket.WelcomeCodeDataSelectCharacter)responsePacket.WelcomeCodeData; _characterRepository.MainCharacter = character - .WithID(data.CharacterID) - .WithName(data.Name) + .WithID(data.CharacterId) + .WithName(char.ToUpper(data.Name[0]) + data.Name.Substring(1)) .WithTitle(data.Title) .WithGuildName(data.GuildName) - .WithGuildRank(data.GuildRank) + .WithGuildRank(data.GuildRankName) .WithGuildTag(data.GuildTag) - .WithClassID(data.ClassID) - .WithMapID(data.MapID) - .WithAdminLevel(data.AdminLevel) - .WithStats(data.CharacterStats); + .WithClassID(data.ClassId) + .WithMapID(data.MapId) + .WithAdminLevel(data.Admin) + .WithStats(CharacterStats.FromSelectCharacterData(data)); - _playerInfoRepository.IsFirstTimePlayer = data.FirstTimePlayer; + _playerInfoRepository.IsFirstTimePlayer = data.LoginMessageCode == LoginMessageCode.Yes; _playerInfoRepository.PlayerHasAdminCharacter = _characterSelectorRepository.Characters.Any(x => x.AdminLevel > 0); - _currentMapStateRepository.CurrentMapID = data.MapID; - _currentMapStateRepository.JailMapID = data.JailMap; + _currentMapStateRepository.CurrentMapID = data.MapId; + _currentMapStateRepository.JailMapID = data.Settings.JailMap; - _paperdollRepository.VisibleCharacterPaperdolls[data.SessionID] = new PaperdollData() - .WithName(data.Name) + _paperdollRepository.VisibleCharacterPaperdolls[data.SessionId] = new PaperdollData() + .WithName(char.ToUpper(data.Name[0]) + data.Name.Substring(1)) .WithTitle(data.Title) .WithGuild(data.GuildName) - .WithRank(data.GuildRank) - .WithClass(data.ClassID) - .WithPlayerID(data.SessionID) - .WithPaperdoll(data.Paperdoll); + .WithRank(data.GuildRankName) + .WithClass(data.ClassId) + .WithPlayerID(data.SessionId) + .WithPaperdoll(data.Equipment.GetPaperdoll()); - _loginFileChecksumRepository.MapChecksum = data.MapRID.ToArray(); - _loginFileChecksumRepository.MapLength = data.MapLen; + _loginFileChecksumRepository.MapChecksum = data.MapRid; + _loginFileChecksumRepository.MapLength = data.MapFileSize; _loginFileChecksumRepository.EIFChecksum = data.EifRid; - _loginFileChecksumRepository.EIFLength = data.EifLen; + _loginFileChecksumRepository.EIFLength = data.EifLength; _loginFileChecksumRepository.ENFChecksum = data.EnfRid; - _loginFileChecksumRepository.ENFLength = data.EnfLen; + _loginFileChecksumRepository.ENFLength = data.EnfLength; _loginFileChecksumRepository.ESFChecksum = data.EsfRid; - _loginFileChecksumRepository.ESFLength = data.EsfLen; + _loginFileChecksumRepository.ESFLength = data.EsfLength; _loginFileChecksumRepository.ECFChecksum = data.EcfRid; - _loginFileChecksumRepository.ECFLength = data.EcfLen; - return data.SessionID; + _loginFileChecksumRepository.ECFLength = data.EcfLength; + + return data.SessionId; } - public async Task CompleteCharacterLogin(int sessionID) + public async Task CompleteCharacterLogin(int sessionID) { - var packet = new PacketBuilder(PacketFamily.Welcome, PacketAction.Message) - .AddThree(sessionID) - .AddInt(_characterRepository.MainCharacter.ID) - .Build(); + var packet = new WelcomeMsgClientPacket + { + SessionId = sessionID, + CharacterId = _characterRepository.MainCharacter.ID + }; var response = await _packetSendService.SendEncodedPacketAndWaitAsync(packet); - if (IsInvalidWelcome(response)) + if (IsInvalidWelcome(response, out var responsePacket)) throw new EmptyPacketReceivedException(); - var data = _loginRequestCompletedPacketTranslator.TranslatePacket(response); + if (responsePacket.WelcomeCode != WelcomeCode.EnterGame) + return responsePacket.WelcomeCode; - if (data.Error == CharacterLoginReply.RequestDenied) - { - return data.Error; - } + var data = (WelcomeReplyServerPacket.WelcomeCodeDataEnterGame)responsePacket.WelcomeCodeData; _newsRepository.NewsHeader = data.News.First(); - _newsRepository.NewsText = data.News.Except(new[] { data.News.First() }).ToList(); + _newsRepository.NewsText = data.News.Skip(1).ToList(); - var mainCharacter = data.MapCharacters.Single( - x => x.Name.ToLower() == _characterRepository.MainCharacter.Name.ToLower()); + var mainCharacter = data.Nearby.Characters.Single( + x => x.Name.Equals(_characterRepository.MainCharacter.Name, StringComparison.OrdinalIgnoreCase)); var stats = _characterRepository.MainCharacter.Stats - .WithNewStat(CharacterStat.Weight, data.CharacterWeight) - .WithNewStat(CharacterStat.MaxWeight, data.CharacterMaxWeight) - .WithNewStat(CharacterStat.Level, mainCharacter.Stats[CharacterStat.Level]) - .WithNewStat(CharacterStat.HP, mainCharacter.Stats[CharacterStat.HP]) - .WithNewStat(CharacterStat.MaxHP, mainCharacter.Stats[CharacterStat.MaxHP]) - .WithNewStat(CharacterStat.TP, mainCharacter.Stats[CharacterStat.TP]) - .WithNewStat(CharacterStat.MaxTP, mainCharacter.Stats[CharacterStat.MaxTP]); + .WithNewStat(CharacterStat.Weight, data.Weight.Current) + .WithNewStat(CharacterStat.MaxWeight, data.Weight.Max) + .WithNewStat(CharacterStat.Level, mainCharacter.Level) + .WithNewStat(CharacterStat.HP, mainCharacter.Hp) + .WithNewStat(CharacterStat.MaxHP, mainCharacter.MaxHp) + .WithNewStat(CharacterStat.TP, mainCharacter.Tp) + .WithNewStat(CharacterStat.MaxTP, mainCharacter.MaxTp); _characterRepository.MainCharacter = _characterRepository.MainCharacter .WithID(_playerInfoRepository.PlayerID) - .WithName(mainCharacter.Name) - .WithMapID(mainCharacter.MapID) + .WithName(char.ToUpper(mainCharacter.Name[0]) + mainCharacter.Name.Substring(1)) + .WithMapID(mainCharacter.MapId) .WithGuildTag(mainCharacter.GuildTag) + // classId is sent in the "enter game" data but eoserv hard-codes this to 6 (with no apparent impact on game function for main player) + //.WithClassID(mainCharacter.ClassId) .WithStats(stats) - .WithRenderProperties(mainCharacter.RenderProperties); - - _characterInventoryRepository.ItemInventory = new HashSet(data.CharacterItemInventory); - _characterInventoryRepository.SpellInventory = new HashSet(data.CharacterSpellInventory); - - _currentMapStateRepository.Characters = new MapEntityCollectionHashSet(c => c.ID, c => new MapCoordinate(c.X, c.Y), data.MapCharacters.Except(new[] { mainCharacter })); - _currentMapStateRepository.NPCs = new MapEntityCollectionHashSet(n => n.Index, n => new MapCoordinate(n.X, n.Y), data.MapNPCs); - _currentMapStateRepository.MapItems = new MapEntityCollectionHashSet(item => item.UniqueID, item => new MapCoordinate(item.X, item.Y), data.MapItems); + .WithRenderProperties(CharacterRenderProperties.FromCharacterMapInfo(mainCharacter)); + + _characterInventoryRepository.ItemInventory = new HashSet(data.Items.Select(InventoryItem.FromNet)); + if (!_characterInventoryRepository.ItemInventory.Any(x => x.ItemID == 1)) + _characterInventoryRepository.ItemInventory.Add(new InventoryItem(1, 0)); + + _characterInventoryRepository.SpellInventory = new HashSet(data.Spells.Select(InventorySpell.FromNet)); + + _currentMapStateRepository.Characters = new MapEntityCollectionHashSet( + c => c.ID, + c => new MapCoordinate(c.X, c.Y), + data.Nearby.Characters + .Where(x => x.ByteSize >= 42 && x.PlayerId != mainCharacter.PlayerId) + .Select(Character.Character.FromNearby) + ); + _currentMapStateRepository.NPCs = new MapEntityCollectionHashSet( + n => n.Index, + n => new MapCoordinate(n.X, n.Y), + data.Nearby.Npcs.Select(NPC.NPC.FromNearby) + ); + _currentMapStateRepository.MapItems = new MapEntityCollectionHashSet( + item => item.UniqueID, + item => new MapCoordinate(item.X, item.Y), + data.Nearby.Items.Select(MapItem.FromNearby) + ); _playerInfoRepository.PlayerIsInGame = true; _characterSessionRepository.ResetState(); - return CharacterLoginReply.RequestCompleted; + return WelcomeCode.EnterGame; } - private bool IsInvalidResponse(IPacket response) + private static bool IsInvalidResponse(IPacket response, out LoginReplyServerPacket responsePacket) { - return !(response.Family == PacketFamily.Login && response.Action == PacketAction.Reply) - && !(response.Family == PacketFamily.Init && response.Action == PacketAction.Init && response.PeekByte() == (byte)InitReply.BannedFromServer); + responsePacket = response as LoginReplyServerPacket; + if (responsePacket == null && response is InitInitServerPacket initPacket && initPacket.ReplyCode == InitReply.Banned) + { + responsePacket = new LoginReplyServerPacket + { + ReplyCode = LoginReply.Banned, + ReplyCodeData = new LoginReplyServerPacket.ReplyCodeDataBanned() + }; + return false; + } + + return !(response.Family == PacketFamily.Login && response.Action == PacketAction.Reply); } - private bool IsInvalidWelcome(IPacket response) + private static bool IsInvalidWelcome(IPacket response, out WelcomeReplyServerPacket responsePacket) { + responsePacket = response as WelcomeReplyServerPacket; return response.Family != PacketFamily.Welcome || response.Action != PacketAction.Reply; } } @@ -215,6 +237,6 @@ public interface ILoginActions Task RequestCharacterLogin(Character.Character character); - Task CompleteCharacterLogin(int sessionID); + Task CompleteCharacterLogin(int sessionID); } } \ No newline at end of file diff --git a/EOLib/Domain/Login/LoginReply.cs b/EOLib/Domain/Login/LoginReply.cs deleted file mode 100644 index 45a78954b..000000000 --- a/EOLib/Domain/Login/LoginReply.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace EOLib.Domain.Login -{ - public enum LoginReply : short - { - WrongUser = 1, - WrongUserPass = 2, - Ok = 3, - AccountBanned = 4, - LoggedIn = 5, - Busy = 6, - THIS_IS_WRONG = 255 - } -} \ No newline at end of file diff --git a/EOLib/Domain/Login/LoginRequestCompletedData.cs b/EOLib/Domain/Login/LoginRequestCompletedData.cs deleted file mode 100644 index 7715b8fd8..000000000 --- a/EOLib/Domain/Login/LoginRequestCompletedData.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Amadevus.RecordGenerator; -using EOLib.Domain.Character; -using EOLib.Domain.Map; -using EOLib.Net.Translators; -using System.Collections.Generic; - -namespace EOLib.Domain.Login -{ - [Record] - public sealed partial class LoginRequestCompletedData : ITranslatedData - { - public IReadOnlyList News { get; } - - public int CharacterWeight { get; } - - public int CharacterMaxWeight { get; } - - public IReadOnlyList CharacterItemInventory { get; } - - public IReadOnlyList CharacterSpellInventory { get; } - - public IReadOnlyList MapCharacters { get; } - - public IReadOnlyList MapNPCs { get; } - - public IReadOnlyList MapItems { get; } - - public CharacterLoginReply Error { get; } - } -} \ No newline at end of file diff --git a/EOLib/Domain/Login/LoginRequestGrantedData.cs b/EOLib/Domain/Login/LoginRequestGrantedData.cs deleted file mode 100644 index 78d959bc1..000000000 --- a/EOLib/Domain/Login/LoginRequestGrantedData.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Amadevus.RecordGenerator; -using EOLib.Domain.Character; -using EOLib.IO; -using EOLib.Net.Translators; -using System.Collections.Generic; - -namespace EOLib.Domain.Login -{ - [Record] - public sealed partial class LoginRequestGrantedData : ITranslatedData - { - public int SessionID { get; } - public int CharacterID { get; } - - public int MapID { get; } - public IReadOnlyList MapRID { get; } - public int MapLen { get; } - - public int EifRid { get; } - public int EifLen { get; } - public int EnfRid { get; } - public int EnfLen { get; } - public int EsfRid { get; } - public int EsfLen { get; } - public int EcfRid { get; } - public int EcfLen { get; } - - public string Name { get; } - public string Title { get; } - public string GuildName { get; } - public string GuildRank { get; } - public int ClassID { get; } - public string GuildTag { get; } - public AdminLevel AdminLevel { get; } - - public CharacterStats CharacterStats { get; } - - public IReadOnlyDictionary Paperdoll { get; } - - public int GuildRankNum { get; } - public int JailMap { get; } - public bool FirstTimePlayer { get; } - } -} diff --git a/EOLib/Domain/Login/PlayerInfoRepository.cs b/EOLib/Domain/Login/PlayerInfoRepository.cs index 4b1fc547e..8b03b51d6 100644 --- a/EOLib/Domain/Login/PlayerInfoRepository.cs +++ b/EOLib/Domain/Login/PlayerInfoRepository.cs @@ -4,6 +4,8 @@ namespace EOLib.Domain.Login { public interface IPlayerInfoRepository { + int LoginAttempts { get; set; } + string LoggedInAccountName { get; set; } string PlayerPassword { get; set; } @@ -19,6 +21,8 @@ public interface IPlayerInfoRepository public interface IPlayerInfoProvider { + int LoginAttempts { get; } + string LoggedInAccountName { get; } string PlayerPassword { get; } @@ -35,6 +39,8 @@ public interface IPlayerInfoProvider [AutoMappedType(IsSingleton = true)] public sealed class PlayerInfoRepository : IPlayerInfoRepository, IPlayerInfoProvider, IResettable { + public int LoginAttempts { get; set; } + public string LoggedInAccountName { get; set; } public string PlayerPassword { get; set; } @@ -47,8 +53,11 @@ public sealed class PlayerInfoRepository : IPlayerInfoRepository, IPlayerInfoPro public bool PlayerHasAdminCharacter { get; set; } + public PlayerInfoRepository() => ResetState(); + public void ResetState() { + LoginAttempts = 0; LoggedInAccountName = ""; PlayerPassword = ""; PlayerID = 0; diff --git a/EOLib/Domain/Map/ChestActions.cs b/EOLib/Domain/Map/ChestActions.cs index 7cd0428a0..c9928544f 100644 --- a/EOLib/Domain/Map/ChestActions.cs +++ b/EOLib/Domain/Map/ChestActions.cs @@ -1,7 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Map { @@ -20,24 +22,33 @@ public ChestActions(IPacketSendService packetSendService, public void AddItemToChest(InventoryItem item) { - var packet = new PacketBuilder(PacketFamily.Chest, PacketAction.Add) - .AddChar(_chestDataProvider.Location.X) - .AddChar(_chestDataProvider.Location.Y) - .AddShort(item.ItemID) - .AddThree(item.Amount) - .Build(); - + var packet = new ChestAddClientPacket + { + Coords = new Coords + { + X = _chestDataProvider.Location.X, + Y = _chestDataProvider.Location.Y, + }, + AddItem = new ThreeItem + { + Id = item.ItemID, + Amount = item.Amount + } + }; _packetSendService.SendPacket(packet); } public void TakeItemFromChest(int itemId) { - var packet = new PacketBuilder(PacketFamily.Chest, PacketAction.Take) - .AddChar(_chestDataProvider.Location.X) - .AddChar(_chestDataProvider.Location.Y) - .AddShort(itemId) - .Build(); - + var packet = new ChestTakeClientPacket + { + Coords = new Coords + { + X = _chestDataProvider.Location.X, + Y = _chestDataProvider.Location.Y, + }, + TakeItemId = itemId + }; _packetSendService.SendPacket(packet); } } diff --git a/EOLib/Domain/Map/CurrentMapStateRepository.cs b/EOLib/Domain/Map/CurrentMapStateRepository.cs index bfef7c49d..e599d0cb8 100644 --- a/EOLib/Domain/Map/CurrentMapStateRepository.cs +++ b/EOLib/Domain/Map/CurrentMapStateRepository.cs @@ -25,7 +25,7 @@ public interface ICurrentMapStateRepository HashSet PendingDoors { get; set; } - HashSet VisibleSpikeTraps { get; set; } + Option LastTimedSpikeEvent { get; set; } WarpState MapWarpState { get; set; } @@ -62,7 +62,7 @@ public interface ICurrentMapStateProvider IReadOnlyCollection PendingDoors { get; } - IReadOnlyCollection VisibleSpikeTraps { get; } + Option LastTimedSpikeEvent { get; set; } WarpState MapWarpState { get; } @@ -74,9 +74,9 @@ public interface ICurrentMapStateProvider bool IsSleepWarp { get; } - HashSet UnknownPlayerIDs { get; } + IReadOnlyCollection UnknownPlayerIDs { get; } - HashSet UnknownNPCIndexes { get; } + IReadOnlyCollection UnknownNPCIndexes { get; } } [AutoMappedType(IsSingleton = true)] @@ -100,7 +100,7 @@ public class CurrentMapStateRepository : ICurrentMapStateRepository, ICurrentMap public HashSet PendingDoors { get; set; } - public HashSet VisibleSpikeTraps { get; set; } + public Option LastTimedSpikeEvent { get; set; } public WarpState MapWarpState { get; set; } @@ -126,7 +126,9 @@ public class CurrentMapStateRepository : ICurrentMapStateRepository, ICurrentMap IReadOnlyCollection ICurrentMapStateProvider.PendingDoors => PendingDoors; - IReadOnlyCollection ICurrentMapStateProvider.VisibleSpikeTraps => VisibleSpikeTraps; + IReadOnlyCollection ICurrentMapStateProvider.UnknownPlayerIDs => UnknownPlayerIDs; + + IReadOnlyCollection ICurrentMapStateProvider.UnknownNPCIndexes => UnknownNPCIndexes; public CurrentMapStateRepository() { @@ -144,7 +146,7 @@ public void ResetState() MapItems = new MapEntityCollectionHashSet(x => x.UniqueID, x => new MapCoordinate(x.X, x.Y)); OpenDoors = new HashSet(); PendingDoors = new HashSet(); - VisibleSpikeTraps = new HashSet(); + LastTimedSpikeEvent = Option.None(); UnknownPlayerIDs = new HashSet(); UnknownNPCIndexes = new HashSet(); diff --git a/EOLib/Domain/Map/LockerActions.cs b/EOLib/Domain/Map/LockerActions.cs index a2f99836f..4a1eb6475 100644 --- a/EOLib/Domain/Map/LockerActions.cs +++ b/EOLib/Domain/Map/LockerActions.cs @@ -1,7 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; using Optional.Collections; namespace EOLib.Domain.Map @@ -21,24 +23,33 @@ public LockerActions(IPacketSendService packetSendService, public void AddItemToLocker(InventoryItem item) { - var packet = new PacketBuilder(PacketFamily.Locker, PacketAction.Add) - .AddChar(_lockerDataProvider.Location.X) - .AddChar(_lockerDataProvider.Location.Y) - .AddShort(item.ItemID) - .AddThree(item.Amount) - .Build(); - + var packet = new LockerAddClientPacket + { + LockerCoords = new Coords + { + X = _lockerDataProvider.Location.X, + Y = _lockerDataProvider.Location.Y, + }, + DepositItem = new ThreeItem + { + Id = item.ItemID, + Amount = item.Amount, + } + }; _packetSendService.SendPacket(packet); } public void TakeItemFromLocker(int itemId) { - var packet = new PacketBuilder(PacketFamily.Locker, PacketAction.Take) - .AddChar(_lockerDataProvider.Location.X) - .AddChar(_lockerDataProvider.Location.Y) - .AddShort(itemId) - .Build(); - + var packet = new LockerTakeClientPacket + { + LockerCoords = new Coords + { + X = _lockerDataProvider.Location.X, + Y = _lockerDataProvider.Location.Y, + }, + TakeItemId = itemId + }; _packetSendService.SendPacket(packet); } diff --git a/EOLib/Domain/Map/MapActions.cs b/EOLib/Domain/Map/MapActions.cs index 742548cbd..9c41b90c2 100644 --- a/EOLib/Domain/Map/MapActions.cs +++ b/EOLib/Domain/Map/MapActions.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Character; using EOLib.Domain.Item; using EOLib.IO.Map; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Map { @@ -26,23 +27,14 @@ public MapActions(IPacketSendService packetSendService, _currentMapStateRepository = currentMapStateRepository; } - public void RequestRefresh() - { - var packet = new PacketBuilder(PacketFamily.Refresh, PacketAction.Request) - .AddByte(255) - .Build(); - _packetSendService.SendPacket(packet); - } + public void RequestRefresh() => _packetSendService.SendPacket(new RefreshRequestClientPacket()); public ItemPickupResult PickUpItem(MapItem item) { var pickupResult = _itemPickupValidator.ValidateItemPickup(_characterProvider.MainCharacter, item); if (pickupResult == ItemPickupResult.Ok) { - var packet = new PacketBuilder(PacketFamily.Item, PacketAction.Get) - .AddShort(item.UniqueID) - .Build(); - + var packet = new ItemGetClientPacket { ItemIndex = item.UniqueID }; _packetSendService.SendPacket(packet); } @@ -54,51 +46,32 @@ public void OpenDoor(Warp warp) if (_currentMapStateRepository.PendingDoors.Contains(warp)) return; - var packet = new PacketBuilder(PacketFamily.Door, PacketAction.Open) - .AddChar(warp.X) - .AddChar(warp.Y) - .Build(); - + var packet = new DoorOpenClientPacket { Coords = new Coords { X = warp.X, Y = warp.Y } }; _packetSendService.SendPacket(packet); _currentMapStateRepository.PendingDoors.Add(warp); } public void OpenChest(MapCoordinate location) { - var packet = new PacketBuilder(PacketFamily.Chest, PacketAction.Open) - .AddChar(location.X) - .AddChar(location.Y) - .Build(); - + var packet = new ChestOpenClientPacket { Coords = new Coords { X = location.X, Y = location.Y } }; _packetSendService.SendPacket(packet); } public void OpenLocker(MapCoordinate location) { - var packet = new PacketBuilder(PacketFamily.Locker, PacketAction.Open) - .AddChar(location.X) - .AddChar(location.Y) - .Build(); - + var packet = new LockerOpenClientPacket { LockerCoords = new Coords { X = location.X, Y = location.Y } }; _packetSendService.SendPacket(packet); } public void OpenBoard(TileSpec boardSpec) { - var packet = new PacketBuilder(PacketFamily.Board, PacketAction.Open) - .AddShort(boardSpec - TileSpec.Board1) - .Build(); - + var packet = new BoardOpenClientPacket { BoardId = boardSpec - TileSpec.Board1 }; _packetSendService.SendPacket(packet); } public void OpenJukebox(MapCoordinate location) { - var packet = new PacketBuilder(PacketFamily.JukeBox, PacketAction.Open) - .AddChar(location.X) - .AddChar(location.Y) - .Build(); - + var packet = new JukeboxOpenClientPacket { Coords = new Coords { X = location.X, Y = location.Y } }; _packetSendService.SendPacket(packet); } } diff --git a/EOLib/Domain/Map/MapCellStateProvider.cs b/EOLib/Domain/Map/MapCellStateProvider.cs index d551685ef..65b0de3da 100644 --- a/EOLib/Domain/Map/MapCellStateProvider.cs +++ b/EOLib/Domain/Map/MapCellStateProvider.cs @@ -39,33 +39,35 @@ public IMapCellState GetCellStateAt(int x, int y) var chest = CurrentMap.Chests.Where(c => c.X == x && c.Y == y && c.Key != ChestKey.None).Select(c => c.Key).FirstOrDefault(); var sign = CurrentMap.Signs.FirstOrDefault(s => s.X == x && s.Y == y); - _mapStateProvider.Characters.TryGetValues(new MapCoordinate(x, y), out var characters); + var characters = new List(); + if (_mapStateProvider.Characters.ContainsKey(new MapCoordinate(x,y))) + characters = _mapStateProvider.Characters[new MapCoordinate(x, y)].ToList(); if (_characterProvider.MainCharacter.X == x && _characterProvider.MainCharacter.Y == y) characters.Add(_characterProvider.MainCharacter); Option npc = Option.None(); - if (_mapStateProvider.NPCs.TryGetValues(new MapCoordinate(x, y), out var npcs)) + if (_mapStateProvider.NPCs.ContainsKey(new MapCoordinate(x, y))) { - npc = npcs.FirstOrNone(); + npc = _mapStateProvider.NPCs[new MapCoordinate(x, y)].FirstOrNone(); if (npc.Map(x => x.IsActing(NPCActionState.Walking)).ValueOr(false)) npc = Option.None(); } - var items = _mapStateProvider.MapItems.TryGetValues(new MapCoordinate(x, y), out var mapItems) - ? mapItems.OrderByDescending(i => i.UniqueID) - : Enumerable.Empty(); + var items = new List(); + if (_mapStateProvider.MapItems.ContainsKey(new MapCoordinate(x, y))) + items = _mapStateProvider.MapItems[new MapCoordinate(x, y)].OrderByDescending(i => i.UniqueID).ToList(); return new MapCellState { InBounds = true, Coordinate = new MapCoordinate(x, y), - Items = items.ToList(), + Items = items, TileSpec = tileSpec, Warp = warp.SomeNotNull().Map(w => new Warp(w)), ChestKey = chest.SomeNotNull(), Sign = sign.SomeNotNull().Map(s => new Sign(s)), Character = characters.FirstOrNone(), - Characters = characters.ToList(), + Characters = characters, NPC = npc }; } diff --git a/EOLib/Domain/Map/MapCoordinate.cs b/EOLib/Domain/Map/MapCoordinate.cs index 1fb8beafc..53f9abc52 100644 --- a/EOLib/Domain/Map/MapCoordinate.cs +++ b/EOLib/Domain/Map/MapCoordinate.cs @@ -1,15 +1,24 @@ -using System; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System; namespace EOLib.Domain.Map { - public struct MapCoordinate : IComparable + public readonly struct MapCoordinate : IComparable { public static MapCoordinate Zero { get; } = new MapCoordinate(0, 0); + public static MapCoordinate Max { get; } = new MapCoordinate(255, 255); + public int X { get; } public int Y { get; } + public MapCoordinate(BigCoords coords) + { + X = coords.X; + Y = coords.Y; + } + public MapCoordinate(int x, int y) { X = x; diff --git a/EOLib/Domain/Map/MapEntityCollectionHashSet.cs b/EOLib/Domain/Map/MapEntityCollectionHashSet.cs index 3d92f45a7..3ca5bc1f8 100644 --- a/EOLib/Domain/Map/MapEntityCollectionHashSet.cs +++ b/EOLib/Domain/Map/MapEntityCollectionHashSet.cs @@ -78,7 +78,7 @@ public void Remove(TValue value) public bool ContainsKey(int uniqueId) => _uniqueIdToHash.ContainsKey(uniqueId); - public bool ContainsKey(MapCoordinate coordinate) => _mapCoordinateToHashList.ContainsKey(coordinate); + public bool ContainsKey(MapCoordinate coordinate) => _mapCoordinateToHashList.ContainsKey(coordinate) && _mapCoordinateToHashList[coordinate].Count > 0; public bool TryGetValue(int uniqueId, out TValue value) { diff --git a/EOLib/Domain/Map/MapItem.cs b/EOLib/Domain/Map/MapItem.cs index bf5f263e0..31352bc00 100644 --- a/EOLib/Domain/Map/MapItem.cs +++ b/EOLib/Domain/Map/MapItem.cs @@ -1,5 +1,6 @@ using Amadevus.RecordGenerator; using EOLib.IO.Map; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using System; @@ -36,5 +37,17 @@ public MapItem(int uid, int id, int x, int y, int amount) } private MapItem() { } + + public static MapItem FromNearby(ItemMapInfo itemMapInfo) + { + return new Builder + { + UniqueID = itemMapInfo.Uid, + ItemID = itemMapInfo.Id, + X = itemMapInfo.Coords.X, + Y = itemMapInfo.Coords.Y, + Amount = itemMapInfo.Amount, + }.ToImmutable(); + } } } \ No newline at end of file diff --git a/EOLib/Domain/Map/RefreshReplyPacketData.cs b/EOLib/Domain/Map/RefreshReplyPacketData.cs deleted file mode 100644 index 2c3d72280..000000000 --- a/EOLib/Domain/Map/RefreshReplyPacketData.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Amadevus.RecordGenerator; -using EOLib.Net.Translators; -using System.Collections.Generic; - -namespace EOLib.Domain.Map -{ - [Record] - public sealed partial class RefreshReplyData : ITranslatedData - { - public IReadOnlyList Characters { get; } - - public IReadOnlyList NPCs { get; } - - public IReadOnlyList Items { get; } - - public RefreshReplyData() - { - Characters = new List(); - NPCs = new List(); - Items = new List(); - } - } -} diff --git a/EOLib/Domain/Map/UnknownEntitiesRequestActions.cs b/EOLib/Domain/Map/UnknownEntitiesRequestActions.cs new file mode 100644 index 000000000..7b63dd48f --- /dev/null +++ b/EOLib/Domain/Map/UnknownEntitiesRequestActions.cs @@ -0,0 +1,62 @@ +using AutomaticTypeMapper; +using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; +using System.Linq; + +namespace EOLib.Domain.Map +{ + [AutoMappedType] + public class UnknownEntitiesRequestActions : IUnknownEntitiesRequestActions + { + private readonly IPacketSendService _packetSendService; + private readonly ICurrentMapStateRepository _currentMapStateRepository; + + public UnknownEntitiesRequestActions(IPacketSendService packetSendService, + ICurrentMapStateRepository currentMapStateRepository) + { + _packetSendService = packetSendService; + _currentMapStateRepository = currentMapStateRepository; + } + + public void RequestUnknownPlayers() + { + var packet = new PlayerRangeRequestClientPacket + { + PlayerIds = _currentMapStateRepository.UnknownPlayerIDs.ToList() + }; + _packetSendService.SendPacket(packet); + _currentMapStateRepository.UnknownPlayerIDs.Clear(); + } + + public void RequestUnknownNPCs() + { + var packet = new NpcRangeRequestClientPacket + { + NpcIndexes = _currentMapStateRepository.UnknownNPCIndexes.ToList() + }; + _packetSendService.SendPacket(packet); + _currentMapStateRepository.UnknownNPCIndexes.Clear(); + } + + public void RequestAll() + { + var packet = new RangeRequestClientPacket + { + PlayerIds = _currentMapStateRepository.UnknownPlayerIDs.ToList(), + NpcIndexes = _currentMapStateRepository.UnknownNPCIndexes.ToList(), + }; + _packetSendService.SendPacket(packet); + _currentMapStateRepository.UnknownPlayerIDs.Clear(); + _currentMapStateRepository.UnknownNPCIndexes.Clear(); + } + } + + public interface IUnknownEntitiesRequestActions + { + void RequestUnknownPlayers(); + + void RequestUnknownNPCs(); + + void RequestAll(); + } +} diff --git a/EOLib/Domain/Map/WarpAgreePacketData.cs b/EOLib/Domain/Map/WarpAgreePacketData.cs deleted file mode 100644 index 8335b77b3..000000000 --- a/EOLib/Domain/Map/WarpAgreePacketData.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Amadevus.RecordGenerator; -using EOLib.Net.Translators; -using System.Collections.Generic; - -namespace EOLib.Domain.Map -{ - [Record] - public sealed partial class WarpAgreePacketData : ITranslatedData - { - public int MapID { get; } - - public WarpAnimation WarpAnimation { get; } - - public IReadOnlyList Characters { get; } - - public IReadOnlyList NPCs { get; } - - public IReadOnlyList Items { get; } - - public WarpAgreePacketData() - { - Characters = new List(); - NPCs = new List(); - Items = new List(); - } - } -} diff --git a/EOLib/Domain/Map/WarpAnimation.cs b/EOLib/Domain/Map/WarpAnimation.cs deleted file mode 100644 index 644ead847..000000000 --- a/EOLib/Domain/Map/WarpAnimation.cs +++ /dev/null @@ -1,10 +0,0 @@ - namespace EOLib.Domain.Map -{ - public enum WarpAnimation - { - None, - Scroll, - Admin, - Invalid = 255 - } -} \ No newline at end of file diff --git a/EOLib/Domain/NPC/NPC.cs b/EOLib/Domain/NPC/NPC.cs index 118112de3..1fc6aaf37 100644 --- a/EOLib/Domain/NPC/NPC.cs +++ b/EOLib/Domain/NPC/NPC.cs @@ -1,5 +1,6 @@ using Amadevus.RecordGenerator; using EOLib.Domain.Spells; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; namespace EOLib.Domain.NPC @@ -22,5 +23,17 @@ public sealed partial class NPC : ISpellTargetable public int ActualAttackFrame { get; } public Option OpponentID { get; } + + public static NPC FromNearby(NpcMapInfo npcMapInfo) + { + return new Builder + { + ID = npcMapInfo.Id, + Index = npcMapInfo.Index, + X = npcMapInfo.Coords.X, + Y = npcMapInfo.Coords.Y, + Direction = (EODirection)npcMapInfo.Direction, + }.ToImmutable(); + } } } \ No newline at end of file diff --git a/EOLib/Domain/Notifiers/IChestEventNotifier.cs b/EOLib/Domain/Notifiers/IChestEventNotifier.cs new file mode 100644 index 000000000..462ebe9f2 --- /dev/null +++ b/EOLib/Domain/Notifiers/IChestEventNotifier.cs @@ -0,0 +1,18 @@ +using EOLib.IO.Map; + +namespace EOLib.Domain.Notifiers +{ + public interface IChestEventNotifier + { + void NotifyChestLocked(ChestKey key); + + void NotifyChestBroken(); + } + + public class NoOpChestEventNotifier : IChestEventNotifier + { + public void NotifyChestLocked(ChestKey key) { } + + public void NotifyChestBroken() { } + } +} diff --git a/EOLib/Domain/Notifiers/IEffectNotifier.cs b/EOLib/Domain/Notifiers/IEffectNotifier.cs index 430828719..5c359a076 100644 --- a/EOLib/Domain/Notifiers/IEffectNotifier.cs +++ b/EOLib/Domain/Notifiers/IEffectNotifier.cs @@ -1,18 +1,18 @@ using AutomaticTypeMapper; using EOLib.Domain.Map; -using EOLib.IO.Map; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.Domain.Notifiers { public interface IEffectNotifier { - void NotifyWarpLeaveEffect(int characterId, WarpAnimation anim); + void NotifyWarpLeaveEffect(int characterId, WarpEffect anim); - void NotifyWarpEnterEffect(int characterId, WarpAnimation anim); + void NotifyWarpEnterEffect(int characterId, WarpEffect anim); void NotifyPotionEffect(int playerId, int effectId); - void NotifyMapEffect(MapEffect effect, int strength = 0); + void NotifyMapEffect(IO.Map.MapEffect effect, int strength = 0); void NotifyEffectAtLocation(MapCoordinate location, int effectId); } @@ -20,13 +20,13 @@ public interface IEffectNotifier [AutoMappedType] public class NoOpEffectNotifier : IEffectNotifier { - public void NotifyWarpLeaveEffect(int characterId, WarpAnimation anim) { } + public void NotifyWarpLeaveEffect(int characterId, WarpEffect anim) { } - public void NotifyWarpEnterEffect(int characterId, WarpAnimation anim) { } + public void NotifyWarpEnterEffect(int characterId, WarpEffect anim) { } public void NotifyPotionEffect(int playerId, int effectId) { } - public void NotifyMapEffect(MapEffect effect, int strength = 0) { } + public void NotifyMapEffect(IO.Map.MapEffect effect, int strength = 0) { } public void NotifyEffectAtLocation(MapCoordinate location, int effectId) { } } diff --git a/EOLib/Domain/Notifiers/IJukeboxNotifier.cs b/EOLib/Domain/Notifiers/IJukeboxNotifier.cs new file mode 100644 index 000000000..16f29bc9e --- /dev/null +++ b/EOLib/Domain/Notifiers/IJukeboxNotifier.cs @@ -0,0 +1,16 @@ +using AutomaticTypeMapper; + +namespace EOLib.Domain.Notifiers +{ + public interface IJukeboxNotifier + { + void JukeboxUnavailable(); + } + + [AutoMappedType] + public class NoOpJukeboxNotifier : IJukeboxNotifier + { + public void JukeboxUnavailable() { } + } + +} \ No newline at end of file diff --git a/EOLib/Domain/Notifiers/ILockerEventNotifier.cs b/EOLib/Domain/Notifiers/ILockerEventNotifier.cs new file mode 100644 index 000000000..01516f84e --- /dev/null +++ b/EOLib/Domain/Notifiers/ILockerEventNotifier.cs @@ -0,0 +1,15 @@ +using AutomaticTypeMapper; + +namespace EOLib.Domain.Notifiers +{ + public interface ILockerEventNotifier + { + void NotifyLockerFull(int maxItems); + } + + [AutoMappedType] + public class NoOpLockerEventNotifier : ILockerEventNotifier + { + public void NotifyLockerFull(int maxItems) { } + } +} diff --git a/EOLib/Domain/Notifiers/IMapChangedNotifier.cs b/EOLib/Domain/Notifiers/IMapChangedNotifier.cs index 24ffad95e..4ee0256fe 100644 --- a/EOLib/Domain/Notifiers/IMapChangedNotifier.cs +++ b/EOLib/Domain/Notifiers/IMapChangedNotifier.cs @@ -1,11 +1,11 @@ using AutomaticTypeMapper; -using EOLib.Domain.Map; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.Domain.Notifiers { public interface IMapChangedNotifier { - void NotifyMapChanged(WarpAnimation warpAnimation, bool differentMapID); + void NotifyMapChanged(WarpEffect warpEffect, bool differentMapID); void NotifyMapMutation(); } @@ -13,7 +13,7 @@ public interface IMapChangedNotifier [AutoMappedType] public class NoOpMapChangedNotifier : IMapChangedNotifier { - public void NotifyMapChanged(WarpAnimation warpAnimation, bool differentMapID) { } + public void NotifyMapChanged(WarpEffect warpEffect, bool differentMapID) { } public void NotifyMapMutation() { } } diff --git a/EOLib/Domain/Notifiers/IPartyEventNotifier.cs b/EOLib/Domain/Notifiers/IPartyEventNotifier.cs index 4ef9b04ba..a4567f4c5 100644 --- a/EOLib/Domain/Notifiers/IPartyEventNotifier.cs +++ b/EOLib/Domain/Notifiers/IPartyEventNotifier.cs @@ -1,5 +1,5 @@ using AutomaticTypeMapper; -using EOLib.Domain.Party; +using Moffat.EndlessOnline.SDK.Protocol.Net; namespace EOLib.Domain.Notifiers { diff --git a/EOLib/Domain/Notifiers/IUserInterfaceNotifier.cs b/EOLib/Domain/Notifiers/IUserInterfaceNotifier.cs index 2ae055e32..ae2533207 100644 --- a/EOLib/Domain/Notifiers/IUserInterfaceNotifier.cs +++ b/EOLib/Domain/Notifiers/IUserInterfaceNotifier.cs @@ -1,7 +1,7 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; using EOLib.Domain.Map; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; using System.Collections.Generic; namespace EOLib.Domain.Notifiers diff --git a/EOLib/Domain/Online/OnlineIcon.cs b/EOLib/Domain/Online/OnlineIcon.cs deleted file mode 100644 index cece85825..000000000 --- a/EOLib/Domain/Online/OnlineIcon.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace EOLib.Domain.Online -{ - public enum OnlineIcon - { - Normal = 0, - GM = 4, - HGM = 5, - Party = 6, - GMParty = 9, - HGMParty = 10, - SLNBot = 20 - } -} diff --git a/EOLib/Domain/Online/OnlinePlayerActions.cs b/EOLib/Domain/Online/OnlinePlayerActions.cs index 93b1accf3..5febe33fd 100644 --- a/EOLib/Domain/Online/OnlinePlayerActions.cs +++ b/EOLib/Domain/Online/OnlinePlayerActions.cs @@ -1,6 +1,7 @@ using AutomaticTypeMapper; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Online { @@ -16,8 +17,7 @@ public OnlinePlayerActions(IPacketSendService packetSendService) public void RequestOnlinePlayers(bool fullList) { - var packet = new PacketBuilder(PacketFamily.Players, fullList ? PacketAction.Request : PacketAction.List).Build(); - _packetSendService.SendPacket(packet); + _packetSendService.SendPacket(fullList ? (IPacket)new PlayersRequestClientPacket() : new PlayersListClientPacket()); } } diff --git a/EOLib/Domain/Online/OnlinePlayerInfo.cs b/EOLib/Domain/Online/OnlinePlayerInfo.cs index da51743a3..01ff54eae 100644 --- a/EOLib/Domain/Online/OnlinePlayerInfo.cs +++ b/EOLib/Domain/Online/OnlinePlayerInfo.cs @@ -1,4 +1,5 @@ using Amadevus.RecordGenerator; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.Domain.Online { @@ -13,10 +14,10 @@ public sealed partial class OnlinePlayerInfo public string Class { get; } - public OnlineIcon Icon { get; } + public CharacterIcon Icon { get; } public OnlinePlayerInfo(string name) - : this(name, string.Empty, string.Empty, string.Empty, OnlineIcon.Normal) + : this(name, string.Empty, string.Empty, string.Empty, CharacterIcon.Player) { } } diff --git a/EOLib/Domain/Online/OnlinePlayerRepository.cs b/EOLib/Domain/Online/OnlinePlayerRepository.cs index 89d7ac302..4f271f538 100644 --- a/EOLib/Domain/Online/OnlinePlayerRepository.cs +++ b/EOLib/Domain/Online/OnlinePlayerRepository.cs @@ -5,7 +5,7 @@ namespace EOLib.Domain.Online { public interface IOnlinePlayerRepository : IResettable { - HashSet OnlinePlayers { get; } + HashSet OnlinePlayers { get; set; } } public interface IOnlinePlayerProvider @@ -16,7 +16,7 @@ public interface IOnlinePlayerProvider [AutoMappedType(IsSingleton = true)] public class OnlinePlayerRepository : IOnlinePlayerRepository, IOnlinePlayerProvider { - public HashSet OnlinePlayers { get; private set; } + public HashSet OnlinePlayers { get; set; } IReadOnlyCollection IOnlinePlayerProvider.OnlinePlayers => OnlinePlayers; diff --git a/EOLib/Domain/Party/PartyActions.cs b/EOLib/Domain/Party/PartyActions.cs index 70e350615..2f6f8b843 100644 --- a/EOLib/Domain/Party/PartyActions.cs +++ b/EOLib/Domain/Party/PartyActions.cs @@ -1,6 +1,7 @@ using AutomaticTypeMapper; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Party { @@ -16,38 +17,35 @@ public PartyActions(IPacketSendService packetSendService) public void RequestParty(PartyRequestType type, int targetCharacterId) { - var packet = new PacketBuilder(PacketFamily.Party, PacketAction.Request) - .AddChar((int)type) - .AddShort(targetCharacterId) - .Build(); - + var packet = new PartyRequestClientPacket + { + RequestType = type, + PlayerId = targetCharacterId + }; _packetSendService.SendPacket(packet); } public void AcceptParty(PartyRequestType type, int targetCharacterId) { - var packet = new PacketBuilder(PacketFamily.Party, PacketAction.Accept) - .AddChar((int)type) - .AddShort(targetCharacterId) - .Build(); - + var packet = new PartyAcceptClientPacket + { + RequestType = type, + InviterPlayerId = targetCharacterId + }; _packetSendService.SendPacket(packet); } public void ListParty() { - var packet = new PacketBuilder(PacketFamily.Party, PacketAction.Take) - .Build(); - - _packetSendService.SendPacket(packet); + _packetSendService.SendPacket(new PartyTakeClientPacket()); } public void RemovePartyMember(int targetCharacterId) { - var packet = new PacketBuilder(PacketFamily.Party, PacketAction.Remove) - .AddShort(targetCharacterId) - .Build(); - + var packet = new PartyRemoveClientPacket + { + PlayerId = targetCharacterId, + }; _packetSendService.SendPacket(packet); } } diff --git a/EOLib/Domain/Party/PartyRequestType.cs b/EOLib/Domain/Party/PartyRequestType.cs deleted file mode 100644 index 3bdca2e5c..000000000 --- a/EOLib/Domain/Party/PartyRequestType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace EOLib.Domain.Party -{ - public enum PartyRequestType - { - Join, - Invite - } -} diff --git a/EOLib/Domain/Protocol/BanType.cs b/EOLib/Domain/Protocol/BanType.cs deleted file mode 100644 index df62fdbab..000000000 --- a/EOLib/Domain/Protocol/BanType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace EOLib.Domain.Protocol -{ - public enum BanType - { - TemporaryBan = 0, - PermanentBan = 2, - ErrorState = 255 - } -} diff --git a/EOLib/Domain/Protocol/IInitializationData.cs b/EOLib/Domain/Protocol/IInitializationData.cs deleted file mode 100644 index 6b09764eb..000000000 --- a/EOLib/Domain/Protocol/IInitializationData.cs +++ /dev/null @@ -1,27 +0,0 @@ -using EOLib.Net.Translators; - -namespace EOLib.Domain.Protocol -{ - public interface IInitializationData : ITranslatedData - { - InitReply Response { get; } - - int this[InitializationDataKey key] { get; } - } - - public enum InitializationDataKey - { - //response: OK - SequenceByte1, - SequenceByte2, - SendMultiple, - ReceiveMultiple, - PlayerID, - HashResponse, - //response: Out of Date - RequiredVersionNumber, - //response: Banned - BanType, - BanTimeRemaining - } -} diff --git a/EOLib/Domain/Protocol/InitFileType.cs b/EOLib/Domain/Protocol/InitFileType.cs deleted file mode 100644 index 2d7e144b0..000000000 --- a/EOLib/Domain/Protocol/InitFileType.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace EOLib.Domain.Protocol -{ - public enum InitFileType : byte - { - Map = 1, - Item = 2, - Npc = 3, - Spell = 4, - Class = 5 - } -} \ No newline at end of file diff --git a/EOLib/Domain/Protocol/InitReply.cs b/EOLib/Domain/Protocol/InitReply.cs deleted file mode 100644 index efc2c4775..000000000 --- a/EOLib/Domain/Protocol/InitReply.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace EOLib.Domain.Protocol -{ - public enum InitReply - { - ClientOutOfDate = 1, - Success = 2, - BannedFromServer = 3, - WarpMap = 4, - MapFile = 5, - ItemFile = 6, - NpcFile = 7, - SpellFile = 8, - AllPlayersList = 9, - MapMutation = 10, - FriendPlayersList = 11, - ClassFile = 12, - ErrorState = 0 - } -} diff --git a/EOLib/Domain/Protocol/InitializationBannedData.cs b/EOLib/Domain/Protocol/InitializationBannedData.cs deleted file mode 100644 index 207a1345d..000000000 --- a/EOLib/Domain/Protocol/InitializationBannedData.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; - -namespace EOLib.Domain.Protocol -{ - public class InitializationBannedData : IInitializationData - { - private readonly BanType _banType; - private readonly byte _banTimeRemaining; - - public InitReply Response => InitReply.BannedFromServer; - - public int this[InitializationDataKey key] => GetValueHelper(key); - - public InitializationBannedData(BanType banType, byte banTimeRemaining) - { - _banType = banType; - _banTimeRemaining = banTimeRemaining; - } - - private int GetValueHelper(InitializationDataKey key) - { - switch (key) - { - case InitializationDataKey.BanType: return (int)_banType; - case InitializationDataKey.BanTimeRemaining: return _banTimeRemaining; - default: throw new ArgumentOutOfRangeException(nameof(key), key, null); - } - } - } -} diff --git a/EOLib/Domain/Protocol/InitializationOutOfDateData.cs b/EOLib/Domain/Protocol/InitializationOutOfDateData.cs deleted file mode 100644 index 5910173d3..000000000 --- a/EOLib/Domain/Protocol/InitializationOutOfDateData.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; - -namespace EOLib.Domain.Protocol -{ - public class InitializationOutOfDateData : IInitializationData - { - private readonly int _requiredVersionNumber; - public InitReply Response => InitReply.ClientOutOfDate; - - public int this[InitializationDataKey key] - { - get - { - if(key != InitializationDataKey.RequiredVersionNumber) - throw new ArgumentOutOfRangeException(nameof(key), key, null); - return _requiredVersionNumber; - } - } - - public InitializationOutOfDateData(int requiredVersionNumber) - { - _requiredVersionNumber = requiredVersionNumber; - } - } -} diff --git a/EOLib/Domain/Protocol/InitializationSuccessData.cs b/EOLib/Domain/Protocol/InitializationSuccessData.cs deleted file mode 100644 index d429da294..000000000 --- a/EOLib/Domain/Protocol/InitializationSuccessData.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; - -namespace EOLib.Domain.Protocol -{ - public class InitializationSuccessData : IInitializationData - { - public InitReply Response => InitReply.Success; - - public int this[InitializationDataKey key] => GetValueHelper(key); - - private readonly int _seq1, _seq2, _sendMulti, _recvMulti; - private readonly int _playerID; - private readonly int _hashResponse; - - public InitializationSuccessData(int sequence1, - int sequence2, - int receiveMultiple, - int sendMultiple, - int playerID, - int hashResponse) - { - _seq1 = sequence1; - _seq2 = sequence2; - _recvMulti = receiveMultiple; - _sendMulti = sendMultiple; - _playerID = playerID; - _hashResponse = hashResponse; - } - - private int GetValueHelper(InitializationDataKey key) - { - switch (key) - { - case InitializationDataKey.SequenceByte1: return _seq1; - case InitializationDataKey.SequenceByte2: return _seq2; - case InitializationDataKey.SendMultiple: return _sendMulti; - case InitializationDataKey.ReceiveMultiple: return _recvMulti; - case InitializationDataKey.PlayerID: return _playerID; - case InitializationDataKey.HashResponse: return _hashResponse; - default: throw new ArgumentOutOfRangeException(nameof(key), key, null); - } - } - } -} diff --git a/EOLib/Domain/Protocol/PingTimeRepository.cs b/EOLib/Domain/Protocol/PingTimeRepository.cs index 1ae9c374d..f50454169 100644 --- a/EOLib/Domain/Protocol/PingTimeRepository.cs +++ b/EOLib/Domain/Protocol/PingTimeRepository.cs @@ -1,22 +1,21 @@ -using System; -using System.Collections.Generic; -using AutomaticTypeMapper; +using AutomaticTypeMapper; +using System.Diagnostics; namespace EOLib.Domain.Protocol { public interface IPingTimeRepository { - Dictionary PingRequests { get; set; } + Stopwatch RequestTimer { get; set; } } [AutoMappedType(IsSingleton = true)] public class PingTimeRepository : IPingTimeRepository { - public Dictionary PingRequests { get; set; } + public Stopwatch RequestTimer { get; set; } public PingTimeRepository() { - PingRequests = new Dictionary(); + RequestTimer = new Stopwatch(); } } } diff --git a/EOLib/Domain/Report/ReportActions.cs b/EOLib/Domain/Report/ReportActions.cs index d583e4167..fb86fc0cd 100644 --- a/EOLib/Domain/Report/ReportActions.cs +++ b/EOLib/Domain/Report/ReportActions.cs @@ -1,6 +1,6 @@ using AutomaticTypeMapper; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Report { @@ -16,19 +16,17 @@ public ReportActions(IPacketSendService packetSendService) public void ReportPlayer(string player, string message) { - var packet = new PacketBuilder(PacketFamily.AdminInteract, PacketAction.Report) - .AddString(player) - .AddByte(255) - .AddString(message) - .Build(); + var packet = new AdminInteractReportClientPacket + { + Reportee = player, + Message = message + }; _packetSendService.SendPacket(packet); } public void SpeakToAdmin(string message) { - var packet = new PacketBuilder(PacketFamily.AdminInteract, PacketAction.Tell) - .AddString(message) - .Build(); + var packet = new AdminInteractTellClientPacket { Message = message }; _packetSendService.SendPacket(packet); } } diff --git a/EOLib/Domain/Spells/SpellTargetType.cs b/EOLib/Domain/Spells/SpellTargetType.cs deleted file mode 100644 index 7a47badbc..000000000 --- a/EOLib/Domain/Spells/SpellTargetType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace EOLib.Domain.Spells -{ - public enum SpellTargetType : byte - { - Player = 1, - NPC = 2 - } -} diff --git a/EOLib/Domain/Trade/TradeActions.cs b/EOLib/Domain/Trade/TradeActions.cs index 0841e8031..96e61aad8 100644 --- a/EOLib/Domain/Trade/TradeActions.cs +++ b/EOLib/Domain/Trade/TradeActions.cs @@ -1,6 +1,6 @@ using AutomaticTypeMapper; -using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; namespace EOLib.Domain.Trade { @@ -16,54 +16,42 @@ public TradeActions(IPacketSendService packetSendService) public void RequestTrade(int characterID) { - var packet = new PacketBuilder(PacketFamily.Trade, PacketAction.Request) - .AddChar(6) - .AddShort(characterID) - .Build(); + var packet = new TradeRequestClientPacket { PlayerId = characterID }; _packetSendService.SendPacket(packet); } public void AcceptTradeRequest(int characterID) { - var packet = new PacketBuilder(PacketFamily.Trade, PacketAction.Accept) - .AddChar(6) - .AddShort(characterID) - .Build(); + var packet = new TradeAcceptClientPacket { PlayerId = characterID }; _packetSendService.SendPacket(packet); } public void RemoveItemFromOffer(int itemID) { - var packet = new PacketBuilder(PacketFamily.Trade, PacketAction.Remove) - .AddShort(itemID) - .Build(); + var packet = new TradeRemoveClientPacket { ItemId = itemID }; _packetSendService.SendPacket(packet); } public void AddItemToOffer(int itemID, int amount) { - var packet = new PacketBuilder(PacketFamily.Trade, PacketAction.Add) - .AddShort(itemID) - .AddInt(amount) - .Build(); + var packet = new TradeAddClientPacket + { + AddItem = new Moffat.EndlessOnline.SDK.Protocol.Net.Item + { + Id = itemID, + Amount = amount, + } + }; _packetSendService.SendPacket(packet); } public void AgreeToTrade(bool agree) { - var packet = new PacketBuilder(PacketFamily.Trade, PacketAction.Agree) - .AddChar(agree ? 1 : 0) - .Build(); + var packet = new TradeAgreeClientPacket { Agree = agree }; _packetSendService.SendPacket(packet); } - public void CancelTrade() - { - var packet = new PacketBuilder(PacketFamily.Trade, PacketAction.Close) - .AddChar(6) - .Build(); - _packetSendService.SendPacket(packet); - } + public void CancelTrade() => _packetSendService.SendPacket(new TradeCloseClientPacket()); } public interface ITradeActions diff --git a/EOLib/EOLib.csproj b/EOLib/EOLib.csproj index 920c81f17..1f422466a 100644 --- a/EOLib/EOLib.csproj +++ b/EOLib/EOLib.csproj @@ -22,6 +22,7 @@ + diff --git a/EOLib/Extensions/OnlineIconExtensions.cs b/EOLib/Extensions/OnlineIconExtensions.cs index feb40dddd..d498859a5 100644 --- a/EOLib/Extensions/OnlineIconExtensions.cs +++ b/EOLib/Extensions/OnlineIconExtensions.cs @@ -1,24 +1,23 @@ using EOLib.Domain.Chat; -using EOLib.Domain.Online; -using System; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.Extensions { public static class OnlineIconExtensions { - public static ChatIcon ToChatIcon(this OnlineIcon icon) + public static ChatIcon ToChatIcon(this CharacterIcon icon) { - switch (icon) + return icon switch { - case OnlineIcon.Normal: return ChatIcon.Player; - case OnlineIcon.GM: return ChatIcon.GM; - case OnlineIcon.HGM: return ChatIcon.HGM; - case OnlineIcon.Party: return ChatIcon.PlayerParty; - case OnlineIcon.GMParty: return ChatIcon.GMParty; - case OnlineIcon.HGMParty: return ChatIcon.HGMParty; - case OnlineIcon.SLNBot: return ChatIcon.PlayerPartyDark; - default: throw new ArgumentOutOfRangeException(nameof(icon), "Invalid Icon type specified."); - } + CharacterIcon.Player => ChatIcon.Player, + CharacterIcon.Gm => ChatIcon.GM, + CharacterIcon.Hgm => ChatIcon.HGM, + CharacterIcon.Party => ChatIcon.PlayerParty, + CharacterIcon.GmParty => ChatIcon.GMParty, + CharacterIcon.HgmParty => ChatIcon.HGMParty, + (CharacterIcon)20 => ChatIcon.PlayerPartyDark, // SLNBot in eoserv + _ => ChatIcon.Player, + }; } } } diff --git a/EOLib/Net/Builders/ChatPacketBuilder.cs b/EOLib/Net/Builders/ChatPacketBuilder.cs deleted file mode 100644 index 33b660a1b..000000000 --- a/EOLib/Net/Builders/ChatPacketBuilder.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using AutomaticTypeMapper; -using EOLib.Domain.Chat; - -namespace EOLib.Net.Builders -{ - [AutoMappedType] - public class ChatPacketBuilder : IChatPacketBuilder - { - public IPacket BuildChatPacket(ChatType chatType, - string chat, - string targetCharacter) - { - IPacketBuilder packetBuilder = new PacketBuilder(PacketFamily.Talk, GetActionFromType(chatType)); - - if (chatType == ChatType.PM) - { - if(string.IsNullOrEmpty(targetCharacter)) - throw new ArgumentException("Target character for PM must not be null or empty", nameof(targetCharacter)); - packetBuilder = packetBuilder.AddBreakString(targetCharacter); - } - - packetBuilder = packetBuilder.AddString(chat); - return packetBuilder.Build(); - } - - private PacketAction GetActionFromType(ChatType chatType) - { - switch (chatType) - { - case ChatType.Local: return PacketAction.Report; - case ChatType.PM: return PacketAction.Tell; - case ChatType.Global: return PacketAction.Message; - case ChatType.Guild: return PacketAction.Request; - case ChatType.Party: return PacketAction.Open; - case ChatType.Admin: return PacketAction.Admin; - case ChatType.Announce: return PacketAction.Announce; - default: throw new ArgumentOutOfRangeException(nameof(chatType)); - } - } - } -} \ No newline at end of file diff --git a/EOLib/Net/Builders/IChatPacketBuilder.cs b/EOLib/Net/Builders/IChatPacketBuilder.cs deleted file mode 100644 index f45dccd90..000000000 --- a/EOLib/Net/Builders/IChatPacketBuilder.cs +++ /dev/null @@ -1,11 +0,0 @@ -using EOLib.Domain.Chat; - -namespace EOLib.Net.Builders -{ - public interface IChatPacketBuilder - { - IPacket BuildChatPacket(ChatType chatType, - string chat, - string targetCharacter); - } -} diff --git a/EOLib/Net/Communication/INetworkClient.cs b/EOLib/Net/Communication/INetworkClient.cs index 472dcd2fe..0d857d723 100644 --- a/EOLib/Net/Communication/INetworkClient.cs +++ b/EOLib/Net/Communication/INetworkClient.cs @@ -1,4 +1,5 @@ -using System; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using System; using System.Threading; using System.Threading.Tasks; diff --git a/EOLib/Net/Communication/IPacketQueue.cs b/EOLib/Net/Communication/IPacketQueue.cs index d4d7780db..45fae7cdd 100644 --- a/EOLib/Net/Communication/IPacketQueue.cs +++ b/EOLib/Net/Communication/IPacketQueue.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using System.Collections.Generic; namespace EOLib.Net.Communication { diff --git a/EOLib/Net/Communication/IPacketSendService.cs b/EOLib/Net/Communication/IPacketSendService.cs index 8ab5b0a83..cb8588548 100644 --- a/EOLib/Net/Communication/IPacketSendService.cs +++ b/EOLib/Net/Communication/IPacketSendService.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using System.Threading.Tasks; namespace EOLib.Net.Communication { diff --git a/EOLib/Net/Communication/IWaitablePacketQueue.cs b/EOLib/Net/Communication/IWaitablePacketQueue.cs index ac79927c3..1977b3a78 100644 --- a/EOLib/Net/Communication/IWaitablePacketQueue.cs +++ b/EOLib/Net/Communication/IWaitablePacketQueue.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using System.Threading.Tasks; namespace EOLib.Net.Communication { diff --git a/EOLib/Net/Communication/NetworkClient.cs b/EOLib/Net/Communication/NetworkClient.cs index 25da376c0..2c1472bf0 100644 --- a/EOLib/Net/Communication/NetworkClient.cs +++ b/EOLib/Net/Communication/NetworkClient.cs @@ -1,14 +1,12 @@ -using System; -using System.Diagnostics; -using System.Linq; +using EOLib.IO.Services; +using EOLib.Net.Handlers; +using EOLib.Net.PacketProcessing; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using System; using System.Net; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; -using EOLib.IO.Services; -using EOLib.Logger; -using EOLib.Net.Handlers; -using EOLib.Net.PacketProcessing; namespace EOLib.Net.Communication { @@ -17,7 +15,6 @@ public class NetworkClient : INetworkClient private readonly IPacketProcessActions _packetProcessActions; private readonly IPacketHandlingActions _packetHandlingActions; private readonly INumberEncoderService _numberEncoderService; - private readonly ILoggerProvider _loggerProvider; private readonly IAsyncSocket _socket; @@ -30,13 +27,11 @@ public class NetworkClient : INetworkClient public NetworkClient(IPacketProcessActions packetProcessActions, IPacketHandlingActions packetHandlingActions, INumberEncoderService numberEncoderService, - ILoggerProvider loggerProvider, TimeSpan receiveTimeout) { _packetProcessActions = packetProcessActions; _packetHandlingActions = packetHandlingActions; _numberEncoderService = numberEncoderService; - _loggerProvider = loggerProvider; ReceiveTimeout = receiveTimeout; _socket = new AsyncSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); @@ -84,37 +79,21 @@ public async Task RunReceiveLoopAsync(CancellationToken cancellationToken) while (!cancellationToken.IsCancellationRequested) { var lengthData = await _socket.ReceiveAsync(2, cancellationToken); - if (cancellationToken.IsCancellationRequested) - { - _loggerProvider.Logger.Log("RECV thread: Cancellation was requested when receiving length"); - break; - } - - if (lengthData.Length != 2) + if (cancellationToken.IsCancellationRequested || lengthData.Length != 2) { - _loggerProvider.Logger.Log("RECV thread: Did not receive two bytes of data"); break; } - var length = _numberEncoderService.DecodeNumber(lengthData); var packetData = await _socket.ReceiveAsync(length, cancellationToken); - if (cancellationToken.IsCancellationRequested) - { - _loggerProvider.Logger.Log("RECV thread: Cancellation was requested when receiving data"); - break; - } - - if (packetData.Length != length) + if (cancellationToken.IsCancellationRequested || packetData.Length != length) { - _loggerProvider.Logger.Log("RECV thread: Did not receive expected {0} bytes of data", length); break; } - var packet = _packetProcessActions.DecodeData(packetData); - LogReceivedPacket(packet); - - _packetHandlingActions.EnqueuePacketForHandling(packet); + _packetProcessActions + .DecodeData(packetData) + .MatchSome(_packetHandlingActions.EnqueuePacketForHandling); } } @@ -126,39 +105,16 @@ public int Send(IPacket packet) public async Task SendAsync(IPacket packet, int timeout = 1500) { - LogSentPacket(packet, true); var bytesToSend = _packetProcessActions.EncodePacket(packet); - using (var cts = new CancellationTokenSource(timeout)) - return await _socket.SendAsync(bytesToSend, cts.Token).ConfigureAwait(false); + using var cts = new CancellationTokenSource(timeout); + return await _socket.SendAsync(bytesToSend, cts.Token).ConfigureAwait(false); } public async Task SendRawPacketAsync(IPacket packet, int timeout = 1500) { - LogSentPacket(packet, false); var bytesToSend = _packetProcessActions.EncodeRawPacket(packet); - using (var cts = new CancellationTokenSource(timeout)) - return await _socket.SendAsync(bytesToSend, cts.Token).ConfigureAwait(false); - } - - [Conditional("DEBUG")] - private void LogReceivedPacket(IPacket packet) - { - _loggerProvider.Logger.Log("RECV thread: Received packet Family={0,-13} Action={1,-8} sz={2,-5} data={3}", - Enum.GetName(typeof(PacketFamily), packet.Family), - Enum.GetName(typeof(PacketAction), packet.Action), - packet.Length, - string.Join(":", packet.RawData.Select(b => $"{b:x2}"))); - } - - [Conditional("DEBUG")] - private void LogSentPacket(IPacket packet, bool encoded) - { - _loggerProvider.Logger.Log("SEND thread: Processing {0,-3} packet Family={1,-13} Action={2,-8} sz={3,-5} data={4}", - encoded ? "ENC" : "RAW", - Enum.GetName(typeof(PacketFamily), packet.Family), - Enum.GetName(typeof(PacketAction), packet.Action), - packet.Length, - string.Join(":", packet.RawData.Select(b => $"{b:x2}"))); + using var cts = new CancellationTokenSource(timeout); + return await _socket.SendAsync(bytesToSend, cts.Token).ConfigureAwait(false); } public void Dispose() diff --git a/EOLib/Net/Communication/NetworkClientFactory.cs b/EOLib/Net/Communication/NetworkClientFactory.cs index f02484cc6..cd8370d92 100644 --- a/EOLib/Net/Communication/NetworkClientFactory.cs +++ b/EOLib/Net/Communication/NetworkClientFactory.cs @@ -13,22 +13,19 @@ public class NetworkClientFactory : INetworkClientFactory private readonly IPacketProcessActions _packetProcessActions; private readonly IPacketHandlingActions _packetHandlingActions; private readonly INumberEncoderService _numberEncoderService; - private readonly ILoggerProvider _loggerProvider; public NetworkClientFactory(IPacketProcessActions packetProcessActions, IPacketHandlingActions packetHandlingActions, - INumberEncoderService numberEncoderService, - ILoggerProvider loggerProvider) + INumberEncoderService numberEncoderService) { _packetProcessActions = packetProcessActions; _packetHandlingActions = packetHandlingActions; _numberEncoderService = numberEncoderService; - _loggerProvider = loggerProvider; } public INetworkClient CreateNetworkClient(int timeout = Constants.ResponseTimeout) { - return new NetworkClient(_packetProcessActions, _packetHandlingActions, _numberEncoderService, _loggerProvider, TimeSpan.FromMilliseconds(timeout)); + return new NetworkClient(_packetProcessActions, _packetHandlingActions, _numberEncoderService, TimeSpan.FromMilliseconds(timeout)); } } } diff --git a/EOLib/Net/Communication/PacketQueue.cs b/EOLib/Net/Communication/PacketQueue.cs index 68fb26aa6..2c0e59ce6 100644 --- a/EOLib/Net/Communication/PacketQueue.cs +++ b/EOLib/Net/Communication/PacketQueue.cs @@ -1,4 +1,5 @@ -using System; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -35,7 +36,7 @@ public void EnqueuePacketAndSignalConsumer(IPacket pkt) public IPacket PeekPacket() { if (QueuedPacketCount == 0) - return new EmptyPacket(); + throw new EmptyPacketReceivedException(); lock (_locker) return _internalQueue.Peek(); @@ -44,7 +45,7 @@ public IPacket PeekPacket() public IPacket DequeueFirstPacket() { if (QueuedPacketCount == 0) - return new EmptyPacket(); + throw new EmptyPacketReceivedException(); lock (_locker) return _internalQueue.Dequeue(); @@ -62,7 +63,7 @@ public async Task WaitForPacketAndDequeue(int timeOut = Constants.Respo var result = await _enqueuedTaskCompletionSource.Task; if (!result) - return new EmptyPacket(); + throw new EmptyPacketReceivedException(); } return DequeueFirstPacket(); diff --git a/EOLib/Net/Communication/PacketSendService.cs b/EOLib/Net/Communication/PacketSendService.cs index 93594d469..ea225b6f2 100644 --- a/EOLib/Net/Communication/PacketSendService.cs +++ b/EOLib/Net/Communication/PacketSendService.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using AutomaticTypeMapper; +using Moffat.EndlessOnline.SDK.Protocol.Net; namespace EOLib.Net.Communication { @@ -36,11 +37,7 @@ public async Task SendRawPacketAndWaitAsync(IPacket packet) if (bytes == 0) throw new NoDataSentException(); - var responsePacket = await InBandQueue.WaitForPacketAndDequeue((int)Client.ReceiveTimeout.TotalMilliseconds); - if (responsePacket is EmptyPacket) - throw new EmptyPacketReceivedException(); - - return responsePacket; + return await InBandQueue.WaitForPacketAndDequeue((int)Client.ReceiveTimeout.TotalMilliseconds); } public async Task SendEncodedPacketAndWaitAsync(IPacket packet) @@ -49,11 +46,7 @@ public async Task SendEncodedPacketAndWaitAsync(IPacket packet) if (bytes == 0) throw new NoDataSentException(); - var responsePacket = await InBandQueue.WaitForPacketAndDequeue((int)Client.ReceiveTimeout.TotalMilliseconds); - if (responsePacket is EmptyPacket) - throw new EmptyPacketReceivedException(); - - return responsePacket; + return await InBandQueue.WaitForPacketAndDequeue((int)Client.ReceiveTimeout.TotalMilliseconds); } private INetworkClient Client => _networkClientProvider.NetworkClient; diff --git a/EOLib/Net/Connection/INetworkConnectionActions.cs b/EOLib/Net/Connection/INetworkConnectionActions.cs index 9f108ac6d..eb0ffcbe6 100644 --- a/EOLib/Net/Connection/INetworkConnectionActions.cs +++ b/EOLib/Net/Connection/INetworkConnectionActions.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; -using EOLib.Domain.Protocol; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.Net.Connection { @@ -10,8 +10,8 @@ public interface INetworkConnectionActions void DisconnectFromServer(); - Task BeginHandshake(); + Task BeginHandshake(int challenge); - void CompleteHandshake(IInitializationData initializationData); + void CompleteHandshake(InitInitServerPacket initializationData); } } diff --git a/EOLib/Net/Connection/NetworkConnectionActions.cs b/EOLib/Net/Connection/NetworkConnectionActions.cs index 03e96dfb4..db84e5e71 100644 --- a/EOLib/Net/Connection/NetworkConnectionActions.cs +++ b/EOLib/Net/Connection/NetworkConnectionActions.cs @@ -1,12 +1,14 @@ -using System; -using System.Threading.Tasks; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EOLib.Config; using EOLib.Domain.Login; -using EOLib.Domain.Protocol; using EOLib.Net.Communication; using EOLib.Net.PacketProcessing; -using EOLib.Net.Translators; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System; +using System.Threading.Tasks; +using Version = Moffat.EndlessOnline.SDK.Protocol.Net.Version; namespace EOLib.Net.Connection { @@ -16,9 +18,7 @@ public class NetworkConnectionActions : INetworkConnectionActions private readonly INetworkClientRepository _networkClientRepository; private readonly ISequenceRepository _sequenceRepository; private readonly IConfigurationProvider _configurationProvider; - private readonly IHashService _hashService; private readonly IHDSerialNumberService _hdSerialNumberService; - private readonly IPacketTranslator _initPacketTranslator; private readonly INetworkClientFactory _networkClientFactory; private readonly IPacketSendService _packetSendService; private readonly IPlayerInfoRepository _playerInfoRepository; @@ -27,9 +27,7 @@ public class NetworkConnectionActions : INetworkConnectionActions public NetworkConnectionActions(INetworkClientRepository networkClientRepository, ISequenceRepository sequenceRepository, IConfigurationProvider configurationProvider, - IHashService hashService, IHDSerialNumberService hdSerialNumberService, - IPacketTranslator initPacketTranslator, INetworkClientFactory networkClientFactory, IPacketSendService packetSendService, IPlayerInfoRepository playerInfoRepository) @@ -37,9 +35,7 @@ public NetworkConnectionActions(INetworkClientRepository networkClientRepository _networkClientRepository = networkClientRepository; _sequenceRepository = sequenceRepository; _configurationProvider = configurationProvider; - _hashService = hashService; _hdSerialNumberService = hdSerialNumberService; - _initPacketTranslator = initPacketTranslator; _networkClientFactory = networkClientFactory; _packetSendService = packetSendService; _playerInfoRepository = playerInfoRepository; @@ -68,48 +64,54 @@ public void DisconnectFromServer() _networkClientRepository.NetworkClient = null; } - _sequenceRepository.SequenceIncrement = 0; - _sequenceRepository.SequenceStart = 0; + _sequenceRepository.ResetState(); } - public async Task BeginHandshake() + public async Task BeginHandshake(int challenge) { - var stupidHash = _hashService.StupidHash(new Random().Next(6, 12)); var hdSerialNumber = _hdSerialNumberService.GetHDSerialNumber(); - var packet = new PacketBuilder(PacketFamily.Init, PacketAction.Init) - .AddThree(stupidHash) - .AddChar(_configurationProvider.VersionMajor) - .AddChar(_configurationProvider.VersionMinor) - .AddChar(_configurationProvider.VersionBuild) - .AddChar(112) - .AddChar(hdSerialNumber.Length) - .AddString(hdSerialNumber) - .Build(); - - var responsePacket = await _packetSendService.SendRawPacketAndWaitAsync(packet); - if (IsInvalidInitPacket(responsePacket)) + var initPacket = new InitInitClientPacket + { + Challenge = challenge, + Version = new Version + { + Major = _configurationProvider.VersionMajor, + Minor = _configurationProvider.VersionMinor, + Patch = _configurationProvider.VersionBuild, + }, + Hdid = hdSerialNumber + }; + + var responsePacket = await _packetSendService.SendRawPacketAndWaitAsync(initPacket); + if (IsInvalidInitPacket(responsePacket, out var initInitServerPacket)) throw new EmptyPacketReceivedException(); - return _initPacketTranslator.TranslatePacket(responsePacket); + return initInitServerPacket; } - public void CompleteHandshake(IInitializationData initializationData) + public void CompleteHandshake(InitInitServerPacket serverPacket) { - _playerInfoRepository.PlayerID = initializationData[InitializationDataKey.PlayerID]; + if (serverPacket.ReplyCode != InitReply.Ok || !(serverPacket.ReplyCodeData is InitInitServerPacket.ReplyCodeDataOk okData)) + throw new InvalidOperationException($"Unable to complete handshake for response code: {serverPacket.ReplyCode}"); - var packet = new PacketBuilder(PacketFamily.Connection, PacketAction.Accept) - .AddShort(initializationData[InitializationDataKey.SendMultiple]) - .AddShort(initializationData[InitializationDataKey.ReceiveMultiple]) - .AddShort(_playerInfoRepository.PlayerID) - .Build(); + _playerInfoRepository.PlayerID = okData.PlayerId; + + var packet = new ConnectionAcceptClientPacket + { + ClientEncryptionMultiple = okData.ClientEncryptionMultiple, + ServerEncryptionMultiple = okData.ServerEncryptionMultiple, + PlayerId = okData.PlayerId, + }; _packetSendService.SendPacket(packet); } - private static bool IsInvalidInitPacket(IPacket responsePacket) + private static bool IsInvalidInitPacket(IPacket responsePacket, out InitInitServerPacket serverPacket) { - return responsePacket.Family != PacketFamily.Init || responsePacket.Action != PacketAction.Init; + var idMatches = responsePacket.Family != PacketFamily.Init || responsePacket.Action != PacketAction.Init; + serverPacket = responsePacket as InitInitServerPacket; + return idMatches && serverPacket != null; } private INetworkClient Client => _networkClientRepository.NetworkClient; diff --git a/EOLib/Net/EmptyPacket.cs b/EOLib/Net/EmptyPacket.cs deleted file mode 100644 index 104973b38..000000000 --- a/EOLib/Net/EmptyPacket.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace EOLib.Net -{ - public class EmptyPacket : Packet - { - private static readonly IReadOnlyList _emptyBytes = new List{ byte.MaxValue, byte.MinValue }; - - public EmptyPacket() : base(_emptyBytes.ToList()) - { - } - } -} diff --git a/EOLib/Net/FileTransfer/FileRequestActions.cs b/EOLib/Net/FileTransfer/FileRequestActions.cs index 96098830a..9b127ef51 100644 --- a/EOLib/Net/FileTransfer/FileRequestActions.cs +++ b/EOLib/Net/FileTransfer/FileRequestActions.cs @@ -7,9 +7,12 @@ using EOLib.IO.Pub; using EOLib.IO.Repositories; using EOLib.IO.Services; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; using Optional; using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading.Tasks; namespace EOLib.Net.FileTransfer @@ -48,20 +51,16 @@ public FileRequestActions(INumberEncoderService numberEncoderService, _playerInfoProvider = playerInfoProvider; } - public bool NeedsFileForLogin(InitFileType fileType, int optionalID = 0) + public bool NeedsFileForLogin(FileType fileType, int optionalID = 0) { - var expectedChecksum = _numberEncoderService.DecodeNumber(_loginFileChecksumProvider.MapChecksum); - var expectedLength = _loginFileChecksumProvider.MapLength; - - return fileType == InitFileType.Map - ? NeedMap(optionalID, expectedChecksum, expectedLength) + return fileType == FileType.Emf + ? NeedMap(optionalID, _loginFileChecksumProvider.MapChecksum, _loginFileChecksumProvider.MapLength) : NeedPub(fileType); } - public bool NeedsMapForWarp(int mapID, byte[] mapRid, int fileSize) + public bool NeedsMapForWarp(int mapID, IReadOnlyList mapRid, int fileSize) { - var expectedChecksum = _numberEncoderService.DecodeNumber(mapRid); - return NeedMap(mapID, expectedChecksum, fileSize); + return NeedMap(mapID, mapRid, fileSize); } public void RequestMapForWarp(int mapID, int sessionID) @@ -86,7 +85,7 @@ public async Task GetItemFileFromServer(int sessionID) { DeleteExisting(PubFileNameConstants.EIFFilter); - var itemFiles = await _fileRequestService.RequestFile(InitFileType.Item, sessionID); + var itemFiles = await _fileRequestService.RequestFile(FileType.Eif, sessionID); foreach (var file in itemFiles) _pubFileSaveService.SaveFile(string.Format(PubFileNameConstants.EIFFormat, file.ID), file, rewriteChecksum: false); @@ -98,7 +97,7 @@ public async Task GetNPCFileFromServer(int sessionID) { DeleteExisting(PubFileNameConstants.ENFFilter); - var npcFiles = await _fileRequestService.RequestFile(InitFileType.Npc, sessionID); + var npcFiles = await _fileRequestService.RequestFile(FileType.Enf, sessionID); foreach (var file in npcFiles) _pubFileSaveService.SaveFile(string.Format(PubFileNameConstants.ENFFormat, file.ID), file, rewriteChecksum: false); _pubFileRepository.ENFFiles = npcFiles; @@ -109,7 +108,7 @@ public async Task GetSpellFileFromServer(int sessionID) { DeleteExisting(PubFileNameConstants.ESFFilter); - var spellFiles = await _fileRequestService.RequestFile(InitFileType.Spell, sessionID); + var spellFiles = await _fileRequestService.RequestFile(FileType.Esf, sessionID); foreach (var file in spellFiles) _pubFileSaveService.SaveFile(string.Format(PubFileNameConstants.ESFFormat, file.ID), file, rewriteChecksum: false); _pubFileRepository.ESFFiles = spellFiles; @@ -120,43 +119,43 @@ public async Task GetClassFileFromServer(int sessionID) { DeleteExisting(PubFileNameConstants.ECFFilter); - var classFiles = await _fileRequestService.RequestFile(InitFileType.Class, sessionID); + var classFiles = await _fileRequestService.RequestFile(FileType.Ecf, sessionID); foreach (var file in classFiles) _pubFileSaveService.SaveFile(string.Format(PubFileNameConstants.ECFFormat, file.ID), file, rewriteChecksum: false); _pubFileRepository.ECFFiles = classFiles; _pubFileRepository.ECFFile = PubFileExtensions.Merge(classFiles); } - private bool NeedMap(int mapID, int expectedChecksum, int expectedLength) + private bool NeedMap(int mapID, IReadOnlyList expectedChecksum, int expectedLength) { if (!_mapFileRepository.MapFiles.ContainsKey(mapID)) return true; //map with that ID is not in the cache, need to get it from the server - var actualChecksum = _numberEncoderService.DecodeNumber(_mapFileRepository.MapFiles[mapID].Properties.Checksum); var actualLength = _mapFileRepository.MapFiles[mapID].Properties.FileSize; - return expectedChecksum != actualChecksum || expectedLength != actualLength; + return !expectedChecksum.SequenceEqual(_mapFileRepository.MapFiles[mapID].Properties.Checksum) || + expectedLength != actualLength; } - private bool NeedPub(InitFileType fileType) + private bool NeedPub(FileType fileType) { switch (fileType) { - case InitFileType.Item: + case FileType.Eif: return _pubFileRepository.EIFFile == null || - _loginFileChecksumProvider.EIFChecksum != _pubFileRepository.EIFFile.CheckSum || + !_loginFileChecksumProvider.EIFChecksum.SequenceEqual(_pubFileRepository.EIFFile.CheckSum) || _loginFileChecksumProvider.EIFLength != _pubFileRepository.EIFFile.Length; - case InitFileType.Npc: + case FileType.Enf: return _pubFileRepository.ENFFile == null || - _loginFileChecksumProvider.ENFChecksum != _pubFileRepository.ENFFile.CheckSum || + !_loginFileChecksumProvider.ENFChecksum.SequenceEqual(_pubFileRepository.ENFFile.CheckSum) || _loginFileChecksumProvider.ENFLength != _pubFileRepository.ENFFile.Length; - case InitFileType.Spell: + case FileType.Esf: return _pubFileRepository.ESFFile == null || - _loginFileChecksumProvider.ESFChecksum != _pubFileRepository.ESFFile.CheckSum || + !_loginFileChecksumProvider.ESFChecksum.SequenceEqual(_pubFileRepository.ESFFile.CheckSum) || _loginFileChecksumProvider.ESFLength != _pubFileRepository.ESFFile.Length; - case InitFileType.Class: + case FileType.Ecf: return _pubFileRepository.ECFFile == null || - _loginFileChecksumProvider.ECFChecksum != _pubFileRepository.ECFFile.CheckSum || + !_loginFileChecksumProvider.ECFChecksum.SequenceEqual(_pubFileRepository.ECFFile.CheckSum) || _loginFileChecksumProvider.ECFLength != _pubFileRepository.ECFFile.Length; default: throw new ArgumentOutOfRangeException(nameof(fileType), fileType, null); @@ -176,9 +175,9 @@ private static void DeleteExisting(string filter) public interface IFileRequestActions { - bool NeedsFileForLogin(InitFileType fileType, int optionalID = 0); + bool NeedsFileForLogin(FileType fileType, int optionalID = 0); - bool NeedsMapForWarp(int mapID, byte[] mapRid, int fileSize); + bool NeedsMapForWarp(int mapID, IReadOnlyList mapRid, int fileSize); void RequestMapForWarp(int mapID, int sessionID); diff --git a/EOLib/Net/FileTransfer/FileRequestService.cs b/EOLib/Net/FileTransfer/FileRequestService.cs index 90d8eec55..017627042 100644 --- a/EOLib/Net/FileTransfer/FileRequestService.cs +++ b/EOLib/Net/FileTransfer/FileRequestService.cs @@ -1,12 +1,13 @@ using AutomaticTypeMapper; -using EOLib.Domain.Protocol; using EOLib.IO.Map; using EOLib.IO.Pub; using EOLib.IO.Services.Serializers; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; namespace EOLib.Net.FileTransfer @@ -29,26 +30,28 @@ public FileRequestService(IPacketSendService packetSendService, public async Task RequestMapFile(int mapID, int sessionID) { - var request = new PacketBuilder(PacketFamily.Welcome, PacketAction.Agree) - .AddChar((int)InitFileType.Map) - .AddShort(sessionID) - .AddShort(mapID) - .Build(); + var request = new WelcomeAgreeClientPacket + { + FileType = FileType.Emf, + FileTypeData = new WelcomeAgreeClientPacket.FileTypeDataEmf { FileId = mapID }, + SessionId = sessionID + }; return await GetMapFile(request, mapID); } public void RequestMapFileForWarp(int mapID, int sessionID) { - var request = new PacketBuilder(PacketFamily.Warp, PacketAction.Take) - .AddShort(mapID) - .AddShort(sessionID) - .Build(); + var request = new WarpTakeClientPacket + { + MapId = mapID, + SessionId = sessionID + }; _packetSendService.SendPacket(request); } - public async Task>> RequestFile(InitFileType fileType, int sessionID) + public async Task>> RequestFile(FileType fileType, int sessionID) where TRecord : class, IPubRecord, new() { var retList = new List>(4); @@ -58,36 +61,33 @@ public async Task>> RequestFile(InitFileType fil do { - var request = new PacketBuilder(PacketFamily.Welcome, PacketAction.Agree) - .AddChar((int)fileType) - .AddShort(sessionID) - .AddChar(fileId) // file id (for chunking oversize pub files) - .Build(); + var request = new WelcomeAgreeClientPacket + { + FileType = fileType, + FileTypeData = GetPubRequestData(fileType, fileId), + SessionId = sessionID, + }; var response = await _packetSendService.SendEncodedPacketAndWaitAsync(request); - if (!PacketIsValid(response)) + if (!PacketIsValid(response, out var responsePacket)) throw new EmptyPacketReceivedException(); - var responseFileType = (InitReply)response.ReadByte(); + var responseFileType = responsePacket.ReplyCode; - var fileIdResponse = response.ReadChar(); - if (fileIdResponse != fileId) - throw new MalformedPacketException($"Unexpected fileId (actual={fileIdResponse}, expected={fileId})", response); + if (!PubFileIdMatches(fileId, responsePacket.ReplyCodeData, out var responseFileId)) + throw new InvalidOperationException($"Unexpected fileId (actual={responseFileId}, expected={fileId})"); Func> factory; switch (responseFileType) { - case InitReply.ItemFile: factory = () => (IPubFile)new EIFFile(); break; - case InitReply.NpcFile: factory = () => (IPubFile)new ENFFile(); break; - case InitReply.SpellFile: factory = () => (IPubFile)new ESFFile(); break; - case InitReply.ClassFile: factory = () => (IPubFile)new ECFFile(); break; + case InitReply.FileEif: factory = () => (IPubFile)new EIFFile(); break; + case InitReply.FileEnf: factory = () => (IPubFile)new ENFFile(); break; + case InitReply.FileEsf: factory = () => (IPubFile)new ESFFile(); break; + case InitReply.FileEcf: factory = () => (IPubFile)new ECFFile(); break; default: throw new EmptyPacketReceivedException(); } - var responseBytes = response - .ReadBytes(response.Length - response.ReadPosition) - .ToArray(); - + var responseBytes = GetFileData(responsePacket.ReplyCodeData); var resultFile = _pubFileDeserializer.DeserializeFromByteArray(fileId, responseBytes, factory); retList.Add(resultFile); @@ -107,25 +107,80 @@ public async Task>> RequestFile(InitFileType fil private async Task GetMapFile(IPacket request, int mapID) { var response = await _packetSendService.SendEncodedPacketAndWaitAsync(request); - if (!PacketIsValid(response)) + if (!PacketIsValid(response, out var responsePacket)) throw new EmptyPacketReceivedException(); - var fileType = (InitReply)response.ReadByte(); - if (fileType != InitReply.MapFile && fileType != InitReply.WarpMap) - throw new MalformedPacketException("Invalid file type " + fileType + " when requesting a map file", response); - - var fileData = response.ReadBytes(response.Length - response.ReadPosition); + var fileType = responsePacket.ReplyCode; + if (fileType != InitReply.FileEmf && fileType != InitReply.WarpMap) + throw new InvalidOperationException($"Invalid file type {fileType} when requesting a map file"); var mapFile = _mapFileSerializer - .DeserializeFromByteArray(fileData.ToArray()) + .DeserializeFromByteArray(GetFileData(responsePacket.ReplyCodeData)) .WithMapID(mapID); return mapFile; } - private static bool PacketIsValid(IPacket packet) + private static bool PacketIsValid(IPacket packet, out InitInitServerPacket responsePacket) { - return packet.Family == PacketFamily.Init && packet.Action == PacketAction.Init; + responsePacket = packet as InitInitServerPacket; + return responsePacket != null && packet.Family == PacketFamily.Init && packet.Action == PacketAction.Init; + } + + private static byte[] GetFileData(InitInitServerPacket.IReplyCodeData replyCodeData) + { + if (replyCodeData is InitInitServerPacket.ReplyCodeDataWarpMap wm) + return wm.MapFile.Content; + else if (replyCodeData is InitInitServerPacket.ReplyCodeDataFileEmf emf) + return emf.MapFile.Content; + else if (replyCodeData is InitInitServerPacket.ReplyCodeDataFileEif eif) + return eif.PubFile.Content; + else if (replyCodeData is InitInitServerPacket.ReplyCodeDataFileEnf enf) + return enf.PubFile.Content; + else if (replyCodeData is InitInitServerPacket.ReplyCodeDataFileEsf esf) + return esf.PubFile.Content; + else if (replyCodeData is InitInitServerPacket.ReplyCodeDataFileEcf ecf) + return ecf.PubFile.Content; + else + throw new ArgumentException("Unexpected reply code data type when requesting file"); + } + + private static WelcomeAgreeClientPacket.IFileTypeData GetPubRequestData(FileType fileType, int fileId) + { + return fileType switch + { + FileType.Eif => new WelcomeAgreeClientPacket.FileTypeDataEif { FileId = fileId }, + FileType.Enf => new WelcomeAgreeClientPacket.FileTypeDataEnf { FileId = fileId }, + FileType.Esf => new WelcomeAgreeClientPacket.FileTypeDataEsf { FileId = fileId }, + FileType.Ecf => new WelcomeAgreeClientPacket.FileTypeDataEcf { FileId = fileId }, + _ => throw new ArgumentOutOfRangeException(nameof(fileType)), + }; + } + + private static bool PubFileIdMatches(int requestedFileId, InitInitServerPacket.IReplyCodeData replyCodeData, out int responseFileId) + { + if (replyCodeData is InitInitServerPacket.ReplyCodeDataFileEif eif) + { + responseFileId = eif.PubFile.FileId; + return responseFileId == requestedFileId; + } + else if (replyCodeData is InitInitServerPacket.ReplyCodeDataFileEnf enf) + { + responseFileId = enf.PubFile.FileId; + return responseFileId == requestedFileId; + } + else if (replyCodeData is InitInitServerPacket.ReplyCodeDataFileEsf esf) + { + responseFileId = esf.PubFile.FileId; + return responseFileId == requestedFileId; + } + else if (replyCodeData is InitInitServerPacket.ReplyCodeDataFileEcf ecf) + { + responseFileId = ecf.PubFile.FileId; + return responseFileId == requestedFileId; + } + + throw new ArgumentException("Unexpected reply code data type when requesting pub file"); } } @@ -135,7 +190,7 @@ public interface IFileRequestService void RequestMapFileForWarp(int mapID, int sessionID); - Task>> RequestFile(InitFileType fileType, int sessionID) + Task>> RequestFile(FileType fileType, int sessionID) where TRecord : class, IPubRecord, new(); } } \ No newline at end of file diff --git a/EOLib/Net/FileTransfer/LoginFileChecksumRepository.cs b/EOLib/Net/FileTransfer/LoginFileChecksumRepository.cs index 49c3631c5..c98dd70a5 100644 --- a/EOLib/Net/FileTransfer/LoginFileChecksumRepository.cs +++ b/EOLib/Net/FileTransfer/LoginFileChecksumRepository.cs @@ -1,4 +1,5 @@ using AutomaticTypeMapper; +using System.Collections.Generic; namespace EOLib.Net.FileTransfer { @@ -7,13 +8,13 @@ namespace EOLib.Net.FileTransfer /// public interface ILoginFileChecksumRepository { - int EIFChecksum { get; set; } + List EIFChecksum { get; set; } - int ENFChecksum { get; set; } + List ENFChecksum { get; set; } - int ESFChecksum { get; set; } + List ESFChecksum { get; set; } - int ECFChecksum { get; set; } + List ECFChecksum { get; set; } int EIFLength { get; set; } @@ -23,7 +24,7 @@ public interface ILoginFileChecksumRepository int ECFLength { get; set; } - byte[] MapChecksum { get; set; } + List MapChecksum { get; set; } int MapLength { get; set; } } @@ -33,13 +34,13 @@ public interface ILoginFileChecksumRepository /// public interface ILoginFileChecksumProvider { - int EIFChecksum { get; } + IReadOnlyList EIFChecksum { get; } - int ENFChecksum { get; } + IReadOnlyList ENFChecksum { get; } - int ESFChecksum { get; } + IReadOnlyList ESFChecksum { get; } - int ECFChecksum { get; } + IReadOnlyList ECFChecksum { get; } int EIFLength { get; } @@ -49,7 +50,7 @@ public interface ILoginFileChecksumProvider int ECFLength { get; } - byte[] MapChecksum { get; } + IReadOnlyList MapChecksum { get; } int MapLength { get; } } @@ -60,13 +61,13 @@ public interface ILoginFileChecksumProvider [AutoMappedType(IsSingleton = true)] public class LoginFileChecksumRepository : ILoginFileChecksumRepository, ILoginFileChecksumProvider { - public int EIFChecksum { get; set; } + public List EIFChecksum { get; set; } - public int ENFChecksum { get; set; } + public List ENFChecksum { get; set; } - public int ESFChecksum { get; set; } + public List ESFChecksum { get; set; } - public int ECFChecksum { get; set; } + public List ECFChecksum { get; set; } public int EIFLength { get; set; } @@ -76,8 +77,18 @@ public class LoginFileChecksumRepository : ILoginFileChecksumRepository, ILoginF public int ECFLength { get; set; } - public byte[] MapChecksum { get; set; } + public List MapChecksum { get; set; } public int MapLength { get; set; } + + IReadOnlyList ILoginFileChecksumProvider.EIFChecksum => EIFChecksum; + + IReadOnlyList ILoginFileChecksumProvider.ENFChecksum => ENFChecksum; + + IReadOnlyList ILoginFileChecksumProvider.ESFChecksum => ESFChecksum; + + IReadOnlyList ILoginFileChecksumProvider.ECFChecksum => ECFChecksum; + + IReadOnlyList ILoginFileChecksumProvider.MapChecksum => MapChecksum; } } diff --git a/EOLib/Net/Handlers/DefaultAsyncPacketHandler.cs b/EOLib/Net/Handlers/DefaultAsyncPacketHandler.cs index 5968d128b..26f669da4 100644 --- a/EOLib/Net/Handlers/DefaultAsyncPacketHandler.cs +++ b/EOLib/Net/Handlers/DefaultAsyncPacketHandler.cs @@ -1,8 +1,10 @@ -using System.Threading.Tasks; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using System.Threading.Tasks; namespace EOLib.Net.Handlers { - public abstract class DefaultAsyncPacketHandler : IPacketHandler + public abstract class DefaultAsyncPacketHandler : IPacketHandler + where TPacket: IPacket { public abstract PacketFamily Family { get; } @@ -10,9 +12,19 @@ public abstract class DefaultAsyncPacketHandler : IPacketHandler public abstract bool CanHandle { get; } - public abstract bool HandlePacket(IPacket packet); + public bool IsHandlerFor(IPacket packet) + { + return typeof(TPacket).IsAssignableFrom(packet.GetType()); + } + + public bool HandlePacket(IPacket packet) + { + return HandlePacket((TPacket)packet); + } + + public abstract bool HandlePacket(TPacket packet); - public async Task HandlePacketAsync(IPacket packet) + public async Task HandlePacketAsync(TPacket packet) { return await Task.Run(() => HandlePacket(packet)); } diff --git a/EOLib/Net/Handlers/FamilyActionPair.cs b/EOLib/Net/Handlers/FamilyActionPair.cs index 3f69c54e7..3ea13eb9e 100644 --- a/EOLib/Net/Handlers/FamilyActionPair.cs +++ b/EOLib/Net/Handlers/FamilyActionPair.cs @@ -1,16 +1,18 @@ -using System.Collections; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using System; +using System.Collections; namespace EOLib.Net.Handlers { - public struct FamilyActionPair : IEqualityComparer + public readonly struct FamilyActionPair : IEqualityComparer { - private readonly PacketFamily fam; - private readonly PacketAction act; + public PacketFamily Family { get; } + public PacketAction Action { get; } public FamilyActionPair(PacketFamily family, PacketAction action) { - fam = family; - act = action; + Family = family; + Action = action; } bool IEqualityComparer.Equals(object obj1, object obj2) @@ -20,7 +22,7 @@ bool IEqualityComparer.Equals(object obj1, object obj2) var fap1 = (FamilyActionPair) obj1; var fap2 = (FamilyActionPair)obj2; - return fap1.fam == fap2.fam && fap1.act == fap2.act; + return fap1.Family == fap2.Family && fap1.Action == fap2.Action; } public int GetHashCode(object obj) @@ -29,7 +31,15 @@ public int GetHashCode(object obj) var fap /*lol*/ = (FamilyActionPair)obj; - return (int)fap.fam << 8 & (byte)fap.act; + return (int)fap.Family << 8 & (byte)fap.Action; + } + + public static FamilyActionPair From(byte[] array) + { + if (array.Length < 2) + throw new ArgumentException("Unable to determine packet ID from input array"); + + return new FamilyActionPair((PacketFamily)array[1], (PacketAction)array[0]); } } } \ No newline at end of file diff --git a/EOLib/Net/Handlers/IPacketHandler.cs b/EOLib/Net/Handlers/IPacketHandler.cs index f69278202..9bffa66e4 100644 --- a/EOLib/Net/Handlers/IPacketHandler.cs +++ b/EOLib/Net/Handlers/IPacketHandler.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using System.Threading.Tasks; namespace EOLib.Net.Handlers { @@ -9,9 +10,17 @@ public interface IPacketHandler bool CanHandle { get; } + bool IsHandlerFor(IPacket packet); + bool HandlePacket(IPacket packet); + } + + public interface IPacketHandler : IPacketHandler + where TPacket : IPacket + { + bool HandlePacket(TPacket packet); //todo: method to determine whether a packet should be handled asynchronously or not - Task HandlePacketAsync(IPacket packet); + Task HandlePacketAsync(TPacket packet); } } diff --git a/EOLib/Net/Handlers/InGameOnlyPacketHandler.cs b/EOLib/Net/Handlers/InGameOnlyPacketHandler.cs index 7c485610a..e691960c4 100644 --- a/EOLib/Net/Handlers/InGameOnlyPacketHandler.cs +++ b/EOLib/Net/Handlers/InGameOnlyPacketHandler.cs @@ -1,8 +1,10 @@ using EOLib.Domain.Login; +using Moffat.EndlessOnline.SDK.Protocol.Net; namespace EOLib.Net.Handlers { - public abstract class InGameOnlyPacketHandler : DefaultAsyncPacketHandler + public abstract class InGameOnlyPacketHandler : DefaultAsyncPacketHandler + where TPacket : IPacket { private readonly IPlayerInfoProvider _playerInfoProvider; diff --git a/EOLib/Net/Handlers/OutOfBandPacketHandler.cs b/EOLib/Net/Handlers/OutOfBandPacketHandler.cs index edd8b8d12..ce5abab16 100644 --- a/EOLib/Net/Handlers/OutOfBandPacketHandler.cs +++ b/EOLib/Net/Handlers/OutOfBandPacketHandler.cs @@ -1,5 +1,6 @@ using AutomaticTypeMapper; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net; namespace EOLib.Net.Handlers { @@ -44,7 +45,7 @@ private bool FindAndHandlePacket(IPacket packet) return false; var handler = _packetHandlerFinder.FindHandler(packet.Family, packet.Action); - if (!handler.CanHandle) + if (!handler.CanHandle || !handler.IsHandlerFor(packet)) return false; //todo: catch exceptions and log error details diff --git a/EOLib/Net/Handlers/PacketHandlerFinder.cs b/EOLib/Net/Handlers/PacketHandlerFinder.cs index 923fdc31e..9ade14f55 100644 --- a/EOLib/Net/Handlers/PacketHandlerFinder.cs +++ b/EOLib/Net/Handlers/PacketHandlerFinder.cs @@ -1,13 +1,14 @@ using System.Collections.Generic; using System.Linq; using AutomaticTypeMapper; +using Moffat.EndlessOnline.SDK.Protocol.Net; namespace EOLib.Net.Handlers { [AutoMappedType] public class PacketHandlerFinder : IPacketHandlerFinder { - private readonly Dictionary _handlers; + private readonly IReadOnlyDictionary _handlers; public PacketHandlerFinder(IPacketHandlerProvider packetHandlerProvider) { diff --git a/EOLib/Net/Handlers/PacketHandlingActions.cs b/EOLib/Net/Handlers/PacketHandlingActions.cs index 765b37ab0..e45fbd0ef 100644 --- a/EOLib/Net/Handlers/PacketHandlingActions.cs +++ b/EOLib/Net/Handlers/PacketHandlingActions.cs @@ -1,6 +1,7 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net; namespace EOLib.Net.Handlers { @@ -24,7 +25,7 @@ public void EnqueuePacketForHandling(IPacket packet) { if (_playerInfoProvider.PlayerIsInGame) { - // all in-game packets should be handled in-band + // all in-game packets should be handled out-of-band _packetQueueProvider.HandleOutOfBandPacketQueue.EnqueuePacketForHandling(packet); } else diff --git a/EOLib/Net/Handlers/PacketHandlingTypeFinder.cs b/EOLib/Net/Handlers/PacketHandlingTypeFinder.cs index 9091a0ed5..e5d4ac478 100644 --- a/EOLib/Net/Handlers/PacketHandlingTypeFinder.cs +++ b/EOLib/Net/Handlers/PacketHandlingTypeFinder.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using AutomaticTypeMapper; +using Moffat.EndlessOnline.SDK.Protocol.Net; namespace EOLib.Net.Handlers { diff --git a/EOLib/Net/IPacket.cs b/EOLib/Net/IPacket.cs deleted file mode 100644 index 6f6db1f62..000000000 --- a/EOLib/Net/IPacket.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System.Collections.Generic; -using System.IO; - -namespace EOLib.Net -{ - public interface IPacket - { - int Length { get; } - - int ReadPosition { get; } - - void Seek(int position, SeekOrigin origin); - - PacketFamily Family { get; } - - PacketAction Action { get; } - - IReadOnlyList RawData { get; } - - byte PeekByte(); - - int PeekChar(); - - int PeekShort(); - - int PeekThree(); - - int PeekInt(); - - string PeekString(int length); - - string PeekEndString(); - - string PeekBreakString(); - - IEnumerable PeekBytes(int length); - - byte ReadByte(); - - int ReadChar(); - - int ReadShort(); - - int ReadThree(); - - int ReadInt(); - - string ReadString(int length); - - string ReadEndString(); - - string ReadBreakString(); - - IEnumerable ReadBytes(int length); - } -} diff --git a/EOLib/Net/IPacketBuilder.cs b/EOLib/Net/IPacketBuilder.cs deleted file mode 100644 index 6cb8c7262..000000000 --- a/EOLib/Net/IPacketBuilder.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections.Generic; - -namespace EOLib.Net -{ - public interface IPacketBuilder - { - int Length { get; } - - PacketFamily Family { get; } - - PacketAction Action { get; } - - IPacketBuilder WithFamily(PacketFamily family); - - IPacketBuilder WithAction(PacketAction action); - - IPacketBuilder AddBreak(); - - IPacketBuilder AddByte(byte b); - - IPacketBuilder AddChar(int b); - - IPacketBuilder AddShort(int s); - - IPacketBuilder AddThree(int t); - - IPacketBuilder AddInt(int i); - - IPacketBuilder AddString(string s); - - IPacketBuilder AddBreakString(string s); - - IPacketBuilder AddBytes(IEnumerable bytes); - - IPacket Build(); - } -} diff --git a/EOLib/Net/MalformedPacketException.cs b/EOLib/Net/MalformedPacketException.cs deleted file mode 100644 index 68453fd86..000000000 --- a/EOLib/Net/MalformedPacketException.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace EOLib.Net -{ - public class MalformedPacketException : Exception - { - public IPacket Packet { get; private set; } - - public MalformedPacketException(string message, IPacket packet) - : base(message) - { - Packet = packet; - } - } -} diff --git a/EOLib/Net/Packet.cs b/EOLib/Net/Packet.cs deleted file mode 100644 index e65fe0b59..000000000 --- a/EOLib/Net/Packet.cs +++ /dev/null @@ -1,197 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using EOLib.IO.Services; - -namespace EOLib.Net -{ - public class Packet : IPacket - { - private readonly INumberEncoderService _encoderService; - - public int Length => RawData.Count; - - public int ReadPosition { get; private set; } - - public PacketFamily Family { get; } - - public PacketAction Action { get; } - - public IReadOnlyList RawData { get; } - - public Packet(IList data) - : this(data.ToArray()) { } - - public Packet(byte[] data) - { - //note: start reading at position 2, skip family/action - //can call seek to read over them - ReadPosition = 2; - Family = (PacketFamily)data[1]; - Action = (PacketAction)data[0]; - RawData = new List(data); - _encoderService = new NumberEncoderService(); - } - - public void Seek(int position, SeekOrigin origin) - { - int newPosition; - switch (origin) - { - case SeekOrigin.Begin: newPosition = position; break; - case SeekOrigin.Current: newPosition = ReadPosition + position; break; - case SeekOrigin.End: newPosition = Length - 1 + position; break; - default: throw new ArgumentOutOfRangeException(nameof(origin), origin, null); - } - - if (newPosition > Length) - throw new ArgumentOutOfRangeException(nameof(position), "Position is out of bounds of the packet!"); - - ReadPosition = newPosition; - } - - public byte PeekByte() - { - ThrowIfOutOfBounds(0); - return RawData[ReadPosition]; - } - - public int PeekChar() - { - ThrowIfOutOfBounds(0); - return _encoderService.DecodeNumber(RawData[ReadPosition]); - } - - public int PeekShort() - { - ThrowIfOutOfBounds(1); - - var bytes = new[] {RawData[ReadPosition], RawData[ReadPosition + 1]}; - return _encoderService.DecodeNumber(bytes); - } - - public int PeekThree() - { - ThrowIfOutOfBounds(2); - - var bytes = new[] - { - RawData[ReadPosition], - RawData[ReadPosition + 1], - RawData[ReadPosition + 2] - }; - return _encoderService.DecodeNumber(bytes); - } - - public int PeekInt() - { - ThrowIfOutOfBounds(3); - - var bytes = new[] - { - RawData[ReadPosition], - RawData[ReadPosition + 1], - RawData[ReadPosition + 2], - RawData[ReadPosition + 3] - }; - return _encoderService.DecodeNumber(bytes); - } - - public string PeekString(int length) - { - return Encoding.ASCII.GetString(PeekBytes(length).ToArray()); - } - - public string PeekEndString() - { - return PeekString(Length - ReadPosition); - } - - public string PeekBreakString() - { - var ndx = ReadPosition; - while (ndx < Length && RawData[ndx] != byte.MaxValue) - ndx++; - return PeekString(ndx - ReadPosition); - } - - public IEnumerable PeekBytes(int length) - { - ThrowIfOutOfBounds(length); - - var bytes = new List(length); - for (var i = ReadPosition; i < ReadPosition + length; ++i) - bytes.Add(RawData[i]); - return bytes; - } - - private void ThrowIfOutOfBounds(int extraBytes) - { - if (ReadPosition + extraBytes > Length) - throw new InvalidOperationException("Operation is out of bounds of the packet"); - } - - public byte ReadByte() - { - var ret = PeekByte(); - ReadPosition += 1; - return ret; - } - - public int ReadChar() - { - var ret = PeekChar(); - ReadPosition += 1; - return ret; - } - - public int ReadShort() - { - var ret = PeekShort(); - ReadPosition += 2; - return ret; - } - - public int ReadThree() - { - var ret = PeekThree(); - ReadPosition += 3; - return ret; - } - - public int ReadInt() - { - var ret = PeekInt(); - ReadPosition += 4; - return ret; - } - - public string ReadString(int length) - { - var ret = PeekString(length); - ReadPosition += length; - return ret; - } - - public string ReadEndString() - { - return ReadString(Length - ReadPosition); - } - - public string ReadBreakString() - { - var ret = PeekBreakString(); - ReadPosition += ret.Length + 1; - return ret; - } - - public IEnumerable ReadBytes(int length) - { - var ret = PeekBytes(length); - ReadPosition += length; - return ret; - } - } -} diff --git a/EOLib/Net/PacketAction.cs b/EOLib/Net/PacketAction.cs deleted file mode 100644 index d51b9ca92..000000000 --- a/EOLib/Net/PacketAction.cs +++ /dev/null @@ -1,43 +0,0 @@ -namespace EOLib.Net -{ - public enum PacketAction : byte - { - Request = (byte)1, - Accept = (byte)2, - Reply = (byte)3, - Remove = (byte)4, - Agree = (byte)5, - Create = (byte)6, - Add = (byte)7, - Player = (byte)8, - Take = (byte)9, - Use = (byte)10, - Buy = (byte)11, - Sell = (byte)12, - Open = (byte)13, - Close = (byte)14, - Message = (byte)15, - Spec = (byte)16, - Admin = (byte)17, - List = (byte)18, - Tell = (byte)20, - Report = (byte)21, - Announce = (byte)22, - Server = (byte)23, - Drop = (byte)24, - Junk = (byte)25, - Obtain = (byte)26, - Get = (byte)27, - Kick = (byte)28, - Rank = (byte)29, - TargetSelf = (byte)30, - TargetOther = (byte)31, - TargetGroup = (byte)33, - Exp = (byte)33, //PACKET_TARGET_GROUP - Dialog = (byte)34, - Ping = (byte)240, - Pong = (byte)241, - Net3 = (byte)242, - Init = (byte)255 - } -} diff --git a/EOLib/Net/PacketBuilder.cs b/EOLib/Net/PacketBuilder.cs deleted file mode 100644 index 92786d2bd..000000000 --- a/EOLib/Net/PacketBuilder.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using EOLib.IO; -using EOLib.IO.Services; - -namespace EOLib.Net -{ - public class PacketBuilder : IPacketBuilder - { - private const byte BREAK_STR_MAXVAL = 121; - - private readonly IReadOnlyList _data; - private readonly INumberEncoderService _encoderService; - - public int Length => _data.Count; - - public PacketFamily Family => (PacketFamily)_data[1]; - - public PacketAction Action => (PacketAction) _data[0]; - - public PacketBuilder() - { - _data = new List(); - _encoderService = new NumberEncoderService(); - } - - public PacketBuilder(PacketFamily family, PacketAction action) - { - _data = new List { (byte) action, (byte) family }; - _encoderService = new NumberEncoderService(); - } - - private PacketBuilder(IReadOnlyList data) - { - _data = data; - _encoderService = new NumberEncoderService(); - } - - public IPacketBuilder WithFamily(PacketFamily family) - { - var newData = new List(_data); - newData[1] = (byte)family; - return new PacketBuilder(newData); - } - - public IPacketBuilder WithAction(PacketAction action) - { - var newData = new List(_data); - newData[0] = (byte)action; - return new PacketBuilder(newData); - } - - public IPacketBuilder AddBreak() - { - return AddByte(byte.MaxValue); - } - - public IPacketBuilder AddByte(byte b) - { - return AddBytes(new[] { b }); - } - - public IPacketBuilder AddChar(int b) - { - ThrowIfOutOfBounds(b, NumericConstants.ONE_BYTE_MAX); - return AddBytes(_encoderService.EncodeNumber(b, 1)); - } - - public IPacketBuilder AddShort(int s) - { - ThrowIfOutOfBounds(s, NumericConstants.TWO_BYTE_MAX); - return AddBytes(_encoderService.EncodeNumber(s, 2)); - } - - public IPacketBuilder AddThree(int t) - { - ThrowIfOutOfBounds(t, NumericConstants.THREE_BYTE_MAX); - return AddBytes(_encoderService.EncodeNumber(t, 3)); - } - - public IPacketBuilder AddInt(int i) - { - ThrowIfOutOfBounds(i, NumericConstants.FOUR_BYTE_MAX); - return AddBytes(_encoderService.EncodeNumber(i, 4)); - } - - public IPacketBuilder AddString(string s) - { - return AddBytes(Encoding.ASCII.GetBytes(s)); - } - - public IPacketBuilder AddBreakString(string s) - { - var sBytes = Encoding.ASCII.GetBytes(s); - var sList = sBytes.Select(b => b == byte.MaxValue ? BREAK_STR_MAXVAL : b).ToList(); - sList.Add(byte.MaxValue); - return AddBytes(sList); - } - - public IPacketBuilder AddBytes(IEnumerable bytes) - { - var list = new List(_data); - list.AddRange(bytes); - return new PacketBuilder(list); - } - - public IPacket Build() - { - return new Packet(_data.ToList()); - } - - private static void ThrowIfOutOfBounds(int input, uint maximum) - { - if ((uint)input > maximum) - { - throw new ArgumentException($"Input value is out of bounds (value={input}, bounds={maximum})", nameof(input)); - } - } - } -} diff --git a/EOLib/Net/PacketFamily.cs b/EOLib/Net/PacketFamily.cs deleted file mode 100644 index 79de2bccf..000000000 --- a/EOLib/Net/PacketFamily.cs +++ /dev/null @@ -1,56 +0,0 @@ -namespace EOLib.Net -{ - public enum PacketFamily : byte - { - Internal = 0, - Connection = (byte)1, - Account = (byte)2, - Character = (byte)3, - Login = (byte)4, - Welcome = (byte)5, - Walk = (byte)6, - Face = (byte)7, - Chair = (byte)8, - Emote = (byte)9, - Attack = (byte)11, - Spell = (byte)12, - Shop = (byte)13, - Item = (byte)14, - StatSkill = (byte)16, - Global = (byte)17, - Talk = (byte)18, - Warp = (byte)19, - JukeBox = (byte)21, - Players = (byte)22, - Avatar = (byte)23, - Party = (byte)24, - Refresh = (byte)25, - NPC = (byte)26, - CharacterMapInfo = (byte)27, - NPCMapInfo = (byte)28, - MapInfo = (byte)29, - PaperDoll = (byte)30, - Effect = (byte)31, - Trade = (byte)32, - Chest = (byte)33, - Door = (byte)34, - Message = (byte)35, - Bank = (byte)36, - Locker = (byte)37, - Barber = (byte)38, - Guild = (byte)39, - Music = (byte)40, - Sit = (byte)41, - Recover = (byte)42, - Board = (byte)43, - Cast = (byte)44, - Arena = (byte)45, - Priest = (byte)46, - Marriage = (byte)47, - AdminInteract = (byte)48, - Citizen = (byte)49, - Quest = (byte)50, - Book = (byte)51, - Init = (byte)255 - } -} diff --git a/EOLib/Net/PacketProcessing/HashService.cs b/EOLib/Net/PacketProcessing/HashService.cs index af8667dd8..0c587a5cb 100644 --- a/EOLib/Net/PacketProcessing/HashService.cs +++ b/EOLib/Net/PacketProcessing/HashService.cs @@ -1,19 +1,16 @@ using AutomaticTypeMapper; +using Moffat.EndlessOnline.SDK.Data; namespace EOLib.Net.PacketProcessing { [AutoMappedType] public class HashService : IHashService { - public int StupidHash(int seed) - { - ++seed; - return 110905 + (seed % 9 + 1) * ((11092004 - seed) % ((seed % 11 + 1) * 119)) * 119 + seed % 2004; - } + public int StupidHash(int challenge) => ServerVerifier.Hash(challenge); } public interface IHashService { - int StupidHash(int seed); + int StupidHash(int challenge); } } diff --git a/EOLib/Net/PacketProcessing/PacketEncoderService.cs b/EOLib/Net/PacketProcessing/PacketEncoderService.cs index 984f2839d..faf59c731 100644 --- a/EOLib/Net/PacketProcessing/PacketEncoderService.cs +++ b/EOLib/Net/PacketProcessing/PacketEncoderService.cs @@ -1,133 +1,80 @@ -// Some of this work is reverse-engineered from -// EOHAX C# DLLs written by Sausage (www.tehsausage.com) -// This file is subject to the GPL v2 License -// For additional details, see the LICENSE file - -using System.Collections.Generic; -using System.Linq; -using AutomaticTypeMapper; -using EOLib.IO; -using EOLib.IO.Services; +using AutomaticTypeMapper; +using Moffat.EndlessOnline.SDK.Data; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Optional; namespace EOLib.Net.PacketProcessing { [AutoMappedType] public sealed class PacketEncoderService : IPacketEncoderService { - private readonly INumberEncoderService _numberEncoderService; - private readonly IDataEncoderService _dataEncoderService; + private const string PACKET_NAMESPACE = "Moffat.EndlessOnline.SDK.Protocol.Net.Server"; - public PacketEncoderService(INumberEncoderService numberEncoderService, - IDataEncoderService dataEncoderService) - { - _numberEncoderService = numberEncoderService; - _dataEncoderService = dataEncoderService; - } + private readonly IPacketFactory _packetFactory; - public byte[] PrependLengthBytes(byte[] data) - { - var ret = PrependLength(data.ToList()); - return ret.ToArray(); - } + public PacketEncoderService(IPacketFactoryFactory packetFactoryFactory) => _packetFactory = packetFactoryFactory.Create(PACKET_NAMESPACE); - public IPacket AddSequenceNumber(IPacket pkt, int sequenceNumber) + public byte[] Encode(IPacket packet, int encodeMultiplier, int sequenceNumber) { - var byteList = pkt.RawData; - byteList = AddSequenceBytes(byteList, sequenceNumber); - return new Packet(byteList.ToList()); - } + var writer = new EoWriter(); + writer.AddByte((byte)packet.Action); + writer.AddByte((byte)packet.Family); + AddSequenceBytes(writer, sequenceNumber); - public byte[] Encode(IPacket original, int encodeMultiplier) - { - if (encodeMultiplier == 0 || !PacketValidForEncode(original)) - return original.RawData.ToArray(); + packet.Serialize(writer); - var byteList = original.RawData.ToList(); - byteList = _dataEncoderService.SwapMultiples(byteList, encodeMultiplier); - byteList = _dataEncoderService.Interleave(byteList); - byteList = _dataEncoderService.FlipMSB(byteList); + if (encodeMultiplier == 0 || !PacketValidForEncode(packet)) + return writer.ToByteArray(); - return byteList.ToArray(); + var encodedBytes = DataEncrypter.SwapMultiples(writer.ToByteArray(), encodeMultiplier); + encodedBytes = DataEncrypter.Interleave(encodedBytes); + encodedBytes = DataEncrypter.FlipMSB(encodedBytes); + return encodedBytes; } - public IPacket Decode(IEnumerable original, int decodeMultiplier) + public Option Decode(byte[] original, int decodeMultiplier) { - var originalBytes = original.ToArray(); - if (decodeMultiplier == 0 || !PacketValidForDecode(originalBytes)) - return new Packet(originalBytes); + var decodedBytes = original; - var byteList = originalBytes.ToList(); - byteList = _dataEncoderService.FlipMSB(byteList); - byteList = _dataEncoderService.Deinterleave(byteList); - byteList = _dataEncoderService.SwapMultiples(byteList, decodeMultiplier); + if (decodeMultiplier > 0 && PacketValidForDecode(original)) + { + decodedBytes = DataEncrypter.FlipMSB(decodedBytes); + decodedBytes = DataEncrypter.Deinterleave(decodedBytes); + decodedBytes = DataEncrypter.SwapMultiples(decodedBytes, decodeMultiplier); + } - return new Packet(byteList); + return _packetFactory.Create(decodedBytes); } - #region Packet Validation - private static bool PacketValidForEncode(IPacket pkt) { - return !IsInitPacket(pkt); + return !IsInitPacket((byte)pkt.Family, (byte)pkt.Action); } private static bool PacketValidForDecode(byte[] data) { - return data.Length >= 2 && !IsInitPacket(new Packet(new[] {data[0], data[1]})); - } - - private static bool IsInitPacket(IPacket pkt) - { - return pkt.Family == PacketFamily.Init && - pkt.Action == PacketAction.Init; + return data.Length >= 2 && !IsInitPacket(data[0], data[1]); } - #endregion - - #region Sequence Byte(s) - - private List AddSequenceBytes(IReadOnlyList original, int seq) + private static bool IsInitPacket(byte family, byte action) { - var numberOfSequenceBytes = seq >= NumericConstants.ONE_BYTE_MAX ? 2 : 1; - var encodedSequenceBytes = _numberEncoderService.EncodeNumber(seq, numberOfSequenceBytes); - - var combined = new List(original.Count + numberOfSequenceBytes); - //family/action copied to [0][1] - combined.AddRange(new[] {original[0], original[1]}); - //sequence number copied to [2] (and [3] if it's a two-byte number) - combined.AddRange(encodedSequenceBytes); - //add the remaining data - rest of data copied to [3] (or [4]) onward [...] - combined.AddRange(original.Where((b, i) => i >= 2)); - - return combined; + return (PacketFamily)family == PacketFamily.Init && + (PacketAction)action == PacketAction.Init; } - #endregion - - #region Length Bytes - - private List PrependLength(IReadOnlyList data) + private void AddSequenceBytes(EoWriter writer, int seq) { - var len = _numberEncoderService.EncodeNumber(data.Count, 2); - var combined = new List(data.Count + len.Length); - - combined.AddRange(len); - combined.AddRange(data); - - return combined; + if (seq >= EoNumericLimits.CHAR_MAX) + writer.AddShort(seq); + else + writer.AddChar(seq); } - - #endregion } public interface IPacketEncoderService { - byte[] PrependLengthBytes(byte[] data); - - IPacket AddSequenceNumber(IPacket pkt, int sequenceNumber); - - byte[] Encode(IPacket original, int encodeMultiplier); + byte[] Encode(IPacket original, int encodeMultiplier, int sequenceNumber); - IPacket Decode(IEnumerable original, int decodeMultiplier); + Option Decode(byte[] original, int decodeMultiplier); } } diff --git a/EOLib/Net/PacketProcessing/PacketFactory.cs b/EOLib/Net/PacketProcessing/PacketFactory.cs new file mode 100644 index 000000000..cbba7cee7 --- /dev/null +++ b/EOLib/Net/PacketProcessing/PacketFactory.cs @@ -0,0 +1,71 @@ +using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Data; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Optional; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; + +namespace EOLib.Net.PacketProcessing +{ + public class PacketFactory : IPacketFactory + { + private readonly IReadOnlyDictionary _map; + + public PacketFactory(string name_space) + { + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) + { + if (assembly.GetTypes().Select(x => x.Namespace).Any(x => x == name_space)) + { + _map = MapTypesFrom(assembly, name_space); + break; + } + } + + if (!_map.Any()) + { + throw new ArgumentException($"No packets were found from {name_space}", nameof(name_space)); + } + } + + public Option Create(byte[] array) + { + var fap = FamilyActionPair.From(array); + if (!_map.ContainsKey(fap)) + { + Debug.WriteLine($"Unrecognized packet id: {fap.Family}_{fap.Action}"); + return Option.None(); + } + + var instance = (IPacket)Activator.CreateInstance(_map[fap]); + var eoReader = new EoReader(array); + instance.Deserialize(eoReader.Slice(2)); + return Option.Some(instance); + } + + private static IReadOnlyDictionary MapTypesFrom(Assembly assembly, string name_space) + { + var ret = new Dictionary(); + + var types = assembly.GetTypes() + .Where(x => x.Namespace == name_space) + .Where(x => x.GetInterfaces().Any(x => x.Name == "IPacket")); + foreach (var type in types) + { + var inst = (IPacket)Activator.CreateInstance(type); + var fap = new FamilyActionPair(inst.Family, inst.Action); + ret.Add(fap, type); + } + + return ret; + } + } + + public interface IPacketFactory + { + Option Create(byte[] array); + } +} diff --git a/EOLib/Net/PacketProcessing/PacketFactoryFactory.cs b/EOLib/Net/PacketProcessing/PacketFactoryFactory.cs new file mode 100644 index 000000000..0423485bd --- /dev/null +++ b/EOLib/Net/PacketProcessing/PacketFactoryFactory.cs @@ -0,0 +1,18 @@ +using AutomaticTypeMapper; + +namespace EOLib.Net.PacketProcessing +{ + [AutoMappedType] + public class PacketFactoryFactory : IPacketFactoryFactory + { + public IPacketFactory Create(string name_space) + { + return new PacketFactory(name_space); + } + } + + public interface IPacketFactoryFactory + { + IPacketFactory Create(string name_space); + } +} diff --git a/EOLib/Net/PacketProcessing/PacketProcessActions.cs b/EOLib/Net/PacketProcessing/PacketProcessActions.cs index 925588072..e69f0f2b3 100644 --- a/EOLib/Net/PacketProcessing/PacketProcessActions.cs +++ b/EOLib/Net/PacketProcessing/PacketProcessActions.cs @@ -1,7 +1,11 @@ -using System.Collections.Generic; -using System.Linq; +using System; using AutomaticTypeMapper; +using Moffat.EndlessOnline.SDK.Data; using EOLib.Logger; +using Moffat.EndlessOnline.SDK.Packet; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using System.Net.Sockets; +using Optional; namespace EOLib.Net.PacketProcessing { @@ -9,7 +13,6 @@ namespace EOLib.Net.PacketProcessing public class PacketProcessActions : IPacketProcessActions { private readonly IPacketEncoderService _encoderService; - private readonly IPacketSequenceService _sequenceService; private readonly ILoggerProvider _loggerProvider; private readonly IPacketEncoderRepository _encoderRepository; private readonly ISequenceRepository _sequenceRepository; @@ -17,27 +20,22 @@ public class PacketProcessActions : IPacketProcessActions public PacketProcessActions(ISequenceRepository sequenceNumberRepository, IPacketEncoderRepository encoderRepository, IPacketEncoderService encoderService, - IPacketSequenceService sequenceService, ILoggerProvider loggerProvider) { _sequenceRepository = sequenceNumberRepository; _encoderRepository = encoderRepository; _encoderService = encoderService; - _sequenceService = sequenceService; _loggerProvider = loggerProvider; } - public void SetInitialSequenceNumber(int seq1, int seq2) + public void SetSequenceStart(ISequenceStart sequenceStart) { - var initialSequence = _sequenceService.CalculateInitialSequenceNumber(seq1, seq2); - _sequenceRepository.SequenceStart = initialSequence; - } - - public void SetUpdatedBaseSequenceNumber(int seq1, int seq2) - { - var updatedSequence = _sequenceService.CalculateNewInitialSequenceNumber(seq1, seq2); - _sequenceRepository.SequenceStart = updatedSequence; + _sequenceRepository.Sequencer = _sequenceRepository.Sequencer.WithSequenceStart(sequenceStart); + if (sequenceStart is InitSequenceStart) + { + _sequenceRepository.Sequencer.NextSequence(); + } } public void SetEncodeMultiples(int emulti_d, int emulti_e) @@ -51,40 +49,37 @@ public void SetEncodeMultiples(int emulti_d, int emulti_e) public byte[] EncodePacket(IPacket pkt) { - var seq = CalculateNextSequenceNumber(); - pkt = _encoderService.AddSequenceNumber(pkt, seq); - - var data = _encoderService.Encode(pkt, _encoderRepository.SendMultiplier); - data = _encoderService.PrependLengthBytes(data); - - return data; + var seq = _sequenceRepository.Sequencer.NextSequence(); + var data = _encoderService.Encode(pkt, _encoderRepository.SendMultiplier, seq); + return PrependLengthBytes(data); } public byte[] EncodeRawPacket(IPacket pkt) { - return _encoderService.PrependLengthBytes(pkt.RawData.ToArray()); + var eoWriter = new EoWriter(); + eoWriter.AddByte((byte)pkt.Action); + eoWriter.AddByte((byte)pkt.Family); + pkt.Serialize(eoWriter); + return PrependLengthBytes(eoWriter.ToByteArray()); } - public IPacket DecodeData(IEnumerable rawData) + public Option DecodeData(byte[] rawData) { return _encoderService.Decode(rawData, _encoderRepository.ReceiveMultiplier); } - private int CalculateNextSequenceNumber() + private static byte[] PrependLengthBytes(byte[] data) { - var oldSequenceIncrement = _sequenceRepository.SequenceIncrement; - var sequenceStart = _sequenceRepository.SequenceStart; - - _sequenceRepository.SequenceIncrement = _sequenceService.CalculateNextSequenceIncrement(oldSequenceIncrement); - return _sequenceService.CalculateNextSequenceNumber(sequenceStart, _sequenceRepository.SequenceIncrement); + var newArray = new byte[data.Length + 2]; + Array.Copy(NumberEncoder.EncodeNumber(data.Length), newArray, 2); + Array.Copy(data, 0, newArray, 2, data.Length); + return newArray; } } public interface IPacketProcessActions { - void SetInitialSequenceNumber(int seq1, int seq2); - - void SetUpdatedBaseSequenceNumber(int seq1, int seq2); + void SetSequenceStart(ISequenceStart sequenceStart); void SetEncodeMultiples(int emulti_d, int emulti_e); @@ -92,6 +87,6 @@ public interface IPacketProcessActions byte[] EncodeRawPacket(IPacket pkt); - IPacket DecodeData(IEnumerable rawData); + Option DecodeData(byte[] rawData); } } diff --git a/EOLib/Net/PacketProcessing/PacketSequenceService.cs b/EOLib/Net/PacketProcessing/PacketSequenceService.cs deleted file mode 100644 index 60c84c6cc..000000000 --- a/EOLib/Net/PacketProcessing/PacketSequenceService.cs +++ /dev/null @@ -1,39 +0,0 @@ -using AutomaticTypeMapper; - -namespace EOLib.Net.PacketProcessing -{ - [AutoMappedType] - public class PacketSequenceService : IPacketSequenceService - { - public int CalculateInitialSequenceNumber(int seq1, int seq2) - { - return seq1*7 - 11 + seq2 - 2; - } - - public int CalculateNextSequenceNumber(int sequence, int increment) - { - return sequence + increment; - } - - public int CalculateNewInitialSequenceNumber(int seq1, int seq2) - { - return seq1 - seq2; - } - - public int CalculateNextSequenceIncrement(int increment) - { - return (increment + 1)%10; - } - } - - public interface IPacketSequenceService - { - int CalculateInitialSequenceNumber(int seq1, int seq2); - - int CalculateNextSequenceNumber(int sequence, int increment); - - int CalculateNewInitialSequenceNumber(int seq1, int seq2); - - int CalculateNextSequenceIncrement(int increment); - } -} diff --git a/EOLib/Net/PacketProcessing/SequenceRepository.cs b/EOLib/Net/PacketProcessing/SequenceRepository.cs index 5eaccd2ca..38fdcbbd6 100644 --- a/EOLib/Net/PacketProcessing/SequenceRepository.cs +++ b/EOLib/Net/PacketProcessing/SequenceRepository.cs @@ -1,17 +1,23 @@ using AutomaticTypeMapper; +using Moffat.EndlessOnline.SDK.Packet; namespace EOLib.Net.PacketProcessing { [AutoMappedType(IsSingleton = true)] public class SequenceRepository : ISequenceRepository { - public int SequenceStart { get; set; } - public int SequenceIncrement { get; set; } + public PacketSequencer Sequencer { get; set; } + + public SequenceRepository() => ResetState(); + + public void ResetState() + { + Sequencer = new PacketSequencer(ZeroSequence.Instance); + } } - public interface ISequenceRepository + public interface ISequenceRepository : IResettable { - int SequenceStart { get; set; } - int SequenceIncrement { get; set; } + PacketSequencer Sequencer { get; set; } } } diff --git a/EOLib/Net/Translators/AccountLoginPacketTranslator.cs b/EOLib/Net/Translators/AccountLoginPacketTranslator.cs deleted file mode 100644 index 92e3b61d0..000000000 --- a/EOLib/Net/Translators/AccountLoginPacketTranslator.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Collections.Generic; -using AutomaticTypeMapper; -using EOLib.Domain.Character; -using EOLib.Domain.Login; -using EOLib.IO.Repositories; -using EOLib.Domain.Protocol; - -namespace EOLib.Net.Translators -{ - [AutoMappedType] - public class AccountLoginPacketTranslator : CharacterDisplayPacketTranslator - { - public AccountLoginPacketTranslator(IEIFFileProvider eifFileProvider) - : base(eifFileProvider) { } - - public override IAccountLoginData TranslatePacket(IPacket packet) - { - LoginReply reply; - var characters = new List(); - - if (packet.Family == PacketFamily.Login && packet.Action == PacketAction.Reply) - { - reply = (LoginReply)packet.ReadShort(); - - if (reply == LoginReply.Ok) - characters.AddRange(GetCharacters(packet)); - } - else if (packet.Family == PacketFamily.Init && packet.Action == PacketAction.Init) - { - var initReply = (InitReply)packet.ReadByte(); - var banType = (BanType)packet.ReadByte(); - - if (initReply != InitReply.BannedFromServer && banType != BanType.PermanentBan) - reply = LoginReply.THIS_IS_WRONG; - else - reply = LoginReply.AccountBanned; - } - else - { - reply = LoginReply.THIS_IS_WRONG; - } - - return new AccountLoginData(reply, characters); - } - } -} diff --git a/EOLib/Net/Translators/CharacterDisplayPacketTranslator.cs b/EOLib/Net/Translators/CharacterDisplayPacketTranslator.cs deleted file mode 100644 index 1f9e20aa4..000000000 --- a/EOLib/Net/Translators/CharacterDisplayPacketTranslator.cs +++ /dev/null @@ -1,81 +0,0 @@ -using EOLib.Domain.Character; -using EOLib.IO.Repositories; -using System.Collections.Generic; - -namespace EOLib.Net.Translators -{ - public abstract class CharacterDisplayPacketTranslator : IPacketTranslator - where T : ITranslatedData - { - private readonly IEIFFileProvider _eifFileProvider; - - protected CharacterDisplayPacketTranslator(IEIFFileProvider eifFileProvider) - { - _eifFileProvider = eifFileProvider; - } - - public abstract T TranslatePacket(IPacket packet); - - protected IEnumerable GetCharacters(IPacket packet) - { - var characters = new List(); - - var numberOfCharacters = (int)packet.ReadChar(); - - // Optional AddByte call. EOSERV sends either 1 or 2, but GameServer appears - // to not send it on character delete - packet.ReadBreakString(); - - for (int i = 0; i < numberOfCharacters; ++i) - { - characters.Add(GetNextCharacter(packet)); - if (packet.ReadByte() != 255) - throw new MalformedPacketException($"{packet.Family}_{packet.Action} packet missing character separator byte", packet); - } - - return characters; - } - - private Character GetNextCharacter(IPacket packet) - { - var character = new Character.Builder - { - Name = packet.ReadBreakString(), - ID = packet.ReadInt() - }; - - var stats = new CharacterStats().WithNewStat(CharacterStat.Level, packet.ReadChar()); - - var gender = packet.ReadChar(); - var hairStyle = packet.ReadChar(); - var hairColor = packet.ReadChar(); - var race = packet.ReadChar(); - var adminLevel = (AdminLevel)packet.ReadChar(); - var boots = packet.ReadShort(); - var armor = packet.ReadShort(); - var hat = packet.ReadShort(); - var shield = packet.ReadShort(); - var weapon = packet.ReadShort(); - - var renderProperties = new CharacterRenderProperties.Builder - { - Gender = gender, - HairStyle = hairStyle, - HairColor = hairColor, - Race = race, - BootsGraphic = boots, - ArmorGraphic = armor, - HatGraphic = hat, - ShieldGraphic = shield, - WeaponGraphic = weapon - }; - - character.Stats = stats; - character.AdminLevel = adminLevel; - character.RenderProperties = renderProperties.ToImmutable(); - - return character.ToImmutable(); - } - - } -} diff --git a/EOLib/Net/Translators/CharacterFromPacketFactory.cs b/EOLib/Net/Translators/CharacterFromPacketFactory.cs deleted file mode 100644 index 4bd9e6a9b..000000000 --- a/EOLib/Net/Translators/CharacterFromPacketFactory.cs +++ /dev/null @@ -1,97 +0,0 @@ -using AutomaticTypeMapper; -using EOLib.Domain.Character; -using EOLib.IO.Repositories; -using System.IO; - -namespace EOLib.Net.Translators -{ - [AutoMappedType] - public class CharacterFromPacketFactory : ICharacterFromPacketFactory - { - private readonly IEIFFileProvider _eifFileProvider; - - public CharacterFromPacketFactory(IEIFFileProvider eifFileProvider) - { - _eifFileProvider = eifFileProvider; - } - - public Character CreateCharacter(IPacket packet) - { - var name = packet.ReadBreakString(); - name = char.ToUpper(name[0]) + name.Substring(1); - - var id = packet.ReadShort(); - var mapID = packet.ReadShort(); - var xLoc = packet.ReadShort(); - var yLoc = packet.ReadShort(); - - var direction = (EODirection)packet.ReadChar(); - var classID = packet.ReadChar(); - var guildTag = packet.ReadString(3); - - var level = packet.ReadChar(); - var gender = packet.ReadChar(); - var hairStyle = packet.ReadChar(); - var hairColor = packet.ReadChar(); - var race = packet.ReadChar(); - - var maxHP = packet.ReadShort(); - var hp = packet.ReadShort(); - var maxTP = packet.ReadShort(); - var tp = packet.ReadShort(); - - var boots = packet.ReadShort(); - packet.Seek(6, SeekOrigin.Current); //0s - var armor = packet.ReadShort(); - packet.Seek(2, SeekOrigin.Current); //0 - var hat = packet.ReadShort(); - var shield = packet.ReadShort(); - var weapon = packet.ReadShort(); - - var sitState = (SitState)packet.ReadChar(); - var hidden = packet.ReadChar() != 0; - - var stats = new CharacterStats() - .WithNewStat(CharacterStat.Level, level) - .WithNewStat(CharacterStat.HP, hp) - .WithNewStat(CharacterStat.MaxHP, maxHP) - .WithNewStat(CharacterStat.TP, tp) - .WithNewStat(CharacterStat.MaxTP, maxTP); - - var renderProps = new CharacterRenderProperties.Builder - { - Direction = direction, - Gender = gender, - HairStyle = hairStyle, - HairColor = hairColor, - Race = race, - BootsGraphic = boots, - ArmorGraphic = armor, - HatGraphic = hat, - ShieldGraphic = shield, - WeaponGraphic = weapon, - SitState = sitState, - CurrentAction = sitState == SitState.Standing ? CharacterActionState.Standing : CharacterActionState.Sitting, - IsHidden = hidden, - MapX = xLoc, - MapY = yLoc, - }; - - return new Character.Builder - { - Name = name, - ID = id, - ClassID = classID, - MapID = mapID, - GuildTag = guildTag, - Stats = stats, - RenderProperties = renderProps.ToImmutable(), - }.ToImmutable(); - } - } - - public interface ICharacterFromPacketFactory - { - Character CreateCharacter(IPacket packet); - } -} diff --git a/EOLib/Net/Translators/CharacterReplyPacketTranslator.cs b/EOLib/Net/Translators/CharacterReplyPacketTranslator.cs deleted file mode 100644 index b545fb49a..000000000 --- a/EOLib/Net/Translators/CharacterReplyPacketTranslator.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections.Generic; -using AutomaticTypeMapper; -using EOLib.Domain.Character; -using EOLib.IO.Repositories; - -namespace EOLib.Net.Translators -{ - [AutoMappedType] - public class CharacterReplyPacketTranslator : CharacterDisplayPacketTranslator - { - public CharacterReplyPacketTranslator(IEIFFileProvider eifFileProvider) - : base(eifFileProvider) { } - - public override ICharacterCreateData TranslatePacket(IPacket packet) - { - var reply = (CharacterReply) packet.ReadShort(); - - var characters = new List(); - if (reply == CharacterReply.Ok || reply == CharacterReply.Deleted) - characters.AddRange(GetCharacters(packet)); - - return new CharacterCreateData(reply, characters); - } - } -} diff --git a/EOLib/Net/Translators/IPacketTranslator.cs b/EOLib/Net/Translators/IPacketTranslator.cs deleted file mode 100644 index 4dda9add4..000000000 --- a/EOLib/Net/Translators/IPacketTranslator.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace EOLib.Net.Translators -{ - public interface IPacketTranslator - where T : ITranslatedData - { - T TranslatePacket(IPacket packet); - } -} diff --git a/EOLib/Net/Translators/ITranslatedData.cs b/EOLib/Net/Translators/ITranslatedData.cs deleted file mode 100644 index ef0128130..000000000 --- a/EOLib/Net/Translators/ITranslatedData.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace EOLib.Net.Translators -{ - public interface ITranslatedData - { - } -} diff --git a/EOLib/Net/Translators/InitDataTranslator.cs b/EOLib/Net/Translators/InitDataTranslator.cs deleted file mode 100644 index 28a4b97c9..000000000 --- a/EOLib/Net/Translators/InitDataTranslator.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.IO; -using AutomaticTypeMapper; -using EOLib.Domain.Protocol; - -namespace EOLib.Net.Translators -{ - [AutoMappedType] - public class InitDataTranslator : IPacketTranslator - { - public IInitializationData TranslatePacket(IPacket packet) - { - var response = (InitReply) packet.ReadByte(); - switch (response) - { - case InitReply.BannedFromServer: return GetInitializationBannedData(packet); - case InitReply.ClientOutOfDate: return GetInitializationOutOfDateData(packet); - case InitReply.Success: return GetInitializationSuccessData(packet); - default: throw new InvalidInitResponseException(response); - } - } - - private IInitializationData GetInitializationBannedData(IPacket packet) - { - var banType = (BanType)packet.ReadByte(); - byte banTimeRemaining = 0; - if(banType == BanType.TemporaryBan) - banTimeRemaining = packet.ReadByte(); - return new InitializationBannedData(banType, banTimeRemaining); - } - - private IInitializationData GetInitializationOutOfDateData(IPacket packet) - { - packet.Seek(2, SeekOrigin.Current); - return new InitializationOutOfDateData(packet.ReadChar()); - } - - private IInitializationData GetInitializationSuccessData(IPacket packet) - { - return new InitializationSuccessData( - packet.ReadByte(), - packet.ReadByte(), - packet.ReadByte(), - packet.ReadByte(), - packet.ReadShort(), - packet.ReadThree() - ); - } - } - - public class InvalidInitResponseException : Exception - { - public InvalidInitResponseException(InitReply reply) - : base($"Invalid InitReply from server: {reply}") { } - } -} diff --git a/EOLib/Net/Translators/LoginRequestCompletedPacketTranslator.cs b/EOLib/Net/Translators/LoginRequestCompletedPacketTranslator.cs deleted file mode 100644 index 16e185dde..000000000 --- a/EOLib/Net/Translators/LoginRequestCompletedPacketTranslator.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using AutomaticTypeMapper; -using EOLib.Domain.Character; -using EOLib.Domain.Login; - -namespace EOLib.Net.Translators -{ - [AutoMappedType] - public class LoginRequestCompletedPacketTranslator : MapStatePacketTranslator - { - private const int MAX_NEWS_LINES = 9; - - public LoginRequestCompletedPacketTranslator(ICharacterFromPacketFactory characterFromPacketFactory) - : base(characterFromPacketFactory) { } - - public override LoginRequestCompletedData TranslatePacket(IPacket packet) - { - var reply = (CharacterLoginReply)packet.ReadShort(); - - if (reply == CharacterLoginReply.RequestDenied) - { - if (packet.ReadEndString() != "NO") - throw new MalformedPacketException("Expected NO bytes in CharacterLoginReply login", packet); - - return new LoginRequestCompletedData.Builder { Error = reply }.ToImmutable(); - } - else if (reply != CharacterLoginReply.RequestCompleted) - { - throw new MalformedPacketException("Unexpected welcome response in packet: " + reply, packet); - } - - if (packet.ReadByte() != 255) - throw new MalformedPacketException("Missing 255 byte separator after CharacterLoginReply type", packet); - - var news = GetNews(packet).ToList(); - - var weight = packet.ReadChar(); - var maxWeight = packet.ReadChar(); - - var inventoryItems = GetInventoryItems(packet).ToList(); - if (!inventoryItems.Any(x => x.ItemID == 1)) - inventoryItems.Insert(0, new InventoryItem(1, 0)); - - var inventorySpells = GetInventorySpells(packet).ToList(); - - if (inventoryItems.All(x => x.ItemID != 1)) - inventoryItems.Add(new InventoryItem(1, 0)); - - var characters = GetCharacters(packet).ToList(); - var npcs = GetNPCs(packet).ToList(); - var items = GetMapItems(packet).ToList(); - - return new LoginRequestCompletedData.Builder - { - News = news, - CharacterWeight = weight, - CharacterMaxWeight = maxWeight, - CharacterItemInventory = inventoryItems, - CharacterSpellInventory = inventorySpells, - MapCharacters = characters, - MapNPCs = npcs, - MapItems = items, - }.ToImmutable(); - } - - private IEnumerable GetNews(IPacket packet) - { - for (int i = 0; i < MAX_NEWS_LINES; ++i) - yield return packet.ReadBreakString(); - } - - private IEnumerable GetInventoryItems(IPacket packet) - { - while (packet.PeekByte() != 255) - yield return new InventoryItem(packet.ReadShort(), packet.ReadInt()); - - packet.ReadByte(); - } - - private IEnumerable GetInventorySpells(IPacket packet) - { - while (packet.PeekByte() != 255) - yield return new InventorySpell(packet.ReadShort(), packet.ReadShort()); - - packet.ReadByte(); - } - } -} diff --git a/EOLib/Net/Translators/LoginRequestGrantedPacketTranslator.cs b/EOLib/Net/Translators/LoginRequestGrantedPacketTranslator.cs deleted file mode 100644 index b816df955..000000000 --- a/EOLib/Net/Translators/LoginRequestGrantedPacketTranslator.cs +++ /dev/null @@ -1,144 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using AutomaticTypeMapper; -using EOLib.Domain.Character; -using EOLib.Domain.Login; -using EOLib.IO; - -namespace EOLib.Net.Translators -{ - [AutoMappedType] - public class LoginRequestGrantedPacketTranslator : IPacketTranslator - { - public LoginRequestGrantedData TranslatePacket(IPacket packet) - { - var reply = (CharacterLoginReply)packet.ReadShort(); - if (reply != CharacterLoginReply.RequestGranted) - throw new MalformedPacketException("Unexpected welcome response in packet: " + reply, packet); - - var sessionID = packet.ReadShort(); - var characterID = packet.ReadInt(); - - var mapID = packet.ReadShort(); - var mapRid = packet.ReadBytes(4).ToArray(); - var mapLen = packet.ReadThree(); - - var eifRid = packet.ReadInt(); - var eifLen = packet.ReadShort(); - - var enfRid = packet.ReadInt(); - var enfLen = packet.ReadShort(); - - var esfRid = packet.ReadInt(); - var esfLen = packet.ReadShort(); - - var ecfRid = packet.ReadInt(); - var ecfLen = packet.ReadShort(); - - var characterName = packet.ReadBreakString(); - var characterTitle = packet.ReadBreakString(); - var guildName = packet.ReadBreakString(); - var guildRank = packet.ReadBreakString(); - var classID = packet.ReadChar(); - var paddedGuildTag = packet.ReadString(3); //padded guild tag is 3 characters - var adminLevel = (AdminLevel)packet.ReadChar(); - - var level = packet.ReadChar(); - var exp = packet.ReadInt(); - var usage = packet.ReadInt(); - - var hp = packet.ReadShort(); - var maxHP = packet.ReadShort(); - var tp = packet.ReadShort(); - var maxTP = packet.ReadShort(); - var maxSP = packet.ReadShort(); - - var statPoints = packet.ReadShort(); - var skillPoints = packet.ReadShort(); - var karma = packet.ReadShort(); - var minDam = packet.ReadShort(); - var maxDam = packet.ReadShort(); - var accuracy = packet.ReadShort(); - var evade = packet.ReadShort(); - var armor = packet.ReadShort(); - var dispStr = packet.ReadShort(); - var dispWis = packet.ReadShort(); - var dispInt = packet.ReadShort(); - var dispAgi = packet.ReadShort(); - var dispCon = packet.ReadShort(); - var dispCha = packet.ReadShort(); - - var characterStats = new CharacterStats() - .WithNewStat(CharacterStat.Level, level) - .WithNewStat(CharacterStat.Experience, exp) - .WithNewStat(CharacterStat.Usage, usage) - .WithNewStat(CharacterStat.HP, hp) - .WithNewStat(CharacterStat.MaxHP, maxHP) - .WithNewStat(CharacterStat.TP, tp) - .WithNewStat(CharacterStat.MaxTP, maxTP) - .WithNewStat(CharacterStat.SP, maxSP) - .WithNewStat(CharacterStat.MaxSP, maxSP) - .WithNewStat(CharacterStat.StatPoints, statPoints) - .WithNewStat(CharacterStat.SkillPoints, skillPoints) - .WithNewStat(CharacterStat.Karma, karma) - .WithNewStat(CharacterStat.MinDam, minDam) - .WithNewStat(CharacterStat.MaxDam, maxDam) - .WithNewStat(CharacterStat.Accuracy, accuracy) - .WithNewStat(CharacterStat.Evade, evade) - .WithNewStat(CharacterStat.Armor, armor) - .WithNewStat(CharacterStat.Strength, dispStr) - .WithNewStat(CharacterStat.Intelligence, dispInt) - .WithNewStat(CharacterStat.Wisdom, dispWis) - .WithNewStat(CharacterStat.Agility, dispAgi) - .WithNewStat(CharacterStat.Constitution, dispCon) - .WithNewStat(CharacterStat.Charisma, dispCha); - - var paperDoll = new Dictionary(); - for (var equipLocation = (EquipLocation)0; equipLocation < EquipLocation.PAPERDOLL_MAX; ++equipLocation) - { - paperDoll[equipLocation] = packet.ReadShort(); - } - - var guildRankNum = packet.ReadChar(); - var jailMap = packet.ReadShort(); - - //unused by eoserv - contains flood rates for commands, etc. - packet.Seek(12, SeekOrigin.Current); - - var firstTimePlayer = packet.ReadChar() == 2; //signal that the player should see the "first timer" message - - if (packet.ReadByte() != 255) - throw new MalformedPacketException("Missing terminating 255 byte", packet); - - return new LoginRequestGrantedData.Builder - { - SessionID = sessionID, - CharacterID = characterID, - MapID = mapID, - MapRID = mapRid, - MapLen = mapLen, - EifRid = eifRid, - EifLen = eifLen, - EnfRid = enfRid, - EnfLen = enfLen, - EsfRid = esfRid, - EsfLen = esfLen, - EcfRid = ecfRid, - EcfLen = ecfLen, - Name = characterName, - Title = characterTitle, - GuildName = guildName, - GuildRank = guildRank, - ClassID = classID, - GuildTag = paddedGuildTag, - AdminLevel = adminLevel, - CharacterStats = characterStats, - Paperdoll = paperDoll, - GuildRankNum = guildRankNum, - JailMap = jailMap, - FirstTimePlayer = firstTimePlayer, - }.ToImmutable(); - } - } -} diff --git a/EOLib/Net/Translators/MapStatePacketTranslator.cs b/EOLib/Net/Translators/MapStatePacketTranslator.cs deleted file mode 100644 index a746553cf..000000000 --- a/EOLib/Net/Translators/MapStatePacketTranslator.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using System.Collections.Generic; -using EOLib.Domain.Character; -using EOLib.Domain.Map; -using EOLib.Domain.NPC; -using Optional; - -namespace EOLib.Net.Translators -{ - public abstract class MapStatePacketTranslator : IPacketTranslator - where T : ITranslatedData - { - private readonly ICharacterFromPacketFactory _characterFromPacketFactory; - - protected MapStatePacketTranslator(ICharacterFromPacketFactory characterFromPacketFactory) - { - _characterFromPacketFactory = characterFromPacketFactory; - } - - public abstract T TranslatePacket(IPacket packet); - - protected IEnumerable GetCharacters(IPacket packet) - { - var numCharacters = packet.ReadChar(); - - for (int i = 0; i < numCharacters; ++i) - { - if (packet.ReadByte() != 255) - throw new MalformedPacketException("Missing 255 byte character delimiter", packet); - - var character = _characterFromPacketFactory.CreateCharacter(packet); - yield return character; - } - - if (packet.ReadByte() != 255) - throw new MalformedPacketException("Missing final 255 byte after characters loop", packet); - } - - protected IEnumerable GetNPCs(IPacket packet) - { - while (packet.PeekByte() != 255) - { - var index = packet.ReadChar(); - var id = packet.ReadShort(); - var x = packet.ReadChar(); - var y = packet.ReadChar(); - var direction = (EODirection) packet.ReadChar(); - - yield return new NPC.Builder() - { - ID = id, - Index = index, - X = x, - Y = y, - Direction = direction, - }.ToImmutable(); - } - - packet.ReadByte(); //consume the tail 255 byte that broke loop iteration - } - - protected IEnumerable GetMapItems(IPacket packet) - { - while (packet.ReadPosition < packet.Length) - { - var uid = packet.ReadShort(); - var itemID = packet.ReadShort(); - var x = packet.ReadChar(); - var y = packet.ReadChar(); - var amount = packet.ReadThree(); - - yield return new MapItem(uid, itemID, x, y, amount); - } - } - } -} diff --git a/EOLib/Net/Translators/NPCFromPacketFactory.cs b/EOLib/Net/Translators/NPCFromPacketFactory.cs deleted file mode 100644 index afc431701..000000000 --- a/EOLib/Net/Translators/NPCFromPacketFactory.cs +++ /dev/null @@ -1,34 +0,0 @@ -using AutomaticTypeMapper; -using EOLib.Domain.NPC; - -namespace EOLib.Net.Translators -{ - [AutoMappedType] - public class NPCFromPacketFactory : INPCFromPacketFactory - { - public NPC CreateNPC(IPacket packet) - { - var index = packet.ReadChar(); - var id = packet.ReadShort(); - var x = packet.ReadChar(); - var y = packet.ReadChar(); - var direction = (EODirection)packet.ReadChar(); - - var npc = new NPC.Builder() - { - ID = id, - Index = index, - X = x, - Y = y, - Direction = direction, - Frame = NPCFrame.Standing, - }; - return npc.ToImmutable(); - } - } - - public interface INPCFromPacketFactory - { - NPC CreateNPC(IPacket packet); - } -} diff --git a/EOLib/Net/Translators/RefreshReplyPacketTranslator.cs b/EOLib/Net/Translators/RefreshReplyPacketTranslator.cs deleted file mode 100644 index 65f659af4..000000000 --- a/EOLib/Net/Translators/RefreshReplyPacketTranslator.cs +++ /dev/null @@ -1,27 +0,0 @@ -using AutomaticTypeMapper; -using EOLib.Domain.Map; -using System.Linq; - -namespace EOLib.Net.Translators -{ - [AutoMappedType] - public class RefreshReplyPacketTranslator : MapStatePacketTranslator - { - public RefreshReplyPacketTranslator(ICharacterFromPacketFactory characterFromPacketFactory) - : base(characterFromPacketFactory) { } - - public override RefreshReplyData TranslatePacket(IPacket packet) - { - var characters = GetCharacters(packet); - var npcs = GetNPCs(packet); - var items = GetMapItems(packet); - - return new RefreshReplyData.Builder - { - Characters = characters.ToList(), - NPCs = npcs.ToList(), - Items = items.ToList(), - }.ToImmutable(); - } - } -} diff --git a/EOLib/Net/Translators/WarpAgreePacketTranslator.cs b/EOLib/Net/Translators/WarpAgreePacketTranslator.cs deleted file mode 100644 index 1285de6c9..000000000 --- a/EOLib/Net/Translators/WarpAgreePacketTranslator.cs +++ /dev/null @@ -1,35 +0,0 @@ -using AutomaticTypeMapper; -using EOLib.Domain.Map; -using System.Linq; - -namespace EOLib.Net.Translators -{ - [AutoMappedType] - public class WarpAgreePacketTranslator : MapStatePacketTranslator - { - public WarpAgreePacketTranslator(ICharacterFromPacketFactory characterFromPacketFactory) - : base(characterFromPacketFactory) { } - - public override WarpAgreePacketData TranslatePacket(IPacket packet) - { - if (packet.ReadChar() != 2) - throw new MalformedPacketException("Missing initial marker value of 2", packet); - - var newMapID = packet.ReadShort(); - var warpAnim = (WarpAnimation)packet.ReadChar(); - - var characters = GetCharacters(packet); - var npcs = GetNPCs(packet); - var items = GetMapItems(packet); - - return new WarpAgreePacketData.Builder - { - MapID = newMapID, - WarpAnimation = warpAnim, - Characters = characters.ToList(), - NPCs = npcs.ToList(), - Items = items.ToList(), - }.ToImmutable(); - } - } -} diff --git a/EOLib/PacketHandlers/AdminInteract/AdminInteractAgree.cs b/EOLib/PacketHandlers/AdminInteract/AdminInteractAgree.cs index 7a8bcf1df..770e00fcc 100644 --- a/EOLib/PacketHandlers/AdminInteract/AdminInteractAgree.cs +++ b/EOLib/PacketHandlers/AdminInteract/AdminInteractAgree.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.AdminInteract { @@ -11,7 +12,7 @@ namespace EOLib.PacketHandlers.AdminInteract /// Admin unhiding /// [AutoMappedType] - public class AdminInteractAgree : InGameOnlyPacketHandler + public class AdminInteractAgree : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; private readonly ICurrentMapStateRepository _currentMapStateRepository; @@ -28,22 +29,22 @@ public AdminInteractAgree(IPlayerInfoProvider playerInfoProvider, _currentMapStateRepository = currentMapStateRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(AdminInteractAgreeServerPacket packet) { - var id = packet.ReadShort(); - - if (id == _characterRepository.MainCharacter.ID) + if (packet.PlayerId == _characterRepository.MainCharacter.ID) + { _characterRepository.MainCharacter = Shown(_characterRepository.MainCharacter); + } else { - if (_currentMapStateRepository.Characters.TryGetValue(id, out var character)) + if (_currentMapStateRepository.Characters.TryGetValue(packet.PlayerId, out var character)) { var updatedCharacter = Shown(character); _currentMapStateRepository.Characters.Update(character, updatedCharacter); } else { - _currentMapStateRepository.UnknownPlayerIDs.Add(id); + _currentMapStateRepository.UnknownPlayerIDs.Add(packet.PlayerId); } } diff --git a/EOLib/PacketHandlers/AdminInteract/AdminInteractList.cs b/EOLib/PacketHandlers/AdminInteract/AdminInteractList.cs index 8caed2c20..6d61ef0a0 100644 --- a/EOLib/PacketHandlers/AdminInteract/AdminInteractList.cs +++ b/EOLib/PacketHandlers/AdminInteract/AdminInteractList.cs @@ -2,9 +2,11 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; +using System.Linq; namespace EOLib.PacketHandlers.AdminInteract { @@ -12,7 +14,7 @@ namespace EOLib.PacketHandlers.AdminInteract /// Response to $inventory command. /// [AutoMappedType] - public class AdminInteractList: InGameOnlyPacketHandler + public class AdminInteractList : InGameOnlyPacketHandler { private readonly IEnumerable _userInterfaceNotifiers; @@ -27,38 +29,13 @@ public AdminInteractList(IPlayerInfoProvider playerInfoProvider, _userInterfaceNotifiers = userInterfaceNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(AdminInteractListServerPacket packet) { - var name = packet.ReadBreakString(); - - var usage = packet.ReadInt(); - if (packet.ReadByte() != 255) - return false; - - var gold_bank = packet.ReadInt(); - if (packet.ReadByte() != 255) - return false; - - var inventory = new List(); - while (packet.PeekByte() != 255) - { - var id = packet.ReadShort(); - var amount = packet.ReadInt(); - inventory.Add(new InventoryItem(id, amount)); - } - packet.ReadByte(); - - var bank = new List(); - while (packet.ReadPosition < packet.Length) - { - var id = packet.ReadShort(); - var amount = packet.ReadThree(); - bank.Add(new InventoryItem(id, amount)); - } - + var inventory = packet.Inventory.Select(x => new InventoryItem(x.Id, x.Amount)).ToList(); + var bank = packet.Bank.Select(x => new InventoryItem(x.Id, x.Amount)).ToList(); foreach (var notifier in _userInterfaceNotifiers) { - notifier.NotifyCharacterInventory(name, usage, gold_bank, inventory, bank); + notifier.NotifyCharacterInventory(packet.Name, packet.Usage, packet.GoldBank, inventory, bank); } return true; diff --git a/EOLib/PacketHandlers/AdminInteract/AdminInteractRemove.cs b/EOLib/PacketHandlers/AdminInteract/AdminInteractRemove.cs index ea6e52392..e02ffdb25 100644 --- a/EOLib/PacketHandlers/AdminInteract/AdminInteractRemove.cs +++ b/EOLib/PacketHandlers/AdminInteract/AdminInteractRemove.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.AdminInteract { @@ -11,7 +12,7 @@ namespace EOLib.PacketHandlers.AdminInteract /// Admin hiding /// [AutoMappedType] - public class AdminInteractRemove : InGameOnlyPacketHandler + public class AdminInteractRemove : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; private readonly ICurrentMapStateRepository _currentMapStateRepository; @@ -28,22 +29,22 @@ public AdminInteractRemove(IPlayerInfoProvider playerInfoProvider, _currentMapStateRepository = currentMapStateRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(AdminInteractRemoveServerPacket packet) { - var id = packet.ReadShort(); - - if (id == _characterRepository.MainCharacter.ID) + if (packet.PlayerId == _characterRepository.MainCharacter.ID) + { _characterRepository.MainCharacter = Hidden(_characterRepository.MainCharacter); + } else { - if (_currentMapStateRepository.Characters.TryGetValue(id, out var character)) + if (_currentMapStateRepository.Characters.TryGetValue(packet.PlayerId, out var character)) { var updatedCharacter = Hidden(character); _currentMapStateRepository.Characters.Update(character, updatedCharacter); } else { - _currentMapStateRepository.UnknownPlayerIDs.Add(id); + _currentMapStateRepository.UnknownPlayerIDs.Add(packet.PlayerId); } } diff --git a/EOLib/PacketHandlers/AdminInteract/AdminInteractReply.cs b/EOLib/PacketHandlers/AdminInteract/AdminInteractReply.cs index 0977ff0b6..11e688494 100644 --- a/EOLib/PacketHandlers/AdminInteract/AdminInteractReply.cs +++ b/EOLib/PacketHandlers/AdminInteract/AdminInteractReply.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Chat; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.AdminInteract { @@ -10,7 +11,7 @@ namespace EOLib.PacketHandlers.AdminInteract /// Received by admins when a report is made by another player. /// [AutoMappedType] - public class AdminInteractReply : InGameOnlyPacketHandler + public class AdminInteractReply : InGameOnlyPacketHandler { private readonly IChatRepository _chatRepository; @@ -25,23 +26,22 @@ public AdminInteractReply(IPlayerInfoProvider playerInfoProvider, _chatRepository = chatRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(AdminInteractReplyServerPacket packet) { - var messageType = (AdminMessageType)packet.ReadChar(); - packet.ReadByte(); - - var playerName = packet.ReadBreakString(); - var message = packet.ReadBreakString(); - ChatData chatData; - switch (messageType) + switch (packet.MessageType) { case AdminMessageType.Message: - chatData = new ChatData(ChatTab.Group, playerName, $"needs help: {message}", ChatIcon.Information, ChatColor.ServerGlobal, filter: false); + { + var message = (AdminInteractReplyServerPacket.MessageTypeDataMessage)packet.MessageTypeData; + chatData = new ChatData(ChatTab.Group, message.PlayerName, $"needs help: {message}", ChatIcon.Information, ChatColor.ServerGlobal, filter: false); + } break; case AdminMessageType.Report: - var reporteeName = packet.ReadBreakString(); - chatData = new ChatData(ChatTab.Group, playerName, $"reports: {reporteeName}, {message}", ChatIcon.Information, ChatColor.ServerGlobal, filter: false); + { + var report = (AdminInteractReplyServerPacket.MessageTypeDataReport)packet.MessageTypeData; + chatData = new ChatData(ChatTab.Group, report.PlayerName, $"reports: {report.ReporteeName}, {report.Message}", ChatIcon.Information, ChatColor.ServerGlobal, filter: false); + } break; default: return false; diff --git a/EOLib/PacketHandlers/AdminInteract/AdminInteractTell.cs b/EOLib/PacketHandlers/AdminInteract/AdminInteractTell.cs index 0761caa72..e4d05358c 100644 --- a/EOLib/PacketHandlers/AdminInteract/AdminInteractTell.cs +++ b/EOLib/PacketHandlers/AdminInteract/AdminInteractTell.cs @@ -3,8 +3,9 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.AdminInteract @@ -13,7 +14,7 @@ namespace EOLib.PacketHandlers.AdminInteract /// Response to $info command. /// [AutoMappedType] - public class AdminInteractTell: InGameOnlyPacketHandler + public class AdminInteractTell: InGameOnlyPacketHandler { private readonly IEnumerable _userInterfaceNotifiers; @@ -28,52 +29,47 @@ public AdminInteractTell(IPlayerInfoProvider playerInfoProvider, _userInterfaceNotifiers = userInterfaceNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(AdminInteractTellServerPacket packet) { - var name = packet.ReadBreakString(); - - var stats = new Dictionary(); - stats[CharacterStat.Usage] = packet.ReadInt(); - if (packet.ReadByte() != 255 || packet.ReadByte() != 255) - return false; - - stats[CharacterStat.Experience] = packet.ReadInt(); - stats[CharacterStat.Level] = packet.ReadChar(); + var stats = new Dictionary + { + [CharacterStat.Usage] = packet.Usage, - var mapId = packet.ReadShort(); - var mapCoords = new MapCoordinate(packet.ReadShort(), packet.ReadShort()); + [CharacterStat.Experience] = packet.Exp, + [CharacterStat.Level] = packet.Level, - stats[CharacterStat.HP] = packet.ReadShort(); - stats[CharacterStat.MaxHP] = packet.ReadShort(); - stats[CharacterStat.TP] = packet.ReadShort(); - stats[CharacterStat.MaxTP] = packet.ReadShort(); + [CharacterStat.HP] = packet.Stats.Hp, + [CharacterStat.MaxHP] = packet.Stats.MaxHp, + [CharacterStat.TP] = packet.Stats.Tp, + [CharacterStat.MaxTP] = packet.Stats.MaxTp, - stats[CharacterStat.Strength] = packet.ReadShort(); - stats[CharacterStat.Intelligence] = packet.ReadShort(); - stats[CharacterStat.Wisdom] = packet.ReadShort(); - stats[CharacterStat.Agility] = packet.ReadShort(); - stats[CharacterStat.Constitution] = packet.ReadShort(); - stats[CharacterStat.Charisma] = packet.ReadShort(); + [CharacterStat.Strength] = packet.Stats.BaseStats.Str, + [CharacterStat.Intelligence] = packet.Stats.BaseStats.Intl, + [CharacterStat.Wisdom] = packet.Stats.BaseStats.Wis, + [CharacterStat.Agility] = packet.Stats.BaseStats.Agi, + [CharacterStat.Constitution] = packet.Stats.BaseStats.Con, + [CharacterStat.Charisma] = packet.Stats.BaseStats.Cha, - stats[CharacterStat.MaxDam] = packet.ReadShort(); - stats[CharacterStat.MinDam] = packet.ReadShort(); - stats[CharacterStat.Accuracy] = packet.ReadShort(); - stats[CharacterStat.Evade] = packet.ReadShort(); - stats[CharacterStat.Armor] = packet.ReadShort(); + [CharacterStat.MaxDam] = packet.Stats.SecondaryStats.MaxDamage, + [CharacterStat.MinDam] = packet.Stats.SecondaryStats.MinDamage, + [CharacterStat.Accuracy] = packet.Stats.SecondaryStats.Accuracy, + [CharacterStat.Evade] = packet.Stats.SecondaryStats.Evade, + [CharacterStat.Armor] = packet.Stats.SecondaryStats.Armor, - stats[CharacterStat.Light] = packet.ReadShort(); - stats[CharacterStat.Dark] = packet.ReadShort(); - stats[CharacterStat.Fire] = packet.ReadShort(); - stats[CharacterStat.Water] = packet.ReadShort(); - stats[CharacterStat.Earth] = packet.ReadShort(); - stats[CharacterStat.Wind] = packet.ReadShort(); + [CharacterStat.Light] = packet.Stats.ElementalStats.Light, + [CharacterStat.Dark] = packet.Stats.ElementalStats.Dark, + [CharacterStat.Fire] = packet.Stats.ElementalStats.Fire, + [CharacterStat.Water] = packet.Stats.ElementalStats.Water, + [CharacterStat.Earth] = packet.Stats.ElementalStats.Earth, + [CharacterStat.Wind] = packet.Stats.ElementalStats.Wind, - stats[CharacterStat.Weight] = packet.ReadChar(); - stats[CharacterStat.MaxWeight] = packet.ReadChar(); + [CharacterStat.Weight] = packet.Weight.Current, + [CharacterStat.MaxWeight] = packet.Weight.Max + }; foreach (var notifier in _userInterfaceNotifiers) { - notifier.NotifyCharacterInfo(name, mapId, mapCoords, new CharacterStats(stats)); + notifier.NotifyCharacterInfo(packet.Name, packet.MapId, new MapCoordinate(packet.MapCoords), new CharacterStats(stats)); } return true; diff --git a/EOLib/PacketHandlers/AdminInteract/AdminMessageType.cs b/EOLib/PacketHandlers/AdminInteract/AdminMessageType.cs deleted file mode 100644 index 609d8d3f9..000000000 --- a/EOLib/PacketHandlers/AdminInteract/AdminMessageType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace EOLib.PacketHandlers.AdminInteract -{ - public enum AdminMessageType - { - Message = 1, - Report = 2, - } -} diff --git a/EOLib/PacketHandlers/Arena/ArenaAcceptHandler.cs b/EOLib/PacketHandlers/Arena/ArenaAcceptHandler.cs index f4b234c9c..61de6d005 100644 --- a/EOLib/PacketHandlers/Arena/ArenaAcceptHandler.cs +++ b/EOLib/PacketHandlers/Arena/ArenaAcceptHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Arena @@ -11,7 +12,7 @@ namespace EOLib.PacketHandlers.Arena /// Arena win message /// [AutoMappedType] - public class ArenaAcceptHandler : InGameOnlyPacketHandler + public class ArenaAcceptHandler : InGameOnlyPacketHandler { private readonly IEnumerable _arenaNotifiers; @@ -26,20 +27,12 @@ public ArenaAcceptHandler(IPlayerInfoProvider playerInfoProvider, _arenaNotifiers = arenaNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(ArenaAcceptServerPacket packet) { - var winnerName = packet.ReadBreakString(); - - var killsCount = packet.ReadInt(); - packet.ReadByte(); - - var killerName = packet.ReadBreakString(); - var victimName = packet.ReadBreakString(); - foreach (var notifier in _arenaNotifiers) { - notifier.NotifyArenaKill(killsCount, killerName, victimName); - notifier.NotifyArenaWin(winnerName); + notifier.NotifyArenaKill(packet.KillsCount, packet.KillerName, packet.VictimName); + notifier.NotifyArenaWin(packet.WinnerName); } return true; diff --git a/EOLib/PacketHandlers/Arena/ArenaDropHandler.cs b/EOLib/PacketHandlers/Arena/ArenaDropHandler.cs index 0bea248ee..e74f3bc27 100644 --- a/EOLib/PacketHandlers/Arena/ArenaDropHandler.cs +++ b/EOLib/PacketHandlers/Arena/ArenaDropHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Arena @@ -11,7 +12,7 @@ namespace EOLib.PacketHandlers.Arena /// "Arena is blocked" message /// [AutoMappedType] - public class ArenaDropHandler : InGameOnlyPacketHandler + public class ArenaDropHandler : InGameOnlyPacketHandler { private readonly IEnumerable _arenaNotifiers; @@ -26,11 +27,8 @@ public ArenaDropHandler(IPlayerInfoProvider playerInfoProvider, _arenaNotifiers = arenaNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(ArenaDropServerPacket packet) { - if (packet.ReadEndString().Length < 1) - return false; - foreach (var notifier in _arenaNotifiers) { notifier.NotifyArenaBusy(); diff --git a/EOLib/PacketHandlers/Arena/ArenaSpecHandler.cs b/EOLib/PacketHandlers/Arena/ArenaSpecHandler.cs index 64f2d3ccc..5985e609f 100644 --- a/EOLib/PacketHandlers/Arena/ArenaSpecHandler.cs +++ b/EOLib/PacketHandlers/Arena/ArenaSpecHandler.cs @@ -3,8 +3,9 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Arena @@ -13,7 +14,7 @@ namespace EOLib.PacketHandlers.Arena /// Arena kill message /// [AutoMappedType] - public class ArenaSpecHandler : InGameOnlyPacketHandler + public class ArenaSpecHandler : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; private readonly ICurrentMapStateRepository _currentMapStateRepository; @@ -34,40 +35,28 @@ public ArenaSpecHandler(IPlayerInfoProvider playerInfoProvider, _arenaNotifiers = arenaNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(ArenaSpecServerPacket packet) { - var playerId = packet.ReadShort(); - packet.ReadByte(); - - var playerDirection = (EODirection)packet.ReadChar(); - packet.ReadByte(); - - if (playerId == _characterRepository.MainCharacter.ID) + if (packet.PlayerId == _characterRepository.MainCharacter.ID) { - var rp = _characterRepository.MainCharacter.RenderProperties.WithDirection(playerDirection); + var rp = _characterRepository.MainCharacter.RenderProperties.WithDirection((EODirection)packet.Direction); _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithRenderProperties(rp); } - else if (_currentMapStateRepository.Characters.ContainsKey(playerId)) + else if (_currentMapStateRepository.Characters.ContainsKey(packet.PlayerId)) { - var character = _currentMapStateRepository.Characters[playerId]; - var rp = character.RenderProperties.WithDirection(playerDirection); + var character = _currentMapStateRepository.Characters[packet.PlayerId]; + var rp = character.RenderProperties.WithDirection((EODirection)packet.Direction); var newCharacter = character.WithRenderProperties(rp); _currentMapStateRepository.Characters.Update(character, newCharacter); } - else if (playerId > 0) + else if (packet.PlayerId > 0) { - _currentMapStateRepository.UnknownPlayerIDs.Add(playerId); + _currentMapStateRepository.UnknownPlayerIDs.Add(packet.PlayerId); } - var killsCount = packet.ReadInt(); - packet.ReadByte(); - - var killerName = packet.ReadBreakString(); - var victimName = packet.ReadBreakString(); - foreach (var notifier in _arenaNotifiers) { - notifier.NotifyArenaKill(killsCount, killerName, victimName); + notifier.NotifyArenaKill(packet.KillsCount, packet.KillerName, packet.VictimName); } return true; diff --git a/EOLib/PacketHandlers/Arena/ArenaUseHandler.cs b/EOLib/PacketHandlers/Arena/ArenaUseHandler.cs index 4ddf35758..a55ddaae8 100644 --- a/EOLib/PacketHandlers/Arena/ArenaUseHandler.cs +++ b/EOLib/PacketHandlers/Arena/ArenaUseHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Arena @@ -11,7 +12,7 @@ namespace EOLib.PacketHandlers.Arena /// Arena start message /// [AutoMappedType] - public class ArenaUseHandler : InGameOnlyPacketHandler + public class ArenaUseHandler : InGameOnlyPacketHandler { private readonly IEnumerable _arenaNotifiers; @@ -26,13 +27,11 @@ public ArenaUseHandler(IPlayerInfoProvider playerInfoProvider, _arenaNotifiers = arenaNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(ArenaUseServerPacket packet) { - var playersCount = packet.ReadChar(); - foreach (var notifier in _arenaNotifiers) { - notifier.NotifyArenaStart(playersCount); + notifier.NotifyArenaStart(packet.PlayersCount); } return true; diff --git a/EOLib/PacketHandlers/Attack/AttackPlayerHandler.cs b/EOLib/PacketHandlers/Attack/AttackPlayerHandler.cs index d84aed677..55ab5bf7d 100644 --- a/EOLib/PacketHandlers/Attack/AttackPlayerHandler.cs +++ b/EOLib/PacketHandlers/Attack/AttackPlayerHandler.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Attack @@ -12,7 +13,7 @@ namespace EOLib.PacketHandlers.Attack /// Sent when another player attacks /// [AutoMappedType] - public class PlayerAttackHandler : InGameOnlyPacketHandler + public class PlayerAttackHandler : InGameOnlyPacketHandler { private readonly ICurrentMapStateRepository _currentMapStateRepository; private readonly IEnumerable _otherCharacterAnimationNotifiers; @@ -30,25 +31,22 @@ public PlayerAttackHandler(IPlayerInfoProvider playerInfoProvider, _otherCharacterAnimationNotifiers = otherCharacterAnimationNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(AttackPlayerServerPacket packet) { - var playerID = packet.ReadShort(); - var direction = (EODirection)packet.ReadChar(); - - if (_currentMapStateRepository.Characters.TryGetValue(playerID, out var character)) + if (_currentMapStateRepository.Characters.TryGetValue(packet.PlayerId, out var character)) { - if (character.RenderProperties.Direction != direction) + if (character.RenderProperties.Direction != (EODirection)packet.Direction) { - var renderProperties = character.RenderProperties.WithDirection(direction); + var renderProperties = character.RenderProperties.WithDirection((EODirection)packet.Direction); _currentMapStateRepository.Characters.Update(character, character.WithRenderProperties(renderProperties)); } foreach (var notifier in _otherCharacterAnimationNotifiers) - notifier.StartOtherCharacterAttackAnimation(playerID); + notifier.StartOtherCharacterAttackAnimation(packet.PlayerId); } else { - _currentMapStateRepository.UnknownPlayerIDs.Add(playerID); + _currentMapStateRepository.UnknownPlayerIDs.Add(packet.PlayerId); } return true; diff --git a/EOLib/PacketHandlers/Avatar/AvatarAdminHandler.cs b/EOLib/PacketHandlers/Avatar/AvatarAdminHandler.cs index 566bf01a7..aef2c89f9 100644 --- a/EOLib/PacketHandlers/Avatar/AvatarAdminHandler.cs +++ b/EOLib/PacketHandlers/Avatar/AvatarAdminHandler.cs @@ -3,8 +3,9 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Avatar @@ -13,7 +14,7 @@ namespace EOLib.PacketHandlers.Avatar /// Sent when a player takes damge from a PK spell /// [AutoMappedType] - public class AvatarAdminHandler : InGameOnlyPacketHandler + public class AvatarAdminHandler : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; private readonly ICurrentMapStateRepository _currentMapStateRepository; @@ -34,15 +35,15 @@ public AvatarAdminHandler(IPlayerInfoProvider playerInfoProvider, _animationNotifiers = animationNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(AvatarAdminServerPacket packet) { - var sourcePlayerId = packet.ReadShort(); - var targetPlayerId = packet.ReadShort(); - var damage = packet.ReadThree(); - var sourcePlayerDirection = (EODirection)packet.ReadChar(); - var targetPercentHealth = packet.ReadChar(); - var targetIsDead = packet.ReadChar() != 0; - var spellId = packet.ReadShort(); + var sourcePlayerId = packet.CasterId; + var targetPlayerId = packet.VictimId; + var damage = packet.Damage; + var sourcePlayerDirection = (EODirection)packet.CasterDirection; + var targetPercentHealth = packet.HpPercentage; + var targetIsDead = packet.VictimDied; + var spellId = packet.SpellId; if (sourcePlayerId == _characterRepository.MainCharacter.ID) { diff --git a/EOLib/PacketHandlers/Avatar/AvatarAgreeHandler.cs b/EOLib/PacketHandlers/Avatar/AvatarAgreeHandler.cs index a89efd44e..29d8a95c3 100644 --- a/EOLib/PacketHandlers/Avatar/AvatarAgreeHandler.cs +++ b/EOLib/PacketHandlers/Avatar/AvatarAgreeHandler.cs @@ -2,9 +2,8 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.IO.Repositories; -using EOLib.Net; -using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Avatar { @@ -12,94 +11,22 @@ namespace EOLib.PacketHandlers.Avatar /// Sent when a character's render properties are changed /// [AutoMappedType] - public class AvatarAgreeHandler : InGameOnlyPacketHandler + public class AvatarAgreeHandler : AvatarChangeHandler { - protected readonly ICurrentMapStateRepository _currentMapStateRepository; - protected readonly ICharacterRepository _characterRepository; - protected readonly IEIFFileProvider _eifFileProvider; - public override PacketFamily Family => PacketFamily.Avatar; public override PacketAction Action => PacketAction.Agree; public AvatarAgreeHandler(IPlayerInfoProvider playerInfoProvider, ICurrentMapStateRepository currentMapStateRepository, - ICharacterRepository characterRepository, - IEIFFileProvider eifFileProvider) - : base(playerInfoProvider) + ICharacterRepository characterRepository) + : base(playerInfoProvider, currentMapStateRepository, characterRepository) { - _currentMapStateRepository = currentMapStateRepository; - _characterRepository = characterRepository; - _eifFileProvider = eifFileProvider; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(AvatarAgreeServerPacket packet) { - var playerID = packet.ReadShort(); - Character currentCharacter; - - if (_characterRepository.MainCharacter.ID == playerID) - { - currentCharacter = _characterRepository.MainCharacter; - } - else if (!_currentMapStateRepository.Characters.TryGetValue(playerID, out currentCharacter)) - { - _currentMapStateRepository.UnknownPlayerIDs.Add(playerID); - return true; - } - - var currentRenderProps = currentCharacter.RenderProperties; - - var slot = (AvatarSlot)packet.ReadChar(); - switch (slot) - { - case AvatarSlot.Clothes: - { - var sound = packet.ReadChar() == 0; //todo: sound? - - currentRenderProps = currentRenderProps - .WithBootsGraphic(packet.ReadShort()) - .WithArmorGraphic(packet.ReadShort()) - .WithHatGraphic(packet.ReadShort()) - .WithWeaponGraphic(packet.ReadShort()) - .WithShieldGraphic(packet.ReadShort()); - - break; - } - case AvatarSlot.Hair: - { - if (packet.ReadChar() != 0) //subloc -- not sure what this does - throw new MalformedPacketException("Missing expected 0 byte in updating hair packet", packet); - - currentRenderProps = currentRenderProps - .WithHairStyle(packet.ReadChar()) - .WithHairColor(packet.ReadChar()); - - break; - } - case AvatarSlot.HairColor: - { - if (packet.ReadChar() != 0) //subloc -- not sure what this does - throw new MalformedPacketException("Missing expected 0 byte in updating hair color packet", packet); - - currentRenderProps = currentRenderProps - .WithHairColor(packet.ReadChar()); - - break; - } - } - - var updatedCharacter = currentCharacter.WithRenderProperties(currentRenderProps); - - if (_characterRepository.MainCharacter.ID == playerID) - { - _characterRepository.MainCharacter = updatedCharacter; - } - else - { - _currentMapStateRepository.Characters.Update(currentCharacter, updatedCharacter); - } - + Handle(packet.Change); return true; } } diff --git a/EOLib/PacketHandlers/Avatar/AvatarChangeHandler.cs b/EOLib/PacketHandlers/Avatar/AvatarChangeHandler.cs new file mode 100644 index 000000000..899e3654b --- /dev/null +++ b/EOLib/PacketHandlers/Avatar/AvatarChangeHandler.cs @@ -0,0 +1,83 @@ +using EOLib.Domain.Character; +using EOLib.Domain.Login; +using EOLib.Domain.Map; +using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; + +namespace EOLib.PacketHandlers.Avatar +{ + public abstract class AvatarChangeHandler : InGameOnlyPacketHandler + where TPacket : IPacket + { + protected readonly ICurrentMapStateRepository _currentMapStateRepository; + protected readonly ICharacterRepository _characterRepository; + + public AvatarChangeHandler(IPlayerInfoProvider playerInfoProvider, + ICurrentMapStateRepository currentMapStateRepository, + ICharacterRepository characterRepository) + : base(playerInfoProvider) + { + _currentMapStateRepository = currentMapStateRepository; + _characterRepository = characterRepository; + } + + protected void Handle(AvatarChange change) + { + var playerID = change.PlayerId; + Character currentCharacter; + + if (_characterRepository.MainCharacter.ID == playerID) + { + currentCharacter = _characterRepository.MainCharacter; + } + else if (!_currentMapStateRepository.Characters.TryGetValue(playerID, out currentCharacter)) + { + _currentMapStateRepository.UnknownPlayerIDs.Add(playerID); + return; + } + + var currentRenderProps = currentCharacter.RenderProperties; + + switch (change.ChangeType) + { + case AvatarChangeType.Equipment: + { + var data = (AvatarChange.ChangeTypeDataEquipment)change.ChangeTypeData; + currentRenderProps = currentRenderProps + .WithBootsGraphic(data.Equipment.Boots) + .WithArmorGraphic(data.Equipment.Armor) + .WithHatGraphic(data.Equipment.Hat) + .WithWeaponGraphic(data.Equipment.Weapon) + .WithShieldGraphic(data.Equipment.Shield); + break; + } + case AvatarChangeType.Hair: + { + var data = (AvatarChange.ChangeTypeDataHair)change.ChangeTypeData; + currentRenderProps = currentRenderProps + .WithHairStyle(data.HairStyle) + .WithHairColor(data.HairColor); + break; + } + case AvatarChangeType.HairColor: + { + var data = (AvatarChange.ChangeTypeDataHairColor)change.ChangeTypeData; + currentRenderProps = currentRenderProps.WithHairColor(data.HairColor); + break; + } + } + + var updatedCharacter = currentCharacter.WithRenderProperties(currentRenderProps); + + if (_characterRepository.MainCharacter.ID == playerID) + { + _characterRepository.MainCharacter = updatedCharacter; + } + else + { + _currentMapStateRepository.Characters.Update(currentCharacter, updatedCharacter); + } + } + } +} diff --git a/EOLib/PacketHandlers/Avatar/AvatarRemoveHandler.cs b/EOLib/PacketHandlers/Avatar/AvatarRemoveHandler.cs index 9cf2ba0ed..f95d05552 100644 --- a/EOLib/PacketHandlers/Avatar/AvatarRemoveHandler.cs +++ b/EOLib/PacketHandlers/Avatar/AvatarRemoveHandler.cs @@ -1,11 +1,11 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; -using EOLib.Domain.Extensions; using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Avatar @@ -14,7 +14,7 @@ namespace EOLib.PacketHandlers.Avatar /// Sent when a player leaves the map /// [AutoMappedType] - public class AvatarRemoveHandler : InGameOnlyPacketHandler + public class AvatarRemoveHandler : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; private readonly ICurrentMapStateRepository _currentMapStateRepository; @@ -35,30 +35,21 @@ public AvatarRemoveHandler(IPlayerInfoProvider playerInfoProvider, _effectNotifiers = effectNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(AvatarRemoveServerPacket packet) { - var id = packet.ReadShort(); - - if (packet.ReadPosition < packet.Length) + if (packet.WarpEffect != null) { - var anim = (WarpAnimation)packet.ReadChar(); foreach (var notifier in _effectNotifiers) - notifier.NotifyWarpLeaveEffect(id, anim); + notifier.NotifyWarpLeaveEffect(packet.PlayerId, packet.WarpEffect.Value); } - if (_characterRepository.MainCharacter.ID == id) + if (_characterRepository.MainCharacter.ID == packet.PlayerId) { _characterRepository.HasAvatar = false; - _currentMapStateRepository.VisibleSpikeTraps.Remove(_characterRepository.MainCharacter.RenderProperties.Coordinates()); } - else if (_currentMapStateRepository.Characters.TryGetValue(id, out var character)) + else if (_currentMapStateRepository.Characters.TryGetValue(packet.PlayerId, out var character)) { _currentMapStateRepository.Characters.Remove(character); - _currentMapStateRepository.VisibleSpikeTraps.Remove(character.RenderProperties.Coordinates()); - } - else - { - _currentMapStateRepository.UnknownPlayerIDs.Add(id); } return true; diff --git a/EOLib/PacketHandlers/Avatar/AvatarReplyHandler.cs b/EOLib/PacketHandlers/Avatar/AvatarReplyHandler.cs index 5a3ed2067..49777336b 100644 --- a/EOLib/PacketHandlers/Avatar/AvatarReplyHandler.cs +++ b/EOLib/PacketHandlers/Avatar/AvatarReplyHandler.cs @@ -1,17 +1,18 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; using EOLib.Domain.Extensions; +using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; -using EOLib.Domain.Login; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Avatar { [AutoMappedType] - public class AvatarReplyHandler : InGameOnlyPacketHandler + public class AvatarReplyHandler : InGameOnlyPacketHandler { private readonly ICurrentMapStateRepository _currentStateRepository; private readonly IEnumerable _otherCharacterAnimationNotifiers; @@ -38,40 +39,49 @@ public AvatarReplyHandler(IPlayerInfoProvider playerInfoProvider, _characterRepository = characterRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(AvatarReplyServerPacket packet) { - var attackerId = packet.ReadShort(); - var victimId = packet.ReadShort(); - var damage = packet.ReadThree(); - var direction = (EODirection)packet.ReadChar(); - var hpPercentage = packet.ReadChar(); - bool dead = packet.ReadChar() != 0; + var direction = (EODirection)packet.Direction; - if (victimId == _characterRepository.MainCharacter.ID) + if (packet.VictimId == _characterRepository.MainCharacter.ID) { - _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithDamage(damage, dead); + _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithDamage(packet.Damage, packet.Dead); foreach (var notifier in _mainCharacterEventNotifiers) { - notifier.NotifyTakeDamage(damage, hpPercentage, isHeal: false); + notifier.NotifyTakeDamage(packet.Damage, packet.HpPercentage, isHeal: false); } } - else if (_currentStateRepository.Characters.TryGetValue(victimId, out var character)) + else if (_currentStateRepository.Characters.TryGetValue(packet.VictimId, out var character)) { - var updatedCharacter = character.WithDamage(damage, dead); + var updatedCharacter = character.WithDamage(packet.Damage, packet.Dead); _currentStateRepository.Characters.Update(character, updatedCharacter); foreach (var notifier in _otherCharacterEventNotifiers) { - notifier.OtherCharacterTakeDamage(victimId, hpPercentage, damage, isHeal: false); + notifier.OtherCharacterTakeDamage(packet.VictimId, packet.HpPercentage, packet.Damage, isHeal: false); } } - if (attackerId != _characterRepository.MainCharacter.ID) + + if (packet.PlayerId == _characterRepository.MainCharacter.ID) + { + _characterRepository.MainCharacter = _characterRepository.MainCharacter + .WithRenderProperties(_characterRepository.MainCharacter.RenderProperties.WithDirection(direction)); + } + else if (_currentStateRepository.Characters.TryGetValue(packet.PlayerId, out var otherCharacter)) { + _currentStateRepository.Characters.Update( + otherCharacter, + otherCharacter.WithRenderProperties(otherCharacter.RenderProperties.WithDirection(direction)) + ); foreach (var notifier in _otherCharacterAnimationNotifiers) { - notifier.StartOtherCharacterAttackAnimation(attackerId); - } + notifier.StartOtherCharacterAttackAnimation(packet.PlayerId); + } + } + else + { + _currentStateRepository.UnknownPlayerIDs.Add(packet.PlayerId); } return true; diff --git a/EOLib/PacketHandlers/Bank/BankOpenHandler.cs b/EOLib/PacketHandlers/Bank/BankOpenHandler.cs index 012f08065..c31491d1b 100644 --- a/EOLib/PacketHandlers/Bank/BankOpenHandler.cs +++ b/EOLib/PacketHandlers/Bank/BankOpenHandler.cs @@ -1,14 +1,15 @@ using AutomaticTypeMapper; using EOLib.Domain.Interact.Bank; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; namespace EOLib.PacketHandlers.Bank { [AutoMappedType] - public class BankOpenHandler : InGameOnlyPacketHandler + public class BankOpenHandler : InGameOnlyPacketHandler { private readonly IBankDataRepository _bankDataRepository; @@ -23,11 +24,11 @@ public BankOpenHandler(IPlayerInfoProvider playerInfoProvider, _bankDataRepository = bankDataRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(BankOpenServerPacket packet) { - _bankDataRepository.AccountValue = packet.ReadInt(); - _bankDataRepository.SessionID = packet.ReadThree(); - _bankDataRepository.LockerUpgrades = Option.Some(packet.ReadChar()); + _bankDataRepository.AccountValue = packet.GoldBank; + _bankDataRepository.SessionID = packet.SessionId; + _bankDataRepository.LockerUpgrades = Option.Some(packet.LockerUpgrades); return true; } diff --git a/EOLib/PacketHandlers/Bank/BankReplyHandler.cs b/EOLib/PacketHandlers/Bank/BankReplyHandler.cs index 60de0e1ab..bcb761267 100644 --- a/EOLib/PacketHandlers/Bank/BankReplyHandler.cs +++ b/EOLib/PacketHandlers/Bank/BankReplyHandler.cs @@ -3,14 +3,15 @@ using EOLib.Domain.Interact.Bank; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Bank { [AutoMappedType] - public class BankReplyHandler : InGameOnlyPacketHandler + public class BankReplyHandler : InGameOnlyPacketHandler { private const byte BuySellSfxId = 26; @@ -33,13 +34,12 @@ public BankReplyHandler(IPlayerInfoProvider playerInfoProvider, _soundNotifiers = soundNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(BankReplyServerPacket packet) { - var characterGold = packet.ReadInt(); _characterInventoryRepository.ItemInventory.RemoveWhere(x => x.ItemID == 1); - _characterInventoryRepository.ItemInventory.Add(new InventoryItem(1, characterGold)); + _characterInventoryRepository.ItemInventory.Add(new InventoryItem(1, packet.GoldInventory)); - _bankDataRepository.AccountValue = packet.ReadInt(); + _bankDataRepository.AccountValue = packet.GoldBank; foreach (var notifier in _soundNotifiers) notifier.NotifySoundEffect(BuySellSfxId); diff --git a/EOLib/PacketHandlers/Barber/BarberAgreeHandler.cs b/EOLib/PacketHandlers/Barber/BarberAgreeHandler.cs index 087ec4e0a..1b4dd2f5c 100644 --- a/EOLib/PacketHandlers/Barber/BarberAgreeHandler.cs +++ b/EOLib/PacketHandlers/Barber/BarberAgreeHandler.cs @@ -1,97 +1,77 @@ using AutomaticTypeMapper; -using EOLib.Domain.Interact; -using EOLib.Net; -using EOLib.Net.Handlers; -using System.Collections.Generic; -using EOLib.Domain.Interact.Barber; using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Domain.Notifiers; +using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Barber { [AutoMappedType] - public class BarberAgreeHandler : InGameOnlyPacketHandler + public class BarberAgreeHandler : InGameOnlyPacketHandler { - private readonly IBarberDataRepository _barberDataRepository; - private readonly IEnumerable _npcInteractionNotifiers; private readonly ICharacterRepository _characterRepository; private readonly ICurrentMapStateRepository _currentMapStateRepository; private readonly ICharacterInventoryRepository _characterInventoryRepository; public override PacketFamily Family => PacketFamily.Barber; + public override PacketAction Action => PacketAction.Agree; public BarberAgreeHandler( IPlayerInfoProvider playerInfoProvider, - IEnumerable npcInteractionNotifiers, - IBarberDataRepository barberDataRepository, ICharacterRepository characterRepository, ICurrentMapStateRepository currentMapStateRepository, ICharacterInventoryRepository characterInventoryRepository) : base(playerInfoProvider) { - _npcInteractionNotifiers = npcInteractionNotifiers; - _barberDataRepository = barberDataRepository; _characterRepository = characterRepository; _currentMapStateRepository = currentMapStateRepository; _characterInventoryRepository = characterInventoryRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(BarberAgreeServerPacket packet) { - var amount = packet.ReadInt(); - var gold = new InventoryItem(1, amount); - var playerID = packet.ReadShort(); - _characterInventoryRepository.ItemInventory.RemoveWhere(x => x.ItemID == 1); - _characterInventoryRepository.ItemInventory.Add(gold); - - var currentCharacter = _characterRepository.MainCharacter.ID == playerID - ? _characterRepository.MainCharacter - : null; + _characterInventoryRepository.ItemInventory.Add(new InventoryItem(1, packet.GoldAmount)); - if (currentCharacter == null) + if (_characterRepository.MainCharacter.ID == packet.Change.PlayerId) { - return false; + var currentCharacter = _characterRepository.MainCharacter; + _characterRepository.MainCharacter = currentCharacter.WithRenderProperties(UpdateRenderProperties(currentCharacter, packet)); } - - var currentRenderProps = currentCharacter.RenderProperties; - var slot = (AvatarSlot)packet.ReadChar(); - - switch (slot) + else if (_currentMapStateRepository.Characters.ContainsKey(packet.Change.PlayerId)) { - case AvatarSlot.Hair: - if (packet.ReadChar() != 0) - throw new MalformedPacketException("Missing expected 0 byte in updating hair packet", packet); - - currentRenderProps = currentRenderProps - .WithHairStyle(packet.ReadChar()) - .WithHairColor(packet.ReadChar()); - break; - - case AvatarSlot.HairColor: - if (packet.ReadChar() != 0) - throw new MalformedPacketException("Missing expected 0 byte in updating hair color packet", packet); - - currentRenderProps = currentRenderProps - .WithHairColor(packet.ReadChar()); - break; + var currentCharacter = _currentMapStateRepository.Characters[packet.Change.PlayerId]; + _currentMapStateRepository.Characters.Update(currentCharacter, currentCharacter.WithRenderProperties(UpdateRenderProperties(currentCharacter, packet))); } - var updatedCharacter = currentCharacter.WithRenderProperties(currentRenderProps); + return true; + } - if (_characterRepository.MainCharacter.ID == playerID) - { - _characterRepository.MainCharacter = updatedCharacter; - } - else + private CharacterRenderProperties UpdateRenderProperties(Character currentCharacter, BarberAgreeServerPacket packet) + { + var currentRenderProps = currentCharacter.RenderProperties; + switch (packet.Change.ChangeType) { - _currentMapStateRepository.Characters.Update(currentCharacter, updatedCharacter); + case AvatarChangeType.Hair: + { + var data = (AvatarChange.ChangeTypeDataHair)packet.Change.ChangeTypeData; + currentRenderProps = currentRenderProps + .WithHairStyle(data.HairStyle) + .WithHairColor(data.HairColor); + } + break; + case AvatarChangeType.HairColor: + { + var data = (AvatarChange.ChangeTypeDataHairColor)packet.Change.ChangeTypeData; + currentRenderProps = currentRenderProps + .WithHairColor(data.HairColor); + } + break; } - - return true; + return currentRenderProps; } } } diff --git a/EOLib/PacketHandlers/Barber/BarberOpenHandler.cs b/EOLib/PacketHandlers/Barber/BarberOpenHandler.cs index 70cbba4f3..505e1438d 100644 --- a/EOLib/PacketHandlers/Barber/BarberOpenHandler.cs +++ b/EOLib/PacketHandlers/Barber/BarberOpenHandler.cs @@ -1,21 +1,22 @@ using AutomaticTypeMapper; using EOLib.Domain.Interact; -using EOLib.Net; -using EOLib.Net.Handlers; -using System.Collections.Generic; using EOLib.Domain.Interact.Barber; -using EOLib.Domain.Character; using EOLib.Domain.Login; +using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Collections.Generic; namespace EOLib.PacketHandlers.Barber { [AutoMappedType] - public class BarberOpenHandler : InGameOnlyPacketHandler + public class BarberOpenHandler : InGameOnlyPacketHandler { private readonly IBarberDataRepository _barberDataRepository; private readonly IEnumerable _npcInteractionNotifiers; public override PacketFamily Family => PacketFamily.Barber; + public override PacketAction Action => PacketAction.Open; public BarberOpenHandler( @@ -28,10 +29,9 @@ public BarberOpenHandler( _barberDataRepository = barberDataRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(BarberOpenServerPacket packet) { - var sessionId = packet.ReadInt(); - _barberDataRepository.SessionID = sessionId; + _barberDataRepository.SessionID = packet.SessionId; foreach (var notifier in _npcInteractionNotifiers) { diff --git a/EOLib/PacketHandlers/Board/BoardOpenHandler.cs b/EOLib/PacketHandlers/Board/BoardOpenHandler.cs index 73e4f07f6..32bf5c0f3 100644 --- a/EOLib/PacketHandlers/Board/BoardOpenHandler.cs +++ b/EOLib/PacketHandlers/Board/BoardOpenHandler.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Interact.Board; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using System.Collections.Generic; @@ -13,7 +14,7 @@ namespace EOLib.PacketHandlers.Board /// Sent by the server when a board should be opened /// [AutoMappedType] - public class BoardOpenHandler : InGameOnlyPacketHandler + public class BoardOpenHandler : InGameOnlyPacketHandler { private readonly IBoardRepository _boardRepository; private readonly IEnumerable _userInterfaceNotifiers; @@ -31,35 +32,15 @@ public BoardOpenHandler(IPlayerInfoProvider playerInfoProvider, _userInterfaceNotifiers = userInterfaceNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(BoardOpenServerPacket packet) { - _boardRepository.BoardId = Option.Some(packet.ReadChar()); + _boardRepository.BoardId = Option.Some(packet.BoardId); - var numPosts = packet.ReadChar(); + var numPosts = packet.Posts; _boardRepository.Posts = new HashSet(); - - var chunks = new List(); - while (packet.ReadPosition < packet.Length) - { - var chunkData = new List { (byte)PacketFamily.Board, (byte)PacketAction.Open }; - while (packet.ReadPosition < packet.Length && packet.PeekByte() != 255) - chunkData.Add(packet.ReadByte()); - - if (packet.ReadPosition < packet.Length) - packet.ReadByte(); - - chunks.Add(new Packet(chunkData)); - } - - if (chunks.Count % 3 != 0 || chunks.Count / 3 != numPosts) - throw new MalformedPacketException("Unexpected number of elements in BOARD_OPEN packet", packet); - - for (int i = 0; i < chunks.Count; i += 3) + foreach (var post in packet.Posts) { - var postId = chunks[i].ReadShort(); - var author = chunks[i + 1].ReadEndString(); - var subject = chunks[i + 2].ReadEndString(); - _boardRepository.Posts.Add(new BoardPostInfo(postId, author, subject)); + _boardRepository.Posts.Add(new BoardPostInfo(post.PostId, post.Author, post.Subject)); } _boardRepository.ActivePost = Option.None(); diff --git a/EOLib/PacketHandlers/Board/BoardPlayerHandler.cs b/EOLib/PacketHandlers/Board/BoardPlayerHandler.cs index bf4103ef0..e1b771808 100644 --- a/EOLib/PacketHandlers/Board/BoardPlayerHandler.cs +++ b/EOLib/PacketHandlers/Board/BoardPlayerHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Interact.Board; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; namespace EOLib.PacketHandlers.Board @@ -11,7 +12,7 @@ namespace EOLib.PacketHandlers.Board /// Sent by the server to read a post on a board /// [AutoMappedType] - public class BoardPlayerHandler : InGameOnlyPacketHandler + public class BoardPlayerHandler : InGameOnlyPacketHandler { private readonly IBoardRepository _boardRepository; @@ -26,17 +27,14 @@ public BoardPlayerHandler(IPlayerInfoProvider playerInfoProvider, _boardRepository = boardRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(BoardPlayerServerPacket packet) { - var postId = packet.ReadShort(); - var message = packet.ReadEndString(); - _boardRepository.ActivePost.MatchSome(post => { - if (post.PostId == postId) + if (post.PostId == packet.PostId) { // EndlessClient uses \n as line split, vanilla client uses \r - _boardRepository.ActivePostMessage = Option.Some(message.Replace('\r', '\n')); + _boardRepository.ActivePostMessage = Option.Some(packet.PostBody.Replace('\r', '\n')); } }); diff --git a/EOLib/PacketHandlers/Book/BookReplyHandler.cs b/EOLib/PacketHandlers/Book/BookReplyHandler.cs index 2690ff8b9..86c69aade 100644 --- a/EOLib/PacketHandlers/Book/BookReplyHandler.cs +++ b/EOLib/PacketHandlers/Book/BookReplyHandler.cs @@ -1,11 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; using EOLib.Domain.Login; -using EOLib.Domain.Online; -using EOLib.Net; using EOLib.Net.Handlers; -using System; -using System.Collections.Generic; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Paperdoll { @@ -13,7 +11,7 @@ namespace EOLib.PacketHandlers.Paperdoll /// Sets book information for a given player /// [AutoMappedType] - internal class BookReplyHandler : InGameOnlyPacketHandler + internal class BookReplyHandler : InGameOnlyPacketHandler { private readonly IPaperdollRepository _paperdollRepository; @@ -28,49 +26,27 @@ public BookReplyHandler(IPlayerInfoProvider playerInfoProvider, _paperdollRepository = paperdollRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(BookReplyServerPacket packet) { - var name = packet.ReadBreakString(); - var home = packet.ReadBreakString(); - var partner = packet.ReadBreakString(); - var title = packet.ReadBreakString(); - var guild = packet.ReadBreakString(); - var rank = packet.ReadBreakString(); - - var playerID = packet.ReadShort(); - var clas = packet.ReadChar(); - var gender = packet.ReadChar(); - - var adminLevel = packet.ReadChar(); - - var iconType = (OnlineIcon)packet.ReadChar(); - - if (packet.ReadByte() != 255) - return false; - - var questNames = new List(); - while (packet.ReadPosition < packet.Length) - questNames.Add(packet.ReadBreakString()); - - var paperdollData = _paperdollRepository.VisibleCharacterPaperdolls.ContainsKey(playerID) - ? _paperdollRepository.VisibleCharacterPaperdolls[playerID] + var paperdollData = _paperdollRepository.VisibleCharacterPaperdolls.ContainsKey(packet.Details.PlayerId) + ? _paperdollRepository.VisibleCharacterPaperdolls[packet.Details.PlayerId] : new PaperdollData(); paperdollData = paperdollData - .WithName(name) - .WithHome(home) - .WithPartner(partner) - .WithTitle(title) - .WithGuild(guild) - .WithRank(rank) - .WithPlayerID(playerID) - .WithClass(clas) - .WithGender(gender) - .WithAdminLevel((AdminLevel)adminLevel) - .WithIcon(iconType) - .WithQuestNames(questNames); - - _paperdollRepository.VisibleCharacterPaperdolls[playerID] = paperdollData; + .WithName(packet.Details.Name) + .WithHome(packet.Details.Home) + .WithPartner(packet.Details.Partner) + .WithTitle(packet.Details.Title) + .WithGuild(packet.Details.Guild) + .WithRank(packet.Details.GuildRank) + .WithPlayerID(packet.Details.PlayerId) + .WithClass(packet.Details.ClassId) + .WithGender((int)packet.Details.Gender) + .WithAdminLevel(packet.Details.Admin) + .WithIcon(packet.Icon) + .WithQuestNames(packet.QuestNames); + + _paperdollRepository.VisibleCharacterPaperdolls[packet.Details.PlayerId] = paperdollData; return true; } diff --git a/EOLib/PacketHandlers/Cast/CastAcceptHandler.cs b/EOLib/PacketHandlers/Cast/CastAcceptHandler.cs index c6e8121c6..a0b6312d8 100644 --- a/EOLib/PacketHandlers/Cast/CastAcceptHandler.cs +++ b/EOLib/PacketHandlers/Cast/CastAcceptHandler.cs @@ -1,11 +1,13 @@ -using System.Collections.Generic; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.PacketHandlers.NPC; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using Optional; +using System.Collections.Generic; namespace EOLib.PacketHandlers.Cast { @@ -13,8 +15,10 @@ namespace EOLib.PacketHandlers.Cast /// Sent when the main character levels up from killing an NPC with a spell /// [AutoMappedType] - public class CastAcceptHandler : NPCAcceptHandler + public class CastAcceptHandler : NPCDeathHandler { + private readonly IEnumerable _emoteNotifiers; + public override PacketFamily Family => PacketFamily.Cast; public override PacketAction Action => PacketAction.Accept; @@ -27,8 +31,21 @@ public CastAcceptHandler(IPlayerInfoProvider playerInfoProvider, IEnumerable mainCharacterEventNotifiers, IEnumerable otherCharacterAnimationNotifiers, IEnumerable emoteNotifiers) - : base(playerInfoProvider, currentMapStateRepository, characterRepository, characterSessionRepository, - npcAnimationNotifiers, mainCharacterEventNotifiers, otherCharacterAnimationNotifiers, emoteNotifiers) - { } + : base(playerInfoProvider, characterRepository, currentMapStateRepository, characterSessionRepository, + npcAnimationNotifiers, mainCharacterEventNotifiers, otherCharacterAnimationNotifiers) + { + _emoteNotifiers = emoteNotifiers; + } + + public override bool HandlePacket(CastAcceptServerPacket packet) + { + DeathWorkflowSpell(packet.NpcKilledData, packet.Experience, Option.Some((packet.SpellId, packet.CasterTp))); + ApplyStats(packet.LevelUp); + + foreach (var notifier in _emoteNotifiers) + notifier.NotifyEmote(_characterRepository.MainCharacter.ID, Domain.Character.Emote.LevelUp); + + return true; + } } } diff --git a/EOLib/PacketHandlers/Cast/CastReplyHandler.cs b/EOLib/PacketHandlers/Cast/CastReplyHandler.cs index 77323a2c2..cce7feaea 100644 --- a/EOLib/PacketHandlers/Cast/CastReplyHandler.cs +++ b/EOLib/PacketHandlers/Cast/CastReplyHandler.cs @@ -3,8 +3,9 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.PacketHandlers.NPC; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Cast @@ -13,7 +14,7 @@ namespace EOLib.PacketHandlers.Cast /// Sent when an NPC takes damage from a spell cast /// [AutoMappedType] - public class CastReplyHandler : NPCTakeDamageHandler + public class CastReplyHandler : NPCTakeDamageHandler { public override PacketFamily Family => PacketFamily.Cast; @@ -23,5 +24,13 @@ public CastReplyHandler(IPlayerInfoProvider playerInfoProvider, IEnumerable npcNotifiers, IEnumerable otherCharacterAnimationNotifiers) : base(playerInfoProvider, characterRepository, currentMapStateRepository, npcNotifiers, otherCharacterAnimationNotifiers) { } + + public override bool HandlePacket(CastReplyServerPacket packet) + { + Handle(packet.CasterId, (EODirection)packet.CasterDirection, + packet.NpcIndex, packet.Damage, packet.HpPercentage, + packet.SpellId, packet.CasterTp); + return true; + } } } diff --git a/EOLib/PacketHandlers/Cast/CastSpecHandler.cs b/EOLib/PacketHandlers/Cast/CastSpecHandler.cs index fcca34a4d..c29e5b49a 100644 --- a/EOLib/PacketHandlers/Cast/CastSpecHandler.cs +++ b/EOLib/PacketHandlers/Cast/CastSpecHandler.cs @@ -3,8 +3,10 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.PacketHandlers.NPC; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using Optional; using System.Collections.Generic; namespace EOLib.PacketHandlers.Cast @@ -16,21 +18,27 @@ namespace EOLib.PacketHandlers.Cast /// that is done from NPCLeaveMapHandler.HandlePlacket (see if packet.Family == PacketFamily.Cast) blocks /// [AutoMappedType] - public class CastSpecHandler : NPCSpecHandler + public class CastSpecHandler : NPCDeathHandler { public override PacketFamily Family => PacketFamily.Cast; public override PacketAction Action => PacketAction.Spec; public CastSpecHandler(IPlayerInfoProvider playerInfoProvider, - ICurrentMapStateRepository currentMapStateRepository, ICharacterRepository characterRepository, + ICurrentMapStateRepository currentMapStateRepository, ICharacterSessionRepository characterSessionRepository, IEnumerable npcAnimationNotifiers, IEnumerable mainCharacterEventNotifiers, IEnumerable otherCharacterAnimationNotifiers) - : base(playerInfoProvider, currentMapStateRepository, characterRepository, characterSessionRepository, + : base(playerInfoProvider, characterRepository, currentMapStateRepository, characterSessionRepository, npcAnimationNotifiers, mainCharacterEventNotifiers, otherCharacterAnimationNotifiers) { } + + public override bool HandlePacket(CastSpecServerPacket packet) + { + DeathWorkflowSpell(packet.NpcKilledData, packet.Experience, Option.Some((packet.SpellId, packet.CasterTp))); + return true; + } } } diff --git a/EOLib/PacketHandlers/Chair/ChairCloseHandler.cs b/EOLib/PacketHandlers/Chair/ChairCloseHandler.cs index bb6ed481c..a157f2543 100644 --- a/EOLib/PacketHandlers/Chair/ChairCloseHandler.cs +++ b/EOLib/PacketHandlers/Chair/ChairCloseHandler.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; using EOLib.PacketHandlers.Sit; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Chair { @@ -11,13 +12,21 @@ namespace EOLib.PacketHandlers.Chair /// Handle the main player standing up from a chair /// [AutoMappedType] - public class ChairCloseHandler : SitCloseHandler + public class ChairCloseHandler : PlayerStandHandlerBase { public override PacketFamily Family => PacketFamily.Chair; + public override PacketAction Action => PacketAction.Close; + public ChairCloseHandler(IPlayerInfoProvider playerInfoProvider, ICharacterRepository characterRepository, ICurrentMapStateRepository currentMapStateRepository) : base(playerInfoProvider, characterRepository, currentMapStateRepository) { } + + public override bool HandlePacket(ChairCloseServerPacket packet) + { + Handle(packet.PlayerId, packet.Coords.X, packet.Coords.Y); + return true; + } } } diff --git a/EOLib/PacketHandlers/Chair/ChairPlayerHandler.cs b/EOLib/PacketHandlers/Chair/ChairPlayerHandler.cs index dc567adab..8434bc759 100644 --- a/EOLib/PacketHandlers/Chair/ChairPlayerHandler.cs +++ b/EOLib/PacketHandlers/Chair/ChairPlayerHandler.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; using EOLib.PacketHandlers.Sit; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Chair { @@ -11,7 +12,7 @@ namespace EOLib.PacketHandlers.Chair /// Handle a player sitting in a chair /// [AutoMappedType] - public class ChairPlayerHandler : PlayerSitHandlerBase + public class ChairPlayerHandler : PlayerSitHandlerBase { public override PacketFamily Family => PacketFamily.Chair; @@ -19,5 +20,11 @@ public ChairPlayerHandler(IPlayerInfoProvider playerInfoProvider, ICharacterRepository characterRepository, ICurrentMapStateRepository currentMapStateRepository) : base(playerInfoProvider, characterRepository, currentMapStateRepository) { } + + public override bool HandlePacket(ChairPlayerServerPacket packet) + { + Handle(packet.PlayerId, packet.Coords.X, packet.Coords.Y, (EODirection)packet.Direction); + return true; + } } } diff --git a/EOLib/PacketHandlers/Chair/ChairRemoveHandler.cs b/EOLib/PacketHandlers/Chair/ChairRemoveHandler.cs new file mode 100644 index 000000000..3c1be6003 --- /dev/null +++ b/EOLib/PacketHandlers/Chair/ChairRemoveHandler.cs @@ -0,0 +1,32 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Character; +using EOLib.Domain.Login; +using EOLib.Domain.Map; +using EOLib.PacketHandlers.Sit; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; + +namespace EOLib.PacketHandlers.Chair +{ + /// + /// Handle another player standing up from a chair + /// + [AutoMappedType] + public class ChairRemoveHandler : PlayerStandHandlerBase + { + public override PacketFamily Family => PacketFamily.Chair; + + public override PacketAction Action => PacketAction.Remove; + + public ChairRemoveHandler(IPlayerInfoProvider playerInfoProvider, + ICharacterRepository characterRepository, + ICurrentMapStateRepository currentMapStateRepository) + : base(playerInfoProvider, characterRepository, currentMapStateRepository) { } + + public override bool HandlePacket(ChairRemoveServerPacket packet) + { + Handle(packet.PlayerId, packet.Coords.X, packet.Coords.Y); + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Chair/ChairReplyHandler.cs b/EOLib/PacketHandlers/Chair/ChairReplyHandler.cs new file mode 100644 index 000000000..4b53e494e --- /dev/null +++ b/EOLib/PacketHandlers/Chair/ChairReplyHandler.cs @@ -0,0 +1,32 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Character; +using EOLib.Domain.Login; +using EOLib.Domain.Map; +using EOLib.PacketHandlers.Sit; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; + +namespace EOLib.PacketHandlers.Chair +{ + /// + /// Handle your player sitting in a chair + /// + [AutoMappedType] + public class ChairReplyHandler : PlayerSitHandlerBase + { + public override PacketFamily Family => PacketFamily.Chair; + + public override PacketAction Action => PacketAction.Reply; + + public ChairReplyHandler(IPlayerInfoProvider playerInfoProvider, + ICharacterRepository characterRepository, + ICurrentMapStateRepository currentMapStateRepository) + : base(playerInfoProvider, characterRepository, currentMapStateRepository) { } + + public override bool HandlePacket(ChairReplyServerPacket packet) + { + Handle(packet.PlayerId, packet.Coords.X, packet.Coords.Y, (EODirection)packet.Direction); + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Chat/AdminMessageHandler.cs b/EOLib/PacketHandlers/Chat/AdminMessageHandler.cs index ea1ad1084..5984ddab7 100644 --- a/EOLib/PacketHandlers/Chat/AdminMessageHandler.cs +++ b/EOLib/PacketHandlers/Chat/AdminMessageHandler.cs @@ -2,13 +2,14 @@ using EOLib.Domain.Chat; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Chat { [AutoMappedType] - public class AdminMessageHandler : PlayerChatByNameBase + public class AdminMessageHandler : PlayerChatByNameBase { private readonly IChatRepository _chatRepository; private readonly IEnumerable _chatEventNotifiers; @@ -24,6 +25,11 @@ public AdminMessageHandler(IPlayerInfoProvider playerInfoProvider, _chatEventNotifiers = chatEventNotifiers; } + public override bool HandlePacket(TalkAdminServerPacket packet) + { + return Handle(packet.PlayerName, packet.Message); + } + protected override void PostChat(string name, string message) { var data = new ChatData(ChatTab.Group, name, message, ChatIcon.HGM, ChatColor.Admin); diff --git a/EOLib/PacketHandlers/Chat/AnnounceMessageHandler.cs b/EOLib/PacketHandlers/Chat/AnnounceMessageHandler.cs index c8f63708d..d1da864f0 100644 --- a/EOLib/PacketHandlers/Chat/AnnounceMessageHandler.cs +++ b/EOLib/PacketHandlers/Chat/AnnounceMessageHandler.cs @@ -1,14 +1,15 @@ -using System.Collections.Generic; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EOLib.Domain.Chat; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Collections.Generic; namespace EOLib.PacketHandlers.Chat { [AutoMappedType] - public class AnnounceMessageHandler : PlayerChatByNameBase + public class AnnounceMessageHandler : PlayerChatByNameBase { private readonly IChatRepository _chatRepository; private readonly IEnumerable _otherCharacterEventNotifiers; @@ -27,6 +28,11 @@ public AnnounceMessageHandler(IPlayerInfoProvider playerInfoProvider, _chatEventNotifiers = chatEventNotifiers; } + public override bool HandlePacket(TalkAnnounceServerPacket packet) + { + return Handle(packet.PlayerName, packet.Message); + } + protected override void PostChat(string name, string message) { var data = new ChatData(ChatTab.Global, name, message, ChatIcon.GlobalAnnounce, ChatColor.ServerGlobal); diff --git a/EOLib/PacketHandlers/Chat/GlobalMessageHandler.cs b/EOLib/PacketHandlers/Chat/GlobalMessageHandler.cs index 332cde905..00035709c 100644 --- a/EOLib/PacketHandlers/Chat/GlobalMessageHandler.cs +++ b/EOLib/PacketHandlers/Chat/GlobalMessageHandler.cs @@ -1,16 +1,17 @@ using AutomaticTypeMapper; using EOLib.Domain.Chat; using EOLib.Domain.Login; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Chat { [AutoMappedType] - public class GlobalMessageHandler : PlayerChatByNameBase + public class GlobalMessageHandler : PlayerChatByNameBase { private readonly IChatRepository _chatRepository; - public override PacketAction Action => PacketAction.Message; + public override PacketAction Action => PacketAction.Msg; public GlobalMessageHandler(IPlayerInfoProvider playerInfoProvider, IChatRepository chatRepository) @@ -19,6 +20,11 @@ public GlobalMessageHandler(IPlayerInfoProvider playerInfoProvider, _chatRepository = chatRepository; } + public override bool HandlePacket(TalkMsgServerPacket packet) + { + return Handle(packet.PlayerName, packet.Message); + } + protected override void PostChat(string name, string message) { var data = new ChatData(ChatTab.Global, name, message, ChatIcon.GlobalAnnounce); diff --git a/EOLib/PacketHandlers/Chat/GroupChatHandler.cs b/EOLib/PacketHandlers/Chat/GroupChatHandler.cs index aebc689c9..aa14e4adb 100644 --- a/EOLib/PacketHandlers/Chat/GroupChatHandler.cs +++ b/EOLib/PacketHandlers/Chat/GroupChatHandler.cs @@ -1,16 +1,17 @@ -using System.Collections.Generic; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EOLib.Domain.Character; using EOLib.Domain.Chat; using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Collections.Generic; namespace EOLib.PacketHandlers.Chat { [AutoMappedType] - public class GroupChatHandler : PlayerChatByIDHandler + public class GroupChatHandler : PlayerChatByIDHandler { private readonly IChatRepository _chatRepository; private readonly IEnumerable _otherCharacterEventNotifiers; @@ -19,33 +20,36 @@ public class GroupChatHandler : PlayerChatByIDHandler public override PacketAction Action => PacketAction.Open; public GroupChatHandler(IPlayerInfoProvider playerInfoProvider, - ICurrentMapStateProvider currentMapStateProvider, + ICurrentMapStateRepository currentMapStateRepository, ICharacterProvider characterProvider, IChatRepository chatRepository, IEnumerable otherCharacterEventNotifiers, IEnumerable chatEventNotifiers) - : base(playerInfoProvider, currentMapStateProvider, characterProvider) + : base(playerInfoProvider, currentMapStateRepository, characterProvider) { _chatRepository = chatRepository; _otherCharacterEventNotifiers = otherCharacterEventNotifiers; _chatEventNotifiers = chatEventNotifiers; } - protected override void DoTalk(IPacket packet, Character character) + public override bool HandlePacket(TalkOpenServerPacket packet) { - var message = packet.ReadBreakString(); + return Handle(packet, packet.PlayerId); + } - var localChatData = new ChatData(ChatTab.Local, character.Name, message, ChatIcon.PlayerPartyDark, ChatColor.PM); + protected override void DoTalk(TalkOpenServerPacket packet, Character character) + { + var localChatData = new ChatData(ChatTab.Local, character.Name, packet.Message, ChatIcon.PlayerPartyDark, ChatColor.PM); _chatRepository.AllChat[ChatTab.Local].Add(localChatData); - var chatData = new ChatData(ChatTab.Group, character.Name, message, ChatIcon.PlayerPartyDark); + var chatData = new ChatData(ChatTab.Group, character.Name, packet.Message, ChatIcon.PlayerPartyDark); _chatRepository.AllChat[ChatTab.Group].Add(chatData); foreach (var notifier in _otherCharacterEventNotifiers) - notifier.OtherCharacterSaySomethingToGroup(character.ID, message); + notifier.OtherCharacterSaySomethingToGroup(character.ID, packet.Message); foreach (var notifier in _chatEventNotifiers) notifier.NotifyChatReceived(ChatEventType.Group); } } -} \ No newline at end of file +} diff --git a/EOLib/PacketHandlers/Chat/GuildMessageHandler.cs b/EOLib/PacketHandlers/Chat/GuildMessageHandler.cs index 6b0bc1765..a790e820b 100644 --- a/EOLib/PacketHandlers/Chat/GuildMessageHandler.cs +++ b/EOLib/PacketHandlers/Chat/GuildMessageHandler.cs @@ -1,12 +1,13 @@ using AutomaticTypeMapper; using EOLib.Domain.Chat; using EOLib.Domain.Login; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Chat { [AutoMappedType] - public class GuildMessageHandler : PlayerChatByNameBase + public class GuildMessageHandler : PlayerChatByNameBase { private readonly IChatRepository _chatRepository; @@ -19,6 +20,11 @@ public GuildMessageHandler(IPlayerInfoProvider playerInfoProvider, _chatRepository = chatRepository; } + public override bool HandlePacket(TalkRequestServerPacket packet) + { + return Handle(packet.PlayerName, packet.Message); + } + protected override void PostChat(string name, string message) { var data = new ChatData(ChatTab.Group, name, message); diff --git a/EOLib/PacketHandlers/Chat/MuteHandler.cs b/EOLib/PacketHandlers/Chat/MuteHandler.cs index 4fe79ecbe..4ae521879 100644 --- a/EOLib/PacketHandlers/Chat/MuteHandler.cs +++ b/EOLib/PacketHandlers/Chat/MuteHandler.cs @@ -1,14 +1,15 @@ -using System.Collections.Generic; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Collections.Generic; namespace EOLib.PacketHandlers.Chat { [AutoMappedType] - public class MuteHandler : InGameOnlyPacketHandler + public class MuteHandler : InGameOnlyPacketHandler { private readonly IEnumerable _chatEventNotifiers; @@ -23,9 +24,9 @@ public MuteHandler(IPlayerInfoProvider playerInfoProvider, _chatEventNotifiers = chatEventNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(TalkSpecServerPacket packet) { - var adminName = packet.ReadEndString(); + var adminName = packet.AdminName; adminName = char.ToUpper(adminName[0]) + adminName.Substring(1).ToLower(); foreach (var notifier in _chatEventNotifiers) diff --git a/EOLib/PacketHandlers/Chat/PlayerChatByIDHandler.cs b/EOLib/PacketHandlers/Chat/PlayerChatByIDHandler.cs index 5d5804309..6921dbb51 100644 --- a/EOLib/PacketHandlers/Chat/PlayerChatByIDHandler.cs +++ b/EOLib/PacketHandlers/Chat/PlayerChatByIDHandler.cs @@ -1,34 +1,34 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; namespace EOLib.PacketHandlers.Chat { - public abstract class PlayerChatByIDHandler : InGameOnlyPacketHandler + public abstract class PlayerChatByIDHandler : InGameOnlyPacketHandler + where TPacket : IPacket { - private readonly ICurrentMapStateProvider _currentMapStateProvider; + private readonly ICurrentMapStateRepository _currentMapStateRepository; private readonly ICharacterProvider _characterProvider; public override PacketFamily Family => PacketFamily.Talk; protected PlayerChatByIDHandler(IPlayerInfoProvider playerInfoProvider, - ICurrentMapStateProvider currentMapStateProvider, + ICurrentMapStateRepository currentMapStateRepository, ICharacterProvider characterProvider) : base(playerInfoProvider) { - _currentMapStateProvider = currentMapStateProvider; + _currentMapStateRepository = currentMapStateRepository; _characterProvider = characterProvider; } - public override bool HandlePacket(IPacket packet) + protected bool Handle(TPacket packet, int fromPlayerID) { - var fromPlayerID = packet.ReadShort(); - if (!_currentMapStateProvider.Characters.TryGetValue(fromPlayerID, out var character) && + if (!_currentMapStateRepository.Characters.TryGetValue(fromPlayerID, out var character) && _characterProvider.MainCharacter.ID != fromPlayerID) { - _currentMapStateProvider.UnknownPlayerIDs.Add(fromPlayerID); + _currentMapStateRepository.UnknownPlayerIDs.Add(fromPlayerID); return true; } @@ -40,6 +40,6 @@ public override bool HandlePacket(IPacket packet) return true; } - protected abstract void DoTalk(IPacket packet, Character character); + protected abstract void DoTalk(TPacket packet, Character character); } } diff --git a/EOLib/PacketHandlers/Chat/PlayerChatByNameBase.cs b/EOLib/PacketHandlers/Chat/PlayerChatByNameBase.cs index 8cb44e9f4..3f81df9c4 100644 --- a/EOLib/PacketHandlers/Chat/PlayerChatByNameBase.cs +++ b/EOLib/PacketHandlers/Chat/PlayerChatByNameBase.cs @@ -1,21 +1,19 @@ using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; namespace EOLib.PacketHandlers.Chat { - public abstract class PlayerChatByNameBase : InGameOnlyPacketHandler + public abstract class PlayerChatByNameBase : InGameOnlyPacketHandler + where TPacket : IPacket { public override PacketFamily Family => PacketFamily.Talk; protected PlayerChatByNameBase(IPlayerInfoProvider playerInfoProvider) : base(playerInfoProvider) { } - public override bool HandlePacket(IPacket packet) + protected bool Handle(string name, string message) { - var name = packet.ReadBreakString(); - var message = packet.ReadBreakString(); - name = char.ToUpper(name[0]) + name.Substring(1).ToLower(); PostChat(name, message); diff --git a/EOLib/PacketHandlers/Chat/PrivateMessageHandler.cs b/EOLib/PacketHandlers/Chat/PrivateMessageHandler.cs index f9aa0d323..934bc338a 100644 --- a/EOLib/PacketHandlers/Chat/PrivateMessageHandler.cs +++ b/EOLib/PacketHandlers/Chat/PrivateMessageHandler.cs @@ -1,15 +1,16 @@ -using System; -using System.Collections.Generic; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EOLib.Domain.Chat; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System; +using System.Collections.Generic; namespace EOLib.PacketHandlers.Chat { [AutoMappedType] - public class PrivateMessageHandler : PlayerChatByNameBase + public class PrivateMessageHandler : PlayerChatByNameBase { private readonly IChatRepository _chatRepository; private readonly IEnumerable _chatEventNotifiers; @@ -25,6 +26,11 @@ public PrivateMessageHandler(IPlayerInfoProvider playerInfoProvider, _chatEventNotifiers = chatEventNotifiers; } + public override bool HandlePacket(TalkTellServerPacket packet) + { + return Handle(packet.PlayerName, packet.Message); + } + protected override void PostChat(string name, string message) { var localData = new ChatData(ChatTab.Local, name, message, ChatIcon.Note, ChatColor.PM, log: false); diff --git a/EOLib/PacketHandlers/Chat/PrivateMessageTargetNotFound.cs b/EOLib/PacketHandlers/Chat/PrivateMessageTargetNotFound.cs index 8ffb18543..0b7bc046b 100644 --- a/EOLib/PacketHandlers/Chat/PrivateMessageTargetNotFound.cs +++ b/EOLib/PacketHandlers/Chat/PrivateMessageTargetNotFound.cs @@ -1,19 +1,18 @@ -using System.Collections.Generic; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EOLib.Domain.Chat; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; using EOLib.Localization; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Collections.Generic; namespace EOLib.PacketHandlers.Chat { [AutoMappedType] - public class PrivateMessageTargetNotFound : InGameOnlyPacketHandler + public class PrivateMessageTargetNotFound : InGameOnlyPacketHandler { - private const int TALK_NOTFOUND = 1; - private readonly IChatRepository _chatRepository; private readonly ILocalizedStringFinder _localizedStringFinder; private readonly IEnumerable _chatEventNotifiers; @@ -33,13 +32,12 @@ public PrivateMessageTargetNotFound(IPlayerInfoProvider playerInfoProvider, _chatEventNotifiers = chatEventNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(TalkReplyServerPacket packet) { - var response = packet.ReadShort(); - if (response != TALK_NOTFOUND) - return false; + if (packet.ReplyCode != TalkReply.NotFound) + return true; - var from = packet.ReadEndString(); + var from = packet.Name; from = char.ToUpper(from[0]) + from.Substring(1).ToLower(); var sysMessage = _localizedStringFinder.GetString(EOResourceID.SYS_CHAT_PM_PLAYER_COULD_NOT_BE_FOUND); var message = $"{@from} {sysMessage}"; diff --git a/EOLib/PacketHandlers/Chat/PublicChatHandler.cs b/EOLib/PacketHandlers/Chat/PublicChatHandler.cs index 12c849cd5..4a22f8746 100644 --- a/EOLib/PacketHandlers/Chat/PublicChatHandler.cs +++ b/EOLib/PacketHandlers/Chat/PublicChatHandler.cs @@ -1,16 +1,17 @@ -using System.Collections.Generic; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EOLib.Domain.Character; using EOLib.Domain.Chat; using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Collections.Generic; namespace EOLib.PacketHandlers.Chat { [AutoMappedType] - public class PublicChatHandler : PlayerChatByIDHandler + public class PublicChatHandler : PlayerChatByIDHandler { private readonly IChatRepository _chatRepository; private readonly IEnumerable _notifiers; @@ -18,25 +19,28 @@ public class PublicChatHandler : PlayerChatByIDHandler public override PacketAction Action => PacketAction.Player; public PublicChatHandler(IPlayerInfoProvider playerInfoProvider, - ICurrentMapStateProvider currentMapStateProvider, + ICurrentMapStateRepository currentMapStateRepository, ICharacterProvider characterProvider, IChatRepository chatRepository, IEnumerable notifiers) - : base(playerInfoProvider, currentMapStateProvider, characterProvider) + : base(playerInfoProvider, currentMapStateRepository, characterProvider) { _chatRepository = chatRepository; _notifiers = notifiers; } - protected override void DoTalk(IPacket packet, Character character) + public override bool HandlePacket(TalkPlayerServerPacket packet) { - var message = packet.ReadEndString(); + return Handle(packet, packet.PlayerId); + } - var chatData = new ChatData(ChatTab.Local, character.Name, message, ChatIcon.SpeechBubble); + protected override void DoTalk(TalkPlayerServerPacket packet, Character character) + { + var chatData = new ChatData(ChatTab.Local, character.Name, packet.Message, ChatIcon.SpeechBubble); _chatRepository.AllChat[ChatTab.Local].Add(chatData); foreach (var notifier in _notifiers) - notifier.OtherCharacterSaySomething(character.ID, message); + notifier.OtherCharacterSaySomething(character.ID, packet.Message); } } } \ No newline at end of file diff --git a/EOLib/PacketHandlers/Chat/TalkServerHandler.cs b/EOLib/PacketHandlers/Chat/TalkServerHandler.cs index a10430fbd..82c871a8c 100644 --- a/EOLib/PacketHandlers/Chat/TalkServerHandler.cs +++ b/EOLib/PacketHandlers/Chat/TalkServerHandler.cs @@ -1,16 +1,15 @@ using AutomaticTypeMapper; -using EOLib.Domain.Chat; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Localization; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Chat { [AutoMappedType] - public class TalkServerHandler : InGameOnlyPacketHandler + public class TalkServerHandler : InGameOnlyPacketHandler { private readonly IEnumerable _chatEventNotifiers; @@ -25,13 +24,11 @@ public TalkServerHandler(IPlayerInfoProvider playerInfoProvider, _chatEventNotifiers = chatEventNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(TalkServerServerPacket packet) { - var serverMessage = packet.ReadEndString(); - foreach (var notifier in _chatEventNotifiers) { - notifier.NotifyServerMessage(serverMessage); + notifier.NotifyServerMessage(packet.Message); } return true; diff --git a/EOLib/PacketHandlers/Chest/ChestAgreeHandler.cs b/EOLib/PacketHandlers/Chest/ChestAgreeHandler.cs index 541e31906..f6f1fdd72 100644 --- a/EOLib/PacketHandlers/Chest/ChestAgreeHandler.cs +++ b/EOLib/PacketHandlers/Chest/ChestAgreeHandler.cs @@ -1,14 +1,16 @@ using AutomaticTypeMapper; -using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Collections.Generic; +using System.Linq; namespace EOLib.PacketHandlers.Chest { [AutoMappedType] - public class ChestAgreeHandler : InGameOnlyPacketHandler + public class ChestAgreeHandler : InGameOnlyPacketHandler { private readonly IChestDataRepository _chestDataRepository; @@ -23,14 +25,9 @@ public ChestAgreeHandler(IPlayerInfoProvider playerInfoProvider, _chestDataRepository = chestDataRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(ChestAgreeServerPacket packet) { - _chestDataRepository.Items.Clear(); - - int i = 0; - while (packet.ReadPosition < packet.Length) - _chestDataRepository.Items.Add(new ChestItem(packet.ReadShort(), packet.ReadThree(), i++)); - + _chestDataRepository.Items = new HashSet(packet.Items.Select((x, i) => new ChestItem(x.Id, x.Amount, i))); return true; } } diff --git a/EOLib/PacketHandlers/Chest/ChestCloseHandler.cs b/EOLib/PacketHandlers/Chest/ChestCloseHandler.cs new file mode 100644 index 000000000..75caeae5b --- /dev/null +++ b/EOLib/PacketHandlers/Chest/ChestCloseHandler.cs @@ -0,0 +1,42 @@ +using EOLib.Domain.Login; +using EOLib.Domain.Notifiers; +using EOLib.IO.Map; +using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Collections.Generic; + +namespace EOLib.PacketHandlers.Chest +{ + public class ChestCloseHandler : InGameOnlyPacketHandler + { + private readonly IEnumerable _chestEventNotifiers; + + public override PacketFamily Family => PacketFamily.Chest; + + public override PacketAction Action => PacketAction.Close; + + public ChestCloseHandler(IPlayerInfoProvider playerInfoProvider, + IEnumerable chestEventNotifiers) + : base(playerInfoProvider) + { + _chestEventNotifiers = chestEventNotifiers; + } + + public override bool HandlePacket(ChestCloseServerPacket packet) + { + if (packet.ByteSize < 2) + { + foreach (var notifier in _chestEventNotifiers) + notifier.NotifyChestBroken(); + } + else + { + foreach (var notifier in _chestEventNotifiers) + notifier.NotifyChestLocked((ChestKey)(packet.Key ?? 0)); + } + + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Chest/ChestGetHandler.cs b/EOLib/PacketHandlers/Chest/ChestGetHandler.cs index 60037abc1..4cf31b4a9 100644 --- a/EOLib/PacketHandlers/Chest/ChestGetHandler.cs +++ b/EOLib/PacketHandlers/Chest/ChestGetHandler.cs @@ -2,8 +2,8 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; -using Optional.Collections; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Chest { @@ -11,11 +11,8 @@ namespace EOLib.PacketHandlers.Chest /// Handler for CHEST_GET packet, sent as confirmation to character that item is being taken /// [AutoMappedType] - public class ChestGetHandler : ChestAgreeHandler + public class ChestGetHandler : ChestItemUpdateHandler { - private readonly ICharacterRepository _characterRepository; - private readonly ICharacterInventoryRepository _characterInventoryRepository; - public override PacketFamily Family => PacketFamily.Chest; public override PacketAction Action => PacketAction.Get; @@ -24,59 +21,14 @@ public ChestGetHandler(IPlayerInfoProvider playerInfoProvider, IChestDataRepository chestDataRepository, ICharacterRepository characterRepository, ICharacterInventoryRepository characterInventoryRepository) - : base(playerInfoProvider, chestDataRepository) - { - _characterRepository = characterRepository; - _characterInventoryRepository = characterInventoryRepository; - } - - public override bool HandlePacket(IPacket packet) + : base(playerInfoProvider, chestDataRepository, characterRepository, characterInventoryRepository) { - var itemId = packet.ReadShort(); - var amount = Action == PacketAction.Get ? packet.ReadThree() : packet.ReadInt(); - var weight = packet.ReadChar(); - var maxWeight = packet.ReadChar(); - - _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == itemId) - .Match( - some: existing => - { - _characterInventoryRepository.ItemInventory.Remove(existing); - if (amount > 0 || itemId == 1) - { - _characterInventoryRepository.ItemInventory.Add(existing.WithAmount(existing.Amount + (Action == PacketAction.Get ? amount : -amount))); - } - }, - none: () => - { - if (amount > 0) - _characterInventoryRepository.ItemInventory.Add(new InventoryItem(itemId, amount)); - }); - - var stats = _characterRepository.MainCharacter.Stats - .WithNewStat(CharacterStat.Weight, weight) - .WithNewStat(CharacterStat.MaxWeight, maxWeight); - - _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); - - return base.HandlePacket(packet); } - } - - /// - /// Handler for CHEST_REPLY packet, sent in response to main player adding an item to a chest - /// - [AutoMappedType] - public class ChestReplyHandler : ChestGetHandler - { - public override PacketAction Action => PacketAction.Reply; - public ChestReplyHandler(IPlayerInfoProvider playerInfoProvider, - IChestDataRepository chestDataRepository, - ICharacterRepository characterRepository, - ICharacterInventoryRepository characterInventoryRepository) - : base(playerInfoProvider, chestDataRepository, characterRepository, characterInventoryRepository) + public override bool HandlePacket(ChestGetServerPacket packet) { + Handle(packet.Items, packet.TakenItem, packet.Weight, addingItemFromInventory: false); + return true; } } } diff --git a/EOLib/PacketHandlers/Chest/ChestItemUpdateHandler.cs b/EOLib/PacketHandlers/Chest/ChestItemUpdateHandler.cs new file mode 100644 index 000000000..a7fe35b4e --- /dev/null +++ b/EOLib/PacketHandlers/Chest/ChestItemUpdateHandler.cs @@ -0,0 +1,68 @@ +using EOLib.Domain.Character; +using EOLib.Domain.Login; +using EOLib.Domain.Map; +using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Optional.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace EOLib.PacketHandlers.Chest +{ + public abstract class ChestItemUpdateHandler : InGameOnlyPacketHandler + where TPacket : IPacket + { + private readonly IChestDataRepository _chestDataRepository; + private readonly ICharacterRepository _characterRepository; + private readonly ICharacterInventoryRepository _characterInventoryRepository; + + protected ChestItemUpdateHandler(IPlayerInfoProvider playerInfoProvider, + IChestDataRepository chestDataRepository, + ICharacterRepository characterRepository, + ICharacterInventoryRepository characterInventoryRepository) + : base(playerInfoProvider) + { + _chestDataRepository = chestDataRepository; + _characterRepository = characterRepository; + _characterInventoryRepository = characterInventoryRepository; + } + + protected void Handle(List items, ThreeItem item, Weight weight, bool addingItemFromInventory) + { + _chestDataRepository.Items = new HashSet(items.Select((x, i) => new ChestItem(x.Id, x.Amount, i))); + + if (addingItemFromInventory) + { + _characterInventoryRepository.ItemInventory.RemoveWhere(x => x.ItemID == item.Id); + if (item.Amount > 0) + { + _characterInventoryRepository.ItemInventory.Add(new InventoryItem(item.Id, item.Amount)); + } + } + else + { + _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == item.Id) + .Match( + some: existing => + { + if (item.Amount > 0 || item.Id == 1) + { + _characterInventoryRepository.ItemInventory.Remove(existing); + _characterInventoryRepository.ItemInventory.Add(existing.WithAmount(existing.Amount + item.Amount)); + } + }, + none: () => + { + if (item.Amount > 0) + _characterInventoryRepository.ItemInventory.Add(new InventoryItem(item.Id, item.Amount)); + }); + } + + var stats = _characterRepository.MainCharacter.Stats + .WithNewStat(CharacterStat.Weight, weight.Current) + .WithNewStat(CharacterStat.MaxWeight, weight.Max); + + _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); + } + } +} diff --git a/EOLib/PacketHandlers/Chest/ChestOpenHandler.cs b/EOLib/PacketHandlers/Chest/ChestOpenHandler.cs index e3d5ddaa5..30841cdc6 100644 --- a/EOLib/PacketHandlers/Chest/ChestOpenHandler.cs +++ b/EOLib/PacketHandlers/Chest/ChestOpenHandler.cs @@ -2,14 +2,16 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; +using System.Linq; namespace EOLib.PacketHandlers.Chest { [AutoMappedType] - public class ChestOpenHandler : InGameOnlyPacketHandler + public class ChestOpenHandler : InGameOnlyPacketHandler { private readonly IChestDataRepository _chestDataRepository; private readonly IEnumerable _userInterfaceNotifiers; @@ -27,17 +29,11 @@ public ChestOpenHandler(IPlayerInfoProvider playerInfoProvider, _userInterfaceNotifiers = userInterfaceNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(ChestOpenServerPacket packet) { - var x = packet.ReadChar(); - var y = packet.ReadChar(); - _chestDataRepository.ResetState(); - _chestDataRepository.Location = new MapCoordinate(x, y); - - int i = 0; - while (packet.ReadPosition < packet.Length) - _chestDataRepository.Items.Add(new ChestItem(packet.ReadShort(), packet.ReadThree(), i++)); + _chestDataRepository.Location = new MapCoordinate(packet.Coords.X, packet.Coords.Y); + _chestDataRepository.Items = new HashSet(packet.Items.Select((x, i) => new ChestItem(x.Id, x.Amount, i))); foreach (var notifier in _userInterfaceNotifiers) notifier.NotifyPacketDialog(Family); diff --git a/EOLib/PacketHandlers/Chest/ChestReplyHandler.cs b/EOLib/PacketHandlers/Chest/ChestReplyHandler.cs new file mode 100644 index 000000000..d3a564f8b --- /dev/null +++ b/EOLib/PacketHandlers/Chest/ChestReplyHandler.cs @@ -0,0 +1,39 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Character; +using EOLib.Domain.Login; +using EOLib.Domain.Map; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; + +namespace EOLib.PacketHandlers.Chest +{ + /// + /// Handler for CHEST_REPLY packet, sent in response to main player adding an item to a chest + /// + [AutoMappedType] + public class ChestReplyHandler : ChestItemUpdateHandler + { + public override PacketFamily Family => PacketFamily.Chest; + + public override PacketAction Action => PacketAction.Reply; + + public ChestReplyHandler(IPlayerInfoProvider playerInfoProvider, + IChestDataRepository chestDataRepository, + ICharacterRepository characterRepository, + ICharacterInventoryRepository characterInventoryRepository) + : base(playerInfoProvider, chestDataRepository, characterRepository, characterInventoryRepository) + { + } + + public override bool HandlePacket(ChestReplyServerPacket packet) + { + var item = new ThreeItem + { + Id = packet.AddedItemId, + Amount = packet.RemainingAmount, + }; + Handle(packet.Items, item, packet.Weight, addingItemFromInventory: true); + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Citizen/CitizenAcceptHandler.cs b/EOLib/PacketHandlers/Citizen/CitizenAcceptHandler.cs index 85a8fb2dd..a17f0da5c 100644 --- a/EOLib/PacketHandlers/Citizen/CitizenAcceptHandler.cs +++ b/EOLib/PacketHandlers/Citizen/CitizenAcceptHandler.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Citizen { @@ -11,7 +12,7 @@ namespace EOLib.PacketHandlers.Citizen /// Sent when the player has accepted the cost of sleeping at an inn /// [AutoMappedType] - public class CitizenAcceptHandler : InGameOnlyPacketHandler + public class CitizenAcceptHandler : InGameOnlyPacketHandler { private readonly ICharacterInventoryRepository _characterInventoryRepository; private readonly ICurrentMapStateRepository _currentMapStateRepository; @@ -32,11 +33,10 @@ public CitizenAcceptHandler(IPlayerInfoProvider playerInfoProvider, _characterRepository = characterRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(CitizenAcceptServerPacket packet) { - var goldRemaining = packet.ReadInt(); _characterInventoryRepository.ItemInventory.RemoveWhere(x => x.ItemID == 1); - _characterInventoryRepository.ItemInventory.Add(new InventoryItem(1, goldRemaining)); + _characterInventoryRepository.ItemInventory.Add(new InventoryItem(1, packet.GoldAmount)); var stats = _characterRepository.MainCharacter.Stats; stats = stats.WithNewStat(CharacterStat.HP, stats[CharacterStat.MaxHP]) diff --git a/EOLib/PacketHandlers/Citizen/CitizenOpenHandler.cs b/EOLib/PacketHandlers/Citizen/CitizenOpenHandler.cs index 0f940f90f..fb90f1a84 100644 --- a/EOLib/PacketHandlers/Citizen/CitizenOpenHandler.cs +++ b/EOLib/PacketHandlers/Citizen/CitizenOpenHandler.cs @@ -3,8 +3,9 @@ using EOLib.Domain.Interact.Citizen; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using System.Collections.Generic; @@ -14,7 +15,7 @@ namespace EOLib.PacketHandlers.Citizen /// Sent when opening an Innkeeper dialog /// [AutoMappedType] - public class CitizenOpenHandler : InGameOnlyPacketHandler + public class CitizenOpenHandler : InGameOnlyPacketHandler { private readonly ICitizenDataRepository _citizenDataRepository; private readonly ICurrentMapStateRepository _currentMapStateRepository; @@ -35,20 +36,13 @@ public CitizenOpenHandler(IPlayerInfoProvider playerInfoProvider, _npcInteractionNotifiers = npcInteractionNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(CitizenOpenServerPacket packet) { - _citizenDataRepository.BehaviorID = Option.Some(packet.ReadThree()); - _citizenDataRepository.CurrentHomeID = packet.ReadChar().SomeWhen(x => x > 0); - _currentMapStateRepository.MapWarpSession = Option.Some(packet.ReadShort()); + _citizenDataRepository.BehaviorID = Option.Some(packet.BehaviorId); + _citizenDataRepository.CurrentHomeID = packet.CurrentHomeId.SomeWhen(x => x > 0); + _currentMapStateRepository.MapWarpSession = Option.Some(packet.SessionId); - if (packet.ReadByte() != 255) - return false; - - var question1 = packet.ReadBreakString(); - var question2 = packet.ReadBreakString(); - var question3 = packet.ReadEndString(); - - _citizenDataRepository.Questions = new List { question1, question2, question3 }; + _citizenDataRepository.Questions = packet.Questions; foreach (var notifier in _npcInteractionNotifiers) notifier.NotifyInteractionFromNPC(IO.NPCType.Inn); diff --git a/EOLib/PacketHandlers/Citizen/CitizenRemoveHandler.cs b/EOLib/PacketHandlers/Citizen/CitizenRemoveHandler.cs index ac33d4038..731769c67 100644 --- a/EOLib/PacketHandlers/Citizen/CitizenRemoveHandler.cs +++ b/EOLib/PacketHandlers/Citizen/CitizenRemoveHandler.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Interact; using EOLib.Domain.Interact.Citizen; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using System.Collections.Generic; @@ -13,7 +14,7 @@ namespace EOLib.PacketHandlers.Citizen /// Sent when unsubscribing from a town /// [AutoMappedType] - public class CitizenRemoveHandler : InGameOnlyPacketHandler + public class CitizenRemoveHandler : InGameOnlyPacketHandler { private readonly ICitizenDataRepository _citizenDataRepository; private readonly IEnumerable _npcInteractionNotifiers; @@ -31,15 +32,13 @@ public CitizenRemoveHandler(IPlayerInfoProvider playerInfoProvider, _npcInteractionNotifiers = npcInteractionNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(CitizenRemoveServerPacket packet) { - var reply = (CitizenUnsubscribeReply)packet.ReadChar(); - - if (reply == CitizenUnsubscribeReply.Unsubscribed) + if (packet.ReplyCode == InnUnsubscribeReply.Unsubscribed) _citizenDataRepository.CurrentHomeID = Option.None(); foreach (var notifier in _npcInteractionNotifiers) - notifier.NotifyCitizenUnsubscribe(reply); + notifier.NotifyCitizenUnsubscribe(packet.ReplyCode); return true; } diff --git a/EOLib/PacketHandlers/Citizen/CitizenReplyHandler.cs b/EOLib/PacketHandlers/Citizen/CitizenReplyHandler.cs index 9e1ed546f..7aac1825c 100644 --- a/EOLib/PacketHandlers/Citizen/CitizenReplyHandler.cs +++ b/EOLib/PacketHandlers/Citizen/CitizenReplyHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Interact; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Citizen @@ -11,7 +12,7 @@ namespace EOLib.PacketHandlers.Citizen /// Sent when signing up to a town /// [AutoMappedType] - public class CitizenReplyHandler : InGameOnlyPacketHandler + public class CitizenReplyHandler : InGameOnlyPacketHandler { private readonly IEnumerable _npcInteractionNotifiers; @@ -26,12 +27,10 @@ public CitizenReplyHandler(IPlayerInfoProvider playerInfoProvider, _npcInteractionNotifiers = npcInteractionNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(CitizenReplyServerPacket packet) { - var questionsWrong = packet.ReadChar(); - foreach (var notifier in _npcInteractionNotifiers) - notifier.NotifyCitizenSignUp(questionsWrong); + notifier.NotifyCitizenSignUp(packet.QuestionsWrong); return true; } diff --git a/EOLib/PacketHandlers/Citizen/CitizenRequestHandler.cs b/EOLib/PacketHandlers/Citizen/CitizenRequestHandler.cs index c4a878b6c..7fa284201 100644 --- a/EOLib/PacketHandlers/Citizen/CitizenRequestHandler.cs +++ b/EOLib/PacketHandlers/Citizen/CitizenRequestHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Interact; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Citizen @@ -11,7 +12,7 @@ namespace EOLib.PacketHandlers.Citizen /// Sent when requesting to sleep at an inn /// [AutoMappedType] - public class CitizenRequestHandler : InGameOnlyPacketHandler + public class CitizenRequestHandler : InGameOnlyPacketHandler { private readonly IEnumerable _npcInteractionNotifiers; @@ -26,12 +27,10 @@ public CitizenRequestHandler(IPlayerInfoProvider playerInfoProvider, _npcInteractionNotifiers = npcInteractionNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(CitizenRequestServerPacket packet) { - var sleepCost = packet.ReadInt(); - foreach (var notifier in _npcInteractionNotifiers) - notifier.NotifyCitizenRequestSleep(sleepCost); + notifier.NotifyCitizenRequestSleep(packet.Cost); return true; } diff --git a/EOLib/PacketHandlers/Commands/FindCommandHandlerBase.cs b/EOLib/PacketHandlers/Commands/FindCommandHandlerBase.cs index 121532ac4..81c076fc2 100644 --- a/EOLib/PacketHandlers/Commands/FindCommandHandlerBase.cs +++ b/EOLib/PacketHandlers/Commands/FindCommandHandlerBase.cs @@ -1,20 +1,19 @@ using EOLib.Domain.Chat; using EOLib.Domain.Login; using EOLib.Localization; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; namespace EOLib.PacketHandlers.Commands { - public abstract class FindCommandHandlerBase : InGameOnlyPacketHandler + public abstract class FindCommandHandlerBase : InGameOnlyPacketHandler + where TPacket : IPacket { private readonly IChatRepository _chatRespository; private readonly ILocalizedStringFinder _localizedStringFinder; public override PacketFamily Family => PacketFamily.Players; - protected abstract EOResourceID ResourceIDForResponse { get; } - protected FindCommandHandlerBase(IChatRepository chatRespository, ILocalizedStringFinder localizedStringFinder, IPlayerInfoProvider playerInfoProvider) @@ -24,16 +23,11 @@ protected FindCommandHandlerBase(IChatRepository chatRespository, _localizedStringFinder = localizedStringFinder; } - public override bool HandlePacket(IPacket packet) + protected void Handle(string playerName, EOResourceID resourceId) { - var playerName = packet.ReadEndString(); - var message = - $"{char.ToUpper(playerName[0]) + playerName.Substring(1)} {_localizedStringFinder.GetString(ResourceIDForResponse)}"; - + var message = $"{char.ToUpper(playerName[0]) + playerName.Substring(1)} {_localizedStringFinder.GetString(resourceId)}"; var chatData = new ChatData(ChatTab.Local, "System", message, ChatIcon.LookingDude); _chatRespository.AllChat[ChatTab.Local].Add(chatData); - - return true; } } } diff --git a/EOLib/PacketHandlers/Commands/FindCommandPlayerDifferentMapHandler.cs b/EOLib/PacketHandlers/Commands/FindCommandPlayerDifferentMapHandler.cs index 946754229..c61604f80 100644 --- a/EOLib/PacketHandlers/Commands/FindCommandPlayerDifferentMapHandler.cs +++ b/EOLib/PacketHandlers/Commands/FindCommandPlayerDifferentMapHandler.cs @@ -2,16 +2,15 @@ using EOLib.Domain.Chat; using EOLib.Domain.Login; using EOLib.Localization; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Commands { [AutoMappedType] - public class FindCommandPlayerDifferentMapHandler : FindCommandHandlerBase + public class FindCommandPlayerDifferentMapHandler : FindCommandHandlerBase { - public override PacketAction Action => PacketAction.Net3; - - protected override EOResourceID ResourceIDForResponse => EOResourceID.STATUS_LABEL_IS_ONLINE_IN_THIS_WORLD; + public override PacketAction Action => PacketAction.Net242; public FindCommandPlayerDifferentMapHandler(IChatRepository chatRespository, ILocalizedStringFinder localizedStringFinder, @@ -19,5 +18,11 @@ public FindCommandPlayerDifferentMapHandler(IChatRepository chatRespository, : base(chatRespository, localizedStringFinder, playerInfoProvider) { } + + public override bool HandlePacket(PlayersNet242ServerPacket packet) + { + Handle(packet.Name, EOResourceID.STATUS_LABEL_IS_ONLINE_IN_THIS_WORLD); + return true; + } } -} \ No newline at end of file +} diff --git a/EOLib/PacketHandlers/Commands/FindCommandPlayerNotFoundHandler.cs b/EOLib/PacketHandlers/Commands/FindCommandPlayerNotFoundHandler.cs index 15c5271a6..4887ed977 100644 --- a/EOLib/PacketHandlers/Commands/FindCommandPlayerNotFoundHandler.cs +++ b/EOLib/PacketHandlers/Commands/FindCommandPlayerNotFoundHandler.cs @@ -2,22 +2,27 @@ using EOLib.Domain.Chat; using EOLib.Domain.Login; using EOLib.Localization; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Commands { [AutoMappedType] - public class FindCommandPlayerNotFoundHandler : FindCommandHandlerBase + public class FindCommandPlayerNotFoundHandler : FindCommandHandlerBase { public override PacketAction Action => PacketAction.Ping; - protected override EOResourceID ResourceIDForResponse => EOResourceID.STATUS_LABEL_IS_ONLINE_NOT_FOUND; - public FindCommandPlayerNotFoundHandler(IChatRepository chatRespository, ILocalizedStringFinder localizedStringFinder, IPlayerInfoProvider playerInfoProvider) : base(chatRespository, localizedStringFinder, playerInfoProvider) { } + + public override bool HandlePacket(PlayersPingServerPacket packet) + { + Handle(packet.Name, EOResourceID.STATUS_LABEL_IS_ONLINE_NOT_FOUND); + return true; + } } -} \ No newline at end of file +} diff --git a/EOLib/PacketHandlers/Commands/FindCommandPlayerSameMapHandler.cs b/EOLib/PacketHandlers/Commands/FindCommandPlayerSameMapHandler.cs index ce74bd10c..e941cffe1 100644 --- a/EOLib/PacketHandlers/Commands/FindCommandPlayerSameMapHandler.cs +++ b/EOLib/PacketHandlers/Commands/FindCommandPlayerSameMapHandler.cs @@ -2,22 +2,27 @@ using EOLib.Domain.Chat; using EOLib.Domain.Login; using EOLib.Localization; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Commands { [AutoMappedType] - public class FindCommandPlayerSameMapHandler : FindCommandHandlerBase + public class FindCommandPlayerSameMapHandler : FindCommandHandlerBase { public override PacketAction Action => PacketAction.Pong; - protected override EOResourceID ResourceIDForResponse => EOResourceID.STATUS_LABEL_IS_ONLINE_SAME_MAP; - public FindCommandPlayerSameMapHandler(IChatRepository chatRespository, ILocalizedStringFinder localizedStringFinder, IPlayerInfoProvider playerInfoProvider) : base(chatRespository, localizedStringFinder, playerInfoProvider) { } + + public override bool HandlePacket(PlayersPongServerPacket packet) + { + Handle(packet.Name, EOResourceID.STATUS_LABEL_IS_ONLINE_SAME_MAP); + return true; + } } -} \ No newline at end of file +} diff --git a/EOLib/PacketHandlers/Commands/PingResponseHandler.cs b/EOLib/PacketHandlers/Commands/PingResponseHandler.cs index 4cd7970dc..53310700b 100644 --- a/EOLib/PacketHandlers/Commands/PingResponseHandler.cs +++ b/EOLib/PacketHandlers/Commands/PingResponseHandler.cs @@ -1,12 +1,11 @@ -using System; -using System.Collections.Generic; -using AutomaticTypeMapper; -using EOLib.Domain.Chat; +using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; using EOLib.Domain.Protocol; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Collections.Generic; namespace EOLib.PacketHandlers.Commands { @@ -14,10 +13,9 @@ namespace EOLib.PacketHandlers.Commands /// Handles MESSAGE_PONG packets which are in response to a #ping command request /// [AutoMappedType] - public class PingResponseHandler : InGameOnlyPacketHandler + public class PingResponseHandler : InGameOnlyPacketHandler { private readonly IPingTimeRepository _pingTimeRepository; - private readonly IChatRepository _chatRepository; private readonly IEnumerable _chatEventNotifiers; public override PacketFamily Family => PacketFamily.Message; @@ -26,27 +24,20 @@ public class PingResponseHandler : InGameOnlyPacketHandler public PingResponseHandler(IPlayerInfoProvider playerInfoProvider, IPingTimeRepository pingTimeRepository, - IChatRepository chatRepository, IEnumerable chatEventNotifiers) : base(playerInfoProvider) { _pingTimeRepository = pingTimeRepository; - _chatRepository = chatRepository; _chatEventNotifiers = chatEventNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(MessagePongServerPacket packet) { - var now = DateTime.Now; - var requestID = packet.ReadShort(); - if (!_pingTimeRepository.PingRequests.ContainsKey(requestID)) - return false; - - var timeInMS = (int) Math.Round((now - _pingTimeRepository.PingRequests[requestID]).TotalMilliseconds); - _pingTimeRepository.PingRequests.Remove(requestID); + var time = (int)_pingTimeRepository.RequestTimer.ElapsedMilliseconds; + _pingTimeRepository.RequestTimer.Reset(); foreach (var notifier in _chatEventNotifiers) - notifier.NotifyServerPing(timeInMS); + notifier.NotifyServerPing(time); return true; } diff --git a/EOLib/PacketHandlers/Connection/ConnectionPlayerHandler.cs b/EOLib/PacketHandlers/Connection/ConnectionPlayerHandler.cs index 45a472ff8..66ab01a83 100644 --- a/EOLib/PacketHandlers/Connection/ConnectionPlayerHandler.cs +++ b/EOLib/PacketHandlers/Connection/ConnectionPlayerHandler.cs @@ -3,6 +3,10 @@ using EOLib.Net.Communication; using EOLib.Net.Handlers; using EOLib.Net.PacketProcessing; +using Moffat.EndlessOnline.SDK.Packet; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Connection { @@ -10,7 +14,7 @@ namespace EOLib.PacketHandlers.Connection /// Sent when the server is updating the sequence numbers for the client /// [AutoMappedType] - public class ConnectionPlayerHandler : DefaultAsyncPacketHandler + public class ConnectionPlayerHandler : DefaultAsyncPacketHandler { private readonly IPacketProcessActions _packetProcessActions; private readonly IPacketSendService _packetSendService; @@ -28,20 +32,13 @@ public ConnectionPlayerHandler(IPacketProcessActions packetProcessActions, _packetSendService = packetSendService; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(ConnectionPlayerServerPacket packet) { - var seq1 = packet.ReadShort(); - var seq2 = packet.ReadChar(); - - _packetProcessActions.SetUpdatedBaseSequenceNumber(seq1, seq2); - - var response = new PacketBuilder(PacketFamily.Connection, PacketAction.Ping) - .AddString("k") - .Build(); + _packetProcessActions.SetSequenceStart(PingSequenceStart.FromPingValues(packet.Seq1, packet.Seq2)); try { - _packetSendService.SendPacket(response); + _packetSendService.SendPacket(new ConnectionPingClientPacket()); } catch (NoDataSentException) { diff --git a/EOLib/PacketHandlers/Door/DoorOpenHandler.cs b/EOLib/PacketHandlers/Door/DoorOpenHandler.cs index cf076fa79..4a669810f 100644 --- a/EOLib/PacketHandlers/Door/DoorOpenHandler.cs +++ b/EOLib/PacketHandlers/Door/DoorOpenHandler.cs @@ -1,10 +1,10 @@ -using System.Linq; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; using EOLib.Net.Handlers; - +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Linq; using DomainWarp = EOLib.Domain.Map.Warp; namespace EOLib.PacketHandlers.Door @@ -13,7 +13,7 @@ namespace EOLib.PacketHandlers.Door /// Sent when a player near you opens a door /// [AutoMappedType] - public class DoorOpenHandler : InGameOnlyPacketHandler + public class DoorOpenHandler : InGameOnlyPacketHandler { private readonly ICurrentMapStateRepository _currentMapStateRepository; private readonly ICurrentMapProvider _currentMapProvider; @@ -31,11 +31,10 @@ public DoorOpenHandler(IPlayerInfoProvider playerInfoProvider, _currentMapProvider = currentMapProvider; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(DoorOpenServerPacket packet) { - var x = packet.ReadChar(); - var y = packet.ReadShort(); - + var x = packet.Coords.X; + var y = packet.Coords.Y; if (_currentMapStateRepository.OpenDoors.Any(d => d.X == x && d.Y == y)) return true; diff --git a/EOLib/PacketHandlers/Effects/EffectAgreeHandler.cs b/EOLib/PacketHandlers/Effects/EffectAgreeHandler.cs index e46c8fc25..352d45b98 100644 --- a/EOLib/PacketHandlers/Effects/EffectAgreeHandler.cs +++ b/EOLib/PacketHandlers/Effects/EffectAgreeHandler.cs @@ -2,14 +2,15 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Effects { [AutoMappedType] - public class EffectAgreeHandler : InGameOnlyPacketHandler + public class EffectAgreeHandler : InGameOnlyPacketHandler { private readonly IEnumerable _effectNotifiers; @@ -23,14 +24,13 @@ public EffectAgreeHandler(IPlayerInfoProvider playerInfoProvider, _effectNotifiers = effectNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(EffectAgreeServerPacket packet) { - var x = packet.ReadChar(); - var y = packet.ReadChar(); - var effectId = packet.ReadShort(); - - foreach (var notifier in _effectNotifiers) - notifier.NotifyEffectAtLocation(new MapCoordinate(x, y), effectId); + foreach (var effect in packet.Effects) + { + foreach (var notifier in _effectNotifiers) + notifier.NotifyEffectAtLocation(new MapCoordinate(effect.Coords.X, effect.Coords.Y), effect.EffectId); + } return true; } diff --git a/EOLib/PacketHandlers/Effects/EffectPotionHandler.cs b/EOLib/PacketHandlers/Effects/EffectPotionHandler.cs index 544b7ae75..567481f33 100644 --- a/EOLib/PacketHandlers/Effects/EffectPotionHandler.cs +++ b/EOLib/PacketHandlers/Effects/EffectPotionHandler.cs @@ -1,14 +1,15 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Effects { [AutoMappedType] - public class EffectPotionHandler : InGameOnlyPacketHandler + public class EffectPotionHandler : InGameOnlyPacketHandler { private readonly IEnumerable _effectNotifiers; @@ -22,13 +23,13 @@ public EffectPotionHandler(IPlayerInfoProvider playerInfoProvider, _effectNotifiers = effectNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(EffectPlayerServerPacket packet) { - var playerId = packet.ReadShort(); - var effectId = packet.ReadThree(); - - foreach (var notifier in _effectNotifiers) - notifier.NotifyPotionEffect(playerId, effectId); + foreach (var effect in packet.Effects) + { + foreach (var notifier in _effectNotifiers) + notifier.NotifyPotionEffect(effect.PlayerId, effect.EffectId); + } return true; } diff --git a/EOLib/PacketHandlers/Effects/MapDebuffHandler.cs b/EOLib/PacketHandlers/Effects/MapDebuffHandler.cs index 0a5c7543c..ee386077f 100644 --- a/EOLib/PacketHandlers/Effects/MapDebuffHandler.cs +++ b/EOLib/PacketHandlers/Effects/MapDebuffHandler.cs @@ -1,22 +1,23 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; using EOLib.Domain.Login; +using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.IO.Map; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using Optional; using System; using System.Collections.Generic; namespace EOLib.PacketHandlers.Effects { [AutoMappedType] - public class MapDebuffHandler : InGameOnlyPacketHandler + public class MapDebuffHandler : InGameOnlyPacketHandler { - private const int EFFECT_DAMAGE_TPDRAIN = 1; - private const int EFFECT_DAMAGE_SPIKE = 2; - private readonly ICharacterRepository _characterRepository; + private readonly ICurrentMapProvider _currentMapProvider; + private readonly ICurrentMapStateRepository _currentMapStateRepository; private readonly IEnumerable _mainCharacterEventNotifiers; private readonly IEnumerable _effectNotifiers; @@ -26,54 +27,57 @@ public class MapDebuffHandler : InGameOnlyPacketHandler public MapDebuffHandler(IPlayerInfoProvider playerInfoProvider, ICharacterRepository characterRepository, + ICurrentMapProvider currentMapProvider, + ICurrentMapStateRepository currentMapStateRepository, IEnumerable mainCharacterEventNotifiers, IEnumerable effectNotifiers) : base(playerInfoProvider) { _characterRepository = characterRepository; + _currentMapProvider = currentMapProvider; + _currentMapStateRepository = currentMapStateRepository; _mainCharacterEventNotifiers = mainCharacterEventNotifiers; _effectNotifiers = effectNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(EffectSpecServerPacket packet) { var character = _characterRepository.MainCharacter; var originalStats = character.Stats; - //1 in eoserv Map::TimedDrains - tp - //2 in eoserv Character::SpikeDamage - var damageType = packet.ReadChar(); - switch (damageType) + switch (packet.MapDamageType) { - case EFFECT_DAMAGE_TPDRAIN: + // todo: show amount in damage counter + case MapDamageType.TpDrain: { - // todo: show amount in damage counter - var amount = packet.ReadShort(); - var tp = packet.ReadShort(); - var maxTp = packet.ReadShort(); + var data = (EffectSpecServerPacket.MapDamageTypeDataTpDrain)packet.MapDamageTypeData; _characterRepository.MainCharacter = character.WithStats( - originalStats.WithNewStat(CharacterStat.TP, tp) - .WithNewStat(CharacterStat.MaxTP, maxTp)); + originalStats.WithNewStat(CharacterStat.TP, data.Tp) + .WithNewStat(CharacterStat.MaxTP, data.MaxTp)); foreach (var notifier in _effectNotifiers) - notifier.NotifyMapEffect(MapEffect.TPDrain); + notifier.NotifyMapEffect(IO.Map.MapEffect.TPDrain); } break; - case EFFECT_DAMAGE_SPIKE: + case MapDamageType.Spikes: { - // todo: show amount in damage counter - var damage = packet.ReadShort(); - var hp = packet.ReadShort(); - var maxHp = packet.ReadShort(); - character = character.WithStats(originalStats.WithNewStat(CharacterStat.HP, hp) - .WithNewStat(CharacterStat.MaxHP, maxHp)); + if (_currentMapProvider.CurrentMap.Tiles[character.RenderProperties.MapY, character.RenderProperties.MapX] == IO.Map.TileSpec.SpikesTimed) + { + _currentMapStateRepository.LastTimedSpikeEvent = Option.Some(DateTime.Now); + foreach (var notifier in _effectNotifiers) + notifier.NotifyMapEffect(IO.Map.MapEffect.Spikes); + } + + var data = (EffectSpecServerPacket.MapDamageTypeDataSpikes)packet.MapDamageTypeData; + character = character.WithStats(originalStats.WithNewStat(CharacterStat.HP, data.Hp) + .WithNewStat(CharacterStat.MaxHP, data.MaxHp)); - character = character.WithRenderProperties(character.RenderProperties.WithIsDead(hp <= 0)); + character = character.WithRenderProperties(character.RenderProperties.WithIsDead(data.Hp <= 0)); _characterRepository.MainCharacter = character; foreach (var notifier in _mainCharacterEventNotifiers) - notifier.NotifyTakeDamage(damage, (int)Math.Round((double)hp / maxHp * 100), isHeal: false); + notifier.NotifyTakeDamage(data.HpDamage, (int)Math.Round((double)data.Hp / data.MaxHp * 100), isHeal: false); } break; default: diff --git a/EOLib/PacketHandlers/Effects/MapHpDrainHandler.cs b/EOLib/PacketHandlers/Effects/MapHpDrainHandler.cs index 831dbe027..2d6b5cc27 100644 --- a/EOLib/PacketHandlers/Effects/MapHpDrainHandler.cs +++ b/EOLib/PacketHandlers/Effects/MapHpDrainHandler.cs @@ -4,16 +4,16 @@ using EOLib.Domain.Extensions; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.IO.Map; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System; using System.Collections.Generic; namespace EOLib.PacketHandlers.Effects { [AutoMappedType] - public class MapHpDrainHandler : InGameOnlyPacketHandler + public class MapHpDrainHandler : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; private readonly IEnumerable _mainCharacterEventNotifiers; @@ -37,11 +37,11 @@ public MapHpDrainHandler(IPlayerInfoProvider playerInfoProvider, _effectNotifiers = effectNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(EffectTargetOtherServerPacket packet) { - var damage = packet.ReadShort(); - var hp = packet.ReadShort(); - var maxhp = packet.ReadShort(); + var damage = packet.Damage; + var hp = packet.Hp; + var maxhp = packet.MaxHp; _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithDamage(damage, hp == 0); @@ -49,16 +49,12 @@ public override bool HandlePacket(IPacket packet) notifier.NotifyTakeDamage(damage, (int)Math.Round(((double)hp / maxhp) * 100), isHeal: false); foreach (var notifier in _effectNotifiers) - notifier.NotifyMapEffect(MapEffect.HPDrain); + notifier.NotifyMapEffect(IO.Map.MapEffect.HPDrain); - while (packet.ReadPosition != packet.Length) + foreach (var other in packet.Others) { - var otherCharacterId = packet.ReadShort(); - var otherCharacterPercentHealth = packet.ReadChar(); - var damageDealt = packet.ReadShort(); - foreach (var notifier in _otherCharacterEventNotifiers) - notifier.OtherCharacterTakeDamage(otherCharacterId, otherCharacterPercentHealth, damageDealt, isHeal: false); + notifier.OtherCharacterTakeDamage(other.PlayerId, other.HpPercentage, other.Damage, isHeal: false); } return true; diff --git a/EOLib/PacketHandlers/Effects/MapQuakeHandler.cs b/EOLib/PacketHandlers/Effects/MapQuakeHandler.cs index 663c3d3cc..ff3a19023 100644 --- a/EOLib/PacketHandlers/Effects/MapQuakeHandler.cs +++ b/EOLib/PacketHandlers/Effects/MapQuakeHandler.cs @@ -1,15 +1,15 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.IO.Map; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Effects { [AutoMappedType] - public class MapQuakeHandler : InGameOnlyPacketHandler + public class MapQuakeHandler : InGameOnlyPacketHandler { private readonly IEnumerable _effectNotifiers; @@ -23,17 +23,13 @@ public MapQuakeHandler(IPlayerInfoProvider playerInfoProvider, _effectNotifiers = effectNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(EffectUseServerPacket packet) { - const int EffectQuake = 1; - - if (packet.ReadChar() != EffectQuake) + if (packet.Effect != MapEffect.Quake) return false; - var strength = packet.ReadChar(); - foreach (var notifier in _effectNotifiers) - notifier.NotifyMapEffect(MapEffect.Quake1, strength); + notifier.NotifyMapEffect(IO.Map.MapEffect.Quake1, ((EffectUseServerPacket.EffectDataQuake)packet.EffectData).QuakeStrength); return true; } diff --git a/EOLib/PacketHandlers/Effects/PlayerSpikeDamageHandler.cs b/EOLib/PacketHandlers/Effects/PlayerSpikeDamageHandler.cs index 222d07d9a..f069fb0ac 100644 --- a/EOLib/PacketHandlers/Effects/PlayerSpikeDamageHandler.cs +++ b/EOLib/PacketHandlers/Effects/PlayerSpikeDamageHandler.cs @@ -3,14 +3,15 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Effects { [AutoMappedType] - public class PlayerSpikeDamageHandler : InGameOnlyPacketHandler + public class PlayerSpikeDamageHandler : InGameOnlyPacketHandler { private readonly ICurrentMapStateRepository _currentMapStateRepository; private readonly IEnumerable _otherCharacterEventNotifiers; @@ -28,26 +29,21 @@ public PlayerSpikeDamageHandler(IPlayerInfoProvider playerInfoProvider, _otherCharacterEventNotifiers = otherCharacterEventNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(EffectAdminServerPacket packet) { - var characterId = packet.ReadShort(); - var playerPercentHealth = packet.ReadChar(); - var isDead = packet.ReadChar() != 0; - var damageTaken = packet.ReadThree(); - - if (_currentMapStateRepository.Characters.TryGetValue(characterId, out var character)) + if (_currentMapStateRepository.Characters.TryGetValue(packet.PlayerId, out var character)) { - var updatedCharacter = character.WithDamage(damageTaken, isDead); + var updatedCharacter = character.WithDamage(packet.Damage, packet.Died); _currentMapStateRepository.Characters.Update(character, updatedCharacter); foreach (var notifier in _otherCharacterEventNotifiers) { - notifier.OtherCharacterTakeDamage(characterId, playerPercentHealth, damageTaken, isHeal: false); + notifier.OtherCharacterTakeDamage(packet.PlayerId, packet.HpPercentage, packet.Damage, isHeal: false); } } else { - _currentMapStateRepository.UnknownPlayerIDs.Add(characterId); + _currentMapStateRepository.UnknownPlayerIDs.Add(packet.PlayerId); } return true; diff --git a/EOLib/PacketHandlers/Effects/TimedSpikeEffectHandler.cs b/EOLib/PacketHandlers/Effects/TimedSpikeEffectHandler.cs index c5479cbd3..65fb871b7 100644 --- a/EOLib/PacketHandlers/Effects/TimedSpikeEffectHandler.cs +++ b/EOLib/PacketHandlers/Effects/TimedSpikeEffectHandler.cs @@ -5,18 +5,21 @@ using EOLib.Domain.Map; using EOLib.Domain.Notifiers; using EOLib.IO.Map; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using Optional; +using System; using System.Collections.Generic; -using System.Linq; namespace EOLib.PacketHandlers.Effects { [AutoMappedType] - public class TimedSpikeEffectHandler : InGameOnlyPacketHandler + public class TimedSpikeEffectHandler : InGameOnlyPacketHandler { private readonly ICurrentMapProvider _currentMapProvider; private readonly ICharacterProvider _characterProvider; + private readonly ICurrentMapStateRepository _currentMapStateRepository; private readonly IEnumerable _effectNotifiers; public override PacketFamily Family => PacketFamily.Effect; @@ -26,18 +29,19 @@ public class TimedSpikeEffectHandler : InGameOnlyPacketHandler public TimedSpikeEffectHandler(IPlayerInfoProvider playerInfoProvider, ICurrentMapProvider currentMapProvider, ICharacterProvider characterProvider, + ICurrentMapStateRepository currentMapStateRepository, IEnumerable effectNotifiers) : base(playerInfoProvider) { _currentMapProvider = currentMapProvider; _characterProvider = characterProvider; + _currentMapStateRepository = currentMapStateRepository; _effectNotifiers = effectNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(EffectReportServerPacket packet) { - if ((char)packet.ReadByte() != 'S') - return false; + _currentMapStateRepository.LastTimedSpikeEvent = Option.Some(DateTime.Now); var characterPosition = _characterProvider.MainCharacter.RenderProperties.Coordinates(); var distanceToSpikes = _currentMapProvider.CurrentMap.GetDistanceToClosestTileSpec(TileSpec.SpikesTimed, characterPosition); @@ -45,7 +49,7 @@ public override bool HandlePacket(IPacket packet) if (distanceToSpikes <= 6) { foreach (var notifier in _effectNotifiers) - notifier.NotifyMapEffect(MapEffect.Spikes); + notifier.NotifyMapEffect(IO.Map.MapEffect.Spikes); } return true; diff --git a/EOLib/PacketHandlers/Emote/EmotePlayerHandler.cs b/EOLib/PacketHandlers/Emote/EmotePlayerHandler.cs index 7acb030fa..a5fdbe1cf 100644 --- a/EOLib/PacketHandlers/Emote/EmotePlayerHandler.cs +++ b/EOLib/PacketHandlers/Emote/EmotePlayerHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Emote @@ -11,7 +12,7 @@ namespace EOLib.PacketHandlers.Emote /// Sent when a player does an emote /// [AutoMappedType] - public class EmotePlayerHandler : InGameOnlyPacketHandler + public class EmotePlayerHandler : InGameOnlyPacketHandler { private readonly IEnumerable _emoteNotifiers; @@ -26,12 +27,10 @@ public EmotePlayerHandler(IPlayerInfoProvider playerInfoProvider, _emoteNotifiers = emoteNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(EmotePlayerServerPacket packet) { - var playerId = packet.ReadShort(); - var emote = (Domain.Character.Emote)packet.ReadChar(); foreach (var notifier in _emoteNotifiers) - notifier.NotifyEmote(playerId, emote); + notifier.NotifyEmote(packet.PlayerId, (Domain.Character.Emote)packet.Emote); return true; } diff --git a/EOLib/PacketHandlers/Face/FacePlayerHandler.cs b/EOLib/PacketHandlers/Face/FacePlayerHandler.cs index 7648745ed..53b7ee521 100644 --- a/EOLib/PacketHandlers/Face/FacePlayerHandler.cs +++ b/EOLib/PacketHandlers/Face/FacePlayerHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Face { @@ -10,7 +11,7 @@ namespace EOLib.PacketHandlers.Face /// Player changing direction /// [AutoMappedType] - public class FacePlayerHandler : InGameOnlyPacketHandler + public class FacePlayerHandler : InGameOnlyPacketHandler { private readonly ICurrentMapStateRepository _mapStateRepository; @@ -25,20 +26,17 @@ public FacePlayerHandler(IPlayerInfoProvider playerInfoProvider, _mapStateRepository = mapStateRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(FacePlayerServerPacket packet) { - var id = packet.ReadShort(); - var direction = (EODirection)packet.ReadChar(); - - if (!_mapStateRepository.Characters.ContainsKey(id)) + if (!_mapStateRepository.Characters.ContainsKey(packet.PlayerId)) { - _mapStateRepository.UnknownPlayerIDs.Add(id); + _mapStateRepository.UnknownPlayerIDs.Add(packet.PlayerId); return true; } - var character = _mapStateRepository.Characters[id]; + var character = _mapStateRepository.Characters[packet.PlayerId]; - var newRenderProps = character.RenderProperties.WithDirection(direction); + var newRenderProps = character.RenderProperties.WithDirection((EODirection)packet.Direction); var newCharacter = character.WithRenderProperties(newRenderProps); _mapStateRepository.Characters.Update(character, newCharacter); diff --git a/EOLib/PacketHandlers/Init/BasePlayersListHandler.cs b/EOLib/PacketHandlers/Init/BasePlayersListHandler.cs deleted file mode 100644 index 01ac250eb..000000000 --- a/EOLib/PacketHandlers/Init/BasePlayersListHandler.cs +++ /dev/null @@ -1,36 +0,0 @@ -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 index 7895bcd5a..a17805da7 100644 --- a/EOLib/PacketHandlers/Init/FriendIgnoreListHandler.cs +++ b/EOLib/PacketHandlers/Init/FriendIgnoreListHandler.cs @@ -1,24 +1,30 @@ using AutomaticTypeMapper; using EOLib.Domain.Online; -using EOLib.Domain.Protocol; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System; +using System.Collections.Generic; +using System.Linq; namespace EOLib.PacketHandlers.Init { [AutoMappedType] - public class FriendIgnoreListHandler : BasePlayersListHandler + public class FriendIgnoreListHandler : BaseInGameInitPacketHandler { - public override InitReply Reply => InitReply.FriendPlayersList; + private readonly IOnlinePlayerRepository _onlinePlayerRepository; + + public override InitReply Reply => InitReply.PlayersListFriends; + + public Type DataType => typeof(InitInitServerPacket.ReplyCodeDataPlayersListFriends); public FriendIgnoreListHandler(IOnlinePlayerRepository onlinePlayerRepository) - : base(onlinePlayerRepository) { + _onlinePlayerRepository = onlinePlayerRepository; } - protected override OnlinePlayerInfo GetNextRecord(IPacket packet) + public override bool HandleData(InitInitServerPacket.ReplyCodeDataPlayersListFriends data) { - string name = packet.ReadBreakString(); - return new OnlinePlayerInfo(name); + _onlinePlayerRepository.OnlinePlayers = new HashSet(data.PlayersList.Players.Select(x => new OnlinePlayerInfo(x))); + return true; } } } diff --git a/EOLib/PacketHandlers/Init/IInGameInitPacketHandler.cs b/EOLib/PacketHandlers/Init/IInGameInitPacketHandler.cs deleted file mode 100644 index 5e58644f7..000000000 --- a/EOLib/PacketHandlers/Init/IInGameInitPacketHandler.cs +++ /dev/null @@ -1,12 +0,0 @@ -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/IInitPacketHandler.cs b/EOLib/PacketHandlers/Init/IInitPacketHandler.cs new file mode 100644 index 000000000..42a65f18f --- /dev/null +++ b/EOLib/PacketHandlers/Init/IInitPacketHandler.cs @@ -0,0 +1,28 @@ +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; + +namespace EOLib.PacketHandlers.Init +{ + public interface IInitPacketHandler + { + InitReply Reply { get; } + + bool HandleData(InitInitServerPacket.IReplyCodeData data); + } + + public interface IInitPacketHandler : IInitPacketHandler + where TData : InitInitServerPacket.IReplyCodeData + { + bool HandleData(TData data); + } + + public abstract class BaseInGameInitPacketHandler : IInitPacketHandler + where TData : InitInitServerPacket.IReplyCodeData + { + public abstract InitReply Reply { get; } + + public bool HandleData(InitInitServerPacket.IReplyCodeData data) + => HandleData((TData)data); + + public abstract bool HandleData(TData data); + } +} diff --git a/EOLib/PacketHandlers/Init/InGameInitPacketHandler.cs b/EOLib/PacketHandlers/Init/InGameInitPacketHandler.cs index fd79cf219..23ee8469d 100644 --- a/EOLib/PacketHandlers/Init/InGameInitPacketHandler.cs +++ b/EOLib/PacketHandlers/Init/InGameInitPacketHandler.cs @@ -1,15 +1,15 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; -using EOLib.Domain.Protocol; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional.Collections; using System.Collections.Generic; namespace EOLib.PacketHandlers.Init { [AutoMappedType] - public class InGameInitPacketHandler : InGameOnlyPacketHandler + public class InGameInitPacketHandler : InGameOnlyPacketHandler { private readonly IEnumerable _initPacketHandlers; @@ -24,11 +24,10 @@ public InGameInitPacketHandler(IPlayerInfoProvider playerInfoProvider, _initPacketHandlers = initPacketHandlers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(InitInitServerPacket packet) { - var reply = (InitReply)packet.ReadByte(); - return _initPacketHandlers.SingleOrNone(x => x.Reply == reply) - .Match(x => x.HandlePacket(packet), () => false); + return _initPacketHandlers.SingleOrNone(x => x.Reply == packet.ReplyCode) + .Match(x => x.HandleData(packet.ReplyCodeData), () => false); } } } diff --git a/EOLib/PacketHandlers/Init/MapMutationHandler.cs b/EOLib/PacketHandlers/Init/MapMutationHandler.cs index 1870f979e..e8832887c 100644 --- a/EOLib/PacketHandlers/Init/MapMutationHandler.cs +++ b/EOLib/PacketHandlers/Init/MapMutationHandler.cs @@ -1,20 +1,17 @@ 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 Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; -using System.Linq; namespace EOLib.PacketHandlers.Init { [AutoMappedType] - public class MapMutationHandler : IInitPacketHandler + public class MapMutationHandler : BaseInGameInitPacketHandler { private readonly IMapFileRepository _mapFileRepository; private readonly IMapDeserializer _mapFileDeserializer; @@ -22,7 +19,7 @@ public class MapMutationHandler : IInitPacketHandler private readonly ICharacterProvider _characterProvider; private readonly IEnumerable _mapChangedNotifiers; - public InitReply Reply => InitReply.MapMutation; + public override InitReply Reply => InitReply.MapMutation; public MapMutationHandler(IMapFileRepository mapFileRepository, IMapDeserializer mapFileDeserializer, @@ -37,12 +34,11 @@ public MapMutationHandler(IMapFileRepository mapFileRepository, _mapChangedNotifiers = mapChangedNotifiers; } - public bool HandlePacket(IPacket packet) + public override bool HandleData(InitInitServerPacket.ReplyCodeDataMapMutation packet) { var mapID = _characterProvider.MainCharacter.MapID; - var fileData = packet.ReadBytes(packet.Length - packet.ReadPosition); var mapFile = _mapFileDeserializer - .DeserializeFromByteArray(fileData.ToArray()) + .DeserializeFromByteArray(packet.MapFile.Content) .WithMapID(mapID); _mapFileRepository.MapFiles[mapID] = mapFile; diff --git a/EOLib/PacketHandlers/Init/MapWarpFileDownloadHandler.cs b/EOLib/PacketHandlers/Init/MapWarpFileDownloadHandler.cs index a1b3ebbb1..0e6d71211 100644 --- a/EOLib/PacketHandlers/Init/MapWarpFileDownloadHandler.cs +++ b/EOLib/PacketHandlers/Init/MapWarpFileDownloadHandler.cs @@ -1,18 +1,17 @@ using AutomaticTypeMapper; using EOLib.Domain.Map; -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.Linq; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Init { [AutoMappedType] - public class MapWarpFileDownloadHandler : IInitPacketHandler + public class MapWarpFileDownloadHandler : BaseInGameInitPacketHandler { private readonly IMapFileRepository _mapFileRepository; private readonly IMapDeserializer _mapFileDeserializer; @@ -20,7 +19,7 @@ public class MapWarpFileDownloadHandler : IInitPacketHandler private readonly ICurrentMapStateProvider _currentMapStateProvider; private readonly IPacketSendService _packetSendService; - public InitReply Reply => InitReply.WarpMap; + public override InitReply Reply => InitReply.WarpMap; public MapWarpFileDownloadHandler(IMapFileRepository mapFileRepository, IMapDeserializer mapFileDeserializer, @@ -35,7 +34,7 @@ public MapWarpFileDownloadHandler(IMapFileRepository mapFileRepository, _packetSendService = packetSendService; } - public bool HandlePacket(IPacket packet) + public override bool HandleData(InitInitServerPacket.ReplyCodeDataWarpMap packet) { if (_currentMapStateProvider.MapWarpState != WarpState.WarpStarted) return false; @@ -47,9 +46,8 @@ public bool HandlePacket(IPacket packet) _currentMapStateProvider.MapWarpID.MatchSome( mapID => { - var fileData = packet.ReadBytes(packet.Length - packet.ReadPosition); var mapFile = _mapFileDeserializer - .DeserializeFromByteArray(fileData.ToArray()) + .DeserializeFromByteArray(packet.MapFile.Content) .WithMapID(mapID); _mapFileRepository.MapFiles[mapID] = mapFile; @@ -63,11 +61,11 @@ public bool HandlePacket(IPacket packet) private void SendWarpAcceptToServer(int mapID, int sessionID) { - var response = new PacketBuilder(PacketFamily.Warp, PacketAction.Accept) - .AddShort(mapID) - .AddShort(sessionID) - .Build(); - _packetSendService.SendPacket(response); + _packetSendService.SendPacket(new WarpAcceptClientPacket + { + MapId = mapID, + SessionId = sessionID + }); } } } diff --git a/EOLib/PacketHandlers/Init/OnlinePlayerListHandler.cs b/EOLib/PacketHandlers/Init/OnlinePlayerListHandler.cs index 495e9330a..51567a18b 100644 --- a/EOLib/PacketHandlers/Init/OnlinePlayerListHandler.cs +++ b/EOLib/PacketHandlers/Init/OnlinePlayerListHandler.cs @@ -1,52 +1,49 @@ using AutomaticTypeMapper; using EOLib.Domain.Online; -using EOLib.Domain.Protocol; using EOLib.IO.Repositories; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Collections.Generic; +using System.Linq; namespace EOLib.PacketHandlers.Init { [AutoMappedType] - public class OnlinePlayerListHandler : BasePlayersListHandler + public class OnlinePlayerListHandler : BaseInGameInitPacketHandler { + private readonly IOnlinePlayerRepository _onlinePlayerRepository; private readonly IECFFileProvider _classFileProvider; - public override InitReply Reply => InitReply.AllPlayersList; + public override InitReply Reply => InitReply.PlayersList; public OnlinePlayerListHandler(IOnlinePlayerRepository onlinePlayerRepository, IECFFileProvider classFileProvider) - : base(onlinePlayerRepository) { + _onlinePlayerRepository = onlinePlayerRepository; _classFileProvider = classFileProvider; } - protected override OnlinePlayerInfo GetNextRecord(IPacket packet) + public override bool HandleData(InitInitServerPacket.ReplyCodeDataPlayersList packet) { - string name = packet.ReadBreakString(); + _onlinePlayerRepository.OnlinePlayers = new HashSet(packet.PlayersList.Players.Select(x => + { + var name = char.ToUpper(x.Name[0]) + x.Name.Substring(1); + var title = string.IsNullOrEmpty(x.Title) + ? "-" + : char.ToUpper(x.Title[0]) + x.Title.Substring(1); - var title = packet.ReadBreakString(); - if (packet.ReadChar() != 0) - throw new MalformedPacketException("Expected 0 char after online entry title", packet); + var className = _classFileProvider.ECFFile.Length < x.ClassId || x.ClassId == 0 + ? "-" + : _classFileProvider.ECFFile[x.ClassId].Name; - var iconType = (OnlineIcon)packet.ReadChar(); - int clsId = packet.ReadChar(); - var guild = packet.ReadBreakString(); + var guild = string.IsNullOrWhiteSpace(x.GuildTag) + ? "-" + : x.GuildTag; - name = char.ToUpper(name[0]) + name.Substring(1); + return new OnlinePlayerInfo(name, title, guild, className, x.Icon); - if (string.IsNullOrWhiteSpace(title)) - title = "-"; - else - title = char.ToUpper(title[0]) + title.Substring(1); + })); - var className = _classFileProvider.ECFFile.Length >= clsId && clsId != 0 - ? _classFileProvider.ECFFile[clsId].Name - : "-"; - - if (string.IsNullOrWhiteSpace(guild)) - guild = "-"; - - return new OnlinePlayerInfo(name, title, guild, className, iconType); + return true; } } } diff --git a/EOLib/PacketHandlers/Items/ItemAcceptHandler.cs b/EOLib/PacketHandlers/Items/ItemAcceptHandler.cs index 1e24d97a4..92a0cb2d2 100644 --- a/EOLib/PacketHandlers/Items/ItemAcceptHandler.cs +++ b/EOLib/PacketHandlers/Items/ItemAcceptHandler.cs @@ -1,9 +1,9 @@ using AutomaticTypeMapper; -using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Items @@ -12,7 +12,7 @@ namespace EOLib.PacketHandlers.Items /// Sent when another player uses an EXP scroll type item /// [AutoMappedType] - public class ItemAcceptHandler : InGameOnlyPacketHandler + public class ItemAcceptHandler : InGameOnlyPacketHandler { private readonly IEnumerable _emoteNotifiers; @@ -27,11 +27,10 @@ public ItemAcceptHandler(IPlayerInfoProvider playerInfoProvider, _emoteNotifiers = emoteNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(ItemAcceptServerPacket packet) { - var playerId = packet.ReadShort(); foreach (var notifier in _emoteNotifiers) - notifier.NotifyEmote(playerId, Domain.Character.Emote.LevelUp); + notifier.NotifyEmote(packet.PlayerId, Domain.Character.Emote.LevelUp); return true; } diff --git a/EOLib/PacketHandlers/Items/ItemAddHandler.cs b/EOLib/PacketHandlers/Items/ItemAddHandler.cs index 903754e0c..2ae3bf71e 100644 --- a/EOLib/PacketHandlers/Items/ItemAddHandler.cs +++ b/EOLib/PacketHandlers/Items/ItemAddHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using System; @@ -12,7 +13,7 @@ namespace EOLib.PacketHandlers.Items /// Sent when another player drops an item on the map /// [AutoMappedType] - public class ItemAddHandler : InGameOnlyPacketHandler + public class ItemAddHandler : InGameOnlyPacketHandler { private readonly ICurrentMapStateRepository _currentMapStateRepository; @@ -27,16 +28,9 @@ public ItemAddHandler(IPlayerInfoProvider playerInfoProvider, _currentMapStateRepository = currentMapStateRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(ItemAddServerPacket packet) { - var id = packet.ReadShort(); - var uid = packet.ReadShort(); - - var amountDropped = packet.ReadThree(); - var dropX = packet.ReadChar(); - var dropY = packet.ReadChar(); - - var mapItem = new MapItem(uid, id, dropX, dropY, amountDropped) + var mapItem = new MapItem(packet.ItemIndex, packet.ItemId, packet.Coords.X, packet.Coords.Y, packet.ItemAmount) .WithDropTime(Option.Some(DateTime.Now)); _currentMapStateRepository.MapItems.Add(mapItem); diff --git a/EOLib/PacketHandlers/Items/ItemAgreeHandler.cs b/EOLib/PacketHandlers/Items/ItemAgreeHandler.cs new file mode 100644 index 000000000..23589e30d --- /dev/null +++ b/EOLib/PacketHandlers/Items/ItemAgreeHandler.cs @@ -0,0 +1,32 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Character; +using EOLib.Domain.Login; +using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; + +namespace EOLib.PacketHandlers.Items +{ + [AutoMappedType] + public class ItemAgreeHandler : InGameOnlyPacketHandler + { + private readonly ICharacterInventoryRepository _characterInventoryRepository; + + public override PacketFamily Family => PacketFamily.Item; + + public override PacketAction Action => PacketAction.Agree; + + public ItemAgreeHandler(IPlayerInfoProvider playerInfoProvider, + ICharacterInventoryRepository characterInventoryRepository) + : base(playerInfoProvider) + { + _characterInventoryRepository = characterInventoryRepository; + } + + public override bool HandlePacket(ItemAgreeServerPacket packet) + { + _characterInventoryRepository.ItemInventory.RemoveWhere(x => x.ItemID == packet.ItemId); + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Items/ItemDropHandler.cs b/EOLib/PacketHandlers/Items/ItemDropHandler.cs index 7f7831393..649daea80 100644 --- a/EOLib/PacketHandlers/Items/ItemDropHandler.cs +++ b/EOLib/PacketHandlers/Items/ItemDropHandler.cs @@ -3,8 +3,9 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using System; using System.Collections.Generic; @@ -15,7 +16,7 @@ namespace EOLib.PacketHandlers.Items /// Sent when the main character drops an item /// [AutoMappedType] - public class ItemDropHandler : InGameOnlyPacketHandler + public class ItemDropHandler : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; private readonly ICharacterInventoryRepository _inventoryRepository; @@ -39,34 +40,23 @@ public ItemDropHandler(IPlayerInfoProvider playerInfoProvider, _mainCharacterEventNotifiers = mainCharacterEventNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(ItemDropServerPacket packet) { - var id = packet.ReadShort(); - var amountDropped = packet.ReadThree(); - var amountRemaining = packet.ReadInt(); - - var uid = packet.ReadShort(); - var dropX = packet.ReadChar(); - var dropY = packet.ReadChar(); - - var weight = packet.ReadChar(); - var maxWeight = packet.ReadChar(); - - _inventoryRepository.ItemInventory.RemoveWhere(x => x.ItemID == id); - if (amountRemaining > 0 || id == 1) - _inventoryRepository.ItemInventory.Add(new InventoryItem(id, amountRemaining)); + _inventoryRepository.ItemInventory.RemoveWhere(x => x.ItemID == packet.DroppedItem.Id); + if (packet.RemainingAmount > 0 || packet.DroppedItem.Id == 1) + _inventoryRepository.ItemInventory.Add(new InventoryItem(packet.DroppedItem.Id, packet.RemainingAmount)); var stats = _characterRepository.MainCharacter.Stats; - stats = stats.WithNewStat(CharacterStat.Weight, weight) - .WithNewStat(CharacterStat.MaxWeight, maxWeight); + stats = stats.WithNewStat(CharacterStat.Weight, packet.Weight.Current) + .WithNewStat(CharacterStat.MaxWeight, packet.Weight.Max); _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); - var mapItem = new MapItem(uid, id, dropX, dropY, amountDropped) + var mapItem = new MapItem(packet.ItemIndex, packet.DroppedItem.Id, packet.Coords.X, packet.Coords.Y, packet.DroppedItem.Amount) .WithDropTime(Option.Some(DateTime.Now.AddSeconds(-5))); _currentMapStateRepository.MapItems.Add(mapItem); foreach (var notifier in _mainCharacterEventNotifiers) - notifier.DropItem(id, amountDropped); + notifier.DropItem(packet.DroppedItem.Id, packet.DroppedItem.Amount); return true; } diff --git a/EOLib/PacketHandlers/Items/ItemGetHandler.cs b/EOLib/PacketHandlers/Items/ItemGetHandler.cs index 9f89e89c6..25e987221 100644 --- a/EOLib/PacketHandlers/Items/ItemGetHandler.cs +++ b/EOLib/PacketHandlers/Items/ItemGetHandler.cs @@ -3,8 +3,9 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional.Collections; using System.Collections.Generic; @@ -14,7 +15,7 @@ namespace EOLib.PacketHandlers.Items /// Sent when a player picks up an item /// [AutoMappedType] - public class ItemGetHandler : InGameOnlyPacketHandler + public class ItemGetHandler : InGameOnlyPacketHandler { private readonly ICharacterInventoryRepository _characterInventoryRepository; private readonly ICharacterRepository _characterRepository; @@ -38,32 +39,27 @@ public ItemGetHandler(IPlayerInfoProvider playerInfoProvider, _mainCharacterEventNotifiers = mainCharacterEventNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(ItemGetServerPacket packet) { - var uid = packet.ReadShort(); - var id = packet.ReadShort(); - var amountTaken = packet.ReadThree(); - var weight = packet.ReadChar(); - var maxWeight = packet.ReadChar(); - var existingInventoryItem = _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == id); + var existingInventoryItem = _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == packet.TakenItem.Id); existingInventoryItem.MatchSome(x => _characterInventoryRepository.ItemInventory.Remove(x)); - existingInventoryItem.Map(x => x.WithAmount(x.Amount + amountTaken)) + existingInventoryItem.Map(x => x.WithAmount(x.Amount + packet.TakenItem.Amount)) .Match(some: _characterInventoryRepository.ItemInventory.Add, - none: () => _characterInventoryRepository.ItemInventory.Add(new InventoryItem(id, amountTaken))); + none: () => _characterInventoryRepository.ItemInventory.Add(new InventoryItem(packet.TakenItem.Id, packet.TakenItem.Amount))); var newStats = _characterRepository.MainCharacter.Stats - .WithNewStat(CharacterStat.Weight, weight) - .WithNewStat(CharacterStat.MaxWeight, maxWeight); + .WithNewStat(CharacterStat.Weight, packet.Weight.Current) + .WithNewStat(CharacterStat.MaxWeight, packet.Weight.Max); _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(newStats); - if (_mapStateRepository.MapItems.ContainsKey(uid)) - _mapStateRepository.MapItems.Remove(_mapStateRepository.MapItems[uid]); + if (_mapStateRepository.MapItems.ContainsKey(packet.TakenItemIndex)) + _mapStateRepository.MapItems.Remove(_mapStateRepository.MapItems[packet.TakenItemIndex]); foreach (var notifier in _mainCharacterEventNotifiers) { - notifier.TakeItemFromMap(id, amountTaken); + notifier.TakeItemFromMap(packet.TakenItem.Id, packet.TakenItem.Amount); } return true; diff --git a/EOLib/PacketHandlers/Items/ItemJunkHandler.cs b/EOLib/PacketHandlers/Items/ItemJunkHandler.cs index 3153672cd..c2947e7d3 100644 --- a/EOLib/PacketHandlers/Items/ItemJunkHandler.cs +++ b/EOLib/PacketHandlers/Items/ItemJunkHandler.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional.Collections; using System.Collections.Generic; @@ -13,7 +14,7 @@ namespace EOLib.PacketHandlers.Items /// Sent when a player junks an item /// [AutoMappedType] - public class ItemJunkHandler : InGameOnlyPacketHandler + public class ItemJunkHandler : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; private readonly ICharacterInventoryRepository _inventoryRepository; @@ -34,31 +35,25 @@ public ItemJunkHandler(IPlayerInfoProvider playerInfoProvider, _mainCharacterEventNotifiers = mainCharacterEventNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(ItemJunkServerPacket packet) { - var id = packet.ReadShort(); - var amountRemoved = packet.ReadThree(); - var amountRemaining = packet.ReadInt(); - var weight = packet.ReadChar(); - var maxWeight = packet.ReadChar(); - - var inventoryItem = _inventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == id); + var inventoryItem = _inventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == packet.JunkedItem.Id); inventoryItem.MatchSome(x => _inventoryRepository.ItemInventory.Remove(x)); - if (amountRemaining > 0) + if (packet.RemainingAmount > 0 || packet.JunkedItem.Id == 1) { - inventoryItem.Map(x => x.WithAmount(amountRemaining)) + inventoryItem.Map(x => x.WithAmount(packet.RemainingAmount)) .MatchSome(x => _inventoryRepository.ItemInventory.Add(x)); } var stats = _characterRepository.MainCharacter.Stats; - stats = stats.WithNewStat(CharacterStat.Weight, weight) - .WithNewStat(CharacterStat.MaxWeight, maxWeight); + stats = stats.WithNewStat(CharacterStat.Weight, packet.Weight.Current) + .WithNewStat(CharacterStat.MaxWeight, packet.Weight.Max); _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); foreach (var notifier in _mainCharacterEventNotifiers) - notifier.JunkItem(id, amountRemoved); + notifier.JunkItem(packet.JunkedItem.Id, packet.JunkedItem.Amount); return true; } diff --git a/EOLib/PacketHandlers/Items/ItemKickHandler.cs b/EOLib/PacketHandlers/Items/ItemKickHandler.cs index 16c7bcbda..6622d1ac8 100644 --- a/EOLib/PacketHandlers/Items/ItemKickHandler.cs +++ b/EOLib/PacketHandlers/Items/ItemKickHandler.cs @@ -1,7 +1,8 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; using EOLib.Domain.Login; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Items { @@ -9,7 +10,7 @@ namespace EOLib.PacketHandlers.Items /// Sent when a quest takes an item from the main character /// [AutoMappedType] - public class ItemKickHandler : QuestItemChangeHandler + public class ItemKickHandler : QuestItemChangeHandler { public override PacketAction Action => PacketAction.Kick; @@ -19,5 +20,11 @@ public ItemKickHandler(IPlayerInfoProvider playerInfoProvider, : base(playerInfoProvider, characterRepository, inventoryRepository) { } + + public override bool HandlePacket(ItemKickServerPacket packet) + { + Handle(packet.Item.Id, packet.Item.Amount, packet.CurrentWeight); + return true; + } } } diff --git a/EOLib/PacketHandlers/Items/ItemObtainHandler.cs b/EOLib/PacketHandlers/Items/ItemObtainHandler.cs index 19b70a5bf..2823250e5 100644 --- a/EOLib/PacketHandlers/Items/ItemObtainHandler.cs +++ b/EOLib/PacketHandlers/Items/ItemObtainHandler.cs @@ -1,7 +1,8 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; using EOLib.Domain.Login; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Items { @@ -9,7 +10,7 @@ namespace EOLib.PacketHandlers.Items /// Sent when a quest gives an item to the main character /// [AutoMappedType] - public class ItemObtainHandler : QuestItemChangeHandler + public class ItemObtainHandler : QuestItemChangeHandler { public override PacketAction Action => PacketAction.Obtain; @@ -19,5 +20,11 @@ public ItemObtainHandler(IPlayerInfoProvider playerInfoProvider, : base(playerInfoProvider, characterRepository, inventoryRepository) { } + + public override bool HandlePacket(ItemObtainServerPacket packet) + { + Handle(packet.Item.Id, packet.Item.Amount, packet.CurrentWeight); + return true; + } } } diff --git a/EOLib/PacketHandlers/Items/ItemRemoveHandler.cs b/EOLib/PacketHandlers/Items/ItemRemoveHandler.cs index b8669ff50..a335d0c39 100644 --- a/EOLib/PacketHandlers/Items/ItemRemoveHandler.cs +++ b/EOLib/PacketHandlers/Items/ItemRemoveHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Items { @@ -10,7 +11,7 @@ namespace EOLib.PacketHandlers.Items /// Sent when an item is removed from the map by someone other than the main character /// [AutoMappedType] - public class ItemRemoveHandler : InGameOnlyPacketHandler + public class ItemRemoveHandler : InGameOnlyPacketHandler { private readonly ICurrentMapStateRepository _currentMapStateRepository; @@ -25,10 +26,10 @@ public ItemRemoveHandler(IPlayerInfoProvider playerInfoProvider, _currentMapStateRepository = currentMapStateRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(ItemRemoveServerPacket packet) { - var uid = packet.ReadShort(); - _currentMapStateRepository.MapItems.Remove(_currentMapStateRepository.MapItems[uid]); + if (_currentMapStateRepository.MapItems.TryGetValue(packet.ItemIndex, out var item)) + _currentMapStateRepository.MapItems.Remove(item); return true; } } diff --git a/EOLib/PacketHandlers/Items/ItemReplyHandler.cs b/EOLib/PacketHandlers/Items/ItemReplyHandler.cs index 6ba4a43d6..2175f08c0 100644 --- a/EOLib/PacketHandlers/Items/ItemReplyHandler.cs +++ b/EOLib/PacketHandlers/Items/ItemReplyHandler.cs @@ -2,10 +2,11 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.IO; using EOLib.IO.Repositories; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using Moffat.EndlessOnline.SDK.Protocol.Pub; using Optional.Collections; using System; using System.Collections.Generic; @@ -17,7 +18,7 @@ namespace EOLib.PacketHandlers.Items /// Sent when the main character uses an item /// [AutoMappedType] - public class ItemReplyHandler : InGameOnlyPacketHandler + public class ItemReplyHandler : InGameOnlyPacketHandler { private readonly ICharacterInventoryRepository _characterInventoryRepository; private readonly ICharacterRepository _characterRepository; @@ -50,142 +51,121 @@ public ItemReplyHandler(IPlayerInfoProvider playerInfoProvider, _itemFileProvider = itemFileProvider; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(ItemReplyServerPacket packet) { - var itemType = (ItemType)packet.ReadChar(); - var itemId = packet.ReadShort(); - var amount = packet.ReadInt(); - var weight = packet.ReadChar(); - var maxWeight = packet.ReadChar(); - - var oldItem = _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == itemId); + var oldItem = _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == packet.UsedItem.Id); oldItem.MatchSome(item => _characterInventoryRepository.ItemInventory.Remove(item)); - if (amount > 0) - _characterInventoryRepository.ItemInventory.Add(new InventoryItem(itemId, amount)); + if (packet.UsedItem.Amount > 0) + _characterInventoryRepository.ItemInventory.Add(new InventoryItem(packet.UsedItem.Id, packet.UsedItem.Amount)); var character = _characterRepository.MainCharacter; var stats = character.Stats; - stats = stats.WithNewStat(CharacterStat.Weight, weight).WithNewStat(CharacterStat.MaxWeight, maxWeight); + stats = stats.WithNewStat(CharacterStat.Weight, packet.Weight.Current).WithNewStat(CharacterStat.MaxWeight, packet.Weight.Max); var renderProps = character.RenderProperties; - switch (itemType) + switch (packet.ItemType) { case ItemType.Teleport: break; // no-op: Warp handles the rest case ItemType.Heal: - var hpGain = packet.ReadInt(); - var hp = packet.ReadShort(); - var tp = packet.ReadShort(); - - stats = stats.WithNewStat(CharacterStat.HP, hp).WithNewStat(CharacterStat.TP, tp); - var percentHealth = (int)Math.Round(100.0 * stats[CharacterStat.HP] / stats[CharacterStat.MaxHP]); + { + var data = (ItemReplyServerPacket.ItemTypeDataHeal)packet.ItemTypeData; - foreach (var notifier in _mainCharacterEventNotifiers) - notifier.NotifyTakeDamage(hpGain, percentHealth, isHeal: true); + stats = stats.WithNewStat(CharacterStat.HP, data.Hp).WithNewStat(CharacterStat.TP, data.Tp); + var percentHealth = (int)Math.Round(100.0 * stats[CharacterStat.HP] / stats[CharacterStat.MaxHP]); + foreach (var notifier in _mainCharacterEventNotifiers) + notifier.NotifyTakeDamage(data.HpGain, percentHealth, isHeal: true); + } break; case ItemType.HairDye: - var hairColor = packet.ReadChar(); - renderProps = renderProps.WithHairColor(hairColor); + { + var data = (ItemReplyServerPacket.ItemTypeDataHairDye)packet.ItemTypeData; + renderProps = renderProps.WithHairColor(data.HairColor); + } break; - case ItemType.Beer: + case ItemType.Alcohol: renderProps = renderProps.WithIsDrunk(true); foreach (var notifier in _emoteNotifiers) notifier.MakeMainPlayerDrunk(); break; case ItemType.EffectPotion: - var potionId = packet.ReadShort(); - - foreach (var notifier in _effectNotifiers) - notifier.NotifyPotionEffect(character.ID, potionId); - + { + var data = (ItemReplyServerPacket.ItemTypeDataEffectPotion)packet.ItemTypeData; + foreach (var notifier in _effectNotifiers) + notifier.NotifyPotionEffect(character.ID, data.EffectId); + } break; case ItemType.CureCurse: - var cureCurseMaxHp = packet.ReadShort(); - var cureCurseMaxTp = packet.ReadShort(); - var cureCurseStr = packet.ReadShort(); - var cureCurseInt = packet.ReadShort(); - var cureCurseWis = packet.ReadShort(); - var cureCurseAgi = packet.ReadShort(); - var cureCurseCon = packet.ReadShort(); - var cureCurseCha = packet.ReadShort(); - var cureCurseMinDam = packet.ReadShort(); - var cureCurseMaxDam = packet.ReadShort(); - var cureCurseAcc = packet.ReadShort(); - var cureCurseEvade = packet.ReadShort(); - var cureCurseArmor = packet.ReadShort(); - - if (_paperdollRepository.VisibleCharacterPaperdolls.ContainsKey(character.ID)) { - var paperdoll = _paperdollRepository.VisibleCharacterPaperdolls[character.ID].Paperdoll.ToDictionary(k => k.Key, v => v.Value); - for (EquipLocation loc = 0; loc < EquipLocation.PAPERDOLL_MAX; loc++) - { - var dollItem = paperdoll[loc]; - if (dollItem <= 0) - continue; + var data = (ItemReplyServerPacket.ItemTypeDataCureCurse)packet.ItemTypeData; - var rec = _itemFileProvider.EIFFile[dollItem]; - if (rec.Special == ItemSpecial.Cursed) + if (_paperdollRepository.VisibleCharacterPaperdolls.ContainsKey(character.ID)) + { + var paperdoll = _paperdollRepository.VisibleCharacterPaperdolls[character.ID].Paperdoll.ToDictionary(k => k.Key, v => v.Value); + for (IO.EquipLocation loc = 0; loc < IO.EquipLocation.PAPERDOLL_MAX; loc++) { - paperdoll[loc] = 0; - - if (loc == EquipLocation.Boots) - renderProps = renderProps.WithBootsGraphic(0); - else if (loc == EquipLocation.Armor) - renderProps = renderProps.WithArmorGraphic(0); - else if (loc == EquipLocation.Hat) - renderProps = renderProps.WithHatGraphic(0); - else if (loc == EquipLocation.Weapon) - renderProps = renderProps.WithWeaponGraphic(0); - else if (loc == EquipLocation.Shield) - renderProps = renderProps.WithShieldGraphic(0); + var dollItem = paperdoll[loc]; + if (dollItem <= 0) + continue; + + var rec = _itemFileProvider.EIFFile[dollItem]; + if (rec.Special == IO.ItemSpecial.Cursed) + { + paperdoll[loc] = 0; + + if (loc == IO.EquipLocation.Boots) + renderProps = renderProps.WithBootsGraphic(0); + else if (loc == IO.EquipLocation.Armor) + renderProps = renderProps.WithArmorGraphic(0); + else if (loc == IO.EquipLocation.Hat) + renderProps = renderProps.WithHatGraphic(0); + else if (loc == IO.EquipLocation.Weapon) + renderProps = renderProps.WithWeaponGraphic(0); + else if (loc == IO.EquipLocation.Shield) + renderProps = renderProps.WithShieldGraphic(0); + } } + + _paperdollRepository.VisibleCharacterPaperdolls[character.ID] = + _paperdollRepository.VisibleCharacterPaperdolls[character.ID].WithPaperdoll(paperdoll); } - _paperdollRepository.VisibleCharacterPaperdolls[character.ID] = - _paperdollRepository.VisibleCharacterPaperdolls[character.ID].WithPaperdoll(paperdoll); + stats = stats.WithNewStat(CharacterStat.MaxHP, data.Stats.MaxHp) + .WithNewStat(CharacterStat.MaxTP, data.Stats.MaxTp) + .WithNewStat(CharacterStat.Strength, data.Stats.BaseStats.Str) + .WithNewStat(CharacterStat.Intelligence, data.Stats.BaseStats.Intl) + .WithNewStat(CharacterStat.Wisdom, data.Stats.BaseStats.Wis) + .WithNewStat(CharacterStat.Agility, data.Stats.BaseStats.Agi) + .WithNewStat(CharacterStat.Constitution, data.Stats.BaseStats.Con) + .WithNewStat(CharacterStat.Charisma, data.Stats.BaseStats.Cha) + .WithNewStat(CharacterStat.MinDam, data.Stats.SecondaryStats.MinDamage) + .WithNewStat(CharacterStat.MaxDam, data.Stats.SecondaryStats.MaxDamage) + .WithNewStat(CharacterStat.Accuracy, data.Stats.SecondaryStats.Accuracy) + .WithNewStat(CharacterStat.Evade, data.Stats.SecondaryStats.Evade) + .WithNewStat(CharacterStat.Armor, data.Stats.SecondaryStats.Armor); } - - stats = stats.WithNewStat(CharacterStat.MaxHP, cureCurseMaxHp) - .WithNewStat(CharacterStat.MaxTP, cureCurseMaxTp) - .WithNewStat(CharacterStat.Strength, cureCurseStr) - .WithNewStat(CharacterStat.Intelligence, cureCurseInt) - .WithNewStat(CharacterStat.Wisdom, cureCurseWis) - .WithNewStat(CharacterStat.Agility, cureCurseAgi) - .WithNewStat(CharacterStat.Constitution, cureCurseCon) - .WithNewStat(CharacterStat.Charisma, cureCurseCha) - .WithNewStat(CharacterStat.MinDam, cureCurseMinDam) - .WithNewStat(CharacterStat.MaxDam, cureCurseMaxDam) - .WithNewStat(CharacterStat.Accuracy, cureCurseAcc) - .WithNewStat(CharacterStat.Evade, cureCurseEvade) - .WithNewStat(CharacterStat.Armor, cureCurseArmor); - break; - case ItemType.EXPReward: - var levelUpExp = packet.ReadInt(); - var levelUpLevel = packet.ReadChar(); - var levelUpStat = packet.ReadShort(); - var levelUpSkill = packet.ReadShort(); - var levelUpMaxHp = packet.ReadShort(); - var levelUpMaxTp = packet.ReadShort(); - var levelUpMaxSp = packet.ReadShort(); - - if (stats[CharacterStat.Level] < levelUpLevel) + case ItemType.ExpReward: { - foreach (var notifier in _emoteNotifiers) + var data = (ItemReplyServerPacket.ItemTypeDataExpReward)packet.ItemTypeData; + + if (stats[CharacterStat.Level] < data.LevelUp) { - notifier.NotifyEmote(_characterRepository.MainCharacter.ID, Domain.Character.Emote.LevelUp); + foreach (var notifier in _emoteNotifiers) + { + notifier.NotifyEmote(_characterRepository.MainCharacter.ID, Domain.Character.Emote.LevelUp); + } + + stats = stats.WithNewStat(CharacterStat.Level, data.LevelUp); } - stats = stats.WithNewStat(CharacterStat.Level, levelUpLevel); + stats = stats.WithNewStat(CharacterStat.Experience, data.Experience) + .WithNewStat(CharacterStat.StatPoints, data.StatPoints) + .WithNewStat(CharacterStat.SkillPoints, data.SkillPoints) + .WithNewStat(CharacterStat.MaxHP, data.MaxHp) + .WithNewStat(CharacterStat.MaxTP, data.MaxTp) + .WithNewStat(CharacterStat.MaxSP, data.MaxSp); } - - stats = stats.WithNewStat(CharacterStat.Experience, levelUpExp) - .WithNewStat(CharacterStat.StatPoints, levelUpStat) - .WithNewStat(CharacterStat.SkillPoints, levelUpSkill) - .WithNewStat(CharacterStat.MaxHP, levelUpMaxHp) - .WithNewStat(CharacterStat.MaxTP, levelUpMaxTp) - .WithNewStat(CharacterStat.MaxSP, levelUpMaxSp); - break; } diff --git a/EOLib/PacketHandlers/Items/QuestItemChangeHandler.cs b/EOLib/PacketHandlers/Items/QuestItemChangeHandler.cs index 42d47dc42..129aa409a 100644 --- a/EOLib/PacketHandlers/Items/QuestItemChangeHandler.cs +++ b/EOLib/PacketHandlers/Items/QuestItemChangeHandler.cs @@ -1,15 +1,17 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; using Optional.Collections; +using System; namespace EOLib.PacketHandlers.Items { /// /// Base handler for when a quest gives/takes items from the main character /// - public abstract class QuestItemChangeHandler : InGameOnlyPacketHandler + public abstract class QuestItemChangeHandler : InGameOnlyPacketHandler + where TPacket : IPacket { private readonly ICharacterRepository _characterRepository; private readonly ICharacterInventoryRepository _inventoryRepository; @@ -25,34 +27,22 @@ protected QuestItemChangeHandler(IPlayerInfoProvider playerInfoProvider, _inventoryRepository = inventoryRepository; } - public override bool HandlePacket(IPacket packet) + protected void Handle(int id, int amount, int weight) { - var id = packet.ReadShort(); - var amount = Action == PacketAction.Obtain ? packet.ReadThree() : packet.ReadInt(); - var weight = packet.ReadChar(); - var inventoryItem = _inventoryRepository.ItemInventory .SingleOrNone(x => x.ItemID == id) .Match(x => x, () => new InventoryItem(id, 0)); _inventoryRepository.ItemInventory.Remove(inventoryItem); - if (amount > 0) + var amountRemaining = Math.Max(0, Action == PacketAction.Kick ? amount : inventoryItem.Amount + amount); + if (amountRemaining > 0 || id == 1) { - var amountRemaining = Action == PacketAction.Kick - ? amount - : inventoryItem.Amount + amount; - - if (amountRemaining > 0) - { - _inventoryRepository.ItemInventory.Add(inventoryItem.WithAmount(amountRemaining)); - } + _inventoryRepository.ItemInventory.Add(inventoryItem.WithAmount(amountRemaining)); } var stats = _characterRepository.MainCharacter.Stats; stats = stats.WithNewStat(CharacterStat.Weight, weight); _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); - - return true; } } } diff --git a/EOLib/PacketHandlers/Jukebox/JukeboxAgreeHandler.cs b/EOLib/PacketHandlers/Jukebox/JukeboxAgreeHandler.cs index f458329cb..c2da3b1c9 100644 --- a/EOLib/PacketHandlers/Jukebox/JukeboxAgreeHandler.cs +++ b/EOLib/PacketHandlers/Jukebox/JukeboxAgreeHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional.Collections; namespace EOLib.PacketHandlers.Jukebox @@ -11,11 +12,11 @@ namespace EOLib.PacketHandlers.Jukebox /// Sent to update character's remaining gold after requesting a song /// [AutoMappedType] - public class JukeboxAgreeHandler : InGameOnlyPacketHandler + public class JukeboxAgreeHandler : InGameOnlyPacketHandler { private readonly ICharacterInventoryRepository _characterInventoryRepository; - public override PacketFamily Family => PacketFamily.JukeBox; + public override PacketFamily Family => PacketFamily.Jukebox; public override PacketAction Action => PacketAction.Agree; @@ -26,12 +27,10 @@ public JukeboxAgreeHandler(IPlayerInfoProvider playerInfoProvider, _characterInventoryRepository = characterInventoryRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(JukeboxAgreeServerPacket packet) { - var goldRemaining = packet.ReadInt(); - _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == 1).MatchSome(x => _characterInventoryRepository.ItemInventory.Remove(x)); - _characterInventoryRepository.ItemInventory.Add(new InventoryItem(1, goldRemaining)); + _characterInventoryRepository.ItemInventory.Add(new InventoryItem(1, packet.GoldAmount)); return true; } diff --git a/EOLib/PacketHandlers/Jukebox/JukeboxMessageHandler.cs b/EOLib/PacketHandlers/Jukebox/JukeboxMessageHandler.cs index 8b2bd562b..dcc101c58 100644 --- a/EOLib/PacketHandlers/Jukebox/JukeboxMessageHandler.cs +++ b/EOLib/PacketHandlers/Jukebox/JukeboxMessageHandler.cs @@ -2,21 +2,22 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Jukebox { [AutoMappedType] - public class JukeboxMessageHandler : InGameOnlyPacketHandler + public class JukeboxMessageHandler : InGameOnlyPacketHandler { private readonly ICurrentMapStateRepository _currentMapStateRepository; private readonly IEnumerable _otherCharacterAnimationNotifiers; - public override PacketFamily Family => PacketFamily.JukeBox; + public override PacketFamily Family => PacketFamily.Jukebox; - public override PacketAction Action => PacketAction.Message; + public override PacketAction Action => PacketAction.Msg; public JukeboxMessageHandler(IPlayerInfoProvider playerInfoProvider, ICurrentMapStateRepository currentMapStateRepository, @@ -27,27 +28,22 @@ public JukeboxMessageHandler(IPlayerInfoProvider playerInfoProvider, _otherCharacterAnimationNotifiers = otherCharacterAnimationNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(JukeboxMsgServerPacket packet) { - var playerId = packet.ReadShort(); - var direction = (EODirection)packet.ReadChar(); - var instrument = packet.ReadChar(); - var note = packet.ReadChar(); - - if (_currentMapStateRepository.Characters.TryGetValue(playerId, out var character)) + if (_currentMapStateRepository.Characters.TryGetValue(packet.PlayerId, out var character)) { - if (character.RenderProperties.WeaponGraphic == instrument) + if (character.RenderProperties.WeaponGraphic == packet.InstrumentId) { - var updatedCharacter = character.WithRenderProperties(character.RenderProperties.WithDirection(direction)); + var updatedCharacter = character.WithRenderProperties(character.RenderProperties.WithDirection((EODirection)packet.Direction)); _currentMapStateRepository.Characters.Update(character, updatedCharacter); foreach (var notifier in _otherCharacterAnimationNotifiers) - notifier.StartOtherCharacterAttackAnimation(playerId, note - 1); + notifier.StartOtherCharacterAttackAnimation(packet.PlayerId, packet.NoteId - 1); } } else { - _currentMapStateRepository.UnknownPlayerIDs.Add(playerId); + _currentMapStateRepository.UnknownPlayerIDs.Add(packet.PlayerId); } return true; diff --git a/EOLib/PacketHandlers/Jukebox/JukeboxOpenHandler.cs b/EOLib/PacketHandlers/Jukebox/JukeboxOpenHandler.cs index 84cd6da05..70d270898 100644 --- a/EOLib/PacketHandlers/Jukebox/JukeboxOpenHandler.cs +++ b/EOLib/PacketHandlers/Jukebox/JukeboxOpenHandler.cs @@ -2,21 +2,21 @@ using EOLib.Domain.Interact.Jukebox; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using System.Collections.Generic; -using System.IO; namespace EOLib.PacketHandlers.Jukebox { [AutoMappedType] - public class JukeboxOpenHandler : InGameOnlyPacketHandler + public class JukeboxOpenHandler : InGameOnlyPacketHandler { private readonly IJukeboxRepository _jukeboxRepository; private readonly IEnumerable _userInterfaceNotifiers; - public override PacketFamily Family => PacketFamily.JukeBox; + public override PacketFamily Family => PacketFamily.Jukebox; public override PacketAction Action => PacketAction.Open; @@ -29,21 +29,12 @@ public JukeboxOpenHandler(IPlayerInfoProvider playerInfoProvider, _userInterfaceNotifiers = userInterfaceNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(JukeboxOpenServerPacket packet) { - packet.Seek(2, SeekOrigin.Current); - - if (packet.ReadPosition < packet.Length) - { - _jukeboxRepository.PlayingRequestName = Option.Some(packet.ReadEndString()); - } - else - { - _jukeboxRepository.PlayingRequestName = Option.None(); - } + _jukeboxRepository.PlayingRequestName = packet.JukeboxPlayer.SomeWhen(x => !string.IsNullOrWhiteSpace(x)); foreach (var notifier in _userInterfaceNotifiers) - notifier.NotifyPacketDialog(PacketFamily.JukeBox); + notifier.NotifyPacketDialog(PacketFamily.Jukebox); return true; } diff --git a/EOLib/PacketHandlers/Jukebox/JukeboxPlayerHandler.cs b/EOLib/PacketHandlers/Jukebox/JukeboxPlayerHandler.cs index b70633cf4..6feb8f16f 100644 --- a/EOLib/PacketHandlers/Jukebox/JukeboxPlayerHandler.cs +++ b/EOLib/PacketHandlers/Jukebox/JukeboxPlayerHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Jukebox @@ -11,11 +12,11 @@ namespace EOLib.PacketHandlers.Jukebox /// Sent when background music should be changed (currently only in weddings) /// [AutoMappedType] - public class JukeboxPlayerHandler : InGameOnlyPacketHandler + public class JukeboxPlayerHandler : InGameOnlyPacketHandler { private readonly IEnumerable _soundNotifiers; - public override PacketFamily Family => PacketFamily.JukeBox; + public override PacketFamily Family => PacketFamily.Jukebox; public override PacketAction Action => PacketAction.Player; @@ -26,11 +27,10 @@ public JukeboxPlayerHandler(IPlayerInfoProvider playerInfoProvider, _soundNotifiers = soundNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(JukeboxPlayerServerPacket packet) { - var id = packet.ReadChar(); foreach (var notifier in _soundNotifiers) - notifier.NotifyMusic(id, isJukebox: false); + notifier.NotifyMusic(packet.MfxId, isJukebox: false); return true; } } diff --git a/EOLib/PacketHandlers/Jukebox/JukeboxReplyHandler.cs b/EOLib/PacketHandlers/Jukebox/JukeboxReplyHandler.cs new file mode 100644 index 000000000..76dbb3bd5 --- /dev/null +++ b/EOLib/PacketHandlers/Jukebox/JukeboxReplyHandler.cs @@ -0,0 +1,34 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Login; +using EOLib.Domain.Notifiers; +using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Collections.Generic; + +namespace EOLib.PacketHandlers.Jukebox +{ + [AutoMappedType] + public class JukeboxReplyHandler : InGameOnlyPacketHandler + { + private readonly IEnumerable _jukeboxNotifiers; + + public override PacketFamily Family => PacketFamily.Jukebox; + + public override PacketAction Action => PacketAction.Reply; + + public JukeboxReplyHandler(IPlayerInfoProvider playerInfoProvider, + IEnumerable jukeboxNotifiers) + : base(playerInfoProvider) + { + _jukeboxNotifiers = jukeboxNotifiers; + } + + public override bool HandlePacket(JukeboxReplyServerPacket packet) + { + foreach (var notifier in _jukeboxNotifiers) + notifier.JukeboxUnavailable(); + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Jukebox/JukeboxUseHandler.cs b/EOLib/PacketHandlers/Jukebox/JukeboxUseHandler.cs index 590d12763..ac6147b05 100644 --- a/EOLib/PacketHandlers/Jukebox/JukeboxUseHandler.cs +++ b/EOLib/PacketHandlers/Jukebox/JukeboxUseHandler.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Interact.Jukebox; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using System.Collections.Generic; @@ -13,12 +14,12 @@ namespace EOLib.PacketHandlers.Jukebox /// Sent when a Jukebox track should be played /// [AutoMappedType] - public class JukeboxUseHandler : InGameOnlyPacketHandler + public class JukeboxUseHandler : InGameOnlyPacketHandler { private readonly IJukeboxRepository _jukeboxRepository; private readonly IEnumerable _soundNotifiers; - public override PacketFamily Family => PacketFamily.JukeBox; + public override PacketFamily Family => PacketFamily.Jukebox; public override PacketAction Action => PacketAction.Use; @@ -31,14 +32,12 @@ public JukeboxUseHandler(IPlayerInfoProvider playerInfoProvider, _soundNotifiers = soundNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(JukeboxUseServerPacket packet) { - var id = packet.ReadShort(); - _jukeboxRepository.PlayingRequestName = Option.Some(string.Empty); foreach (var notifier in _soundNotifiers) - notifier.NotifyMusic(id, isJukebox: true); + notifier.NotifyMusic(packet.TrackId, isJukebox: true); return true; } diff --git a/EOLib/PacketHandlers/Locker/LockerBuyHandler.cs b/EOLib/PacketHandlers/Locker/LockerBuyHandler.cs index 415b31d3e..441290903 100644 --- a/EOLib/PacketHandlers/Locker/LockerBuyHandler.cs +++ b/EOLib/PacketHandlers/Locker/LockerBuyHandler.cs @@ -3,15 +3,16 @@ using EOLib.Domain.Interact.Bank; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using System.Collections.Generic; namespace EOLib.PacketHandlers.Locker { [AutoMappedType] - public class LockerBuyHandler : InGameOnlyPacketHandler + public class LockerBuyHandler : InGameOnlyPacketHandler { private const byte BuySellSfxId = 26; @@ -34,13 +35,12 @@ public LockerBuyHandler(IPlayerInfoProvider playerInfoProvider, _soundNotifiers = soundNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(LockerBuyServerPacket packet) { - var inventoryGold = packet.ReadInt(); _characterInventoryRepository.ItemInventory.RemoveWhere(x => x.ItemID == 1); - _characterInventoryRepository.ItemInventory.Add(new InventoryItem(1, inventoryGold)); + _characterInventoryRepository.ItemInventory.Add(new InventoryItem(1, packet.GoldAmount)); - _bankDataRepository.LockerUpgrades = Option.Some(packet.ReadChar()); + _bankDataRepository.LockerUpgrades = Option.Some(packet.LockerUpgrades); foreach (var notifier in _soundNotifiers) notifier.NotifySoundEffect(BuySellSfxId); diff --git a/EOLib/PacketHandlers/Locker/LockerGetHandler.cs b/EOLib/PacketHandlers/Locker/LockerGetHandler.cs index 2c4614c8d..c6c0aa019 100644 --- a/EOLib/PacketHandlers/Locker/LockerGetHandler.cs +++ b/EOLib/PacketHandlers/Locker/LockerGetHandler.cs @@ -2,88 +2,32 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; -using EOLib.Net.Handlers; -using Optional.Collections; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Locker { + /// /// Handles LOCKER_GET from server for taking an item from locker /// [AutoMappedType] - public class LockerGetHandler : InGameOnlyPacketHandler + public class LockerGetHandler : LockerModifyHandler { - private readonly ILockerDataRepository _lockerDataRepository; - private readonly ICharacterRepository _characterRepository; - private readonly ICharacterInventoryRepository _characterInventoryRepository; - - public override PacketFamily Family => PacketFamily.Locker; - public override PacketAction Action => PacketAction.Get; public LockerGetHandler(IPlayerInfoProvider playerInfoProvider, ILockerDataRepository lockerDataRepository, ICharacterRepository characterRepository, ICharacterInventoryRepository characterInventoryRepository) - : base(playerInfoProvider) + : base(playerInfoProvider, lockerDataRepository, characterRepository, characterInventoryRepository) { - _lockerDataRepository = lockerDataRepository; - _characterRepository = characterRepository; - _characterInventoryRepository = characterInventoryRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(LockerGetServerPacket packet) { - var itemId = packet.ReadShort(); - var amount = Action == PacketAction.Get ? packet.ReadThree() : packet.ReadInt(); - var weight = packet.ReadChar(); - var maxWeight = packet.ReadChar(); - - _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == itemId) - .Match( - some: existing => - { - _characterInventoryRepository.ItemInventory.Remove(existing); - if (amount > 0 || itemId == 1) - { - _characterInventoryRepository.ItemInventory.Add(existing.WithAmount(Action == PacketAction.Get ? existing.Amount + amount : amount)); - } - }, - none: () => - { - if (amount > 0) - _characterInventoryRepository.ItemInventory.Add(new InventoryItem(itemId, amount)); - }); - - var stats = _characterRepository.MainCharacter.Stats - .WithNewStat(CharacterStat.Weight, weight) - .WithNewStat(CharacterStat.MaxWeight, maxWeight); - - _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); - - _lockerDataRepository.Items.Clear(); - while (packet.ReadPosition < packet.Length) - _lockerDataRepository.Items.Add(new InventoryItem(packet.ReadShort(), packet.ReadThree())); - + Handle(packet.TakenItem.Id, packet.TakenItem.Amount, packet.Weight, packet.LockerItems); return true; } } - - /// - /// Handles LOCKER_REPLY from server for adding an item to locker - /// - [AutoMappedType] - public class LockerReplyHandler : LockerGetHandler - { - public override PacketAction Action => PacketAction.Reply; - - public LockerReplyHandler(IPlayerInfoProvider playerInfoProvider, - ILockerDataRepository lockerDataRepository, - ICharacterRepository characterRepository, - ICharacterInventoryRepository characterInventoryRepository) - : base(playerInfoProvider, lockerDataRepository, characterRepository, characterInventoryRepository) - { - } - } } diff --git a/EOLib/PacketHandlers/Locker/LockerModifyHandler.cs b/EOLib/PacketHandlers/Locker/LockerModifyHandler.cs new file mode 100644 index 000000000..3e0c48fc8 --- /dev/null +++ b/EOLib/PacketHandlers/Locker/LockerModifyHandler.cs @@ -0,0 +1,60 @@ +using EOLib.Domain.Character; +using EOLib.Domain.Login; +using EOLib.Domain.Map; +using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Optional.Collections; +using System.Collections.Generic; + +namespace EOLib.PacketHandlers.Locker +{ + public abstract class LockerModifyHandler : InGameOnlyPacketHandler + where TPacket : IPacket + { + private readonly ILockerDataRepository _lockerDataRepository; + private readonly ICharacterRepository _characterRepository; + private readonly ICharacterInventoryRepository _characterInventoryRepository; + + public override PacketFamily Family => PacketFamily.Locker; + + protected LockerModifyHandler(IPlayerInfoProvider playerInfoProvider, + ILockerDataRepository lockerDataRepository, + ICharacterRepository characterRepository, + ICharacterInventoryRepository characterInventoryRepository) + : base(playerInfoProvider) + { + _lockerDataRepository = lockerDataRepository; + _characterRepository = characterRepository; + _characterInventoryRepository = characterInventoryRepository; + } + + protected void Handle(int itemId, int amount, Weight weight, IReadOnlyList items) + { + _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == itemId) + .Match( + some: existing => + { + _characterInventoryRepository.ItemInventory.Remove(existing); + if (amount > 0 || itemId == 1) + { + _characterInventoryRepository.ItemInventory.Add(existing.WithAmount(Action == PacketAction.Get ? existing.Amount + amount : amount)); + } + }, + none: () => + { + if (amount > 0) + _characterInventoryRepository.ItemInventory.Add(new InventoryItem(itemId, amount)); + }); + + var stats = _characterRepository.MainCharacter.Stats + .WithNewStat(CharacterStat.Weight, weight.Current) + .WithNewStat(CharacterStat.MaxWeight, weight.Max); + + _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); + + _lockerDataRepository.Items.Clear(); + foreach (var item in items) + _lockerDataRepository.Items.Add(new InventoryItem(item.Id, item.Amount)); + } + } +} diff --git a/EOLib/PacketHandlers/Locker/LockerOpenHandler.cs b/EOLib/PacketHandlers/Locker/LockerOpenHandler.cs index cfc47113a..8cfa3ca99 100644 --- a/EOLib/PacketHandlers/Locker/LockerOpenHandler.cs +++ b/EOLib/PacketHandlers/Locker/LockerOpenHandler.cs @@ -3,8 +3,9 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Locker @@ -13,7 +14,7 @@ namespace EOLib.PacketHandlers.Locker /// Handles LOCKER_OPEN from server for opening a locker /// [AutoMappedType] - public class LockerOpenHandler : InGameOnlyPacketHandler + public class LockerOpenHandler : InGameOnlyPacketHandler { private readonly ILockerDataRepository _lockerDataRepository; private readonly IEnumerable _userInterfaceNotifiers; @@ -31,16 +32,13 @@ public LockerOpenHandler(IPlayerInfoProvider playerInfoProvider, _userInterfaceNotifiers = userInterfaceNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(LockerOpenServerPacket packet) { - var x = packet.ReadChar(); - var y = packet.ReadChar(); - _lockerDataRepository.ResetState(); - _lockerDataRepository.Location = new MapCoordinate(x, y); + _lockerDataRepository.Location = new MapCoordinate(packet.LockerCoords.X, packet.LockerCoords.Y); - while (packet.ReadPosition < packet.Length) - _lockerDataRepository.Items.Add(new InventoryItem(packet.ReadShort(), packet.ReadThree())); + foreach (var item in packet.LockerItems) + _lockerDataRepository.Items.Add(new InventoryItem(item.Id, item.Amount)); foreach (var notifier in _userInterfaceNotifiers) notifier.NotifyPacketDialog(Family); diff --git a/EOLib/PacketHandlers/Locker/LockerReplyHandler.cs b/EOLib/PacketHandlers/Locker/LockerReplyHandler.cs new file mode 100644 index 000000000..8a589b404 --- /dev/null +++ b/EOLib/PacketHandlers/Locker/LockerReplyHandler.cs @@ -0,0 +1,32 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Character; +using EOLib.Domain.Login; +using EOLib.Domain.Map; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; + +namespace EOLib.PacketHandlers.Locker +{ + /// + /// Handles LOCKER_REPLY from server for adding an item to locker + /// + [AutoMappedType] + public class LockerReplyHandler : LockerModifyHandler + { + public override PacketAction Action => PacketAction.Reply; + + public LockerReplyHandler(IPlayerInfoProvider playerInfoProvider, + ILockerDataRepository lockerDataRepository, + ICharacterRepository characterRepository, + ICharacterInventoryRepository characterInventoryRepository) + : base(playerInfoProvider, lockerDataRepository, characterRepository, characterInventoryRepository) + { + } + + public override bool HandlePacket(LockerReplyServerPacket packet) + { + Handle(packet.DepositedItem.Id, packet.DepositedItem.Amount, packet.Weight, packet.LockerItems); + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Locker/LockerSpecHandler.cs b/EOLib/PacketHandlers/Locker/LockerSpecHandler.cs new file mode 100644 index 000000000..1d91da976 --- /dev/null +++ b/EOLib/PacketHandlers/Locker/LockerSpecHandler.cs @@ -0,0 +1,37 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Login; +using EOLib.Domain.Notifiers; +using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Collections.Generic; + +namespace EOLib.PacketHandlers.Locker +{ + [AutoMappedType] + public class LockerSpecHandler : InGameOnlyPacketHandler + { + private readonly IEnumerable _lockerEventNotifiers; + + public override PacketFamily Family => PacketFamily.Locker; + + public override PacketAction Action => PacketAction.Spec; + + public LockerSpecHandler(IPlayerInfoProvider playerInfoProvider, + IEnumerable lockerEventNotifiers) + : base(playerInfoProvider) + { + _lockerEventNotifiers = lockerEventNotifiers; + } + + public override bool HandlePacket(LockerSpecServerPacket packet) + { + foreach (var notifier in _lockerEventNotifiers) + { + notifier.NotifyLockerFull(packet.LockerMaxItems); + } + + return true; + } + } +} diff --git a/EOLib/PacketHandlers/MapInfo/MapInfoReplyHandler.cs b/EOLib/PacketHandlers/MapInfo/MapInfoReplyHandler.cs index 2b40b3b83..8e65efd9d 100644 --- a/EOLib/PacketHandlers/MapInfo/MapInfoReplyHandler.cs +++ b/EOLib/PacketHandlers/MapInfo/MapInfoReplyHandler.cs @@ -1,63 +1,47 @@ using AutomaticTypeMapper; +using EOLib.Domain.Character; using EOLib.Domain.Extensions; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.IO.Repositories; -using EOLib.Net; using EOLib.Net.Handlers; -using EOLib.Net.Translators; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Linq; namespace EOLib.PacketHandlers.MapInfo { [AutoMappedType] - public class MapInfoReplyHandler : InGameOnlyPacketHandler + public class MapInfoReplyHandler : InGameOnlyPacketHandler { private readonly ICurrentMapStateRepository _currentMapStateRepository; - private readonly ICharacterFromPacketFactory _characterFromPacketFactory; - private readonly INPCFromPacketFactory _npcFromPacketFactory; - private readonly IEIFFileProvider _eifFileProvider; - public override PacketFamily Family => PacketFamily.MapInfo; + public override PacketFamily Family => PacketFamily.Range; public override PacketAction Action => PacketAction.Reply; public MapInfoReplyHandler(IPlayerInfoProvider playerInfoProvider, - ICurrentMapStateRepository currentMapStateRepository, - ICharacterFromPacketFactory characterFromPacketFactory, - INPCFromPacketFactory npcFromPacketFactory, - IEIFFileProvider eifFileProvider) + ICurrentMapStateRepository currentMapStateRepository) : base(playerInfoProvider) { _currentMapStateRepository = currentMapStateRepository; - _characterFromPacketFactory = characterFromPacketFactory; - _npcFromPacketFactory = npcFromPacketFactory; - _eifFileProvider = eifFileProvider; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(RangeReplyServerPacket packet) { - var numberOfCharacters = packet.ReadChar(); - - if (packet.PeekByte() == byte.MaxValue) + foreach (var character in packet.Nearby.Characters.Where(x => x.ByteSize >= 42).Select(Character.FromNearby)) { - packet.ReadByte(); - for (var i = 0; i < numberOfCharacters; i++) + if (_currentMapStateRepository.Characters.ContainsKey(character.ID)) { - var character = _characterFromPacketFactory.CreateCharacter(packet); - if (_currentMapStateRepository.Characters.TryGetValue(character.ID, out var existingCharacter)) - { - character = existingCharacter.WithAppliedData(character); - } - - _currentMapStateRepository.Characters.Update(existingCharacter, character); - if (packet.ReadByte() != byte.MaxValue) - throw new MalformedPacketException("Missing 255 byte after character data", packet); + _currentMapStateRepository.Characters.Update( + _currentMapStateRepository.Characters[character.ID], + _currentMapStateRepository.Characters[character.ID].WithAppliedData(character)); } + else + _currentMapStateRepository.Characters.Add(character); } - while (packet.ReadPosition < packet.Length) + foreach (var npc in packet.Nearby.Npcs.Select(Domain.NPC.NPC.FromNearby)) { - var npc = _npcFromPacketFactory.CreateNPC(packet); if (_currentMapStateRepository.NPCs.ContainsKey(npc.Index)) _currentMapStateRepository.NPCs.Update(_currentMapStateRepository.NPCs[npc.Index], npc); else diff --git a/EOLib/PacketHandlers/Marriage/MarriageOpenHandler.cs b/EOLib/PacketHandlers/Marriage/MarriageOpenHandler.cs index 0342238b1..b227c9fd6 100644 --- a/EOLib/PacketHandlers/Marriage/MarriageOpenHandler.cs +++ b/EOLib/PacketHandlers/Marriage/MarriageOpenHandler.cs @@ -2,14 +2,15 @@ using EOLib.Domain.Interact; using EOLib.Domain.Interact.Law; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Marriage { [AutoMappedType] - public class MarriageOpenHandler : InGameOnlyPacketHandler + public class MarriageOpenHandler : InGameOnlyPacketHandler { private readonly ILawSessionRepository _lawSessionRepository; private readonly IEnumerable _npcInteractionNotifiers; @@ -27,9 +28,9 @@ public MarriageOpenHandler(IPlayerInfoProvider playerInfoProvider, _npcInteractionNotifiers = npcInteractionNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(MarriageOpenServerPacket packet) { - _lawSessionRepository.SessionID = packet.ReadThree(); + _lawSessionRepository.SessionID = packet.SessionId; foreach (var notifier in _npcInteractionNotifiers) notifier.NotifyInteractionFromNPC(IO.NPCType.Law); diff --git a/EOLib/PacketHandlers/Marriage/MarriageReplyHandler.cs b/EOLib/PacketHandlers/Marriage/MarriageReplyHandler.cs index 5eca0176e..701512dbc 100644 --- a/EOLib/PacketHandlers/Marriage/MarriageReplyHandler.cs +++ b/EOLib/PacketHandlers/Marriage/MarriageReplyHandler.cs @@ -1,16 +1,16 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; using EOLib.Domain.Interact; -using EOLib.Domain.Interact.Law; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Marriage { [AutoMappedType] - public class MarriageReplyHandler : InGameOnlyPacketHandler + public class MarriageReplyHandler : InGameOnlyPacketHandler { private readonly ICharacterInventoryRepository _characterInventoryRepository; private readonly IEnumerable _npcInteractionNotifiers; @@ -28,20 +28,17 @@ public MarriageReplyHandler(IPlayerInfoProvider playerInfoProvider, _npcInteractionNotifiers = npcInteractionNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(MarriageReplyServerPacket packet) { - var replyCode = (MarriageReply)packet.ReadShort(); - - if (replyCode == MarriageReply.Success) + if (packet.ReplyCode == MarriageReply.Success) { - var goldAmount = packet.ReadInt(); - + var data = (MarriageReplyServerPacket.ReplyCodeDataSuccess)packet.ReplyCodeData; _characterInventoryRepository.ItemInventory.RemoveWhere(x => x.ItemID == 1); - _characterInventoryRepository.ItemInventory.Add(new InventoryItem(1, goldAmount)); + _characterInventoryRepository.ItemInventory.Add(new InventoryItem(1, data.GoldAmount)); } foreach (var notifier in _npcInteractionNotifiers) - notifier.NotifyMarriageReply(replyCode); + notifier.NotifyMarriageReply(packet.ReplyCode); return true; } diff --git a/EOLib/PacketHandlers/Message/MessageAcceptHandler.cs b/EOLib/PacketHandlers/Message/MessageAcceptHandler.cs index c3f23458e..b75e4ed77 100644 --- a/EOLib/PacketHandlers/Message/MessageAcceptHandler.cs +++ b/EOLib/PacketHandlers/Message/MessageAcceptHandler.cs @@ -1,9 +1,11 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; +using System.Linq; namespace EOLib.PacketHandlers.Message { @@ -11,7 +13,7 @@ namespace EOLib.PacketHandlers.Message /// Shows a message dialog (ScrollingListDialogSize.Large, ScrollingListDialog.ListItemStyle.Small) /// [AutoMappedType] - public class MessageAcceptHandler : InGameOnlyPacketHandler + public class MessageAcceptHandler : InGameOnlyPacketHandler { private readonly IEnumerable _userInterfaceNotifiers; @@ -26,15 +28,10 @@ public MessageAcceptHandler(IPlayerInfoProvider playerInfoProvider, _userInterfaceNotifiers = userInterfaceNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(MessageAcceptServerPacket packet) { - var title = packet.ReadBreakString(); - var messages = new List(); - while (packet.ReadPosition < packet.Length) - messages.Add(packet.ReadBreakString()); - foreach (var notifier in _userInterfaceNotifiers) - notifier.NotifyMessageDialog(title, messages); + notifier.NotifyMessageDialog(packet.Messages[0], packet.Messages.Skip(1).ToList()); return true; } diff --git a/EOLib/PacketHandlers/Music/MusicPlayerHandler.cs b/EOLib/PacketHandlers/Music/MusicPlayerHandler.cs index 6f4d8a1cf..f8bc48cdd 100644 --- a/EOLib/PacketHandlers/Music/MusicPlayerHandler.cs +++ b/EOLib/PacketHandlers/Music/MusicPlayerHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Music @@ -11,7 +12,7 @@ namespace EOLib.PacketHandlers.Music /// Sent by the server when a sound effect should be played /// [AutoMappedType] - public class MusicPlayerHandler : InGameOnlyPacketHandler + public class MusicPlayerHandler : InGameOnlyPacketHandler { private readonly IEnumerable _notifiers; @@ -26,11 +27,10 @@ public MusicPlayerHandler(IPlayerInfoProvider playerInfoProvider, _notifiers = notifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(MusicPlayerServerPacket packet) { - var sfxId = packet.ReadChar(); foreach (var notifier in _notifiers) - notifier.NotifySoundEffect(sfxId); + notifier.NotifySoundEffect(packet.SoundId); return true; } } diff --git a/EOLib/PacketHandlers/NPC/NPCAcceptHandler.cs b/EOLib/PacketHandlers/NPC/NPCAcceptHandler.cs index 58ea5aaa7..dd2ac0343 100644 --- a/EOLib/PacketHandlers/NPC/NPCAcceptHandler.cs +++ b/EOLib/PacketHandlers/NPC/NPCAcceptHandler.cs @@ -1,10 +1,11 @@ -using System.Collections.Generic; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Collections.Generic; namespace EOLib.PacketHandlers.NPC { @@ -12,48 +13,32 @@ namespace EOLib.PacketHandlers.NPC /// Sent when the main character levels up from killing an NPC /// [AutoMappedType] - public class NPCAcceptHandler : NPCSpecHandler + public class NPCAcceptHandler : NPCDeathHandler { private readonly IEnumerable _emoteNotifiers; - public override PacketFamily Family => PacketFamily.NPC; + public override PacketFamily Family => PacketFamily.Npc; public override PacketAction Action => PacketAction.Accept; public NPCAcceptHandler(IPlayerInfoProvider playerInfoProvider, - ICurrentMapStateRepository currentMapStateRepository, ICharacterRepository characterRepository, + ICurrentMapStateRepository currentMapStateRepository, ICharacterSessionRepository characterSessionRepository, IEnumerable npcAnimationNotifiers, IEnumerable mainCharacterEventNotifiers, IEnumerable otherCharacterAnimationNotifiers, IEnumerable emoteNotifiers) - : base(playerInfoProvider, currentMapStateRepository, characterRepository, characterSessionRepository, + : base(playerInfoProvider, characterRepository, currentMapStateRepository, characterSessionRepository, npcAnimationNotifiers, mainCharacterEventNotifiers, otherCharacterAnimationNotifiers) { _emoteNotifiers = emoteNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(NpcAcceptServerPacket packet) { - if (!base.HandlePacket(packet)) - return false; - - var level = packet.ReadChar(); - var stat = packet.ReadShort(); - var skill = packet.ReadShort(); - var maxhp = packet.ReadShort(); - var maxtp = packet.ReadShort(); - var maxsp = packet.ReadShort(); - - var stats = _characterRepository.MainCharacter.Stats; - stats = stats.WithNewStat(CharacterStat.Level, level) - .WithNewStat(CharacterStat.StatPoints, stat) - .WithNewStat(CharacterStat.SkillPoints, skill) - .WithNewStat(CharacterStat.MaxHP, maxhp) - .WithNewStat(CharacterStat.MaxTP, maxtp) - .WithNewStat(CharacterStat.MaxSP, maxsp); - _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); + DeathWorkflow(packet.NpcKilledData, packet.Experience); + ApplyStats(packet.LevelUp); foreach (var notifier in _emoteNotifiers) notifier.NotifyEmote(_characterRepository.MainCharacter.ID, Domain.Character.Emote.LevelUp); diff --git a/EOLib/PacketHandlers/NPC/NPCAgreeHandler.cs b/EOLib/PacketHandlers/NPC/NPCAgreeHandler.cs index 04dd13534..2b6429694 100644 --- a/EOLib/PacketHandlers/NPC/NPCAgreeHandler.cs +++ b/EOLib/PacketHandlers/NPC/NPCAgreeHandler.cs @@ -1,9 +1,10 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; using EOLib.Net.Handlers; -using EOLib.Net.Translators; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Linq; namespace EOLib.PacketHandlers.NPC { @@ -11,31 +12,25 @@ namespace EOLib.PacketHandlers.NPC /// Sent in response to an NpcMapInfo request /// [AutoMappedType] - public class NPCAgreeHandler : InGameOnlyPacketHandler + public class NPCAgreeHandler : InGameOnlyPacketHandler { private readonly ICurrentMapStateRepository _currentMapStateRepository; - private readonly INPCFromPacketFactory _npcFromPacketFactory; - public override PacketFamily Family => PacketFamily.NPC; + public override PacketFamily Family => PacketFamily.Npc; public override PacketAction Action => PacketAction.Agree; public NPCAgreeHandler(IPlayerInfoProvider playerInfoProvider, - ICurrentMapStateRepository currentMapStateRepository, - INPCFromPacketFactory npcFromPacketFactory) + ICurrentMapStateRepository currentMapStateRepository) : base(playerInfoProvider) { _currentMapStateRepository = currentMapStateRepository; - _npcFromPacketFactory = npcFromPacketFactory; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(NpcAgreeServerPacket packet) { - var length = packet.ReadChar(); - - for (int i = 0; i < length; i++) + foreach (var npc in packet.Npcs.Select(Domain.NPC.NPC.FromNearby)) { - var npc = _npcFromPacketFactory.CreateNPC(packet); if (_currentMapStateRepository.NPCs.TryGetValue(npc.Index, out var oldNpc)) { _currentMapStateRepository.NPCs.Update(oldNpc, npc); diff --git a/EOLib/PacketHandlers/NPC/NPCDeathHandler.cs b/EOLib/PacketHandlers/NPC/NPCDeathHandler.cs new file mode 100644 index 000000000..7ec8ae91e --- /dev/null +++ b/EOLib/PacketHandlers/NPC/NPCDeathHandler.cs @@ -0,0 +1,167 @@ +using EOLib.Domain.Character; +using EOLib.Domain.Login; +using EOLib.Domain.Notifiers; +using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using Optional; +using System; +using EOLib.Domain.Map; +using System.Collections.Generic; +using EOLib.Domain.Interact.Skill; + +namespace EOLib.PacketHandlers.NPC +{ + public abstract class NPCDeathHandler : InGameOnlyPacketHandler + where TPacket : IPacket + { + protected readonly ICharacterRepository _characterRepository; + private readonly ICurrentMapStateRepository _currentMapStateRepository; + private readonly ICharacterSessionRepository _characterSessionRepository; + private readonly IEnumerable _npcActionNotifiers; + private readonly IEnumerable _mainCharacterEventNotifiers; + private readonly IEnumerable _otherCharacterAnimationNotifiers; + + protected NPCDeathHandler(IPlayerInfoProvider playerInfoProvider, + ICharacterRepository characterRepository, + ICurrentMapStateRepository currentMapStateRepository, + ICharacterSessionRepository characterSessionRepository, + IEnumerable npcActionNotifiers, + IEnumerable mainCharacterEventNotifiers, + IEnumerable otherCharacterAnimationNotifiers) + : base(playerInfoProvider) + { + _characterRepository = characterRepository; + _currentMapStateRepository = currentMapStateRepository; + _characterSessionRepository = characterSessionRepository; + _npcActionNotifiers = npcActionNotifiers; + _mainCharacterEventNotifiers = mainCharacterEventNotifiers; + _otherCharacterAnimationNotifiers = otherCharacterAnimationNotifiers; + } + + protected void DeathWorkflow(NpcKilledData killData, int? experience) + { + DeathWorkflowSpell(killData, experience, Option.None<(int, int)>()); + } + + protected void DeathWorkflowSpell(NpcKilledData killData, int? experience, Option<(int SpellId, int CasterTp)> castProperties) + { + var optionalDamage = killData.Damage.SomeWhen(x => x > 0); + // note: this replicates prior functionality implemented based on EOSERV + // EOSERV sends a 5-byte packet in Npc::RemoveFromView to kill without the animation + var showDeathAnimation = (killData.ByteSize > 7 && castProperties.HasValue) || killData.ByteSize > 5; + RemoveNPCFromView(killData.NpcIndex, killData.KillerId, castProperties.Map(x => x.SpellId), optionalDamage, showDeathAnimation); + + if (killData.KillerId > 0) + { + UpdatePlayerDirection(killData.KillerId, (EODirection)killData.KillerDirection); + } + + if (killData.DropId > 0) + { + ShowDroppedItem(killData); + } + + if (experience.HasValue) + { + UpdatePlayerExperience(experience.Value); + } + + castProperties.MatchSome(x => + { + UpdateCharacterStat(CharacterStat.TP, x.CasterTp); + NotifySpellCast(killData.KillerId); + }); + } + + protected void UpdatePlayerDirection(int playerID, EODirection playerDirection) + { + if (playerID == _characterRepository.MainCharacter.ID) + { + var updatedRenderProps = _characterRepository.MainCharacter.RenderProperties.WithDirection(playerDirection); + _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithRenderProperties(updatedRenderProps); + } + else if (_currentMapStateRepository.Characters.TryGetValue(playerID, out var character)) + { + var updatedRenderProps = character.RenderProperties.WithDirection(playerDirection); + _currentMapStateRepository.Characters.Update(character, character.WithRenderProperties(updatedRenderProps)); + } + else + { + _currentMapStateRepository.UnknownPlayerIDs.Add(playerID); + } + } + + protected void RemoveNPCFromView(int deadNPCIndex, int playerId, Option spellId, Option damage, bool showDeathAnimation) + { + foreach (var notifier in _npcActionNotifiers) + notifier.RemoveNPCFromView(deadNPCIndex, playerId, spellId, damage, showDeathAnimation); + + if (_currentMapStateRepository.NPCs.TryGetValue(deadNPCIndex, out var npc)) + _currentMapStateRepository.NPCs.Remove(npc); + } + + protected void UpdateCharacterStat(CharacterStat whichStat, int statValue) + { + var stats = _characterRepository.MainCharacter.Stats; + stats = stats.WithNewStat(whichStat, statValue); + _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); + } + + protected void UpdatePlayerExperience(int experienceValue) + { + var expDifference = experienceValue - _characterRepository.MainCharacter.Stats[CharacterStat.Experience]; + + if (expDifference > 0) + { + foreach (var notifier in _mainCharacterEventNotifiers) + notifier.NotifyGainedExp(expDifference); + + UpdateCharacterStat(CharacterStat.Experience, experienceValue); + + _characterSessionRepository.LastKillExp = expDifference; + if (expDifference > _characterSessionRepository.BestKillExp) + _characterSessionRepository.BestKillExp = expDifference; + _characterSessionRepository.TodayTotalExp += Convert.ToUInt64(Math.Max(expDifference, 0)); + } + } + + protected void ApplyStats(LevelUpStats levelUpStats) + { + var stats = _characterRepository.MainCharacter.Stats; + stats = stats.WithNewStat(CharacterStat.Level, levelUpStats.Level) + .WithNewStat(CharacterStat.StatPoints, levelUpStats.StatPoints) + .WithNewStat(CharacterStat.SkillPoints, levelUpStats.SkillPoints) + .WithNewStat(CharacterStat.MaxHP, levelUpStats.MaxHp) + .WithNewStat(CharacterStat.MaxTP, levelUpStats.MaxTp) + .WithNewStat(CharacterStat.MaxSP, levelUpStats.MaxSp); + _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); + } + + protected void ShowDroppedItem(NpcKilledData npcKilledData) + { + var mapItem = new MapItem(npcKilledData.DropIndex, + npcKilledData.DropId, + npcKilledData.DropCoords.X, + npcKilledData.DropCoords.Y, + npcKilledData.DropAmount) + .WithIsNPCDrop(true) + .WithDropTime(Option.Some(DateTime.Now)) + .WithOwningPlayerID(Option.Some(npcKilledData.KillerId)); + + if (_currentMapStateRepository.MapItems.TryGetValue(npcKilledData.DropIndex, out var oldItem)) + _currentMapStateRepository.MapItems.Update(oldItem, mapItem); + else + _currentMapStateRepository.MapItems.Add(mapItem); + + foreach (var notifier in _npcActionNotifiers) + notifier.NPCDropItem(mapItem); + } + + protected void NotifySpellCast(int playerID) + { + foreach (var notifier in _otherCharacterAnimationNotifiers) + notifier.NotifyTargetNpcSpellCast(playerID); + } + } +} diff --git a/EOLib/PacketHandlers/NPC/NPCDialogHandler.cs b/EOLib/PacketHandlers/NPC/NPCDialogHandler.cs index 072f2c527..3770ca8d8 100644 --- a/EOLib/PacketHandlers/NPC/NPCDialogHandler.cs +++ b/EOLib/PacketHandlers/NPC/NPCDialogHandler.cs @@ -4,9 +4,9 @@ using EOLib.Domain.Map; using EOLib.Domain.Notifiers; using EOLib.IO.Repositories; -using EOLib.Net; using EOLib.Net.Handlers; -using Optional; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional.Collections; using System.Collections.Generic; @@ -16,14 +16,14 @@ namespace EOLib.PacketHandlers.NPC /// Special dialog packet for NPC speech. Sent by GameServer when the priest talks. /// [AutoMappedType] - public class NPCDialogHandler : InGameOnlyPacketHandler + public class NPCDialogHandler : InGameOnlyPacketHandler { private readonly ICurrentMapStateRepository _currentMapStateRepository; private readonly IENFFileProvider _enfFileProvider; private readonly IChatRepository _chatRepository; private readonly IEnumerable _npcActionNotifiers; - public override PacketFamily Family => PacketFamily.NPC; + public override PacketFamily Family => PacketFamily.Npc; public override PacketAction Action => PacketAction.Dialog; @@ -41,31 +41,24 @@ public NPCDialogHandler(IPlayerInfoProvider playerInfoProvider, } // note: this is the same implementation as NPCPlayerHandler::HandleNPCTalk - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(NpcDialogServerPacket packet) { - var index = packet.ReadShort(); - var message = packet.ReadEndString(); + _currentMapStateRepository.NPCs + .SingleOrNone(n => n.Index == packet.NpcIndex) + .Match( + some: n => + { + var npcData = _enfFileProvider.ENFFile[n.ID]; - var npc = GetNPC(index); - npc.Match( - some: n => - { - var npcData = _enfFileProvider.ENFFile[n.ID]; + var chatData = new ChatData(ChatTab.Local, npcData.Name, packet.Message, ChatIcon.Note, filter: false); + _chatRepository.AllChat[ChatTab.Local].Add(chatData); - var chatData = new ChatData(ChatTab.Local, npcData.Name, message, ChatIcon.Note, filter: false); - _chatRepository.AllChat[ChatTab.Local].Add(chatData); - - foreach (var notifier in _npcActionNotifiers) - notifier.ShowNPCSpeechBubble(index, message); - }, - none: () => _currentMapStateRepository.UnknownNPCIndexes.Add(index)); + foreach (var notifier in _npcActionNotifiers) + notifier.ShowNPCSpeechBubble(packet.NpcIndex, packet.Message); + }, + none: () => _currentMapStateRepository.UnknownNPCIndexes.Add(packet.NpcIndex)); return true; } - - private Option GetNPC(int index) - { - return _currentMapStateRepository.NPCs.SingleOrNone(n => n.Index == index); - } } } diff --git a/EOLib/PacketHandlers/NPC/NPCJunkHandler.cs b/EOLib/PacketHandlers/NPC/NPCJunkHandler.cs index 7b390736d..c387ddeed 100644 --- a/EOLib/PacketHandlers/NPC/NPCJunkHandler.cs +++ b/EOLib/PacketHandlers/NPC/NPCJunkHandler.cs @@ -3,8 +3,9 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using System.Collections.Generic; using System.Linq; @@ -15,13 +16,13 @@ namespace EOLib.PacketHandlers.NPC /// Sent when despawning child NPCs after a boss is killed /// [AutoMappedType] - public class NPCJunkHandler : InGameOnlyPacketHandler + public class NPCJunkHandler : InGameOnlyPacketHandler { private readonly ICharacterProvider _characterProvider; private readonly ICurrentMapStateRepository _currentMapStateRepository; private readonly IEnumerable _npcActionNotifiers; - public override PacketFamily Family => PacketFamily.NPC; + public override PacketFamily Family => PacketFamily.Npc; public override PacketAction Action => PacketAction.Junk; @@ -36,24 +37,23 @@ public NPCJunkHandler(IPlayerInfoProvider playerInfoProvider, _npcActionNotifiers = npcActionNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(NpcJunkServerPacket packet) { - var childNpcId = packet.ReadShort(); + var indexes = _currentMapStateRepository.NPCs + .Where(npc => npc.ID == packet.NpcId) + .Select(x => x.Index); - var indexes = _currentMapStateRepository.NPCs.Where(npc => npc.ID == childNpcId).Select(x => x.Index).ToList(); - foreach (var notifier in _npcActionNotifiers) + foreach (var index in indexes) { - foreach (var index in indexes) - { + foreach (var notifier in _npcActionNotifiers) notifier.RemoveNPCFromView(index, _characterProvider.MainCharacter.ID, spellId: Option.None(), damage: Option.None(), showDeathAnimation: true); - } } - foreach (var npc in _currentMapStateRepository.NPCs.Where(npc => npc.ID == childNpcId)) + foreach (var npc in _currentMapStateRepository.NPCs.Where(npc => npc.ID == packet.NpcId)) _currentMapStateRepository.NPCs.Remove(npc); return true; diff --git a/EOLib/PacketHandlers/NPC/NPCPlayerHandler.cs b/EOLib/PacketHandlers/NPC/NPCPlayerHandler.cs index 7c63f3281..b3172a5d9 100644 --- a/EOLib/PacketHandlers/NPC/NPCPlayerHandler.cs +++ b/EOLib/PacketHandlers/NPC/NPCPlayerHandler.cs @@ -5,16 +5,14 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Domain.NPC; using EOLib.IO.Repositories; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using Optional.Collections; using System; using System.Collections.Generic; -using System.IO; -using System.Linq; using DomainNPC = EOLib.Domain.NPC.NPC; @@ -24,7 +22,7 @@ namespace EOLib.PacketHandlers.NPC /// Sent when an NPC does something (walk/attack/talk) /// [AutoMappedType] - public class NPCPlayerHandler : InGameOnlyPacketHandler + public class NPCPlayerHandler : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; private readonly IChatRepository _chatRepository; @@ -34,7 +32,7 @@ public class NPCPlayerHandler : InGameOnlyPacketHandler private readonly IEnumerable _mainCharacterNotifiers; private readonly IEnumerable _otherCharacterNotifiers; - public override PacketFamily Family => PacketFamily.NPC; + public override PacketFamily Family => PacketFamily.Npc; public override PacketAction Action => PacketAction.Player; @@ -57,77 +55,55 @@ public NPCPlayerHandler(IPlayerInfoProvider playerInfoProvider, _otherCharacterNotifiers = otherCharacterNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(NpcPlayerServerPacket packet) { - var chunks = new List(); - while (packet.ReadPosition < packet.Length) - { - var data = packet.RawData.Skip(packet.ReadPosition).TakeWhile(x => x != 255).ToArray(); - packet.Seek(data.Length, SeekOrigin.Current); - if (packet.ReadPosition < packet.Length) - packet.ReadByte(); + HandleNPCWalk(packet.Positions); + HandleNPCAttack(packet.Attacks); + HandleNPCTalk(packet.Chats); - chunks.Add(new PacketBuilder(packet.Family, packet.Action).AddBytes(data).Build()); + var stats = _characterRepository.MainCharacter.Stats; + if (packet.Hp.HasValue) + { + stats = stats.WithNewStat(CharacterStat.HP, packet.Hp.Value); } - - if (chunks.Count < 3 || chunks.Count > 4) - throw new MalformedPacketException($"Expected 3 or 4 chunks in NPC_PLAYER packet, got {chunks.Count}", packet); - - HandleNPCWalk(chunks[0]); - HandleNPCAttack(chunks[1]); - HandleNPCTalk(chunks[2]); - - if (chunks.Count > 3) + if (packet.Tp.HasValue) { - var hp = chunks[3].ReadShort(); - var tp = chunks[3].ReadShort(); - - var stats = _characterRepository.MainCharacter.Stats - .WithNewStat(CharacterStat.HP, hp) - .WithNewStat(CharacterStat.TP, tp); - _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); + stats = stats.WithNewStat(CharacterStat.TP, packet.Tp.Value); } + _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); return true; } - private void HandleNPCWalk(IPacket packet) + private void HandleNPCWalk(IReadOnlyList positions) { - while (packet.ReadPosition < packet.Length) + foreach (var position in positions) { - var index = packet.ReadChar(); - var x = packet.ReadChar(); - var y = packet.ReadChar(); - var npcDirection = (EODirection)packet.ReadChar(); - - var npc = GetNPC(index); + var npc = GetNPC(position.NpcIndex); npc.Match( some: n => { - var updated = n.WithDirection(npcDirection); - updated = EnsureCorrectXAndY(updated, x, y); - ReplaceNPC(n, updated); + var updated = n.WithDirection((EODirection)position.Direction); + updated = EnsureCorrectXAndY(updated, position.Coords.X, position.Coords.Y); + _currentMapStateRepository.NPCs.Update(n, updated); foreach (var notifier in _npcAnimationNotifiers) notifier.StartNPCWalkAnimation(n.Index); }, - none: () => _currentMapStateRepository.UnknownNPCIndexes.Add(index)); + none: () => _currentMapStateRepository.UnknownNPCIndexes.Add(position.NpcIndex)); } } - private void HandleNPCAttack(IPacket packet) + private void HandleNPCAttack(IReadOnlyList attacks) { - // note: eoserv incorrectly sends playerPercentHealth as a three byte number. GameServer sends a single char. - const int DATA_LENGTH = 9; - - while (packet.ReadPosition + DATA_LENGTH < packet.Length) + foreach (var attack in attacks) { - var index = packet.ReadChar(); - var isDead = packet.ReadChar() == 2; // 2 if target player is dead, 1 if alive - var npcDirection = (EODirection)packet.ReadChar(); - var characterID = packet.ReadShort(); - var damageTaken = packet.ReadThree(); - var playerPercentHealth = packet.ReadChar(); + var index = attack.NpcIndex; + var isDead = attack.Killed == PlayerKilledState.Killed; + var npcDirection = (EODirection)attack.Direction; + var characterID = attack.PlayerId; + var damageTaken = attack.Damage; + var playerPercentHealth = attack.HpPercentage; if (characterID == _characterRepository.MainCharacter.ID) { @@ -150,7 +126,7 @@ private void HandleNPCAttack(IPacket packet) foreach (var notifier in _otherCharacterNotifiers) notifier.OtherCharacterTakeDamage(characterID, playerPercentHealth, damageTaken, isHeal: false); } - else + else if (characterID > 0) { _currentMapStateRepository.UnknownPlayerIDs.Add(characterID); } @@ -160,7 +136,7 @@ private void HandleNPCAttack(IPacket packet) some: n => { var updated = n.WithDirection(npcDirection); - ReplaceNPC(n, updated); + _currentMapStateRepository.NPCs.Update(n, updated); foreach (var notifier in _npcAnimationNotifiers) notifier.StartNPCAttackAnimation(index); @@ -169,27 +145,23 @@ private void HandleNPCAttack(IPacket packet) } } - private void HandleNPCTalk(IPacket packet) + private void HandleNPCTalk(IReadOnlyList chats) { - while (packet.ReadPosition < packet.Length) + foreach (var chat in chats) { - var index = packet.ReadChar(); - var messageLength = packet.ReadChar(); - var message = packet.ReadString(messageLength); - - var npc = GetNPC(index); + var npc = GetNPC(chat.NpcIndex); npc.Match( some: n => { var npcData = _enfFileProvider.ENFFile[n.ID]; - var chatData = new ChatData(ChatTab.Local, npcData.Name, message, ChatIcon.Note, filter: false); + var chatData = new ChatData(ChatTab.Local, npcData.Name, chat.Message, ChatIcon.Note, filter: false); _chatRepository.AllChat[ChatTab.Local].Add(chatData); foreach (var notifier in _npcAnimationNotifiers) - notifier.ShowNPCSpeechBubble(index, message); + notifier.ShowNPCSpeechBubble(chat.NpcIndex, chat.Message); }, - none: () => _currentMapStateRepository.UnknownNPCIndexes.Add(index)); + none: () => _currentMapStateRepository.UnknownNPCIndexes.Add(chat.NpcIndex)); } } @@ -198,12 +170,6 @@ private Option GetNPC(int index) return _currentMapStateRepository.NPCs.SingleOrNone(n => n.Index == index); } - private void ReplaceNPC(DomainNPC npc, DomainNPC updatedNPC) - { - _currentMapStateRepository.NPCs.Remove(npc); - _currentMapStateRepository.NPCs.Add(updatedNPC); - } - private static DomainNPC EnsureCorrectXAndY(DomainNPC npc, int destinationX, int destinationY) { var opposite = npc.Direction.Opposite(); diff --git a/EOLib/PacketHandlers/NPC/NPCReplyHandler.cs b/EOLib/PacketHandlers/NPC/NPCReplyHandler.cs index fb9e07922..402e113fc 100644 --- a/EOLib/PacketHandlers/NPC/NPCReplyHandler.cs +++ b/EOLib/PacketHandlers/NPC/NPCReplyHandler.cs @@ -3,7 +3,8 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.NPC @@ -12,9 +13,9 @@ namespace EOLib.PacketHandlers.NPC /// Sent when an NPC takes damage from a weapon /// [AutoMappedType] - public class NPCReplyHandler : NPCTakeDamageHandler + public class NPCReplyHandler : NPCTakeDamageHandler { - public override PacketFamily Family => PacketFamily.NPC; + public override PacketFamily Family => PacketFamily.Npc; public NPCReplyHandler(IPlayerInfoProvider playerInfoProvider, ICharacterRepository characterRepository, @@ -22,5 +23,13 @@ public NPCReplyHandler(IPlayerInfoProvider playerInfoProvider, IEnumerable npcNotifiers, IEnumerable otherCharacterAnimationNotifiers) : base(playerInfoProvider, characterRepository, currentMapStateRepository, npcNotifiers, otherCharacterAnimationNotifiers) { } + + public override bool HandlePacket(NpcReplyServerPacket packet) + { + // todo: npc kill steal protection + Handle(packet.PlayerId, (EODirection)packet.PlayerDirection, + packet.NpcIndex, packet.Damage, packet.HpPercentage); + return true; + } } } diff --git a/EOLib/PacketHandlers/NPC/NPCSpecHandler.cs b/EOLib/PacketHandlers/NPC/NPCSpecHandler.cs index ca4586f1c..ed8949044 100644 --- a/EOLib/PacketHandlers/NPC/NPCSpecHandler.cs +++ b/EOLib/PacketHandlers/NPC/NPCSpecHandler.cs @@ -3,8 +3,8 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; -using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using System; using System.Collections.Generic; @@ -15,151 +15,26 @@ namespace EOLib.PacketHandlers.NPC /// Sent when an NPC dies to a weapon /// [AutoMappedType] - public class NPCSpecHandler : InGameOnlyPacketHandler + public class NPCSpecHandler : NPCDeathHandler { - protected readonly ICurrentMapStateRepository _currentMapStateRepository; - protected readonly ICharacterRepository _characterRepository; - private readonly ICharacterSessionRepository _characterSessionRepository; - private readonly IEnumerable _npcActionNotifiers; - private readonly IEnumerable _mainCharacterEventNotifiers; - private readonly IEnumerable _otherCharacterAnimationNotifiers; - - public override PacketFamily Family => PacketFamily.NPC; + public override PacketFamily Family => PacketFamily.Npc; public override PacketAction Action => PacketAction.Spec; public NPCSpecHandler(IPlayerInfoProvider playerInfoProvider, - ICurrentMapStateRepository currentMapStateRepository, ICharacterRepository characterRepository, + ICurrentMapStateRepository currentMapStateRepository, ICharacterSessionRepository characterSessionRepository, IEnumerable npcActionNotifiers, IEnumerable mainCharacterEventNotifiers, IEnumerable otherCharacterAnimationNotifiers) - : base(playerInfoProvider) - { - _currentMapStateRepository = currentMapStateRepository; - _characterRepository = characterRepository; - _characterSessionRepository = characterSessionRepository; - _npcActionNotifiers = npcActionNotifiers; - _mainCharacterEventNotifiers = mainCharacterEventNotifiers; - _otherCharacterAnimationNotifiers = otherCharacterAnimationNotifiers; - } + : base(playerInfoProvider, characterRepository, currentMapStateRepository, characterSessionRepository, + npcActionNotifiers, mainCharacterEventNotifiers, otherCharacterAnimationNotifiers) { } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(NpcSpecServerPacket packet) { - var spellId = packet.Family - .SomeWhen(f => f == PacketFamily.Cast) - .Map(f => packet.ReadShort()); - - var fromPlayerId = packet.ReadShort(); //player that is protecting the item - var playerDirection = (EODirection)packet.ReadChar(); - if (fromPlayerId > 0) - UpdatePlayerDirection(fromPlayerId, playerDirection); - - var deadNPCIndex = packet.ReadShort(); - - //packet is removing the NPC from view due to out of range of character - if (packet.ReadPosition == packet.Length) - { - RemoveNPCFromView(deadNPCIndex, fromPlayerId, spellId, damage: Option.None(), showDeathAnimation: false); - return true; - } - - var droppedItemUID = packet.ReadShort(); - var droppedItemID = packet.ReadShort(); - var x = packet.ReadChar(); - var y = packet.ReadChar(); - var droppedAmount = packet.ReadInt(); - - var damageDoneToNPC = packet.ReadThree(); - RemoveNPCFromView(deadNPCIndex, fromPlayerId, spellId, Option.Some(damageDoneToNPC), showDeathAnimation: true); - - if (packet.Family == PacketFamily.Cast) - { - var characterTPRemaining = packet.ReadShort(); - UpdateCharacterStat(CharacterStat.TP, characterTPRemaining); - } - - if (packet.ReadPosition != packet.Length) - { - var playerExp = packet.ReadInt(); - var expDifference = playerExp - _characterRepository.MainCharacter.Stats[CharacterStat.Experience]; - foreach (var notifier in _mainCharacterEventNotifiers) - notifier.NotifyGainedExp(expDifference); - - UpdateCharacterStat(CharacterStat.Experience, playerExp); - - _characterSessionRepository.LastKillExp = expDifference; - if (expDifference > _characterSessionRepository.BestKillExp) - _characterSessionRepository.BestKillExp = expDifference; - _characterSessionRepository.TodayTotalExp += Convert.ToUInt64(Math.Max(expDifference, 0)); - } - - if (droppedItemID > 0) - ShowDroppedItem(fromPlayerId, droppedItemUID, droppedItemID, x, y, droppedAmount); - - spellId.MatchSome(_ => - { - foreach (var notifier in _otherCharacterAnimationNotifiers) - notifier.NotifyTargetNpcSpellCast(fromPlayerId); - }); - + DeathWorkflow(packet.NpcKilledData, packet.Experience); return true; } - - private void RemoveNPCFromView(int deadNPCIndex, int playerId, Option spellId, Option damage, bool showDeathAnimation) - { - foreach (var notifier in _npcActionNotifiers) - notifier.RemoveNPCFromView(deadNPCIndex, playerId, spellId, damage, showDeathAnimation); - - if (_currentMapStateRepository.NPCs.TryGetValue(deadNPCIndex, out var npc)) - _currentMapStateRepository.NPCs.Remove(npc); - } - - private void UpdatePlayerDirection(int playerID, EODirection playerDirection) - { - if (playerID == _characterRepository.MainCharacter.ID) - { - var updatedRenderProps = _characterRepository.MainCharacter - .RenderProperties.WithDirection(playerDirection); - var updatedCharacter = _characterRepository.MainCharacter - .WithRenderProperties(updatedRenderProps); - - _characterRepository.MainCharacter = updatedCharacter; - } - else if (_currentMapStateRepository.Characters.TryGetValue(playerID, out var character)) - { - var updatedRenderProps = character.RenderProperties.WithDirection(playerDirection); - var updatedCharacter = character.WithRenderProperties(updatedRenderProps); - _currentMapStateRepository.Characters.Update(character, updatedCharacter); - } - else - { - _currentMapStateRepository.UnknownPlayerIDs.Add(playerID); - } - } - - private void UpdateCharacterStat(CharacterStat whichStat, int statValue) - { - var stats = _characterRepository.MainCharacter.Stats; - stats = stats.WithNewStat(whichStat, statValue); - _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); - } - - private void ShowDroppedItem(int playerID, int droppedItemUID, int droppedItemID, int x, int y, int droppedAmount) - { - var mapItem = new MapItem(droppedItemUID, droppedItemID, x, y, droppedAmount) - .WithIsNPCDrop(true) - .WithDropTime(Option.Some(DateTime.Now)) - .WithOwningPlayerID(Option.Some(playerID)); - - if (_currentMapStateRepository.MapItems.TryGetValue(droppedItemID, out var oldItem)) - _currentMapStateRepository.MapItems.Remove(oldItem); - - _currentMapStateRepository.MapItems.Add(mapItem); - - foreach (var notifier in _npcActionNotifiers) - notifier.NPCDropItem(mapItem); - } } } diff --git a/EOLib/PacketHandlers/NPC/NPCTakeDamageHandler.cs b/EOLib/PacketHandlers/NPC/NPCTakeDamageHandler.cs index cb6224470..aadcbe2f7 100644 --- a/EOLib/PacketHandlers/NPC/NPCTakeDamageHandler.cs +++ b/EOLib/PacketHandlers/NPC/NPCTakeDamageHandler.cs @@ -2,19 +2,19 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; -using System; using System.Collections.Generic; -using System.Linq; namespace EOLib.PacketHandlers.NPC { /// /// Base type for NPC taking damage /// - public abstract class NPCTakeDamageHandler : InGameOnlyPacketHandler + public abstract class NPCTakeDamageHandler : InGameOnlyPacketHandler + where TPacket : IPacket { private readonly ICharacterRepository _characterRepository; private readonly ICurrentMapStateRepository _currentMapStateRepository; @@ -36,33 +36,19 @@ public NPCTakeDamageHandler(IPlayerInfoProvider playerInfoProvider, _otherCharacterAnimationNotifiers = otherCharacterAnimationNotifiers; } - public override bool HandlePacket(IPacket packet) + protected void Handle(int fromPlayerId, EODirection fromDirection, + int npcIndex, int damageToNpc, int npcPctHealth, + int? spellId = null, int? fromTp = null) { - var spellId = Family - .SomeWhen(x => x == PacketFamily.Cast) - .Map(_ => packet.ReadShort()); - - var fromPlayerId = packet.ReadShort(); - var fromDirection = (EODirection)packet.ReadChar(); - var npcIndex = packet.ReadShort(); - var damageToNpc = packet.ReadThree(); - var npcPctHealth = packet.ReadShort(); - - var fromTp = -1; - if (Family == PacketFamily.Cast) - fromTp = packet.ReadShort(); - else if (packet.ReadChar() != 1) //some constant 1 in EOSERV - return false; - if (fromPlayerId == _characterRepository.MainCharacter.ID) { var renderProps = _characterRepository.MainCharacter.RenderProperties; var character = _characterRepository.MainCharacter.WithRenderProperties(renderProps.WithDirection(fromDirection)); - if (fromTp > 0) + if (fromTp.HasValue) { var stats = _characterRepository.MainCharacter.Stats; - character = character.WithStats(stats.WithNewStat(CharacterStat.TP, fromTp)); + character = character.WithStats(stats.WithNewStat(CharacterStat.TP, fromTp.Value)); } _characterRepository.MainCharacter = character; @@ -78,6 +64,10 @@ public override bool HandlePacket(IPacket packet) _currentMapStateRepository.UnknownPlayerIDs.Add(fromPlayerId); } + var spellIdOptional = spellId.HasValue + ? Option.Some(spellId.Value) + : Option.None(); + // todo: this has the potential to bug out if the opponent ID is never reset and the player dies/leaves if (_currentMapStateRepository.NPCs.TryGetValue(npcIndex, out var npc)) { @@ -85,20 +75,18 @@ public override bool HandlePacket(IPacket packet) _currentMapStateRepository.NPCs.Update(npc, newNpc); foreach (var notifier in _npcNotifiers) - notifier.NPCTakeDamage(npcIndex, fromPlayerId, damageToNpc, npcPctHealth, spellId); + notifier.NPCTakeDamage(npcIndex, fromPlayerId, damageToNpc, npcPctHealth, spellIdOptional); } else { _currentMapStateRepository.UnknownNPCIndexes.Add(npcIndex); } - spellId.MatchSome(_ => + spellIdOptional.MatchSome(_ => { foreach (var notifier in _otherCharacterAnimationNotifiers) notifier.NotifyTargetNpcSpellCast(fromPlayerId); }); - - return true; } } } diff --git a/EOLib/PacketHandlers/Paperdoll/ItemEquipHandler.cs b/EOLib/PacketHandlers/Paperdoll/ItemEquipHandler.cs index a7c09fa3f..63ae34d9d 100644 --- a/EOLib/PacketHandlers/Paperdoll/ItemEquipHandler.cs +++ b/EOLib/PacketHandlers/Paperdoll/ItemEquipHandler.cs @@ -3,8 +3,9 @@ using EOLib.Domain.Map; using EOLib.IO.Extensions; using EOLib.IO.Repositories; -using EOLib.Net; using EOLib.PacketHandlers.Avatar; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using Optional.Collections; using System.Linq; @@ -14,51 +15,35 @@ namespace EOLib.PacketHandlers.Paperdoll /// /// Base handler for Paperdoll equip/unequip /// - public abstract class ItemEquipHandler : AvatarAgreeHandler + public abstract class ItemEquipHandler : AvatarChangeHandler + where TPacket : IPacket { private readonly IPaperdollRepository _paperdollRepository; private readonly ICharacterInventoryRepository _characterInventoryRepository; + private readonly IEIFFileProvider _eifFileProvider; protected ItemEquipHandler(IPlayerInfoProvider playerInfoProvider, ICurrentMapStateRepository currentMapStateRepository, ICharacterRepository characterRepository, - IEIFFileProvider eifFileProvider, IPaperdollRepository paperdollRepository, - ICharacterInventoryRepository characterInventoryRepository) - : base(playerInfoProvider, currentMapStateRepository, characterRepository, eifFileProvider) + ICharacterInventoryRepository characterInventoryRepository, + IEIFFileProvider eifFileProvider) + : base(playerInfoProvider, currentMapStateRepository, characterRepository) { _paperdollRepository = paperdollRepository; _characterInventoryRepository = characterInventoryRepository; + _eifFileProvider = eifFileProvider; } - protected bool HandlePaperdollPacket(IPacket packet, bool itemUnequipped) + protected bool HandlePaperdollPacket(AvatarChange change, int itemId, int amount, int subLoc, CharacterStatsEquipmentChange stats) { - var playerId = packet.PeekShort(); - - if (!base.HandlePacket(packet)) - return false; - - var itemId = packet.ReadShort(); - var amount = itemUnequipped ? 1 : packet.ReadThree(); - var subLoc = packet.ReadChar(); - - var maxhp = packet.ReadShort(); - var maxtp = packet.ReadShort(); - var disp_str = packet.ReadShort(); - var disp_int = packet.ReadShort(); - var disp_wis = packet.ReadShort(); - var disp_agi = packet.ReadShort(); - var disp_con = packet.ReadShort(); - var disp_cha = packet.ReadShort(); - var mindam = packet.ReadShort(); - var maxdam = packet.ReadShort(); - var accuracy = packet.ReadShort(); - var evade = packet.ReadShort(); - var armor = packet.ReadShort(); - - if (_paperdollRepository.VisibleCharacterPaperdolls.ContainsKey(playerId)) + Handle(change); + + var itemUnequipped = Action == PacketAction.Remove; + + if (_paperdollRepository.VisibleCharacterPaperdolls.ContainsKey(change.PlayerId)) { - var paperdollData = _paperdollRepository.VisibleCharacterPaperdolls[playerId]; + var paperdollData = _paperdollRepository.VisibleCharacterPaperdolls[change.PlayerId]; var itemRec = _eifFileProvider.EIFFile[itemId]; var paperdollSlot = itemRec.GetEquipLocation() + subLoc; @@ -66,35 +51,35 @@ protected bool HandlePaperdollPacket(IPacket packet, bool itemUnequipped) var paperdollEquipData = paperdollData.Paperdoll.ToDictionary(k => k.Key, v => v.Value); paperdollEquipData[paperdollSlot] = itemUnequipped ? 0 : itemId; - _paperdollRepository.VisibleCharacterPaperdolls[playerId] = paperdollData.WithPaperdoll(paperdollEquipData); + _paperdollRepository.VisibleCharacterPaperdolls[change.PlayerId] = paperdollData.WithPaperdoll(paperdollEquipData); } - var update = _characterRepository.MainCharacter.ID == playerId + var update = _characterRepository.MainCharacter.ID == change.PlayerId ? Option.Some(_characterRepository.MainCharacter) - : _currentMapStateRepository.Characters.TryGetValue(playerId, out var character) + : _currentMapStateRepository.Characters.TryGetValue(change.PlayerId, out var character) ? Option.Some(character) : Option.None(); update.MatchSome(c => { - var stats = c.Stats - .WithNewStat(CharacterStat.MaxHP, maxhp) - .WithNewStat(CharacterStat.MaxTP, maxtp) - .WithNewStat(CharacterStat.Strength, disp_str) - .WithNewStat(CharacterStat.Intelligence, disp_int) - .WithNewStat(CharacterStat.Wisdom, disp_wis) - .WithNewStat(CharacterStat.Agility, disp_agi) - .WithNewStat(CharacterStat.Constitution, disp_con) - .WithNewStat(CharacterStat.Charisma, disp_cha) - .WithNewStat(CharacterStat.MinDam, mindam) - .WithNewStat(CharacterStat.MaxDam, maxdam) - .WithNewStat(CharacterStat.Accuracy, accuracy) - .WithNewStat(CharacterStat.Evade, evade) - .WithNewStat(CharacterStat.Armor, armor); + var characterStats = c.Stats + .WithNewStat(CharacterStat.MaxHP, stats.MaxHp) + .WithNewStat(CharacterStat.MaxTP, stats.MaxTp) + .WithNewStat(CharacterStat.Strength, stats.BaseStats.Str) + .WithNewStat(CharacterStat.Intelligence, stats.BaseStats.Intl) + .WithNewStat(CharacterStat.Wisdom, stats.BaseStats.Wis) + .WithNewStat(CharacterStat.Agility, stats.BaseStats.Agi) + .WithNewStat(CharacterStat.Constitution, stats.BaseStats.Con) + .WithNewStat(CharacterStat.Charisma, stats.BaseStats.Cha) + .WithNewStat(CharacterStat.MinDam, stats.SecondaryStats.MinDamage) + .WithNewStat(CharacterStat.MaxDam, stats.SecondaryStats.MaxDamage) + .WithNewStat(CharacterStat.Accuracy, stats.SecondaryStats.Accuracy) + .WithNewStat(CharacterStat.Evade, stats.SecondaryStats.Evade) + .WithNewStat(CharacterStat.Armor, stats.SecondaryStats.Armor); if (c == _characterRepository.MainCharacter) { - _characterRepository.MainCharacter = c.WithStats(stats); + _characterRepository.MainCharacter = c.WithStats(characterStats); var updatedItem = _characterInventoryRepository.ItemInventory .SingleOrNone(x => x.ItemID == itemId) @@ -108,13 +93,13 @@ protected bool HandlePaperdollPacket(IPacket packet, bool itemUnequipped) } else { - _currentMapStateRepository.Characters.Update(c, c.WithStats(stats)); + _currentMapStateRepository.Characters.Update(c, c.WithStats(characterStats)); } }); update.MatchNone(() => { - _currentMapStateRepository.UnknownPlayerIDs.Add(playerId); + _currentMapStateRepository.UnknownPlayerIDs.Add(change.PlayerId); }); return true; diff --git a/EOLib/PacketHandlers/Paperdoll/PaperdollAgreeHandler.cs b/EOLib/PacketHandlers/Paperdoll/PaperdollAgreeHandler.cs index 6047e4da3..0378152a8 100644 --- a/EOLib/PacketHandlers/Paperdoll/PaperdollAgreeHandler.cs +++ b/EOLib/PacketHandlers/Paperdoll/PaperdollAgreeHandler.cs @@ -3,7 +3,8 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.IO.Repositories; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Paperdoll { @@ -11,25 +12,25 @@ namespace EOLib.PacketHandlers.Paperdoll /// Handler for equipping an item /// [AutoMappedType] - public class PaperdollAgreeHandler : ItemEquipHandler + public class PaperdollAgreeHandler : ItemEquipHandler { - public override PacketFamily Family => PacketFamily.PaperDoll; + public override PacketFamily Family => PacketFamily.Paperdoll; public override PacketAction Action => PacketAction.Agree; public PaperdollAgreeHandler(IPlayerInfoProvider playerInfoProvider, ICurrentMapStateRepository currentMapStateRepository, ICharacterRepository characterRepository, - IEIFFileProvider eifFileProvider, IPaperdollRepository paperdollRepository, - ICharacterInventoryRepository characterInventoryRepository) - : base(playerInfoProvider, currentMapStateRepository, characterRepository, eifFileProvider, paperdollRepository, characterInventoryRepository) + ICharacterInventoryRepository characterInventoryRepository, + IEIFFileProvider eifFileProvider) + : base(playerInfoProvider, currentMapStateRepository, characterRepository, paperdollRepository, characterInventoryRepository, eifFileProvider) { } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(PaperdollAgreeServerPacket packet) { - return HandlePaperdollPacket(packet, itemUnequipped: false); + return HandlePaperdollPacket(packet.Change, packet.ItemId, packet.RemainingAmount, packet.SubLoc, packet.Stats); } } } diff --git a/EOLib/PacketHandlers/Paperdoll/PaperdollRemoveHandler.cs b/EOLib/PacketHandlers/Paperdoll/PaperdollRemoveHandler.cs index ebf8968ec..30089fce3 100644 --- a/EOLib/PacketHandlers/Paperdoll/PaperdollRemoveHandler.cs +++ b/EOLib/PacketHandlers/Paperdoll/PaperdollRemoveHandler.cs @@ -3,7 +3,8 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.IO.Repositories; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Paperdoll { @@ -11,25 +12,25 @@ namespace EOLib.PacketHandlers.Paperdoll /// Handler for unequipping an item /// [AutoMappedType] - public class PaperdollRemoveHandler : ItemEquipHandler + public class PaperdollRemoveHandler : ItemEquipHandler { - public override PacketFamily Family => PacketFamily.PaperDoll; + public override PacketFamily Family => PacketFamily.Paperdoll; public override PacketAction Action => PacketAction.Remove; public PaperdollRemoveHandler(IPlayerInfoProvider playerInfoProvider, ICurrentMapStateRepository currentMapStateRepository, ICharacterRepository characterRepository, - IEIFFileProvider eifFileProvider, IPaperdollRepository paperdollRepository, - ICharacterInventoryRepository characterInventoryRepository) - : base(playerInfoProvider, currentMapStateRepository, characterRepository, eifFileProvider, paperdollRepository, characterInventoryRepository) + ICharacterInventoryRepository characterInventoryRepository, + IEIFFileProvider eifFileProvider) + : base(playerInfoProvider, currentMapStateRepository, characterRepository, paperdollRepository, characterInventoryRepository, eifFileProvider) { } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(PaperdollRemoveServerPacket packet) { - return HandlePaperdollPacket(packet, itemUnequipped: true); + return HandlePaperdollPacket(packet.Change, packet.ItemId, 1, packet.SubLoc, packet.Stats); } } } diff --git a/EOLib/PacketHandlers/Paperdoll/PaperdollReplyHandler.cs b/EOLib/PacketHandlers/Paperdoll/PaperdollReplyHandler.cs index e61c15978..c4d2650bf 100644 --- a/EOLib/PacketHandlers/Paperdoll/PaperdollReplyHandler.cs +++ b/EOLib/PacketHandlers/Paperdoll/PaperdollReplyHandler.cs @@ -1,11 +1,10 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; +using EOLib.Domain.Extensions; using EOLib.Domain.Login; -using EOLib.Domain.Online; -using EOLib.IO; -using EOLib.Net; using EOLib.Net.Handlers; -using System.Collections.Generic; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Paperdoll { @@ -13,11 +12,11 @@ namespace EOLib.PacketHandlers.Paperdoll /// Sets paperdoll information for a given player /// [AutoMappedType] - internal class PaperdollReplyHandler : InGameOnlyPacketHandler + internal class PaperdollReplyHandler : InGameOnlyPacketHandler { private readonly IPaperdollRepository _paperdollRepository; - public override PacketFamily Family => PacketFamily.PaperDoll; + public override PacketFamily Family => PacketFamily.Paperdoll; public override PacketAction Action => PacketAction.Reply; @@ -28,27 +27,24 @@ public PaperdollReplyHandler(IPlayerInfoProvider playerInfoProvider, _paperdollRepository = paperdollRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(PaperdollReplyServerPacket packet) { - var name = packet.ReadBreakString(); - var home = packet.ReadBreakString(); - var partner = packet.ReadBreakString(); - var title = packet.ReadBreakString(); - var guild = packet.ReadBreakString(); - var rank = packet.ReadBreakString(); + var name = packet.Details.Name; + var home = packet.Details.Home; + var partner = packet.Details.Partner; + var title = packet.Details.Title; + var guild = packet.Details.Guild; + var rank = packet.Details.GuildRank; - var playerID = packet.ReadShort(); - var clas = packet.ReadChar(); - var gender = packet.ReadChar(); + var playerID = packet.Details.PlayerId; + var clas = packet.Details.ClassId; + var gender = packet.Details.Gender; - var adminLevel = packet.ReadChar(); + var adminLevel = packet.Details.Admin; - var paperdoll = new Dictionary((int)EquipLocation.PAPERDOLL_MAX); - for (var loc = (EquipLocation)0; loc < EquipLocation.PAPERDOLL_MAX; ++loc) - paperdoll[loc] = packet.ReadShort(); - - var iconType = (OnlineIcon)packet.ReadChar(); + var paperdoll = packet.Equipment.GetPaperdoll(); + var iconType = packet.Icon; var paperdollData = _paperdollRepository.VisibleCharacterPaperdolls.ContainsKey(playerID) ? _paperdollRepository.VisibleCharacterPaperdolls[playerID] @@ -63,8 +59,8 @@ public override bool HandlePacket(IPacket packet) .WithRank(rank) .WithPlayerID(playerID) .WithClass(clas) - .WithGender(gender) - .WithAdminLevel((AdminLevel)adminLevel) + .WithGender((int)gender) + .WithAdminLevel(adminLevel) .WithPaperdoll(paperdoll) .WithIcon(iconType); diff --git a/EOLib/PacketHandlers/Party/PartyAddHandler.cs b/EOLib/PacketHandlers/Party/PartyAddHandler.cs index e707694d7..06297ac57 100644 --- a/EOLib/PacketHandlers/Party/PartyAddHandler.cs +++ b/EOLib/PacketHandlers/Party/PartyAddHandler.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Login; using EOLib.Domain.Notifiers; using EOLib.Domain.Party; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Party @@ -12,7 +13,7 @@ namespace EOLib.PacketHandlers.Party /// Handles new member joining party /// [AutoMappedType] - public class PartyAddHandler : InGameOnlyPacketHandler + public class PartyAddHandler : InGameOnlyPacketHandler { private readonly IPartyDataRepository _partyDataRepository; private readonly IEnumerable _partyEventNotifiers; @@ -30,23 +31,20 @@ public PartyAddHandler(IPlayerInfoProvider playerInfoProvider, _partyEventNotifiers = partyEventNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(PartyAddServerPacket packet) { - var partyMember = new PartyMember.Builder + _partyDataRepository.Members.Add(new Domain.Party.PartyMember.Builder { - CharacterID = packet.ReadShort(), - IsLeader = packet.ReadChar() != 0, - Level = packet.ReadChar(), - PercentHealth = packet.ReadChar(), - Name = packet.ReadBreakString(), - }; - partyMember.Name = char.ToUpper(partyMember.Name[0]) + partyMember.Name.Substring(1); - - _partyDataRepository.Members.Add(partyMember.ToImmutable()); + CharacterID = packet.Member.PlayerId, + IsLeader = packet.Member.Leader, + Level = packet.Member.Level, + PercentHealth = packet.Member.HpPercentage, + Name = char.ToUpper(packet.Member.Name[0]) + packet.Member.Name.Substring(1), + }.ToImmutable()); foreach (var notifier in _partyEventNotifiers) { - notifier.NotifyPartyMemberAdd(partyMember.Name); + notifier.NotifyPartyMemberAdd(packet.Member.Name); } return true; diff --git a/EOLib/PacketHandlers/Party/PartyAgreeHandler.cs b/EOLib/PacketHandlers/Party/PartyAgreeHandler.cs index dbf6e04b7..8305bee4d 100644 --- a/EOLib/PacketHandlers/Party/PartyAgreeHandler.cs +++ b/EOLib/PacketHandlers/Party/PartyAgreeHandler.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Party; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional.Collections; namespace EOLib.PacketHandlers.Party @@ -12,10 +13,10 @@ namespace EOLib.PacketHandlers.Party /// Handles HP update for party members /// [AutoMappedType] - public class PartyAgreeHandler : InGameOnlyPacketHandler + public class PartyAgreeHandler : InGameOnlyPacketHandler { private readonly IPartyDataRepository _partyDataRepository; - private readonly ICurrentMapStateProvider _currentMapStateProvider; + private readonly ICurrentMapStateRepository _currentMapStateRepository; public override PacketFamily Family => PacketFamily.Party; @@ -23,29 +24,23 @@ public class PartyAgreeHandler : InGameOnlyPacketHandler public PartyAgreeHandler(IPlayerInfoProvider playerInfoProvider, IPartyDataRepository partyDataRepository, - ICurrentMapStateProvider currentMapStateProvider) + ICurrentMapStateRepository currentMapStateRepository) : base(playerInfoProvider) { _partyDataRepository = partyDataRepository; - _currentMapStateProvider = currentMapStateProvider; + _currentMapStateRepository = currentMapStateRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(PartyAgreeServerPacket packet) { - while (packet.ReadPosition < packet.Length) - { - var playerId = packet.ReadShort(); - var percentHealth = packet.ReadChar(); - - _partyDataRepository.Members.SingleOrNone(x => x.CharacterID == playerId) - .Match( - some: x => - { - _partyDataRepository.Members.Remove(x); - _partyDataRepository.Members.Add(x.WithPercentHealth(percentHealth)); - }, - none: () => _currentMapStateProvider.UnknownPlayerIDs.Add(playerId)); - } + _partyDataRepository.Members.SingleOrNone(x => x.CharacterID == packet.PlayerId) + .Match( + some: x => + { + _partyDataRepository.Members.Remove(x); + _partyDataRepository.Members.Add(x.WithPercentHealth(packet.HpPercentage)); + }, + none: () => _currentMapStateRepository.UnknownPlayerIDs.Add(packet.PlayerId)); return true; } diff --git a/EOLib/PacketHandlers/Party/PartyCloseHandler.cs b/EOLib/PacketHandlers/Party/PartyCloseHandler.cs index 549e16d35..52f284bbd 100644 --- a/EOLib/PacketHandlers/Party/PartyCloseHandler.cs +++ b/EOLib/PacketHandlers/Party/PartyCloseHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Party; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Party { @@ -10,7 +11,7 @@ namespace EOLib.PacketHandlers.Party /// Handles leaving (or being removed from) a party /// [AutoMappedType] - public class PartyCloseHandler : InGameOnlyPacketHandler + public class PartyCloseHandler : InGameOnlyPacketHandler { private readonly IPartyDataRepository _partyDataRepository; @@ -25,10 +26,10 @@ public PartyCloseHandler(IPlayerInfoProvider playerInfoProvider, _partyDataRepository = partyDataRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(PartyCloseServerPacket packet) { _partyDataRepository.Members.Clear(); - return packet.ReadByte() == 255; + return true; } } } diff --git a/EOLib/PacketHandlers/Party/PartyCreateHandler.cs b/EOLib/PacketHandlers/Party/PartyCreateHandler.cs index f4fa1b3d5..67f1c3b23 100644 --- a/EOLib/PacketHandlers/Party/PartyCreateHandler.cs +++ b/EOLib/PacketHandlers/Party/PartyCreateHandler.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Login; using EOLib.Domain.Notifiers; using EOLib.Domain.Party; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Party @@ -12,7 +13,7 @@ namespace EOLib.PacketHandlers.Party /// Handles HP update for party members /// [AutoMappedType] - public class PartyCreateHandler : InGameOnlyPacketHandler + public class PartyCreateHandler : InGameOnlyPacketHandler { private readonly IPartyDataRepository _partyDataRepository; private readonly IEnumerable _partyEventNotifiers; @@ -30,31 +31,24 @@ public PartyCreateHandler(IPlayerInfoProvider playerInfoProvider, _partyEventNotifiers = partyEventNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(PartyCreateServerPacket packet) { _partyDataRepository.Members.Clear(); - while (packet.ReadPosition < packet.Length) + foreach (var member in packet.Members) { - var partyMember = new PartyMember.Builder + _partyDataRepository.Members.Add(new Domain.Party.PartyMember.Builder { - CharacterID = packet.ReadShort(), - IsLeader = packet.ReadChar() != 0, - Level = packet.ReadChar(), - PercentHealth = packet.ReadChar(), - Name = packet.ReadBreakString(), - }; - partyMember.Name = char.ToUpper(partyMember.Name[0]) + partyMember.Name.Substring(1); - - _partyDataRepository.Members.Add(partyMember.ToImmutable()); + CharacterID = member.PlayerId, + IsLeader = member.Leader, + Level = member.Level, + PercentHealth = member.HpPercentage, + Name = char.ToUpper(member.Name[0]) + member.Name.Substring(1), + }.ToImmutable()); } - if (Action == PacketAction.Create) - { - // don't notify a party was joined for LIST packet handling - foreach (var notifier in _partyEventNotifiers) - notifier.NotifyPartyJoined(); - } + foreach (var notifier in _partyEventNotifiers) + notifier.NotifyPartyJoined(); return true; } diff --git a/EOLib/PacketHandlers/Party/PartyListHandler.cs b/EOLib/PacketHandlers/Party/PartyListHandler.cs index 9ce0e7783..392866582 100644 --- a/EOLib/PacketHandlers/Party/PartyListHandler.cs +++ b/EOLib/PacketHandlers/Party/PartyListHandler.cs @@ -1,9 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; -using EOLib.Domain.Notifiers; using EOLib.Domain.Party; -using EOLib.Net; -using System.Collections.Generic; +using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Party { @@ -11,13 +11,38 @@ namespace EOLib.PacketHandlers.Party /// Handles data update for party members /// [AutoMappedType] - public class PartyListHandler : PartyCreateHandler + public class PartyListHandler : InGameOnlyPacketHandler { + private readonly IPartyDataRepository _partyDataRepository; + + public override PacketFamily Family => PacketFamily.Party; + public override PacketAction Action => PacketAction.List; public PartyListHandler(IPlayerInfoProvider playerInfoProvider, - IPartyDataRepository partyDataRepository, - IEnumerable partyEventNotifiers) - : base(playerInfoProvider, partyDataRepository, partyEventNotifiers) { } + IPartyDataRepository partyDataRepository) + : base(playerInfoProvider) + { + _partyDataRepository = partyDataRepository; + } + + public override bool HandlePacket(PartyListServerPacket packet) + { + _partyDataRepository.Members.Clear(); + + foreach (var member in packet.Members) + { + _partyDataRepository.Members.Add(new Domain.Party.PartyMember.Builder + { + CharacterID = member.PlayerId, + IsLeader = member.Leader, + Level = member.Level, + PercentHealth = member.HpPercentage, + Name = char.ToUpper(member.Name[0]) + member.Name.Substring(1), + }.ToImmutable()); + } + + return true; + } } } diff --git a/EOLib/PacketHandlers/Party/PartyRemoveHandler.cs b/EOLib/PacketHandlers/Party/PartyRemoveHandler.cs index 1864c0db4..5ae585670 100644 --- a/EOLib/PacketHandlers/Party/PartyRemoveHandler.cs +++ b/EOLib/PacketHandlers/Party/PartyRemoveHandler.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Login; using EOLib.Domain.Notifiers; using EOLib.Domain.Party; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional.Collections; using System.Collections.Generic; @@ -13,7 +14,7 @@ namespace EOLib.PacketHandlers.Party /// Handles removing a member from the party /// [AutoMappedType] - public class PartyRemoveHandler : InGameOnlyPacketHandler + public class PartyRemoveHandler : InGameOnlyPacketHandler { private readonly IPartyDataRepository _partyDataRepository; private readonly IEnumerable _partyEventNotifiers; @@ -31,11 +32,9 @@ public PartyRemoveHandler(IPlayerInfoProvider playerInfoProvider, _partyEventNotifiers = partyEventNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(PartyRemoveServerPacket packet) { - var memberToRemove = packet.ReadShort(); - - _partyDataRepository.Members.SingleOrNone(x => x.CharacterID == memberToRemove) + _partyDataRepository.Members.SingleOrNone(x => x.CharacterID == packet.PlayerId) .MatchSome(x => { _partyDataRepository.Members.Remove(x); diff --git a/EOLib/PacketHandlers/Party/PartyRequestHandler.cs b/EOLib/PacketHandlers/Party/PartyRequestHandler.cs index a49f12332..539cb3787 100644 --- a/EOLib/PacketHandlers/Party/PartyRequestHandler.cs +++ b/EOLib/PacketHandlers/Party/PartyRequestHandler.cs @@ -1,9 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Domain.Party; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Party @@ -12,7 +12,7 @@ namespace EOLib.PacketHandlers.Party /// Handles invite/join request from another player /// [AutoMappedType] - public class PartyRequestHandler : InGameOnlyPacketHandler + public class PartyRequestHandler : InGameOnlyPacketHandler { private readonly IEnumerable _partyEventNotifiers; @@ -27,14 +27,10 @@ public PartyRequestHandler(IPlayerInfoProvider playerInfoProvider, _partyEventNotifiers = partyEventNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(PartyRequestServerPacket packet) { - var type = (PartyRequestType)packet.ReadChar(); - var playerId = packet.ReadShort(); - var name = packet.ReadEndString(); - foreach (var notifier in _partyEventNotifiers) - notifier.NotifyPartyRequest(type, playerId, name); + notifier.NotifyPartyRequest(packet.RequestType, packet.InviterPlayerId, packet.PlayerName); return true; } diff --git a/EOLib/PacketHandlers/Players/PlayersAgreeHandler.cs b/EOLib/PacketHandlers/Players/PlayersAgreeHandler.cs index 9852d8c9b..8e88df0e6 100644 --- a/EOLib/PacketHandlers/Players/PlayersAgreeHandler.cs +++ b/EOLib/PacketHandlers/Players/PlayersAgreeHandler.cs @@ -4,11 +4,11 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.IO.Repositories; -using EOLib.Net; using EOLib.Net.Handlers; -using EOLib.Net.Translators; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; +using System.Linq; namespace EOLib.PacketHandlers.Players { @@ -16,12 +16,10 @@ namespace EOLib.PacketHandlers.Players /// Sent when a player is entering the map /// [AutoMappedType] - public class PlayersAgreeHandler : InGameOnlyPacketHandler + public class PlayersAgreeHandler : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; private readonly ICurrentMapStateRepository _mapStateRepository; - private readonly ICharacterFromPacketFactory _characterFromPacketFactory; - private readonly IEIFFileProvider _eifFileProvider; private readonly IEnumerable _effectNotifiers; public override PacketFamily Family => PacketFamily.Players; @@ -29,55 +27,66 @@ public class PlayersAgreeHandler : InGameOnlyPacketHandler public override PacketAction Action => PacketAction.Agree; public PlayersAgreeHandler(IPlayerInfoProvider playerInfoProvider, - ICharacterRepository characterRepository, - ICurrentMapStateRepository mapStateRepository, - ICharacterFromPacketFactory characterFromPacketFactory, - IEIFFileProvider eifFileProvider, - IEnumerable effectNotifiers) + ICharacterRepository characterRepository, + ICurrentMapStateRepository mapStateRepository, + IEnumerable effectNotifiers) : base(playerInfoProvider) { _characterRepository = characterRepository; _mapStateRepository = mapStateRepository; - _characterFromPacketFactory = characterFromPacketFactory; - _eifFileProvider = eifFileProvider; _effectNotifiers = effectNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(PlayersAgreeServerPacket packet) { - if (packet.ReadByte() != 255) - throw new MalformedPacketException("Missing 255 header byte for player enter map handler", packet); - - var character = _characterFromPacketFactory.CreateCharacter(packet); - - if (packet.PeekByte() != 255) // next byte was the warp animation: sent on Map::Enter in eoserv + foreach (var charInfo in packet.Nearby.Characters.Where(x => x.ByteSize >= 42)) { - var anim = (WarpAnimation)packet.ReadChar(); - - foreach (var notifier in _effectNotifiers) - notifier.NotifyWarpEnterEffect(character.ID, anim); - } + var character = Character.FromNearby(charInfo); - if (packet.ReadByte() != 255) - throw new MalformedPacketException("Missing 255 byte after the warp animation for player enter map handler", packet); + if (charInfo.WarpEffect.HasValue) + { + foreach (var notifier in _effectNotifiers) + notifier.NotifyWarpEnterEffect(character.ID, charInfo.WarpEffect.Value); + } - // 0 for NPC, 1 for player. In eoserv it is never 0. - if (packet.ReadChar() != 1) - throw new MalformedPacketException("Missing '1' char after warp animation for player enter map handler. Are you using a non-standard version of EOSERV?", packet); - - if (_characterRepository.MainCharacter.ID == character.ID) - { - var existingCharacter = _characterRepository.MainCharacter; - _characterRepository.MainCharacter = existingCharacter.WithAppliedData(character); - _characterRepository.HasAvatar = true; + if (_characterRepository.MainCharacter.ID == character.ID) + { + var existingCharacter = _characterRepository.MainCharacter; + _characterRepository.MainCharacter = existingCharacter.WithAppliedData(character); + _characterRepository.HasAvatar = true; + } + else if (_mapStateRepository.Characters.TryGetValue(character.ID, out var existingCharacter)) + { + _mapStateRepository.Characters.Update(existingCharacter, existingCharacter.WithAppliedData(character)); + } + else + { + _mapStateRepository.Characters.Add(character); + } } - else if (_mapStateRepository.Characters.TryGetValue(character.ID, out var existingCharacter)) + + foreach (var npc in packet.Nearby.Npcs.Select(Domain.NPC.NPC.FromNearby)) { - _mapStateRepository.Characters.Update(existingCharacter, existingCharacter.WithAppliedData(character)); + if (_mapStateRepository.NPCs.TryGetValue(npc.Index, out var existing)) + { + _mapStateRepository.NPCs.Update(existing, npc); + } + else + { + _mapStateRepository.NPCs.Add(npc); + } } - else + + foreach (var item in packet.Nearby.Items.Select(MapItem.FromNearby)) { - _mapStateRepository.Characters.Add(character); + if (_mapStateRepository.MapItems.TryGetValue(item.UniqueID, out var existing)) + { + _mapStateRepository.MapItems.Update(existing, item); + } + else + { + _mapStateRepository.MapItems.Add(item); + } } return true; diff --git a/EOLib/PacketHandlers/Priest/PriestOpenHandler.cs b/EOLib/PacketHandlers/Priest/PriestOpenHandler.cs index 23285db0f..a787b8e93 100644 --- a/EOLib/PacketHandlers/Priest/PriestOpenHandler.cs +++ b/EOLib/PacketHandlers/Priest/PriestOpenHandler.cs @@ -2,14 +2,15 @@ using EOLib.Domain.Interact; using EOLib.Domain.Interact.Priest; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Priest { [AutoMappedType] - public class PriestOpenHandler : InGameOnlyPacketHandler + public class PriestOpenHandler : InGameOnlyPacketHandler { private readonly IPriestSessionRepository _priestSessionRepository; private readonly IEnumerable _npcInteractionNotifiers; @@ -27,9 +28,9 @@ public PriestOpenHandler(IPlayerInfoProvider playerInfoProvider, _npcInteractionNotifiers = npcInteractionNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(PriestOpenServerPacket packet) { - _priestSessionRepository.SessionID = packet.ReadInt(); + _priestSessionRepository.SessionID = packet.SessionId; foreach (var notifier in _npcInteractionNotifiers) notifier.NotifyInteractionFromNPC(IO.NPCType.Priest); diff --git a/EOLib/PacketHandlers/Priest/PriestReplyHandler.cs b/EOLib/PacketHandlers/Priest/PriestReplyHandler.cs index 975c94ce4..c1241ab36 100644 --- a/EOLib/PacketHandlers/Priest/PriestReplyHandler.cs +++ b/EOLib/PacketHandlers/Priest/PriestReplyHandler.cs @@ -1,16 +1,15 @@ using AutomaticTypeMapper; using EOLib.Domain.Interact; -using EOLib.Domain.Interact.Priest; using EOLib.Domain.Login; -using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Priest { [AutoMappedType] - public class PriestReplyHandler : InGameOnlyPacketHandler + public class PriestReplyHandler : InGameOnlyPacketHandler { private readonly IEnumerable _npcInteractionNotifiers; @@ -25,12 +24,10 @@ public PriestReplyHandler(IPlayerInfoProvider playerInfoProvider, _npcInteractionNotifiers = npcInteractionNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(PriestReplyServerPacket packet) { - var replyCode = (PriestReply)packet.ReadShort(); - foreach (var notifier in _npcInteractionNotifiers) - notifier.NotifyPriestReply(replyCode); + notifier.NotifyPriestReply(packet.ReplyCode); return true; } diff --git a/EOLib/PacketHandlers/Priest/PriestRequestHandler.cs b/EOLib/PacketHandlers/Priest/PriestRequestHandler.cs index 43255c4a0..4db7646a8 100644 --- a/EOLib/PacketHandlers/Priest/PriestRequestHandler.cs +++ b/EOLib/PacketHandlers/Priest/PriestRequestHandler.cs @@ -2,14 +2,15 @@ using EOLib.Domain.Interact; using EOLib.Domain.Interact.Priest; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Priest { [AutoMappedType] - public class PriestRequestHandler : InGameOnlyPacketHandler + public class PriestRequestHandler : InGameOnlyPacketHandler { private readonly IPriestSessionRepository _priestSessionRepository; private readonly IEnumerable _npcInteractionNotifiers; @@ -27,14 +28,12 @@ public PriestRequestHandler(IPlayerInfoProvider playerInfoProvider, _npcInteractionNotifiers = npcInteractionNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(PriestRequestServerPacket packet) { - _priestSessionRepository.SessionID = packet.ReadShort(); - - var partnerName = packet.ReadEndString(); + _priestSessionRepository.SessionID = packet.SessionId; foreach (var notifier in _npcInteractionNotifiers) - notifier.NotifyPriestRequest(partnerName); + notifier.NotifyPriestRequest(packet.PartnerName); return true; } diff --git a/EOLib/PacketHandlers/Quest/QuestDialogHandler.cs b/EOLib/PacketHandlers/Quest/QuestDialogHandler.cs index e3d3fb9d9..c4f1c368c 100644 --- a/EOLib/PacketHandlers/Quest/QuestDialogHandler.cs +++ b/EOLib/PacketHandlers/Quest/QuestDialogHandler.cs @@ -2,25 +2,21 @@ using EOLib.Domain.Interact; using EOLib.Domain.Interact.Quest; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using System.Collections.Generic; +using System.Linq; namespace EOLib.PacketHandlers.Quest { [AutoMappedType] - public class QuestDialogHandler : InGameOnlyPacketHandler + public class QuestDialogHandler : InGameOnlyPacketHandler { private readonly IQuestDataRepository _questDataRepository; private readonly IEnumerable _npcInteractionNotifiers; - private enum DialogEntryType : byte - { - Text = 1, - Link - } - public override PacketFamily Family => PacketFamily.Quest; public override PacketAction Action => PacketAction.Dialog; @@ -34,45 +30,33 @@ public QuestDialogHandler(IPlayerInfoProvider playerInfoProvider, _npcInteractionNotifiers = npcInteractionNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(QuestDialogServerPacket packet) { - var numDialogs = packet.ReadChar(); - var vendorID = packet.ReadShort(); - var questID = packet.ReadShort(); - var sessionID = packet.ReadShort(); - var dialogID = packet.ReadShort(); - - if (packet.ReadByte() != 255) - return false; - - var questData = new QuestDialogData.Builder - { - VendorID = vendorID, - QuestID = questID, - SessionID = sessionID, // not used by eoserv - DialogID = dialogID, // not used by eoserv - }; - - var dialogTitles = new Dictionary(numDialogs); - for (int i = 0; i < numDialogs; i++) - dialogTitles.Add(packet.ReadShort(), packet.ReadBreakString()); - var pages = new List(); var links = new List<(int, string)>(); - while (packet.ReadPosition < packet.Length) + foreach (var entry in packet.DialogEntries) { - var entryType = (DialogEntryType)packet.ReadShort(); - switch (entryType) + if (entry.EntryType == DialogEntryType.Link) + { + var data = (DialogEntry.EntryTypeDataLink)entry.EntryTypeData; + links.Add((data.LinkId, entry.Line)); + } + else { - case DialogEntryType.Text: pages.Add(packet.ReadBreakString()); break; - case DialogEntryType.Link: links.Add((packet.ReadShort(), packet.ReadBreakString())); break; - default: return false; + pages.Add(entry.Line); } } - questData.DialogTitles = dialogTitles; - questData.PageText = pages; - questData.Actions = links; + var questData = new QuestDialogData.Builder + { + VendorID = packet.BehaviorId, + QuestID = packet.QuestId, + SessionID = packet.SessionId, + DialogID = packet.DialogId, + DialogTitles = packet.QuestEntries.ToDictionary(k => k.QuestId, v => v.QuestName), + PageText = pages, + Actions = links + }; _questDataRepository.QuestDialogData = Option.Some(questData.ToImmutable()); diff --git a/EOLib/PacketHandlers/Quest/QuestListHandler.cs b/EOLib/PacketHandlers/Quest/QuestListHandler.cs index 79fcf5f13..509492d59 100644 --- a/EOLib/PacketHandlers/Quest/QuestListHandler.cs +++ b/EOLib/PacketHandlers/Quest/QuestListHandler.cs @@ -1,14 +1,15 @@ using AutomaticTypeMapper; using EOLib.Domain.Interact.Quest; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; -using System.Collections.Generic; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Linq; namespace EOLib.PacketHandlers.Quest { [AutoMappedType] - public class QuestListHandler : InGameOnlyPacketHandler + public class QuestListHandler : InGameOnlyPacketHandler { private readonly IQuestDataRepository _questDataRepository; @@ -23,49 +24,26 @@ public QuestListHandler(IPlayerInfoProvider playerInfoProvider, _questDataRepository = questDataRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(QuestListServerPacket packet) { - var page = (QuestPage)packet.ReadChar(); - var numQuests = packet.ReadShort(); - - switch (page) + switch (packet.Page) { case QuestPage.Progress: - { - var progress = new List(numQuests); - - for (int i = 0; packet.ReadPosition < packet.Length && i < numQuests; i++) - { - var progressData = new QuestProgressData.Builder - { - Name = packet.ReadBreakString(), - Description = packet.ReadBreakString(), - Icon = (BookIcon)packet.ReadShort(), - Progress = packet.ReadShort(), - Target = packet.ReadShort(), - }; - - progress.Add(progressData.ToImmutable()); - - if (packet.ReadByte() != 255) - return false; - } - - _questDataRepository.QuestProgress = progress; - } + _questDataRepository.QuestProgress = ((QuestListServerPacket.PageDataProgress)packet.PageData) + .QuestProgressEntries + .Select(x => new QuestProgressData.Builder + { + Name = x.Name, + Description = x.Description, + Icon = x.Icon, + Progress = x.Progress, + Target = x.Target, + }.ToImmutable()) + .ToList(); break; case QuestPage.History: - { - var completedQuests = new List(numQuests); - - for (int i = 0; packet.ReadPosition < packet.Length && i < numQuests; i++) - completedQuests.Add(packet.ReadBreakString()); - - _questDataRepository.QuestHistory = completedQuests; - } + _questDataRepository.QuestHistory = ((QuestListServerPacket.PageDataHistory)packet.PageData).CompletedQuests; break; - default: - return false; } return true; diff --git a/EOLib/PacketHandlers/Quest/QuestStatusMessageHandler.cs b/EOLib/PacketHandlers/Quest/QuestStatusMessageHandler.cs index 23919d8e9..eaa05780b 100644 --- a/EOLib/PacketHandlers/Quest/QuestStatusMessageHandler.cs +++ b/EOLib/PacketHandlers/Quest/QuestStatusMessageHandler.cs @@ -2,14 +2,15 @@ using EOLib.Domain.Chat; using EOLib.Domain.Interact.Quest; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Quest { [AutoMappedType] - public class QuestStatusMessageHandler : InGameOnlyPacketHandler + public class QuestStatusMessageHandler : InGameOnlyPacketHandler { private readonly IChatRepository _chatRepository; private readonly IEnumerable _statusLabelNotifiers; @@ -27,14 +28,12 @@ public QuestStatusMessageHandler(IPlayerInfoProvider playerInfoProvider, _statusLabelNotifiers = statusLabelNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(MessageOpenServerPacket packet) { - var message = packet.ReadEndString(); - foreach (var notifier in _statusLabelNotifiers) - notifier.ShowWarning(message); + notifier.ShowWarning(packet.Message); - var chatData = new ChatData(ChatTab.System, string.Empty, message, ChatIcon.QuestMessage, ChatColor.Server); + var chatData = new ChatData(ChatTab.System, string.Empty, packet.Message, ChatIcon.QuestMessage, ChatColor.Server); _chatRepository.AllChat[ChatTab.System].Add(chatData); return true; diff --git a/EOLib/PacketHandlers/Recover/RecoverAgreeHandler.cs b/EOLib/PacketHandlers/Recover/RecoverAgreeHandler.cs index 6fe49e1e1..3cb204f9b 100644 --- a/EOLib/PacketHandlers/Recover/RecoverAgreeHandler.cs +++ b/EOLib/PacketHandlers/Recover/RecoverAgreeHandler.cs @@ -3,8 +3,9 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System; using System.Collections.Generic; @@ -14,7 +15,7 @@ namespace EOLib.PacketHandlers.Recover /// Sent when a player uses a heal item /// [AutoMappedType] - public class RecoverAgreeHandler : InGameOnlyPacketHandler + public class RecoverAgreeHandler : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; private readonly ICurrentMapStateRepository _currentMapStateRepository; @@ -38,30 +39,26 @@ public RecoverAgreeHandler(IPlayerInfoProvider playerInfoProvider, _otherCharacterEventNotifiers = otherCharacterEventNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(RecoverAgreeServerPacket packet) { - var playerId = packet.ReadShort(); - var hpGain = packet.ReadInt(); - var percentHealth = packet.ReadChar(); - - if (_characterRepository.MainCharacter.ID == playerId) + if (_characterRepository.MainCharacter.ID == packet.PlayerId) { var c = _characterRepository.MainCharacter; var stats = c.Stats; - var hp = Math.Min(stats[CharacterStat.HP] + hpGain, stats[CharacterStat.MaxHP]); + var hp = Math.Min(stats[CharacterStat.HP] + packet.HealHp, stats[CharacterStat.MaxHP]); _characterRepository.MainCharacter = c.WithStats(stats.WithNewStat(CharacterStat.HP, hp)); foreach (var notifier in _mainCharacterEventNotifiers) - notifier.NotifyTakeDamage(hpGain, percentHealth, isHeal: true); + notifier.NotifyTakeDamage(packet.HealHp, packet.HpPercentage, isHeal: true); } - else if (_currentMapStateRepository.Characters.ContainsKey(playerId)) + else if (_currentMapStateRepository.Characters.ContainsKey(packet.PlayerId)) { foreach (var notifier in _otherCharacterEventNotifiers) - notifier.OtherCharacterTakeDamage(playerId, percentHealth, hpGain, isHeal: true); + notifier.OtherCharacterTakeDamage(packet.PlayerId, packet.HpPercentage, packet.HealHp, isHeal: true); } else { - _currentMapStateRepository.UnknownPlayerIDs.Add(playerId); + _currentMapStateRepository.UnknownPlayerIDs.Add(packet.PlayerId); } return true; diff --git a/EOLib/PacketHandlers/Recover/RecoverListHandler.cs b/EOLib/PacketHandlers/Recover/RecoverListHandler.cs index de5618b7b..20c346c69 100644 --- a/EOLib/PacketHandlers/Recover/RecoverListHandler.cs +++ b/EOLib/PacketHandlers/Recover/RecoverListHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Recover { @@ -10,7 +11,7 @@ namespace EOLib.PacketHandlers.Recover /// Sent when the main character's stats are updated by a quest (or stat change command) /// [AutoMappedType] - public class RecoverListHandler : InGameOnlyPacketHandler + public class RecoverListHandler : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; @@ -24,46 +25,13 @@ public RecoverListHandler(IPlayerInfoProvider playerInfoProvider, _characterRepository = characterRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(RecoverListServerPacket packet) { - //note: nearly identical code exists in StatTrainingHandler.HandlePacket - //todo: consolidate - var @class = packet.ReadShort(); - var str = packet.ReadShort(); - var intl = packet.ReadShort(); - var wis = packet.ReadShort(); - var agi = packet.ReadShort(); - var con = packet.ReadShort(); - var cha = packet.ReadShort(); - var hp = packet.ReadShort(); - var tp = packet.ReadShort(); - var sp = packet.ReadShort(); - var maxWeight = packet.ReadShort(); - var minDam = packet.ReadShort(); - var maxDam = packet.ReadShort(); - var accuracy = packet.ReadShort(); - var evade = packet.ReadShort(); - var armor = packet.ReadShort(); - var stats = _characterRepository.MainCharacter.Stats - .WithNewStat(CharacterStat.Strength, str) - .WithNewStat(CharacterStat.Intelligence, intl) - .WithNewStat(CharacterStat.Wisdom, wis) - .WithNewStat(CharacterStat.Agility, agi) - .WithNewStat(CharacterStat.Constitution, con) - .WithNewStat(CharacterStat.Charisma, cha) - .WithNewStat(CharacterStat.MaxHP, hp) - .WithNewStat(CharacterStat.MaxTP, tp) - .WithNewStat(CharacterStat.MaxSP, sp) - .WithNewStat(CharacterStat.MaxWeight, maxWeight) - .WithNewStat(CharacterStat.MinDam, minDam) - .WithNewStat(CharacterStat.MaxDam, maxDam) - .WithNewStat(CharacterStat.Accuracy, accuracy) - .WithNewStat(CharacterStat.Evade, evade) - .WithNewStat(CharacterStat.Armor, armor); + .Apply(CharacterStats.FromStatUpdate(packet.Stats)); _characterRepository.MainCharacter = _characterRepository.MainCharacter - .WithClassID(@class) + .WithClassID(packet.ClassId) .WithStats(stats); return true; diff --git a/EOLib/PacketHandlers/Recover/RecoverPlayerHandler.cs b/EOLib/PacketHandlers/Recover/RecoverPlayerHandler.cs index 7edcb60a5..7f9f7d380 100644 --- a/EOLib/PacketHandlers/Recover/RecoverPlayerHandler.cs +++ b/EOLib/PacketHandlers/Recover/RecoverPlayerHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Recover { @@ -10,7 +11,7 @@ namespace EOLib.PacketHandlers.Recover /// Sent when the main character gains HP/TP /// [AutoMappedType] - public class RecoverPlayerHandler : InGameOnlyPacketHandler + public class RecoverPlayerHandler : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; @@ -24,14 +25,11 @@ public RecoverPlayerHandler(IPlayerInfoProvider playerInfoProvider, _characterRepository = characterRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(RecoverPlayerServerPacket packet) { - var newHP = packet.ReadShort(); - var newTP = packet.ReadShort(); - var stats = _characterRepository.MainCharacter.Stats - .WithNewStat(CharacterStat.HP, newHP) - .WithNewStat(CharacterStat.TP, newTP); + .WithNewStat(CharacterStat.HP, packet.Hp) + .WithNewStat(CharacterStat.TP, packet.Tp); _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); diff --git a/EOLib/PacketHandlers/Recover/RecoverReplyHandler.cs b/EOLib/PacketHandlers/Recover/RecoverReplyHandler.cs index 9989045f4..ed6be1d5e 100644 --- a/EOLib/PacketHandlers/Recover/RecoverReplyHandler.cs +++ b/EOLib/PacketHandlers/Recover/RecoverReplyHandler.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Recover @@ -12,7 +13,7 @@ namespace EOLib.PacketHandlers.Recover /// Sent when the main character is given EXP or Karma in a quest /// [AutoMappedType] - public class RecoverReplyHandler : InGameOnlyPacketHandler + public class RecoverReplyHandler : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; private readonly IEnumerable _emoteNotifiers; @@ -30,27 +31,27 @@ public RecoverReplyHandler(IPlayerInfoProvider playerInfoProvider, _emoteNotifiers = emoteNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(RecoverReplyServerPacket packet) { - var exp = packet.ReadInt(); - var karma = packet.ReadShort(); - var level = packet.ReadChar(); - var stats = _characterRepository.MainCharacter.Stats - .WithNewStat(CharacterStat.Experience, exp) - .WithNewStat(CharacterStat.Karma, karma); + .WithNewStat(CharacterStat.Experience, packet.Experience) + .WithNewStat(CharacterStat.Karma, packet.Karma); - if (level > 0) + if (packet.LevelUp.HasValue && packet.LevelUp > 0) { - stats = stats.WithNewStat(CharacterStat.Level, level); + stats = stats.WithNewStat(CharacterStat.Level, packet.LevelUp.Value); foreach (var notifier in _emoteNotifiers) notifier.NotifyEmote(_characterRepository.MainCharacter.ID, Domain.Character.Emote.LevelUp); } - if (packet.ReadPosition < packet.Length) + if (packet.StatPoints.HasValue) + { + stats = stats.WithNewStat(CharacterStat.StatPoints, packet.StatPoints.Value); + } + + if (packet.SkillPoints.HasValue) { - stats = stats.WithNewStat(CharacterStat.StatPoints, packet.ReadShort()) - .WithNewStat(CharacterStat.SkillPoints, packet.ReadShort()); + stats = stats.WithNewStat(CharacterStat.SkillPoints, packet.SkillPoints.Value); } _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); diff --git a/EOLib/PacketHandlers/Refresh/RefreshReplyHandler.cs b/EOLib/PacketHandlers/Refresh/RefreshReplyHandler.cs index e00bbf45e..482a1018f 100644 --- a/EOLib/PacketHandlers/Refresh/RefreshReplyHandler.cs +++ b/EOLib/PacketHandlers/Refresh/RefreshReplyHandler.cs @@ -3,9 +3,9 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; -using EOLib.Net.Translators; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; using System.Linq; @@ -17,9 +17,8 @@ namespace EOLib.PacketHandlers.Refresh /// Sent when the map state (characters, npcs, and map items) should be refreshed /// [AutoMappedType] - public class RefreshReplyHandler : InGameOnlyPacketHandler + public class RefreshReplyHandler : InGameOnlyPacketHandler { - private readonly IPacketTranslator _refreshReplyTranslator; private readonly ICharacterRepository _characterRepository; private readonly ICurrentMapStateRepository _currentMapStateRepository; private readonly IEnumerable _mapChangedNotifiers; @@ -29,45 +28,42 @@ public class RefreshReplyHandler : InGameOnlyPacketHandler public override PacketAction Action => PacketAction.Reply; public RefreshReplyHandler(IPlayerInfoProvider playerInfoProvider, - IPacketTranslator refreshReplyTranslator, ICharacterRepository characterRepository, ICurrentMapStateRepository currentMapStateRepository, IEnumerable mapChangedNotifiers) : base(playerInfoProvider) { - _refreshReplyTranslator = refreshReplyTranslator; _characterRepository = characterRepository; _currentMapStateRepository = currentMapStateRepository; _mapChangedNotifiers = mapChangedNotifiers; } - //todo: this is almost identical to EndPlayerWarpHandler - see if there is some way to share - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(RefreshReplyServerPacket packet) { - var data = _refreshReplyTranslator.TranslatePacket(packet); + var characters = packet.Nearby.Characters + .Where(x => x.ByteSize >= 42) + .Select(Character.FromNearby) + .ToList(); - var updatedMainCharacter = data.Characters.Single(MainCharacterIDMatches); + var updatedMainCharacter = characters.Single(MainCharacterIDMatches); var updatedRenderProperties = _characterRepository.MainCharacter.RenderProperties .WithMapX(updatedMainCharacter.RenderProperties.MapX) .WithMapY(updatedMainCharacter.RenderProperties.MapY); - - var withoutMainCharacter = data.Characters.Where(x => !MainCharacterIDMatches(x)); - _characterRepository.MainCharacter = _characterRepository.MainCharacter .WithRenderProperties(updatedRenderProperties); + var withoutMainCharacter = characters.Where(x => !MainCharacterIDMatches(x)); _currentMapStateRepository.Characters = new MapEntityCollectionHashSet(c => c.ID, c => new MapCoordinate(c.X, c.Y), withoutMainCharacter); - _currentMapStateRepository.NPCs = new MapEntityCollectionHashSet(n => n.Index, n => new MapCoordinate(n.X, n.Y), data.NPCs); - _currentMapStateRepository.MapItems = new MapEntityCollectionHashSet(item => item.UniqueID, item => new MapCoordinate(item.X, item.Y), data.Items); + _currentMapStateRepository.NPCs = new MapEntityCollectionHashSet(n => n.Index, n => new MapCoordinate(n.X, n.Y), packet.Nearby.Npcs.Select(DomainNPC.FromNearby)); + _currentMapStateRepository.MapItems = new MapEntityCollectionHashSet(item => item.UniqueID, item => new MapCoordinate(item.X, item.Y), packet.Nearby.Items.Select(MapItem.FromNearby)); _currentMapStateRepository.OpenDoors.Clear(); _currentMapStateRepository.PendingDoors.Clear(); - _currentMapStateRepository.VisibleSpikeTraps.Clear(); _currentMapStateRepository.MapWarpTime = Optional.Option.Some(System.DateTime.Now.AddMilliseconds(-100)); foreach (var notifier in _mapChangedNotifiers) - notifier.NotifyMapChanged(differentMapID: false, warpAnimation: WarpAnimation.None); + notifier.NotifyMapChanged(WarpEffect.None, differentMapID: false); return true; } diff --git a/EOLib/PacketHandlers/Shop/ShopCraftHandler.cs b/EOLib/PacketHandlers/Shop/ShopCraftHandler.cs index cfa654106..1fe6b2b74 100644 --- a/EOLib/PacketHandlers/Shop/ShopCraftHandler.cs +++ b/EOLib/PacketHandlers/Shop/ShopCraftHandler.cs @@ -2,15 +2,16 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional.Collections; using System.Collections.Generic; namespace EOLib.PacketHandlers.Shop { [AutoMappedType] - public class ShopCraftHandler : InGameOnlyPacketHandler + public class ShopCraftHandler : InGameOnlyPacketHandler { private const int ShopCraftSfxId = 27; @@ -33,49 +34,44 @@ public ShopCraftHandler(IPlayerInfoProvider playerInfoProvider, _soundNotifiers = soundNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(ShopCreateServerPacket packet) { - var itemId = packet.ReadShort(); - var weight = packet.ReadChar(); - var maxWeight = packet.ReadChar(); - while (packet.ReadPosition < packet.Length) + foreach (var item in packet.Ingredients) { - if (packet.PeekShort() == 0) break; + if (item.Id == 0) + break; - var nextItemId = packet.ReadShort(); - var nextItemAmount = packet.ReadInt(); - - _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == nextItemId) + _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == item.Id) .Match( some: existing => { _characterInventoryRepository.ItemInventory.Remove(existing); - if (nextItemAmount > 0) - _characterInventoryRepository.ItemInventory.Add(existing.WithAmount(nextItemAmount)); + if (item.Amount > 0) + _characterInventoryRepository.ItemInventory.Add(existing.WithAmount(item.Amount)); }, none: () => { - if (nextItemAmount > 0) - _characterInventoryRepository.ItemInventory.Add(new InventoryItem(nextItemId, nextItemAmount)); + if (item.Amount > 0) + _characterInventoryRepository.ItemInventory.Add(new InventoryItem(item.Id, item.Amount)); }); } foreach (var notifier in _soundNotifiers) notifier.NotifySoundEffect(ShopCraftSfxId); - _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == itemId) + _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == packet.CraftItemId) .Match( some: existing => { _characterInventoryRepository.ItemInventory.Remove(existing); _characterInventoryRepository.ItemInventory.Add(existing.WithAmount(existing.Amount + 1)); }, - none: () => _characterInventoryRepository.ItemInventory.Add(new InventoryItem(itemId, 1))); + none: () => _characterInventoryRepository.ItemInventory.Add(new InventoryItem(packet.CraftItemId, 1))); var stats = _characterRepository.MainCharacter.Stats; - stats = stats.WithNewStat(CharacterStat.Weight, weight) - .WithNewStat(CharacterStat.MaxWeight, maxWeight); + stats = stats.WithNewStat(CharacterStat.Weight, packet.Weight.Current) + .WithNewStat(CharacterStat.MaxWeight, packet.Weight.Max); _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); return true; diff --git a/EOLib/PacketHandlers/Shop/ShopOpenHandler.cs b/EOLib/PacketHandlers/Shop/ShopOpenHandler.cs index a1a80ca79..d44740a35 100644 --- a/EOLib/PacketHandlers/Shop/ShopOpenHandler.cs +++ b/EOLib/PacketHandlers/Shop/ShopOpenHandler.cs @@ -2,14 +2,16 @@ using EOLib.Domain.Interact; using EOLib.Domain.Interact.Shop; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; +using System.Linq; namespace EOLib.PacketHandlers.Shop { [AutoMappedType] - public class ShopOpenHandler : InGameOnlyPacketHandler + public class ShopOpenHandler : InGameOnlyPacketHandler { private readonly IShopDataRepository _shopDataRepository; private readonly IEnumerable _npcInteractionNotifiers; @@ -27,44 +29,22 @@ public ShopOpenHandler(IPlayerInfoProvider playerInfoProvider, _npcInteractionNotifiers = npcInteractionNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(ShopOpenServerPacket packet) { - _shopDataRepository.ShopID = packet.ReadShort(); - _shopDataRepository.ShopName = packet.ReadBreakString(); - - var tradeItems = new List(); - while (packet.PeekByte() != 255) - { - var nextItem = new ShopItem( - id: packet.ReadShort(), - buyPrice: packet.ReadThree(), - sellPrice: packet.ReadThree(), - maxBuy: packet.ReadChar()); - tradeItems.Add(nextItem); - } - packet.ReadByte(); - - _shopDataRepository.TradeItems = tradeItems; - - var craftItems = new List(); - while (packet.PeekByte() != 255) - { - var id = packet.ReadShort(); - var ingreds = new List(); - - for (int i = 0; i < 4; ++i) - { - var nextIngredient = new ShopCraftIngredient(id: packet.ReadShort(), amount: packet.ReadChar()); - if (nextIngredient.ID == 0) - continue; - - ingreds.Add(nextIngredient); - } - craftItems.Add(new ShopCraftItem(id, ingreds)); - } - packet.ReadByte(); - - _shopDataRepository.CraftItems = craftItems; + _shopDataRepository.SessionID = packet.SessionId; + _shopDataRepository.ShopName = packet.ShopName; + + _shopDataRepository.TradeItems = packet.TradeItems + .Where(x => x.ItemId > 0) + .Select(x => new ShopItem(x.ItemId, x.BuyPrice, x.SellPrice, x.MaxBuyAmount)) + .ToList(); + + _shopDataRepository.CraftItems = packet.CraftItems + .Where(x => x.ItemId > 0) + .Select(x => new Domain.Interact.Shop.ShopCraftItem( + x.ItemId, + x.Ingredients.Where(x => x.Id > 0).Select(ing => new ShopCraftIngredient(ing.Id, ing.Amount)).ToList())) + .ToList(); foreach (var notifier in _npcInteractionNotifiers) notifier.NotifyInteractionFromNPC(IO.NPCType.Shop); diff --git a/EOLib/PacketHandlers/Shop/ShopTradeHandler.cs b/EOLib/PacketHandlers/Shop/ShopTradeHandler.cs index 7c2998971..17ac815fd 100644 --- a/EOLib/PacketHandlers/Shop/ShopTradeHandler.cs +++ b/EOLib/PacketHandlers/Shop/ShopTradeHandler.cs @@ -4,12 +4,15 @@ using EOLib.Domain.Notifiers; using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional.Collections; using System.Collections.Generic; namespace EOLib.PacketHandlers.Shop { - public abstract class ShopTradeHandler : InGameOnlyPacketHandler + public abstract class ShopTradeHandler : InGameOnlyPacketHandler + where TPacket : IPacket { private const byte BuySellSfxId = 26; @@ -30,14 +33,8 @@ protected ShopTradeHandler(IPlayerInfoProvider playerInfoProvider, _soundNotifiers = soundNotifiers; } - public override bool HandlePacket(IPacket packet) + protected void Handle(int remaining, int itemId, int acquired, Weight weight) { - var remaining = packet.ReadInt(); // character gold remaining on buy; item amount remaining on sell - var itemId = packet.ReadShort(); - var acquired = packet.ReadInt(); // amount acquired on buy; gold acquired on sell - var weight = packet.ReadChar(); - var maxWeight = packet.ReadChar(); - if (Action == PacketAction.Buy) { var gold = new InventoryItem(1, remaining); @@ -67,23 +64,21 @@ public override bool HandlePacket(IPacket packet) } else { - return false; + return; } foreach (var notifier in _soundNotifiers) notifier.NotifySoundEffect(BuySellSfxId); var stats = _characterRepository.MainCharacter.Stats; - stats = stats.WithNewStat(CharacterStat.Weight, weight) - .WithNewStat(CharacterStat.MaxWeight, maxWeight); + stats = stats.WithNewStat(CharacterStat.Weight, weight.Current) + .WithNewStat(CharacterStat.MaxWeight, weight.Max); _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); - - return true; } } [AutoMappedType] - public class ShopBuyHandler : ShopTradeHandler + public class ShopBuyHandler : ShopTradeHandler { public override PacketAction Action => PacketAction.Buy; @@ -94,10 +89,16 @@ public ShopBuyHandler(IPlayerInfoProvider playerInfoProvider, : base(playerInfoProvider, characterRepository, characterInventoryRepository, soundNotifiers) { } + + public override bool HandlePacket(ShopBuyServerPacket packet) + { + Handle(packet.GoldAmount, packet.BoughtItem.Id, packet.BoughtItem.Amount, packet.Weight); + return true; + } } [AutoMappedType] - public class ShopSellHandler : ShopTradeHandler + public class ShopSellHandler : ShopTradeHandler { public override PacketAction Action => PacketAction.Sell; @@ -108,5 +109,11 @@ public ShopSellHandler(IPlayerInfoProvider playerInfoProvider, : base(playerInfoProvider, characterRepository, characterInventoryRepository, soundNotifiers) { } + + public override bool HandlePacket(ShopSellServerPacket packet) + { + Handle(packet.SoldItem.Amount, packet.SoldItem.Id, packet.GoldAmount, packet.Weight); + return true; + } } } diff --git a/EOLib/PacketHandlers/Sit/PlayerSitHandlerBase.cs b/EOLib/PacketHandlers/Sit/PlayerSitHandlerBase.cs index 0d2595d29..4a8347427 100644 --- a/EOLib/PacketHandlers/Sit/PlayerSitHandlerBase.cs +++ b/EOLib/PacketHandlers/Sit/PlayerSitHandlerBase.cs @@ -1,15 +1,16 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; namespace EOLib.PacketHandlers.Sit { /// /// Base class for handling a character sitting down /// - public abstract class PlayerSitHandlerBase : InGameOnlyPacketHandler + public abstract class PlayerSitHandlerBase : InGameOnlyPacketHandler + where TPacket : IPacket { private readonly ICharacterRepository _characterRepository; private readonly ICurrentMapStateRepository _currentMapStateRepository; @@ -25,18 +26,10 @@ public PlayerSitHandlerBase(IPlayerInfoProvider playerInfoProvider, _currentMapStateRepository = currentMapStateRepository; } - public override bool HandlePacket(IPacket packet) + protected void Handle(int playerId, int x, int y, EODirection direction) { - var playerId = packet.ReadShort(); - var x = packet.ReadChar(); - var y = packet.ReadChar(); - var direction = (EODirection)packet.ReadChar(); - var sitState = Family == PacketFamily.Sit ? SitState.Floor : SitState.Chair; - if (packet.ReadChar() != 0) - return false; - if (playerId == _characterRepository.MainCharacter.ID) { var renderProperties = _characterRepository.MainCharacter.RenderProperties; @@ -61,8 +54,6 @@ public override bool HandlePacket(IPacket packet) { _currentMapStateRepository.UnknownPlayerIDs.Add(playerId); } - - return true; } } } diff --git a/EOLib/PacketHandlers/Sit/PlayerStandHandlerBase.cs b/EOLib/PacketHandlers/Sit/PlayerStandHandlerBase.cs index 82d967f1f..ca14b8a93 100644 --- a/EOLib/PacketHandlers/Sit/PlayerStandHandlerBase.cs +++ b/EOLib/PacketHandlers/Sit/PlayerStandHandlerBase.cs @@ -1,15 +1,16 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; namespace EOLib.PacketHandlers.Sit { /// /// Base class for handling a character standing up /// - public abstract class PlayerStandHandlerBase : InGameOnlyPacketHandler + public abstract class PlayerStandHandlerBase : InGameOnlyPacketHandler + where TPacket : IPacket { private readonly ICharacterRepository _characterRepository; private readonly ICurrentMapStateRepository _currentMapStateRepository; @@ -25,12 +26,8 @@ public PlayerStandHandlerBase(IPlayerInfoProvider playerInfoProvider, _currentMapStateRepository = currentMapStateRepository; } - public override bool HandlePacket(IPacket packet) + protected void Handle(int playerId, int x, int y) { - var playerId = packet.ReadShort(); - var x = packet.ReadChar(); - var y = packet.ReadChar(); - if (playerId == _characterRepository.MainCharacter.ID) { var renderProperties = _characterRepository.MainCharacter.RenderProperties; @@ -53,8 +50,6 @@ public override bool HandlePacket(IPacket packet) { _currentMapStateRepository.UnknownPlayerIDs.Add(playerId); } - - return true; } } } diff --git a/EOLib/PacketHandlers/Sit/SitCloseHandler.cs b/EOLib/PacketHandlers/Sit/SitCloseHandler.cs index 2632895ff..58b5643da 100644 --- a/EOLib/PacketHandlers/Sit/SitCloseHandler.cs +++ b/EOLib/PacketHandlers/Sit/SitCloseHandler.cs @@ -2,7 +2,8 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Sit { @@ -10,7 +11,7 @@ namespace EOLib.PacketHandlers.Sit /// Handle the main player standing up /// [AutoMappedType] - public class SitCloseHandler : PlayerStandHandlerBase + public class SitCloseHandler : PlayerStandHandlerBase { public override PacketAction Action => PacketAction.Close; @@ -18,5 +19,11 @@ public SitCloseHandler(IPlayerInfoProvider playerInfoProvider, ICharacterRepository characterRepository, ICurrentMapStateRepository currentMapStateRepository) : base(playerInfoProvider, characterRepository, currentMapStateRepository) { } + + public override bool HandlePacket(SitCloseServerPacket packet) + { + Handle(packet.PlayerId, packet.Coords.X, packet.Coords.Y); + return true; + } } } diff --git a/EOLib/PacketHandlers/Sit/SitPlayerHandler.cs b/EOLib/PacketHandlers/Sit/SitPlayerHandler.cs index ab9159c83..f4dbd5cda 100644 --- a/EOLib/PacketHandlers/Sit/SitPlayerHandler.cs +++ b/EOLib/PacketHandlers/Sit/SitPlayerHandler.cs @@ -2,7 +2,8 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Sit { @@ -10,7 +11,7 @@ namespace EOLib.PacketHandlers.Sit /// Sent when a player sits on the floor via F11 /// [AutoMappedType] - public class SitPlayerHandler : PlayerSitHandlerBase + public class SitPlayerHandler : PlayerSitHandlerBase { public override PacketFamily Family => PacketFamily.Sit; @@ -18,5 +19,11 @@ public SitPlayerHandler(IPlayerInfoProvider playerInfoProvider, ICharacterRepository characterRepository, ICurrentMapStateRepository currentMapStateRepository) : base(playerInfoProvider, characterRepository, currentMapStateRepository) { } + + public override bool HandlePacket(SitPlayerServerPacket packet) + { + Handle(packet.PlayerId, packet.Coords.X, packet.Coords.Y, (EODirection)packet.Direction); + return true; + } } } diff --git a/EOLib/PacketHandlers/Sit/SitRemoveHandler.cs b/EOLib/PacketHandlers/Sit/SitRemoveHandler.cs index 863deebc8..f9e652e45 100644 --- a/EOLib/PacketHandlers/Sit/SitRemoveHandler.cs +++ b/EOLib/PacketHandlers/Sit/SitRemoveHandler.cs @@ -2,7 +2,8 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.Sit { @@ -10,7 +11,7 @@ namespace EOLib.PacketHandlers.Sit /// Handle another player standing up /// [AutoMappedType] - public class SitRemoveHandler : PlayerStandHandlerBase + public class SitRemoveHandler : PlayerStandHandlerBase { public override PacketAction Action => PacketAction.Remove; @@ -18,5 +19,11 @@ public SitRemoveHandler(IPlayerInfoProvider playerInfoProvider, ICharacterRepository characterRepository, ICurrentMapStateRepository currentMapStateRepository) : base(playerInfoProvider, characterRepository, currentMapStateRepository) { } + + public override bool HandlePacket(SitRemoveServerPacket packet) + { + Handle(packet.PlayerId, packet.Coords.X, packet.Coords.Y); + return true; + } } } diff --git a/EOLib/PacketHandlers/Sit/SitReplyHandler.cs b/EOLib/PacketHandlers/Sit/SitReplyHandler.cs new file mode 100644 index 000000000..d4e532bf2 --- /dev/null +++ b/EOLib/PacketHandlers/Sit/SitReplyHandler.cs @@ -0,0 +1,31 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Character; +using EOLib.Domain.Login; +using EOLib.Domain.Map; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; + +namespace EOLib.PacketHandlers.Sit +{ + /// + /// Handle your player sitting + /// + [AutoMappedType] + public class SitReplyHandler : PlayerSitHandlerBase + { + public override PacketFamily Family => PacketFamily.Sit; + + public override PacketAction Action => PacketAction.Reply; + + public SitReplyHandler(IPlayerInfoProvider playerInfoProvider, + ICharacterRepository characterRepository, + ICurrentMapStateRepository currentMapStateRepository) + : base(playerInfoProvider, characterRepository, currentMapStateRepository) { } + + public override bool HandlePacket(SitReplyServerPacket packet) + { + Handle(packet.PlayerId, packet.Coords.X, packet.Coords.Y, (EODirection)packet.Direction); + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Spell/SpellRequestHandler.cs b/EOLib/PacketHandlers/Spell/SpellRequestHandler.cs index 404c6dc79..7c102a36e 100644 --- a/EOLib/PacketHandlers/Spell/SpellRequestHandler.cs +++ b/EOLib/PacketHandlers/Spell/SpellRequestHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Spell @@ -11,7 +12,7 @@ namespace EOLib.PacketHandlers.Spell /// Sent when a player starts a spell chant /// [AutoMappedType] - public class SpellRequestHandler : InGameOnlyPacketHandler + public class SpellRequestHandler : InGameOnlyPacketHandler { private readonly IEnumerable animationNotifiers; @@ -25,13 +26,10 @@ public SpellRequestHandler(IPlayerInfoProvider playerInfoProvider, this.animationNotifiers = animationNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(SpellRequestServerPacket packet) { - var playerId = packet.ReadShort(); - var spellId = packet.ReadShort(); - foreach (var notifier in animationNotifiers) - notifier.NotifyStartSpellCast(playerId, spellId); + notifier.NotifyStartSpellCast(packet.PlayerId, packet.SpellId); return true; } diff --git a/EOLib/PacketHandlers/Spell/SpellTargetGroupHandler.cs b/EOLib/PacketHandlers/Spell/SpellTargetGroupHandler.cs index fa11c8b15..79525bea7 100644 --- a/EOLib/PacketHandlers/Spell/SpellTargetGroupHandler.cs +++ b/EOLib/PacketHandlers/Spell/SpellTargetGroupHandler.cs @@ -4,8 +4,9 @@ using EOLib.Domain.Notifiers; using EOLib.Domain.Party; using EOLib.Domain.Spells; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional.Collections; using System.Collections.Generic; using System.Linq; @@ -16,7 +17,7 @@ namespace EOLib.PacketHandlers.Spell /// Sent when a spell targeting a group is successfully cast /// [AutoMappedType] - public class SpellTargetGroupHandler : InGameOnlyPacketHandler + public class SpellTargetGroupHandler : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; private readonly IPartyDataRepository _partyDataRepository; @@ -37,55 +38,43 @@ public SpellTargetGroupHandler(IPlayerInfoProvider playerInfoProvider, _notifiers = notifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(SpellTargetGroupServerPacket packet) { - var spellId = packet.ReadShort(); - var sourcePlayerId = packet.ReadShort(); - var fromPlayerTp = packet.ReadShort(); - var spellHealthGain = packet.ReadShort(); - - if (sourcePlayerId == _characterRepository.MainCharacter.ID) + if (packet.CasterId == _characterRepository.MainCharacter.ID) { - var stats = _characterRepository.MainCharacter.Stats.WithNewStat(CharacterStat.TP, fromPlayerTp); + var stats = _characterRepository.MainCharacter.Stats.WithNewStat(CharacterStat.TP, packet.CasterTp); _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); } - var spellTargets = new List(); - while (packet.ReadPosition != packet.Length) - { - // eoserv puts 5 '255' bytes between party members - // unknown what data structures are supposed to be represented between these break bytes - // todo: these bytes are garbage data for an empty record (5 bytes read per group spell target) - handle accordingly - if (packet.ReadBytes(5).Any(x => x != 255)) return false; - - var targetId = packet.ReadShort(); - var targetPercentHealth = packet.ReadChar(); - var targetHp = packet.ReadShort(); - - spellTargets.Add(new GroupSpellTarget.Builder - { - TargetId = targetId, - PercentHealth = targetPercentHealth, - TargetHp = targetHp, - }.ToImmutable()); + var spellTargets = packet.Players + .Select(x => new GroupSpellTarget.Builder + { + TargetId = x.PlayerId, + TargetHp = x.Hp, + PercentHealth = x.HpPercentage, + }.ToImmutable()) + .ToList(); - _partyDataRepository.Members.SingleOrNone(x => x.CharacterID == targetId) + // todo: eoserv potentially sends garbage 255 bytes in packet.Players + foreach (var target in spellTargets) + { + _partyDataRepository.Members.SingleOrNone(x => x.CharacterID == target.TargetId) .MatchSome(x => { _partyDataRepository.Members.Remove(x); - _partyDataRepository.Members.Add(x.WithPercentHealth(targetPercentHealth)); + _partyDataRepository.Members.Add(x.WithPercentHealth(target.PercentHealth)); }); - if (targetId == _characterRepository.MainCharacter.ID) + if (target.TargetId == _characterRepository.MainCharacter.ID) { - var stats = _characterRepository.MainCharacter.Stats.WithNewStat(CharacterStat.HP, targetHp); + var stats = _characterRepository.MainCharacter.Stats.WithNewStat(CharacterStat.HP, target.TargetHp); _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); } } foreach (var notifier in _notifiers) { - notifier.NotifyGroupSpellCast(sourcePlayerId, spellId, spellHealthGain, spellTargets); + notifier.NotifyGroupSpellCast(packet.CasterId, packet.SpellId, packet.SpellHealHp, spellTargets); } return true; diff --git a/EOLib/PacketHandlers/Spell/SpellTargetOtherHandler.cs b/EOLib/PacketHandlers/Spell/SpellTargetOtherHandler.cs index e075837c5..eda20f4b9 100644 --- a/EOLib/PacketHandlers/Spell/SpellTargetOtherHandler.cs +++ b/EOLib/PacketHandlers/Spell/SpellTargetOtherHandler.cs @@ -3,8 +3,9 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Spell @@ -13,7 +14,7 @@ namespace EOLib.PacketHandlers.Spell /// Sent when a player targets another player with a heal spell /// [AutoMappedType] - public class SpellTargetOtherHandler : InGameOnlyPacketHandler + public class SpellTargetOtherHandler : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; private readonly ICurrentMapStateRepository _currentMapStateRepository; @@ -33,40 +34,32 @@ public SpellTargetOtherHandler(IPlayerInfoProvider playerInfoProvider, _animationNotifiers = animationNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(SpellTargetOtherServerPacket packet) { - var targetPlayerId = packet.ReadShort(); - var sourcePlayerId = packet.ReadShort(); - var sourcePlayerDirection = (EODirection)packet.ReadChar(); - var spellId = packet.ReadShort(); - var recoveredHP = packet.ReadInt(); - var targetPercentHealth = packet.ReadChar(); - - if (sourcePlayerId == _characterRepository.MainCharacter.ID) + if (packet.CasterId == _characterRepository.MainCharacter.ID) { - var renderProps = _characterRepository.MainCharacter.RenderProperties.WithDirection(sourcePlayerDirection); + var renderProps = _characterRepository.MainCharacter.RenderProperties.WithDirection((EODirection)packet.CasterDirection); _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithRenderProperties(renderProps); } - else if (_currentMapStateRepository.Characters.TryGetValue(sourcePlayerId, out var character)) + else if (_currentMapStateRepository.Characters.TryGetValue(packet.CasterId, out var character)) { - var updatedCharacter = character.WithRenderProperties(character.RenderProperties.WithDirection(sourcePlayerDirection)); + var updatedCharacter = character.WithRenderProperties(character.RenderProperties.WithDirection((EODirection)packet.CasterDirection)); _currentMapStateRepository.Characters.Update(character, updatedCharacter); } else { - _currentMapStateRepository.UnknownPlayerIDs.Add(sourcePlayerId); + _currentMapStateRepository.UnknownPlayerIDs.Add(packet.CasterId); return true; } - if (packet.ReadPosition != packet.Length) + if (packet.Hp.HasValue) { - var targetPlayerCurrentHp = packet.ReadShort(); - var stats = _characterRepository.MainCharacter.Stats.WithNewStat(CharacterStat.HP, targetPlayerCurrentHp); + var stats = _characterRepository.MainCharacter.Stats.WithNewStat(CharacterStat.HP, packet.Hp.Value); _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); } foreach (var notifier in _animationNotifiers) - notifier.NotifyTargetOtherSpellCast(sourcePlayerId, targetPlayerId, spellId, recoveredHP, targetPercentHealth); + notifier.NotifyTargetOtherSpellCast(packet.CasterId, packet.VictimId, packet.SpellId, packet.SpellHealHp, packet.HpPercentage); return true; } diff --git a/EOLib/PacketHandlers/Spell/SpellTargetSelfHandler.cs b/EOLib/PacketHandlers/Spell/SpellTargetSelfHandler.cs index aad97bb8a..060b71c65 100644 --- a/EOLib/PacketHandlers/Spell/SpellTargetSelfHandler.cs +++ b/EOLib/PacketHandlers/Spell/SpellTargetSelfHandler.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Spell @@ -12,7 +13,7 @@ namespace EOLib.PacketHandlers.Spell /// Sent when a player cast a spell targeting themselves /// [AutoMappedType] - public class SpellTargetSelfHandler : InGameOnlyPacketHandler + public class SpellTargetSelfHandler : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; private readonly IEnumerable _animationNotifiers; @@ -29,24 +30,18 @@ public SpellTargetSelfHandler(IPlayerInfoProvider playerInfoProvider, _animationNotifiers = animationNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(SpellTargetSelfServerPacket packet) { - var fromPlayerID = packet.ReadShort(); - var spellID = packet.ReadShort(); - var spellHP = packet.ReadInt(); - var percentHealth = packet.ReadChar(); + var fromPlayerID = packet.PlayerId; + var spellID = packet.SpellId; + var spellHP = packet.SpellHealHp; + var percentHealth = packet.HpPercentage; - if (packet.ReadPosition != packet.Length) + if (packet.ByteSize > 12) { - //main player was source of this packet (otherwise, other player was source) - var characterHP = packet.ReadShort(); - var characterTP = packet.ReadShort(); - if (packet.ReadShort() != 1) //malformed packet! eoserv sends '1' here - return false; - var stats = _characterRepository.MainCharacter.Stats; - stats = stats.WithNewStat(CharacterStat.HP, characterHP) - .WithNewStat(CharacterStat.TP, characterTP); + stats = stats.WithNewStat(CharacterStat.HP, packet.Hp.Value) + .WithNewStat(CharacterStat.TP, packet.Tp.Value); _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); } diff --git a/EOLib/PacketHandlers/StatSkill/StatskillAcceptHandler.cs b/EOLib/PacketHandlers/StatSkill/StatskillAcceptHandler.cs index 53c4bbf7c..de80c6c61 100644 --- a/EOLib/PacketHandlers/StatSkill/StatskillAcceptHandler.cs +++ b/EOLib/PacketHandlers/StatSkill/StatskillAcceptHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.StatSkill { @@ -10,7 +11,7 @@ namespace EOLib.PacketHandlers.StatSkill /// Sent when spending skill points on a spell /// [AutoMappedType] - public class StatskillAcceptHandler : InGameOnlyPacketHandler + public class StatskillAcceptHandler : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; private readonly ICharacterInventoryRepository _characterInventoryRepository; @@ -28,19 +29,15 @@ public StatskillAcceptHandler(IPlayerInfoProvider playerInfoProvider, _characterInventoryRepository = characterInventoryRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(StatSkillAcceptServerPacket packet) { - var skillPoints = packet.ReadShort(); - var spellId = packet.ReadShort(); - var spellLevel = packet.ReadShort(); - - if (spellId > 0) + if (packet.Spell.Id > 0) { - _characterInventoryRepository.SpellInventory.RemoveWhere(x => x.ID == spellId); - _characterInventoryRepository.SpellInventory.Add(new InventorySpell(spellId, spellLevel)); + _characterInventoryRepository.SpellInventory.RemoveWhere(x => x.ID == packet.Spell.Id); + _characterInventoryRepository.SpellInventory.Add(new InventorySpell(packet.Spell.Id, packet.Spell.Level)); } - var stats = _characterRepository.MainCharacter.Stats.WithNewStat(CharacterStat.SkillPoints, skillPoints); + var stats = _characterRepository.MainCharacter.Stats.WithNewStat(CharacterStat.SkillPoints, packet.SkillPoints); _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); return true; diff --git a/EOLib/PacketHandlers/StatSkill/StatskillJunkHandler.cs b/EOLib/PacketHandlers/StatSkill/StatskillJunkHandler.cs index c0276aa2f..7108a2924 100644 --- a/EOLib/PacketHandlers/StatSkill/StatskillJunkHandler.cs +++ b/EOLib/PacketHandlers/StatSkill/StatskillJunkHandler.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Character; using EOLib.Domain.Interact; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.StatSkill @@ -12,7 +13,7 @@ namespace EOLib.PacketHandlers.StatSkill /// Sent when resetting a character's stats/skills /// [AutoMappedType] - public class StatskillJunkHandler : InGameOnlyPacketHandler + public class StatskillJunkHandler : InGameOnlyPacketHandler { private readonly ICharacterInventoryRepository _characterInventoryRepository; private readonly ICharacterRepository _characterRepository; @@ -33,27 +34,9 @@ public StatskillJunkHandler(IPlayerInfoProvider playerInfoProvider, _npcInteractionNotifiers = npcInteractionNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(StatSkillJunkServerPacket packet) { - var stats = _characterRepository.MainCharacter.Stats - .WithNewStat(CharacterStat.StatPoints, packet.ReadShort()) - .WithNewStat(CharacterStat.SkillPoints, packet.ReadShort()) - .WithNewStat(CharacterStat.HP, packet.ReadShort()) - .WithNewStat(CharacterStat.MaxHP, packet.ReadShort()) - .WithNewStat(CharacterStat.TP, packet.ReadShort()) - .WithNewStat(CharacterStat.MaxTP, packet.ReadShort()) - .WithNewStat(CharacterStat.MaxSP, packet.ReadShort()) - .WithNewStat(CharacterStat.Strength, packet.ReadShort()) - .WithNewStat(CharacterStat.Intelligence, packet.ReadShort()) - .WithNewStat(CharacterStat.Wisdom, packet.ReadShort()) - .WithNewStat(CharacterStat.Agility, packet.ReadShort()) - .WithNewStat(CharacterStat.Constitution, packet.ReadShort()) - .WithNewStat(CharacterStat.Charisma, packet.ReadShort()) - .WithNewStat(CharacterStat.MinDam, packet.ReadShort()) - .WithNewStat(CharacterStat.MaxDam, packet.ReadShort()) - .WithNewStat(CharacterStat.Accuracy, packet.ReadShort()) - .WithNewStat(CharacterStat.Evade, packet.ReadShort()) - .WithNewStat(CharacterStat.Armor, packet.ReadShort()); + var stats = _characterRepository.MainCharacter.Stats.Apply(CharacterStats.FromStatReset(packet.Stats)); _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); _characterInventoryRepository.SpellInventory.Clear(); diff --git a/EOLib/PacketHandlers/StatSkill/StatskillOpenHandler.cs b/EOLib/PacketHandlers/StatSkill/StatskillOpenHandler.cs index 93be0a0f6..52dcf4f6b 100644 --- a/EOLib/PacketHandlers/StatSkill/StatskillOpenHandler.cs +++ b/EOLib/PacketHandlers/StatSkill/StatskillOpenHandler.cs @@ -2,9 +2,11 @@ using EOLib.Domain.Interact; using EOLib.Domain.Interact.Skill; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; +using System.Linq; namespace EOLib.PacketHandlers.StatSkill { @@ -12,7 +14,7 @@ namespace EOLib.PacketHandlers.StatSkill /// Sent when opening a skillmaster dialog /// [AutoMappedType] - public class StatskillOpenHandler : InGameOnlyPacketHandler + public class StatskillOpenHandler : InGameOnlyPacketHandler { private readonly ISkillDataRepository _skillDataRepository; private readonly IEnumerable _npcInteractionNotifiers; @@ -30,37 +32,25 @@ public StatskillOpenHandler(IPlayerInfoProvider playerInfoProvider, _npcInteractionNotifiers = npcInteractionNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(StatSkillOpenServerPacket packet) { - _skillDataRepository.ID = packet.ReadShort(); - _skillDataRepository.Title = packet.ReadBreakString(); - _skillDataRepository.Skills.Clear(); - - while (packet.ReadPosition < packet.Length) - { - var skill = new Domain.Interact.Skill.Skill.Builder + _skillDataRepository.ID = packet.SessionId; + _skillDataRepository.Title = packet.ShopName; + _skillDataRepository.Skills = new HashSet(packet.Skills.Select(x => + new Skill.Builder { - Id = packet.ReadShort(), - LevelRequirement = packet.ReadChar(), - ClassRequirement = packet.ReadChar(), - GoldRequirement = packet.ReadInt(), - SkillRequirements = new List - { - packet.ReadShort(), - packet.ReadShort(), - packet.ReadShort(), - packet.ReadShort() - }, - StrRequirement = packet.ReadShort(), - IntRequirement = packet.ReadShort(), - WisRequirement = packet.ReadShort(), - AgiRequirement = packet.ReadShort(), - ConRequirement = packet.ReadShort(), - ChaRequirement = packet.ReadShort() - }.ToImmutable(); - - _skillDataRepository.Skills.Add(skill); - } + Id = x.Id, + LevelRequirement = x.LevelRequirement, + ClassRequirement = x.ClassRequirement, + GoldRequirement = x.Cost, + SkillRequirements = x.SkillRequirements, + StrRequirement = x.StatRequirements.Str, + IntRequirement = x.StatRequirements.Intl, + WisRequirement = x.StatRequirements.Wis, + AgiRequirement = x.StatRequirements.Agi, + ConRequirement = x.StatRequirements.Con, + ChaRequirement = x.StatRequirements.Cha, + }.ToImmutable())); foreach (var notifier in _npcInteractionNotifiers) notifier.NotifyInteractionFromNPC(IO.NPCType.Skills); diff --git a/EOLib/PacketHandlers/StatSkill/StatskillPlayerHandler.cs b/EOLib/PacketHandlers/StatSkill/StatskillPlayerHandler.cs index ff1a5e4eb..150fed9ef 100644 --- a/EOLib/PacketHandlers/StatSkill/StatskillPlayerHandler.cs +++ b/EOLib/PacketHandlers/StatSkill/StatskillPlayerHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EOLib.PacketHandlers.StatSkill { @@ -10,7 +11,7 @@ namespace EOLib.PacketHandlers.StatSkill /// Sent when the main character spends their stat points /// [AutoMappedType] - public class StatskillPlayerHandler : InGameOnlyPacketHandler + public class StatskillPlayerHandler : InGameOnlyPacketHandler { private readonly ICharacterRepository _characterRepository; @@ -24,44 +25,11 @@ public StatskillPlayerHandler(IPlayerInfoProvider playerInfoProvider, _characterRepository = characterRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(StatSkillPlayerServerPacket packet) { - //note: nearly identical code exists in RecoverStatListHandler.HandlePacket - //todo: consolidate - var statPoints = packet.ReadShort(); - var str = packet.ReadShort(); - var intl = packet.ReadShort(); - var wis = packet.ReadShort(); - var agi = packet.ReadShort(); - var con = packet.ReadShort(); - var cha = packet.ReadShort(); - var hp = packet.ReadShort(); - var tp = packet.ReadShort(); - var sp = packet.ReadShort(); - var maxWeight = packet.ReadShort(); - var minDam = packet.ReadShort(); - var maxDam = packet.ReadShort(); - var accuracy = packet.ReadShort(); - var evade = packet.ReadShort(); - var armor = packet.ReadShort(); - var stats = _characterRepository.MainCharacter.Stats - .WithNewStat(CharacterStat.StatPoints, statPoints) - .WithNewStat(CharacterStat.Strength, str) - .WithNewStat(CharacterStat.Intelligence, intl) - .WithNewStat(CharacterStat.Wisdom, wis) - .WithNewStat(CharacterStat.Agility, agi) - .WithNewStat(CharacterStat.Constitution, con) - .WithNewStat(CharacterStat.Charisma, cha) - .WithNewStat(CharacterStat.MaxHP, hp) - .WithNewStat(CharacterStat.MaxTP, tp) - .WithNewStat(CharacterStat.MaxSP, sp) - .WithNewStat(CharacterStat.MaxWeight, maxWeight) - .WithNewStat(CharacterStat.MinDam, minDam) - .WithNewStat(CharacterStat.MaxDam, maxDam) - .WithNewStat(CharacterStat.Accuracy, accuracy) - .WithNewStat(CharacterStat.Evade, evade) - .WithNewStat(CharacterStat.Armor, armor); + .WithNewStat(CharacterStat.StatPoints, packet.StatPoints) + .Apply(CharacterStats.FromStatUpdate(packet.Stats)); _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); diff --git a/EOLib/PacketHandlers/StatSkill/StatskillRemoveHandler.cs b/EOLib/PacketHandlers/StatSkill/StatskillRemoveHandler.cs index 303bea7a7..aeb7b1964 100644 --- a/EOLib/PacketHandlers/StatSkill/StatskillRemoveHandler.cs +++ b/EOLib/PacketHandlers/StatSkill/StatskillRemoveHandler.cs @@ -2,10 +2,10 @@ using EOLib.Domain.Character; using EOLib.Domain.Interact; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; -using System.Linq; namespace EOLib.PacketHandlers.StatSkill { @@ -13,7 +13,7 @@ namespace EOLib.PacketHandlers.StatSkill /// Sent when forgetting a skill /// [AutoMappedType] - public class StatskillRemoveHandler : InGameOnlyPacketHandler + public class StatskillRemoveHandler : InGameOnlyPacketHandler { private readonly ICharacterInventoryRepository _characterInventoryRepository; private readonly IEnumerable _npcInteractionNotifiers; @@ -31,10 +31,9 @@ public StatskillRemoveHandler(IPlayerInfoProvider playerInfoProvider, _npcInteractionNotifiers = npcInteractionNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(StatSkillRemoveServerPacket packet) { - var spellId = packet.ReadShort(); - _characterInventoryRepository.SpellInventory.RemoveWhere(x => x.ID == spellId); + _characterInventoryRepository.SpellInventory.RemoveWhere(x => x.ID == packet.SpellId); foreach (var notifier in _npcInteractionNotifiers) notifier.NotifySkillForget(); diff --git a/EOLib/PacketHandlers/StatSkill/StatskillReplyHandler.cs b/EOLib/PacketHandlers/StatSkill/StatskillReplyHandler.cs index 73eae1d63..d60fdb338 100644 --- a/EOLib/PacketHandlers/StatSkill/StatskillReplyHandler.cs +++ b/EOLib/PacketHandlers/StatSkill/StatskillReplyHandler.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Interact; using EOLib.Domain.Interact.Skill; using EOLib.Domain.Login; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.StatSkill @@ -12,7 +13,7 @@ namespace EOLib.PacketHandlers.StatSkill /// Sent when failing to learn a skill from skillmaster /// [AutoMappedType] - public class StatskillReplyHandler : InGameOnlyPacketHandler + public class StatskillReplyHandler : InGameOnlyPacketHandler { private readonly IEnumerable _npcInteractionNotifiers; @@ -27,10 +28,12 @@ public StatskillReplyHandler(IPlayerInfoProvider playerInfoProvider, _npcInteractionNotifiers = npcInteractionNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(StatSkillReplyServerPacket packet) { - var skillmasterReply = (SkillmasterReply)packet.ReadShort(); - var classId = packet.ReadShort(); + var skillmasterReply = (SkillmasterReply)packet.ReplyCode; + var classId = skillmasterReply == SkillmasterReply.ErrorWrongClass + ? ((StatSkillReplyServerPacket.ReplyCodeDataWrongClass)packet.ReplyCodeData).ClassId + : 0; foreach (var notifier in _npcInteractionNotifiers) notifier.NotifySkillLearnFail(skillmasterReply, classId); diff --git a/EOLib/PacketHandlers/StatSkill/StatskillTakeHandler.cs b/EOLib/PacketHandlers/StatSkill/StatskillTakeHandler.cs index 78d821c15..7c7aab8f6 100644 --- a/EOLib/PacketHandlers/StatSkill/StatskillTakeHandler.cs +++ b/EOLib/PacketHandlers/StatSkill/StatskillTakeHandler.cs @@ -4,6 +4,8 @@ using EOLib.Domain.Login; using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; using System.Linq; @@ -13,7 +15,7 @@ namespace EOLib.PacketHandlers.StatSkill /// Sent when learning a skill, either via $learn command or from skillmaster /// [AutoMappedType] - public class StatskillTakeHandler : InGameOnlyPacketHandler + public class StatskillTakeHandler : InGameOnlyPacketHandler { private readonly ICharacterInventoryRepository _characterInventoryRepository; private readonly IEnumerable _npcInteractionNotifiers; @@ -31,21 +33,18 @@ public StatskillTakeHandler(IPlayerInfoProvider playerInfoProvider, _npcInteractionNotifiers = npcInteractionNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(StatSkillTakeServerPacket packet) { - var spellId = packet.ReadShort(); - var characterGold = packet.ReadInt(); - - if (!_characterInventoryRepository.SpellInventory.Any(x => x.ID == spellId)) + if (!_characterInventoryRepository.SpellInventory.Any(x => x.ID == packet.SpellId)) { - _characterInventoryRepository.SpellInventory.Add(new InventorySpell(spellId, 0)); + _characterInventoryRepository.SpellInventory.Add(new InventorySpell(packet.SpellId, 0)); } _characterInventoryRepository.ItemInventory.RemoveWhere(x => x.ItemID == 1); - _characterInventoryRepository.ItemInventory.Add(new InventoryItem(1, characterGold)); + _characterInventoryRepository.ItemInventory.Add(new InventoryItem(1, packet.GoldAmount)); foreach (var notifier in _npcInteractionNotifiers) - notifier.NotifySkillLearnSuccess(spellId, characterGold); + notifier.NotifySkillLearnSuccess(packet.SpellId, packet.GoldAmount); return true; } diff --git a/EOLib/PacketHandlers/Trade/TradeAdminHandler.cs b/EOLib/PacketHandlers/Trade/TradeAdminHandler.cs new file mode 100644 index 000000000..90df7e008 --- /dev/null +++ b/EOLib/PacketHandlers/Trade/TradeAdminHandler.cs @@ -0,0 +1,28 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Login; +using EOLib.Domain.Trade; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; + +namespace EOLib.PacketHandlers.Trade +{ + [AutoMappedType] + public class TradeAdminHandler : TradeOfferUpdateHandler + { + public override PacketFamily Family => PacketFamily.Trade; + + public override PacketAction Action => PacketAction.Admin; + + public TradeAdminHandler(IPlayerInfoProvider playerInfoProvider, + ITradeRepository tradeRepository) + : base(playerInfoProvider, tradeRepository) + { + } + + public override bool HandlePacket(TradeAdminServerPacket packet) + { + Handle(packet.TradeData); + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Trade/TradeAgreeHandler.cs b/EOLib/PacketHandlers/Trade/TradeAgreeHandler.cs index aebf1711d..6ac83c4ca 100644 --- a/EOLib/PacketHandlers/Trade/TradeAgreeHandler.cs +++ b/EOLib/PacketHandlers/Trade/TradeAgreeHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Trade; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; namespace EOLib.PacketHandlers.Trade @@ -11,8 +12,9 @@ namespace EOLib.PacketHandlers.Trade /// Other party agrees to a trade /// [AutoMappedType] - public class TradeAgreeHandler : InGameOnlyPacketHandler + public class TradeAgreeHandler : InGameOnlyPacketHandler { + private readonly IPlayerInfoProvider _playerInfoProvider; private readonly ITradeRepository _tradeRepository; public override PacketFamily Family => PacketFamily.Trade; @@ -23,18 +25,15 @@ public TradeAgreeHandler(IPlayerInfoProvider playerInfoProvider, ITradeRepository tradeRepository) : base(playerInfoProvider) { + _playerInfoProvider = playerInfoProvider; _tradeRepository = tradeRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(TradeAgreeServerPacket packet) { - var mainPlayerId = packet.ReadShort(); - var otherPlayerAgrees = packet.ReadChar() != 0; - - _tradeRepository.SomeWhen(x => x.PlayerOneOffer.PlayerID == mainPlayerId) - .Map(x => x.PlayerOneOffer = x.PlayerOneOffer.WithAgrees(otherPlayerAgrees)) - .Or(() => _tradeRepository.PlayerTwoOffer = _tradeRepository.PlayerTwoOffer.WithAgrees(otherPlayerAgrees)); - + _tradeRepository.SomeWhen(x => x.PlayerOneOffer.PlayerID != _playerInfoProvider.PlayerID) + .Map(x => x.PlayerOneOffer = x.PlayerOneOffer.WithAgrees(packet.Agree)) + .Or(() => _tradeRepository.PlayerTwoOffer = _tradeRepository.PlayerTwoOffer.WithAgrees(packet.Agree)); return true; } } diff --git a/EOLib/PacketHandlers/Trade/TradeCloseHandler.cs b/EOLib/PacketHandlers/Trade/TradeCloseHandler.cs index 421d4239f..e0824090a 100644 --- a/EOLib/PacketHandlers/Trade/TradeCloseHandler.cs +++ b/EOLib/PacketHandlers/Trade/TradeCloseHandler.cs @@ -2,8 +2,9 @@ using EOLib.Domain.Login; using EOLib.Domain.Notifiers; using EOLib.Domain.Trade; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Trade @@ -12,7 +13,7 @@ namespace EOLib.PacketHandlers.Trade /// Other party agrees to a trade /// [AutoMappedType] - public class TradeCloseHandler : InGameOnlyPacketHandler + public class TradeCloseHandler : InGameOnlyPacketHandler { private readonly ITradeRepository _tradeRepository; private readonly IEnumerable _tradeEventNotifiers; @@ -30,7 +31,7 @@ public TradeCloseHandler(IPlayerInfoProvider playerInfoProvider, _tradeEventNotifiers = tradeEventNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(TradeCloseServerPacket packet) { foreach (var notifier in _tradeEventNotifiers) notifier.NotifyTradeClose(cancel: true); diff --git a/EOLib/PacketHandlers/Trade/TradeOfferUpdateHandler.cs b/EOLib/PacketHandlers/Trade/TradeOfferUpdateHandler.cs index 1fbedd2be..fb9d0495d 100644 --- a/EOLib/PacketHandlers/Trade/TradeOfferUpdateHandler.cs +++ b/EOLib/PacketHandlers/Trade/TradeOfferUpdateHandler.cs @@ -1,19 +1,16 @@ -using AutomaticTypeMapper; -using EOLib.Domain.Character; +using EOLib.Domain.Character; using EOLib.Domain.Login; -using EOLib.Domain.Notifiers; using EOLib.Domain.Trade; -using EOLib.IO.Repositories; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; -using Optional.Collections; -using System.Collections.Generic; using System.Linq; namespace EOLib.PacketHandlers.Trade { - public abstract class TradeOfferUpdateHandler : InGameOnlyPacketHandler + public abstract class TradeOfferUpdateHandler : InGameOnlyPacketHandler + where TPacket : IPacket { protected readonly ITradeRepository _tradeRepository; @@ -26,23 +23,13 @@ protected TradeOfferUpdateHandler(IPlayerInfoProvider playerInfoProvider, _tradeRepository = tradeRepository; } - public override bool HandlePacket(IPacket packet) + protected void Handle(TradeItemData data) { - var player1Id = packet.ReadShort(); - var player1Items = new List(); - while (packet.PeekByte() != 255) - { - player1Items.Add(new InventoryItem(packet.ReadShort(), packet.ReadInt())); - } - packet.ReadByte(); + var player1Id = data.PartnerPlayerId; + var player1Items = data.PartnerItems.Select(x => new InventoryItem(x.Id, x.Amount)).ToList(); - var player2Id = packet.ReadShort(); - var player2Items = new List(); - while (packet.PeekByte() != 255) - { - player2Items.Add(new InventoryItem(packet.ReadShort(), packet.ReadInt())); - } - packet.ReadByte(); + var player2Id = data.YourPlayerId; + var player2Items = data.YourItems.Select(x => new InventoryItem(x.Id, x.Amount)).ToList(); _tradeRepository.SomeWhen(x => x.PlayerOneOffer.PlayerID == player1Id) .Match(some: x => @@ -59,103 +46,6 @@ public override bool HandlePacket(IPacket packet) _tradeRepository.PlayerOneOffer = _tradeRepository.PlayerOneOffer.WithAgrees(false); _tradeRepository.PlayerTwoOffer = _tradeRepository.PlayerTwoOffer.WithAgrees(false); - - return true; - } - } - - /// - /// Either player makes an update to their offer - /// - [AutoMappedType] - public class TradeReplyHandler : TradeOfferUpdateHandler - { - public override PacketAction Action => PacketAction.Reply; - - public TradeReplyHandler(IPlayerInfoProvider playerInfoProvider, - ITradeRepository tradeRepository) - : base(playerInfoProvider, tradeRepository) - { - } - } - - /// - /// Trade completed - /// - [AutoMappedType] - public class TradeUseHandler : TradeOfferUpdateHandler - { - private readonly ICharacterRepository _characterRepository; - private readonly ICharacterInventoryRepository _characterInventoryRepository; - private readonly IEIFFileProvider _eifFileProvider; - private readonly IEnumerable _tradeEventNotifiers; - - public override PacketAction Action => PacketAction.Use; - - public TradeUseHandler(IPlayerInfoProvider playerInfoProvider, - ITradeRepository tradeRepository, - ICharacterRepository characterRepository, - ICharacterInventoryRepository characterInventoryRepository, - IEIFFileProvider eifFileProvider, - IEnumerable tradeEventNotifiers) - : base(playerInfoProvider, tradeRepository) - { - _characterRepository = characterRepository; - _characterInventoryRepository = characterInventoryRepository; - _eifFileProvider = eifFileProvider; - _tradeEventNotifiers = tradeEventNotifiers; - } - - public override bool HandlePacket(IPacket packet) - { - base.HandlePacket(packet); - - var (removeItems, addItems) = _tradeRepository - .SomeWhen(x => x.PlayerOneOffer.PlayerID == _characterRepository.MainCharacter.ID) - .Match(some: x => (x.PlayerOneOffer.Items, x.PlayerTwoOffer.Items), - none: () => (_tradeRepository.PlayerTwoOffer.Items, _tradeRepository.PlayerOneOffer.Items)); - - var stats = _characterRepository.MainCharacter.Stats; - foreach (var removedItem in removeItems) - { - _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == removedItem.ItemID) - .MatchSome(x => - { - _characterInventoryRepository.ItemInventory.Remove(x); - if (x.Amount - removedItem.Amount > 0) - { - _characterInventoryRepository.ItemInventory.Add(x.WithAmount(x.Amount - removedItem.Amount)); - } - }); - - stats = stats.WithNewStat(CharacterStat.Weight, stats[CharacterStat.Weight] - _eifFileProvider.EIFFile[removedItem.ItemID].Weight * removedItem.Amount); - } - - foreach (var newItem in addItems) - { - _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == newItem.ItemID) - .Match(some: x => - { - _characterInventoryRepository.ItemInventory.Remove(x); - _characterInventoryRepository.ItemInventory.Add(x.WithAmount(x.Amount + newItem.Amount)); - }, - none: () => - { - _characterInventoryRepository.ItemInventory.Add(newItem); - }); - - stats = stats.WithNewStat(CharacterStat.Weight, stats[CharacterStat.Weight] + _eifFileProvider.EIFFile[newItem.ItemID].Weight * newItem.Amount); - } - - if (stats[CharacterStat.Weight] < 0) - stats = stats.WithNewStat(CharacterStat.Weight, 0); - - _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); - - foreach (var notifier in _tradeEventNotifiers) - notifier.NotifyTradeClose(cancel: false); - - return true; } } } diff --git a/EOLib/PacketHandlers/Trade/TradeOpenHandler.cs b/EOLib/PacketHandlers/Trade/TradeOpenHandler.cs index e58fb2699..798a2a230 100644 --- a/EOLib/PacketHandlers/Trade/TradeOpenHandler.cs +++ b/EOLib/PacketHandlers/Trade/TradeOpenHandler.cs @@ -3,8 +3,9 @@ using EOLib.Domain.Login; using EOLib.Domain.Notifiers; using EOLib.Domain.Trade; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Trade @@ -13,7 +14,7 @@ namespace EOLib.PacketHandlers.Trade /// Trade request is accepted /// [AutoMappedType] - public class TradeOpenHandler : InGameOnlyPacketHandler + public class TradeOpenHandler : InGameOnlyPacketHandler { private readonly ITradeRepository _tradeRepository; private readonly IEnumerable _tradeEventNotifiers; @@ -31,18 +32,18 @@ public TradeOpenHandler(IPlayerInfoProvider playerInfoProvider, _tradeEventNotifiers = tradeEventNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(TradeOpenServerPacket packet) { _tradeRepository.PlayerOneOffer = _tradeRepository.PlayerOneOffer .WithAgrees(false) - .WithPlayerID(packet.ReadShort()) - .WithPlayerName(packet.ReadBreakString()) + .WithPlayerID(packet.PartnerPlayerId) + .WithPlayerName(packet.PartnerPlayerName) .WithItems(new List()); _tradeRepository.PlayerTwoOffer = _tradeRepository.PlayerTwoOffer .WithAgrees(false) - .WithPlayerID(packet.ReadShort()) - .WithPlayerName(packet.ReadBreakString()) + .WithPlayerID(packet.YourPlayerId) + .WithPlayerName(packet.YourPlayerName) .WithItems(new List()); foreach (var notifier in _tradeEventNotifiers) diff --git a/EOLib/PacketHandlers/Trade/TradeReplyHandler.cs b/EOLib/PacketHandlers/Trade/TradeReplyHandler.cs new file mode 100644 index 000000000..1f9ef1b94 --- /dev/null +++ b/EOLib/PacketHandlers/Trade/TradeReplyHandler.cs @@ -0,0 +1,29 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Login; +using EOLib.Domain.Trade; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; + +namespace EOLib.PacketHandlers.Trade +{ + /// + /// Either player makes an update to their offer + /// + [AutoMappedType] + public class TradeReplyHandler : TradeOfferUpdateHandler + { + public override PacketAction Action => PacketAction.Reply; + + public TradeReplyHandler(IPlayerInfoProvider playerInfoProvider, + ITradeRepository tradeRepository) + : base(playerInfoProvider, tradeRepository) + { + } + + public override bool HandlePacket(TradeReplyServerPacket packet) + { + Handle(packet.TradeData); + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Trade/TradeRequestHandler.cs b/EOLib/PacketHandlers/Trade/TradeRequestHandler.cs index 366600664..363a4912d 100644 --- a/EOLib/PacketHandlers/Trade/TradeRequestHandler.cs +++ b/EOLib/PacketHandlers/Trade/TradeRequestHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Collections.Generic; namespace EOLib.PacketHandlers.Trade @@ -11,7 +12,7 @@ namespace EOLib.PacketHandlers.Trade /// Another player requests a trade /// [AutoMappedType] - public class TradeRequestHandler : InGameOnlyPacketHandler + public class TradeRequestHandler : InGameOnlyPacketHandler { private readonly IEnumerable _tradeEventNotifiers; @@ -26,14 +27,10 @@ public TradeRequestHandler(IPlayerInfoProvider playerInfoProvider, _tradeEventNotifiers = tradeEventNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(TradeRequestServerPacket packet) { - packet.ReadChar(); // ? - var playerId = packet.ReadShort(); - var name = packet.ReadEndString(); - foreach (var notifier in _tradeEventNotifiers) - notifier.NotifyTradeRequest(playerId, name); + notifier.NotifyTradeRequest(packet.PartnerPlayerId, packet.PartnerPlayerName); return true; } diff --git a/EOLib/PacketHandlers/Trade/TradeSpecHandler.cs b/EOLib/PacketHandlers/Trade/TradeSpecHandler.cs index 622c855dc..7fb3fbb01 100644 --- a/EOLib/PacketHandlers/Trade/TradeSpecHandler.cs +++ b/EOLib/PacketHandlers/Trade/TradeSpecHandler.cs @@ -1,9 +1,9 @@ using AutomaticTypeMapper; -using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Trade; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; namespace EOLib.PacketHandlers.Trade @@ -12,9 +12,9 @@ namespace EOLib.PacketHandlers.Trade /// You agree to a trade /// [AutoMappedType] - public class TradeSpecHandler : InGameOnlyPacketHandler + public class TradeSpecHandler : InGameOnlyPacketHandler { - private readonly ICharacterProvider _characterProvider; + private readonly IPlayerInfoProvider _playerInfoProvider; private readonly ITradeRepository _tradeRepository; public override PacketFamily Family => PacketFamily.Trade; @@ -22,21 +22,18 @@ public class TradeSpecHandler : InGameOnlyPacketHandler public override PacketAction Action => PacketAction.Spec; public TradeSpecHandler(IPlayerInfoProvider playerInfoProvider, - ICharacterProvider characterProvider, ITradeRepository tradeRepository) : base(playerInfoProvider) { - _characterProvider = characterProvider; + _playerInfoProvider = playerInfoProvider; _tradeRepository = tradeRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(TradeSpecServerPacket packet) { - var youAgree = packet.ReadChar() != 0; - - _tradeRepository.SomeWhen(x => x.PlayerOneOffer.PlayerID == _characterProvider.MainCharacter.ID) - .Map(x => x.PlayerOneOffer = x.PlayerOneOffer.WithAgrees(youAgree)) - .Or(() => _tradeRepository.PlayerTwoOffer = _tradeRepository.PlayerTwoOffer.WithAgrees(youAgree)); + _tradeRepository.SomeWhen(x => x.PlayerOneOffer.PlayerID == _playerInfoProvider.PlayerID) + .Map(x => x.PlayerOneOffer = x.PlayerOneOffer.WithAgrees(packet.Agree)) + .Or(() => _tradeRepository.PlayerTwoOffer = _tradeRepository.PlayerTwoOffer.WithAgrees(packet.Agree)); return true; } diff --git a/EOLib/PacketHandlers/Trade/TradeUseHandler.cs b/EOLib/PacketHandlers/Trade/TradeUseHandler.cs new file mode 100644 index 000000000..f7212b673 --- /dev/null +++ b/EOLib/PacketHandlers/Trade/TradeUseHandler.cs @@ -0,0 +1,94 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Character; +using EOLib.Domain.Login; +using EOLib.Domain.Notifiers; +using EOLib.Domain.Trade; +using EOLib.IO.Repositories; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using Optional; +using Optional.Collections; +using System.Collections.Generic; + +namespace EOLib.PacketHandlers.Trade +{ + /// + /// Trade completed + /// + [AutoMappedType] + public class TradeUseHandler : TradeOfferUpdateHandler + { + private readonly ICharacterRepository _characterRepository; + private readonly ICharacterInventoryRepository _characterInventoryRepository; + private readonly IEIFFileProvider _eifFileProvider; + private readonly IEnumerable _tradeEventNotifiers; + + public override PacketAction Action => PacketAction.Use; + + public TradeUseHandler(IPlayerInfoProvider playerInfoProvider, + ITradeRepository tradeRepository, + ICharacterRepository characterRepository, + ICharacterInventoryRepository characterInventoryRepository, + IEIFFileProvider eifFileProvider, + IEnumerable tradeEventNotifiers) + : base(playerInfoProvider, tradeRepository) + { + _characterRepository = characterRepository; + _characterInventoryRepository = characterInventoryRepository; + _eifFileProvider = eifFileProvider; + _tradeEventNotifiers = tradeEventNotifiers; + } + + public override bool HandlePacket(TradeUseServerPacket packet) + { + Handle(packet.TradeData); + + var (removeItems, addItems) = _tradeRepository + .SomeWhen(x => x.PlayerOneOffer.PlayerID == _characterRepository.MainCharacter.ID) + .Match(some: x => (x.PlayerOneOffer.Items, x.PlayerTwoOffer.Items), + none: () => (_tradeRepository.PlayerTwoOffer.Items, _tradeRepository.PlayerOneOffer.Items)); + + var stats = _characterRepository.MainCharacter.Stats; + foreach (var removedItem in removeItems) + { + _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == removedItem.ItemID) + .MatchSome(x => + { + _characterInventoryRepository.ItemInventory.Remove(x); + if (x.Amount - removedItem.Amount > 0) + { + _characterInventoryRepository.ItemInventory.Add(x.WithAmount(x.Amount - removedItem.Amount)); + } + }); + + stats = stats.WithNewStat(CharacterStat.Weight, stats[CharacterStat.Weight] - _eifFileProvider.EIFFile[removedItem.ItemID].Weight * removedItem.Amount); + } + + foreach (var newItem in addItems) + { + _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == newItem.ItemID) + .Match(some: x => + { + _characterInventoryRepository.ItemInventory.Remove(x); + _characterInventoryRepository.ItemInventory.Add(x.WithAmount(x.Amount + newItem.Amount)); + }, + none: () => + { + _characterInventoryRepository.ItemInventory.Add(newItem); + }); + + stats = stats.WithNewStat(CharacterStat.Weight, stats[CharacterStat.Weight] + _eifFileProvider.EIFFile[newItem.ItemID].Weight * newItem.Amount); + } + + if (stats[CharacterStat.Weight] < 0) + stats = stats.WithNewStat(CharacterStat.Weight, 0); + + _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); + + foreach (var notifier in _tradeEventNotifiers) + notifier.NotifyTradeClose(cancel: false); + + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Walk/WalkPlayerHandler.cs b/EOLib/PacketHandlers/Walk/WalkPlayerHandler.cs index 1d2004d14..c8f4cc7cd 100644 --- a/EOLib/PacketHandlers/Walk/WalkPlayerHandler.cs +++ b/EOLib/PacketHandlers/Walk/WalkPlayerHandler.cs @@ -1,12 +1,13 @@ -using System.Collections.Generic; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EOLib.Domain.Character; using EOLib.Domain.Extensions; using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System.Collections.Generic; namespace EOLib.PacketHandlers.Walk { @@ -14,7 +15,7 @@ namespace EOLib.PacketHandlers.Walk /// Sent in response to another player walking successfully /// [AutoMappedType] - public class WalkPlayerHandler : InGameOnlyPacketHandler + public class WalkPlayerHandler : InGameOnlyPacketHandler { private readonly ICurrentMapStateRepository _currentMapStateRepository; private readonly IEnumerable _otherCharacterAnimationNotifiers; @@ -32,30 +33,26 @@ public WalkPlayerHandler(IPlayerInfoProvider playerInfoProvider, _otherCharacterAnimationNotifiers = otherCharacterAnimationNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(WalkPlayerServerPacket packet) { - var characterID = packet.ReadShort(); - if (_currentMapStateRepository.Characters.TryGetValue(characterID, out var character)) + if (_currentMapStateRepository.Characters.TryGetValue(packet.PlayerId, out var character)) { - var dir = (EODirection)packet.ReadChar(); - var x = packet.ReadChar(); - var y = packet.ReadChar(); // if character is walking, that means animator is handling position of character // if character is not walking (this is true in EOBot), update the domain model here if (!character.RenderProperties.IsActing(CharacterActionState.Walking)) { - var renderProperties = EnsureCorrectXAndY(character.RenderProperties.WithDirection(dir), x, y); + var renderProperties = EnsureCorrectXAndY(character.RenderProperties.WithDirection((EODirection)packet.Direction), packet.Coords.X, packet.Coords.Y); _currentMapStateRepository.Characters.Update(character, character.WithRenderProperties(renderProperties)); } foreach (var notifier in _otherCharacterAnimationNotifiers) - notifier.StartOtherCharacterWalkAnimation(characterID, new MapCoordinate(x, y), dir); + notifier.StartOtherCharacterWalkAnimation(packet.PlayerId, new MapCoordinate(packet.Coords.X, packet.Coords.Y), (EODirection)packet.Direction); } else { - _currentMapStateRepository.UnknownPlayerIDs.Add(characterID); + _currentMapStateRepository.UnknownPlayerIDs.Add(packet.PlayerId); } return true; diff --git a/EOLib/PacketHandlers/Walk/WalkReplyHandler.cs b/EOLib/PacketHandlers/Walk/WalkReplyHandler.cs index a4d25fe64..e2d7e8db1 100644 --- a/EOLib/PacketHandlers/Walk/WalkReplyHandler.cs +++ b/EOLib/PacketHandlers/Walk/WalkReplyHandler.cs @@ -1,8 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Net; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Linq; namespace EOLib.PacketHandlers.Walk @@ -11,7 +12,7 @@ namespace EOLib.PacketHandlers.Walk /// Sent in response to the main character walking successfully /// [AutoMappedType] - public class WalkReplyHandler : InGameOnlyPacketHandler + public class WalkReplyHandler : InGameOnlyPacketHandler { private readonly ICurrentMapStateRepository _currentMapStateRepository; @@ -25,39 +26,23 @@ public WalkReplyHandler(IPlayerInfoProvider playerInfoProvider, _currentMapStateRepository = currentMapStateRepository; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(WalkReplyServerPacket packet) { - while (packet.PeekByte() != 0xFF) - { - var playerID = packet.ReadShort(); - if (!_currentMapStateRepository.Characters.ContainsKey(playerID)) - { - _currentMapStateRepository.UnknownPlayerIDs.Add(playerID); - } - } - packet.ReadByte(); + foreach (var unknownPlayer in packet.PlayerIds.Where(x => !_currentMapStateRepository.Characters.ContainsKey(x))) + _currentMapStateRepository.UnknownPlayerIDs.Add(unknownPlayer); + foreach (var unknownNpc in packet.NpcIndexes.Where(x => !_currentMapStateRepository.NPCs.ContainsKey(x))) + _currentMapStateRepository.UnknownNPCIndexes.Add(unknownNpc); - while (packet.PeekByte() != 0xFF) + foreach (var item in packet.Items) { - var index = packet.ReadChar(); - if (!_currentMapStateRepository.NPCs.Any((npc) => npc.Index == index)) + _currentMapStateRepository.MapItems.Add(new MapItem.Builder { - _currentMapStateRepository.UnknownNPCIndexes.Add(index); - } - } - packet.ReadByte(); - - var numberOfMapItems = packet.PeekEndString().Length / 9; - for (int i = 0; i < numberOfMapItems; ++i) - { - var uid = packet.ReadShort(); - var itemID = packet.ReadShort(); - var x = packet.ReadChar(); - var y = packet.ReadChar(); - var amount = packet.ReadThree(); - - var newItem = new MapItem(uid, itemID, x, y, amount); - _currentMapStateRepository.MapItems.Add(newItem); + UniqueID = item.Id, + ItemID = item.Id, + X = item.Coords.X, + Y = item.Coords.Y, + Amount = item.Amount, + }.ToImmutable()); } return true; diff --git a/EOLib/PacketHandlers/Warp/WarpAgreeHandler.cs b/EOLib/PacketHandlers/Warp/WarpAgreeHandler.cs index 51b3ac34c..b17d758b0 100644 --- a/EOLib/PacketHandlers/Warp/WarpAgreeHandler.cs +++ b/EOLib/PacketHandlers/Warp/WarpAgreeHandler.cs @@ -5,9 +5,9 @@ using EOLib.Domain.Map; using EOLib.Domain.Notifiers; using EOLib.IO.Repositories; -using EOLib.Net; using EOLib.Net.Handlers; -using EOLib.Net.Translators; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using System; using System.Collections.Generic; @@ -21,9 +21,8 @@ namespace EOLib.PacketHandlers.Warp /// Sent when completing warp for the main character /// [AutoMappedType] - public class WarpAgreeHandler : InGameOnlyPacketHandler + public class WarpAgreeHandler : InGameOnlyPacketHandler { - private readonly IPacketTranslator _warpAgreePacketTranslator; private readonly ICharacterRepository _characterRepository; private readonly ICurrentMapStateRepository _currentMapStateRepository; private readonly ICurrentMapProvider _currentMapProvider; @@ -35,7 +34,6 @@ public class WarpAgreeHandler : InGameOnlyPacketHandler public override PacketAction Action => PacketAction.Agree; public WarpAgreeHandler(IPlayerInfoProvider playerInfoProvider, - IPacketTranslator warpAgreePacketTranslator, ICharacterRepository characterRepository, ICurrentMapStateRepository currentMapStateRepository, ICurrentMapProvider currentMapProvider, @@ -43,7 +41,6 @@ public WarpAgreeHandler(IPlayerInfoProvider playerInfoProvider, IEnumerable mapChangedNotifiers) : base(playerInfoProvider) { - _warpAgreePacketTranslator = warpAgreePacketTranslator; _characterRepository = characterRepository; _currentMapStateRepository = currentMapStateRepository; _currentMapProvider = currentMapProvider; @@ -51,16 +48,26 @@ public WarpAgreeHandler(IPlayerInfoProvider playerInfoProvider, _mapChangedNotifiers = mapChangedNotifiers; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(WarpAgreeServerPacket packet) { _currentMapStateRepository.MapWarpState = WarpState.WarpCompleting; - var warpAgreePacketData = _warpAgreePacketTranslator.TranslatePacket(packet); + var differentMapID = false; + var warpAnimation = WarpEffect.None; + if (packet.WarpType == WarpType.MapSwitch) + { + var data = (WarpAgreeServerPacket.WarpTypeDataMapSwitch)packet.WarpTypeData; + differentMapID = _currentMapStateRepository.CurrentMapID != data.MapId; + warpAnimation = data.WarpEffect; + _currentMapStateRepository.CurrentMapID = data.MapId; + } - var differentMapID = _currentMapStateRepository.CurrentMapID != warpAgreePacketData.MapID; - _currentMapStateRepository.CurrentMapID = warpAgreePacketData.MapID; + var characters = packet.Nearby.Characters.Select(Character.FromNearby).ToList(); + var updatedMainCharacter = characters.Single(x => x.ID == _characterRepository.MainCharacter.ID); + var withoutMainCharacter = characters.Except(new[] { updatedMainCharacter }); - var updatedMainCharacter = warpAgreePacketData.Characters.Single(MainCharacterIDMatches); + var npcs = packet.Nearby.Npcs.Select(DomainNPC.FromNearby); + var items = packet.Nearby.Items.Select(MapItem.FromNearby); //character.renderproperties.isdead is set True by the attack handler //the character needs to be brought back to life when they are taken to the home map @@ -69,30 +76,21 @@ public override bool HandlePacket(IPacket packet) .WithRenderProperties(bringBackToLife) .WithAppliedData(updatedMainCharacter); - var withoutMainCharacter = warpAgreePacketData.Characters.Where(x => !MainCharacterIDMatches(x)); - warpAgreePacketData = warpAgreePacketData.WithCharacters(withoutMainCharacter.ToList()); - - _currentMapStateRepository.Characters = new MapEntityCollectionHashSet(c => c.ID, c => new MapCoordinate(c.X, c.Y), warpAgreePacketData.Characters); - _currentMapStateRepository.NPCs = new MapEntityCollectionHashSet(n => n.Index, n => new MapCoordinate(n.X, n.Y), warpAgreePacketData.NPCs); - _currentMapStateRepository.MapItems = new MapEntityCollectionHashSet(item => item.UniqueID, item => new MapCoordinate(item.X, item.Y), warpAgreePacketData.Items); + _currentMapStateRepository.Characters = new MapEntityCollectionHashSet(c => c.ID, c => new MapCoordinate(c.X, c.Y), withoutMainCharacter); + _currentMapStateRepository.NPCs = new MapEntityCollectionHashSet(n => n.Index, n => new MapCoordinate(n.X, n.Y), npcs); + _currentMapStateRepository.MapItems = new MapEntityCollectionHashSet(item => item.UniqueID, item => new MapCoordinate(item.X, item.Y), items); _currentMapStateRepository.OpenDoors.Clear(); - _currentMapStateRepository.VisibleSpikeTraps.Clear(); + _currentMapStateRepository.PendingDoors.Clear(); _currentMapStateRepository.ShowMiniMap = _currentMapStateRepository.ShowMiniMap && _currentMapProvider.CurrentMap.Properties.MapAvailable; foreach (var notifier in _mapChangedNotifiers) - notifier.NotifyMapChanged(differentMapID: differentMapID, - warpAnimation: warpAgreePacketData.WarpAnimation); + notifier.NotifyMapChanged(warpAnimation, differentMapID); _currentMapStateRepository.MapWarpState = WarpState.None; _currentMapStateRepository.MapWarpTime = Option.Some(DateTime.Now); return true; } - - private bool MainCharacterIDMatches(Character x) - { - return x.ID == _characterRepository.MainCharacter.ID; - } } } diff --git a/EOLib/PacketHandlers/Warp/WarpRequestHandler.cs b/EOLib/PacketHandlers/Warp/WarpRequestHandler.cs index c7decbc54..92d0c9657 100644 --- a/EOLib/PacketHandlers/Warp/WarpRequestHandler.cs +++ b/EOLib/PacketHandlers/Warp/WarpRequestHandler.cs @@ -3,13 +3,14 @@ using EOLib.Domain.Map; using EOLib.IO.Actions; using EOLib.IO.Repositories; -using EOLib.Net; using EOLib.Net.Communication; using EOLib.Net.FileTransfer; using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System; using System.IO; -using System.Linq; namespace EOLib.PacketHandlers.Warp { @@ -17,10 +18,8 @@ namespace EOLib.PacketHandlers.Warp /// Sent when the server requests warp for the main character /// [AutoMappedType] - public class WarpRequestHandler : InGameOnlyPacketHandler + public class WarpRequestHandler : InGameOnlyPacketHandler { - private const int WARP_SAME_MAP = 1, WARP_NEW_MAP = 2; - private readonly IPacketSendService _packetSendService; private readonly IFileRequestActions _fileRequestActions; private readonly IMapFileLoadActions _mapFileLoadActions; @@ -46,29 +45,24 @@ public WarpRequestHandler(IPlayerInfoProvider playerInfoProvider, _mapFileProvider = mapFileProvider; } - public override bool HandlePacket(IPacket packet) + public override bool HandlePacket(WarpRequestServerPacket 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(); + var warpType = packet.WarpType; + var mapID = packet.MapId; switch (warpType) { - case WARP_SAME_MAP: - { - var sessionID = packet.ReadShort(); - SendWarpAcceptToServer(mapID, sessionID); - } + case WarpType.Local: + SendWarpAcceptToServer(mapID, packet.SessionId); break; - case WARP_NEW_MAP: + case WarpType.MapSwitch: { - var mapRid = packet.ReadBytes(4).ToArray(); - var fileSize = packet.ReadThree(); - var sessionID = packet.ReadShort(); + var data = (WarpRequestServerPacket.WarpTypeDataMapSwitch)packet.WarpTypeData; var mapIsDownloaded = true; try @@ -78,13 +72,13 @@ public override bool HandlePacket(IPacket packet) } catch (IOException) { mapIsDownloaded = false; } - if (!mapIsDownloaded || _fileRequestActions.NeedsMapForWarp(mapID, mapRid, fileSize)) + if (!mapIsDownloaded || _fileRequestActions.NeedsMapForWarp(mapID, data.MapRid, data.MapFileSize)) { - _fileRequestActions.RequestMapForWarp(mapID, sessionID); + _fileRequestActions.RequestMapForWarp(mapID, packet.SessionId); } else { - SendWarpAcceptToServer(mapID, sessionID); + SendWarpAcceptToServer(mapID, packet.SessionId); } } break; @@ -98,11 +92,11 @@ public override bool HandlePacket(IPacket packet) private void SendWarpAcceptToServer(int mapID, int sessionID) { - var response = new PacketBuilder(PacketFamily.Warp, PacketAction.Accept) - .AddShort(mapID) - .AddShort(sessionID) - .Build(); - _packetSendService.SendPacket(response); + _packetSendService.SendPacket(new WarpAcceptClientPacket + { + MapId = mapID, + SessionId = sessionID + }); } } } diff --git a/EOLib/misc.cs b/EOLib/misc.cs index fe50633de..8f975832d 100644 --- a/EOLib/misc.cs +++ b/EOLib/misc.cs @@ -2,6 +2,8 @@ { public static class Constants { + public const int MaxChallenge = 11_092_110; + public const int ResponseTimeout = 5000; public const int ResponseFileTimeout = 10000; diff --git a/EndlessClient.sln b/EndlessClient.sln index 92d5d434c..e034dff40 100644 --- a/EndlessClient.sln +++ b/EndlessClient.sln @@ -13,7 +13,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EOLib", "EOLib\EOLib.csproj EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EOLib.Config", "EOLib.Config\EOLib.Config.csproj", "{B6AD3196-D307-4352-9979-9237CB08B102}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EOLib.Graphics", "EOLib.Graphics\EOLib.Graphics.csproj", "{8C4BC247-89ED-4629-B34B-15A5AEE88E2D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EOLib.Graphics", "EOLib.Graphics\EOLib.Graphics.csproj", "{8C4BC247-89ED-4629-B34B-15A5AEE88E2D}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EOLib.IO", "EOLib.IO\EOLib.IO.csproj", "{51B93DB4-896E-497F-A56E-F7BE47CF0170}" EndProject @@ -23,7 +23,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EOLib.Logger", "EOLib.Logge EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EOLib.Config.Test", "EOLib.Config.Test\EOLib.Config.Test.csproj", "{12BC6C2E-CEB1-4943-9843-AB4606658376}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EOLib.Graphics.Test", "EOLib.Graphics.Test\EOLib.Graphics.Test.csproj", "{2A903DEF-46C6-4E67-A039-A1561DB26C53}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EOLib.Graphics.Test", "EOLib.Graphics.Test\EOLib.Graphics.Test.csproj", "{2A903DEF-46C6-4E67-A039-A1561DB26C53}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EOLib.IO.Test", "EOLib.IO.Test\EOLib.IO.Test.csproj", "{FF9D8961-6E65-4B87-82FA-1C920CA9D37F}" EndProject @@ -31,15 +31,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EOLib.Localization.Test", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EOLib.Test", "EOLib.Test\EOLib.Test.csproj", "{A55498F8-78C2-4760-AA2C-429D39F35BB8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BatchMap", "BatchMap\BatchMap.csproj", "{09B4B9F7-64AF-4E6A-AAE1-52C41201179A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BatchMap", "BatchMap\BatchMap.csproj", "{09B4B9F7-64AF-4E6A-AAE1-52C41201179A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BatchPub", "BatchPub\BatchPub.csproj", "{18DC9959-1C79-4956-9FD1-438B9D445439}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BatchPub", "BatchPub\BatchPub.csproj", "{18DC9959-1C79-4956-9FD1-438B9D445439}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EOBot", "EOBot\EOBot.csproj", "{1061D316-7F0B-4BD5-9821-A8FF7DE32F6E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PacketDecoder", "PacketDecoder\PacketDecoder.csproj", "{D6D15D36-E7F3-4A08-9A3D-6AA382D0DE14}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EndlessClient", "EndlessClient\EndlessClient.csproj", "{0EC2FDA3-00E9-4DF4-8743-85E2C911E6E8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EndlessClient", "EndlessClient\EndlessClient.csproj", "{0EC2FDA3-00E9-4DF4-8743-85E2C911E6E8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -103,10 +101,6 @@ Global {1061D316-7F0B-4BD5-9821-A8FF7DE32F6E}.Debug|Any CPU.Build.0 = Debug|Any CPU {1061D316-7F0B-4BD5-9821-A8FF7DE32F6E}.Release|Any CPU.ActiveCfg = Release|Any CPU {1061D316-7F0B-4BD5-9821-A8FF7DE32F6E}.Release|Any CPU.Build.0 = Release|Any CPU - {D6D15D36-E7F3-4A08-9A3D-6AA382D0DE14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D6D15D36-E7F3-4A08-9A3D-6AA382D0DE14}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D6D15D36-E7F3-4A08-9A3D-6AA382D0DE14}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D6D15D36-E7F3-4A08-9A3D-6AA382D0DE14}.Release|Any CPU.Build.0 = Release|Any CPU {0EC2FDA3-00E9-4DF4-8743-85E2C911E6E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0EC2FDA3-00E9-4DF4-8743-85E2C911E6E8}.Debug|Any CPU.Build.0 = Debug|Any CPU {0EC2FDA3-00E9-4DF4-8743-85E2C911E6E8}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -130,7 +124,6 @@ Global {09B4B9F7-64AF-4E6A-AAE1-52C41201179A} = {795A3BFF-4306-456D-86AB-6A680A2B7C0B} {18DC9959-1C79-4956-9FD1-438B9D445439} = {795A3BFF-4306-456D-86AB-6A680A2B7C0B} {1061D316-7F0B-4BD5-9821-A8FF7DE32F6E} = {795A3BFF-4306-456D-86AB-6A680A2B7C0B} - {D6D15D36-E7F3-4A08-9A3D-6AA382D0DE14} = {795A3BFF-4306-456D-86AB-6A680A2B7C0B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {CED36352-F489-4071-A4F8-51FC08795DC7} diff --git a/EndlessClient/Audio/SoundEffectID.cs b/EndlessClient/Audio/SoundEffectID.cs index 0d7b70202..c0275e276 100644 --- a/EndlessClient/Audio/SoundEffectID.cs +++ b/EndlessClient/Audio/SoundEffectID.cs @@ -13,11 +13,12 @@ public enum SoundEffectID ChestOpen = TextBoxFocus, SpellActivate = TextBoxFocus, ServerCommand = TextBoxFocus, + TradeItemOfferChanged = TextBoxFocus, Login, ServerMessage = Login, DeleteCharacter, MapMutation = DeleteCharacter, - UnknownStaticSound, + Banned, ScreenCapture = 8, PrivateMessageReceived, PunchAttack, @@ -46,6 +47,7 @@ public enum SoundEffectID AdminWarp = 32, NoWallWalk, GhostPlayer = NoWallWalk, + ScrollTeleport = NoWallWalk, PotionOfEvilTerrorEffect, PotionOfFireworksEffect, PotionOfSparklesEffect = 36, diff --git a/EndlessClient/Controllers/AccountController.cs b/EndlessClient/Controllers/AccountController.cs index ed2b3bc76..79394a599 100644 --- a/EndlessClient/Controllers/AccountController.cs +++ b/EndlessClient/Controllers/AccountController.cs @@ -4,6 +4,7 @@ using EOLib.Domain.Account; using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Threading.Tasks; using XNAControls; @@ -48,7 +49,7 @@ public async Task CreateAccount(ICreateAccountParameters createAccountParameters return; var nameResult = checkNameOperation.Result; - if (nameResult < AccountReply.OK_CodeRange) + if (nameResult < (AccountReply)10) { _accountDialogDisplayActions.ShowCreateAccountServerError(nameResult); return; diff --git a/EndlessClient/Controllers/ArrowKeyController.cs b/EndlessClient/Controllers/ArrowKeyController.cs index d00583346..29eff85c4 100644 --- a/EndlessClient/Controllers/ArrowKeyController.cs +++ b/EndlessClient/Controllers/ArrowKeyController.cs @@ -3,7 +3,6 @@ using EndlessClient.HUD; using EndlessClient.Input; using EndlessClient.Rendering.Character; -using EndlessClient.Rendering.Map; using EOLib; using EOLib.Domain.Character; using EOLib.Domain.Extensions; @@ -20,7 +19,6 @@ public class ArrowKeyController : IArrowKeyController private readonly ICharacterAnimationActions _characterAnimationActions; private readonly ICharacterProvider _characterProvider; private readonly IUnwalkableTileActions _unwalkableTileActions; - private readonly ISpikeTrapActions _spikeTrapActions; private readonly IUnwalkableTileActionsHandler _unwalkableTileActionsHandler; private readonly IStatusLabelSetter _statusLabelSetter; private readonly IGhostingRepository _ghostingRepository; @@ -30,7 +28,6 @@ public ArrowKeyController(IWalkValidationActions walkValidationActions, ICharacterAnimationActions characterAnimationActions, ICharacterProvider characterProvider, IUnwalkableTileActions walkErrorHandler, - ISpikeTrapActions spikeTrapActions, IUnwalkableTileActionsHandler unwalkableTileActionsHandler, IStatusLabelSetter statusLabelSetter, IGhostingRepository ghostingRepository, @@ -40,7 +37,6 @@ public ArrowKeyController(IWalkValidationActions walkValidationActions, _characterAnimationActions = characterAnimationActions; _characterProvider = characterProvider; _unwalkableTileActions = walkErrorHandler; - _spikeTrapActions = spikeTrapActions; _unwalkableTileActionsHandler = unwalkableTileActionsHandler; _statusLabelSetter = statusLabelSetter; _ghostingRepository = ghostingRepository; @@ -134,12 +130,6 @@ private void AttemptToStartWalking() case WalkValidationResult.GhostComplete: case WalkValidationResult.Walkable: _characterAnimationActions.StartWalking(Option.None()); - - var coordinate = _characterProvider.MainCharacter.RenderProperties.Coordinates(); - _spikeTrapActions.HideSpikeTrap(coordinate); - - coordinate = _characterProvider.MainCharacter.RenderProperties.DestinationCoordinates(); - _spikeTrapActions.ShowSpikeTrap(coordinate, isMainCharacter: true); break; } } diff --git a/EndlessClient/Controllers/CharacterManagementController.cs b/EndlessClient/Controllers/CharacterManagementController.cs index d1b6e315b..90eb67e2a 100644 --- a/EndlessClient/Controllers/CharacterManagementController.cs +++ b/EndlessClient/Controllers/CharacterManagementController.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EndlessClient.Audio; using EndlessClient.Dialogs.Actions; using EndlessClient.GameExecution; @@ -8,7 +7,9 @@ using EOLib.Net; using EOLib.Net.Communication; using EOLib.Net.Connection; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; +using System.Threading.Tasks; using XNAControls; namespace EndlessClient.Controllers diff --git a/EndlessClient/Controllers/FunctionKeyController.cs b/EndlessClient/Controllers/FunctionKeyController.cs index ca5d339f3..8a1f5d7fc 100644 --- a/EndlessClient/Controllers/FunctionKeyController.cs +++ b/EndlessClient/Controllers/FunctionKeyController.cs @@ -1,10 +1,14 @@ using AutomaticTypeMapper; using EndlessClient.Audio; +using EndlessClient.ControlSets; using EndlessClient.Dialogs.Actions; using EndlessClient.HUD; +using EndlessClient.HUD.Controls; using EndlessClient.HUD.Panels; using EndlessClient.HUD.Spells; +using EndlessClient.Rendering; using EndlessClient.Rendering.Character; +using EndlessClient.Rendering.Map; using EOLib.Domain.Character; using EOLib.Domain.Extensions; using EOLib.Domain.Map; @@ -28,6 +32,7 @@ public class FunctionKeyController : IFunctionKeyController private readonly ICharacterProvider _characterProvider; private readonly IESFFileProvider _esfFileProvider; private readonly ISpellSlotDataProvider _spellSlotDataProvider; + private readonly IHudControlProvider _hudControlProvider; private readonly ISfxPlayer _sfxPlayer; public FunctionKeyController(IMapActions mapActions, @@ -40,6 +45,7 @@ public FunctionKeyController(IMapActions mapActions, ICharacterProvider characterProvider, IESFFileProvider esfFileProvider, ISpellSlotDataProvider spellSlotDataProvider, + IHudControlProvider hudControlProvider, ISfxPlayer sfxPlayer) { _mapActions = mapActions; @@ -52,6 +58,7 @@ public FunctionKeyController(IMapActions mapActions, _characterProvider = characterProvider; _esfFileProvider = esfFileProvider; _spellSlotDataProvider = spellSlotDataProvider; + _hudControlProvider = hudControlProvider; _sfxPlayer = sfxPlayer; } @@ -96,7 +103,9 @@ public bool Sit() if (_characterProvider.MainCharacter.RenderProperties.IsActing(CharacterActionState.Walking, CharacterActionState.Attacking, CharacterActionState.SpellCast)) return false; - _characterActions.ToggleSit(); + var cursorRenderer = _hudControlProvider.GetComponent(HudControlIdentifier.MapRenderer); + _characterActions.Sit(cursorRenderer.GridCoordinates); + return true; } diff --git a/EndlessClient/Controllers/InventoryController.cs b/EndlessClient/Controllers/InventoryController.cs index 166efa385..94a9b1730 100644 --- a/EndlessClient/Controllers/InventoryController.cs +++ b/EndlessClient/Controllers/InventoryController.cs @@ -1,17 +1,16 @@ using AutomaticTypeMapper; +using EndlessClient.Audio; using EndlessClient.ControlSets; using EndlessClient.Dialogs; using EndlessClient.Dialogs.Actions; using EndlessClient.Dialogs.Factories; using EndlessClient.HUD; using EndlessClient.HUD.Controls; -using EndlessClient.HUD.Panels; using EndlessClient.Rendering.Character; using EndlessClient.Rendering.Map; -using EndlessClient.Audio; using EOLib; -using EOLib.Domain.Chat; using EOLib.Domain.Character; +using EOLib.Domain.Chat; using EOLib.Domain.Interact; using EOLib.Domain.Interact.Bank; using EOLib.Domain.Item; @@ -210,19 +209,14 @@ public void UnequipItem(EquipLocation equipLocation) _itemActions.UnequipItem(equipId, alternateLocation: locName.Contains('2')); } - public void DropItem(EIFRecord itemData, InventoryItem inventoryItem) + public void DropItem(EIFRecord itemData, InventoryItem inventoryItem, MapCoordinate coords) { var mapRenderer = _hudControlProvider.GetComponent(HudControlIdentifier.MapRenderer); - var inventoryPanel = _hudControlProvider.GetComponent(HudControlIdentifier.InventoryPanel); if (_activeDialogProvider.ActiveDialogs.Any(x => x.HasValue) && mapRenderer.MouseOver) return; var rp = _characterProvider.MainCharacter.RenderProperties; - var dropPoint = mapRenderer.MouseOver && !inventoryPanel.MouseOver - ? mapRenderer.GridCoordinates - : new MapCoordinate(rp.MapX, rp.MapY); - - var validationResult = _itemDropValidator.ValidateItemDrop(_characterProvider.MainCharacter, inventoryItem, dropPoint); + var validationResult = _itemDropValidator.ValidateItemDrop(_characterProvider.MainCharacter, inventoryItem, coords); if (validationResult == ItemDropResult.Lore) { @@ -239,7 +233,7 @@ public void DropItem(EIFRecord itemData, InventoryItem inventoryItem) } else if (validationResult == ItemDropResult.Ok) { - DoItemDrop(itemData, inventoryItem, a => _itemActions.DropItem(inventoryItem.ItemID, a, dropPoint)); + DoItemDrop(itemData, inventoryItem, a => _itemActions.DropItem(inventoryItem.ItemID, a, coords)); } else if (validationResult == ItemDropResult.TooFar) { @@ -382,7 +376,6 @@ private void DoItemDrop(EIFRecord itemData, InventoryItem inventoryItem, Action< if (warningArgs.Result == XNADialogResult.OK) { _goldWarningShown = true; - dropAction(transferDialog.SelectedAmount); } }; warningMsg.ShowDialog(); @@ -412,7 +405,7 @@ public interface IInventoryController void UnequipItem(EquipLocation equipLocation); - void DropItem(EIFRecord itemData, InventoryItem inventoryItem); + void DropItem(EIFRecord itemData, InventoryItem inventoryItem, MapCoordinate coords); void DropItemInChest(EIFRecord itemData, InventoryItem inventoryItem); diff --git a/EndlessClient/Controllers/LoginController.cs b/EndlessClient/Controllers/LoginController.cs index de1974a48..d46fcc03f 100644 --- a/EndlessClient/Controllers/LoginController.cs +++ b/EndlessClient/Controllers/LoginController.cs @@ -14,19 +14,20 @@ using EOLib.Domain.Chat; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.Domain.Protocol; using EOLib.IO.Actions; using EOLib.Localization; using EOLib.Net; using EOLib.Net.Communication; using EOLib.Net.FileTransfer; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System; using System.IO; using System.Threading.Tasks; namespace EndlessClient.Controllers { - [MappedType(BaseType = typeof(ILoginController))] + [AutoMappedType] public class LoginController : ILoginController { private readonly ILoginActions _loginActions; @@ -41,6 +42,7 @@ public class LoginController : ILoginController private readonly IUserInputTimeRepository _userInputTimeRepository; private readonly IClientWindowSizeRepository _clientWindowSizeRepository; private readonly IConfigurationProvider _configurationProvider; + private readonly IPlayerInfoRepository _playerInfoRepository; private readonly IErrorDialogDisplayAction _errorDisplayAction; private readonly ISafeNetworkOperationFactory _networkOperationFactory; private readonly IGameLoadingDialogFactory _gameLoadingDialogFactory; @@ -65,7 +67,8 @@ public LoginController(ILoginActions loginActions, INewsProvider newsProvider, IUserInputTimeRepository userInputTimeRepository, IClientWindowSizeRepository clientWindowSizeRepository, - IConfigurationProvider configurationProvider) + IConfigurationProvider configurationProvider, + IPlayerInfoRepository playerInfoRepository) { _loginActions = loginActions; _mapFileLoadActions = mapFileLoadActions; @@ -85,6 +88,7 @@ public LoginController(ILoginActions loginActions, _userInputTimeRepository = userInputTimeRepository; _clientWindowSizeRepository = clientWindowSizeRepository; _configurationProvider = configurationProvider; + _playerInfoRepository = playerInfoRepository; } public async Task LoginToAccount(ILoginParameters loginParameters) @@ -106,8 +110,18 @@ public async Task LoginToAccount(ILoginParameters loginParameters) } else { + if (reply == LoginReply.WrongUser || reply == LoginReply.WrongUserPassword) + _playerInfoRepository.LoginAttempts++; + else + _playerInfoRepository.LoginAttempts = 3; + _errorDisplayAction.ShowLoginError(reply); - _gameStateActions.ChangeToState(GameStates.Initial); + + if (_playerInfoRepository.LoginAttempts >= 3) + { + _gameStateActions.ChangeToState(GameStates.Initial); + _playerInfoRepository.LoginAttempts = 0; + } } } @@ -141,7 +155,7 @@ public async Task LoginToCharacter(Character character) await InitialDelayInReleaseMode().ConfigureAwait(false); - if (unableToLoadMap || _fileRequestActions.NeedsFileForLogin(InitFileType.Map, _currentMapStateProvider.CurrentMapID)) + if (unableToLoadMap || _fileRequestActions.NeedsFileForLogin(FileType.Emf, _currentMapStateProvider.CurrentMapID)) { gameLoadingDialog.SetState(GameLoadingDialogState.Map); if (!await SafeGetFile(() => _fileRequestActions.GetMapFromServer(_currentMapStateProvider.CurrentMapID, sessionID)).ConfigureAwait(false)) @@ -149,7 +163,7 @@ public async Task LoginToCharacter(Character character) await Task.Delay(1000).ConfigureAwait(false); } - if (_fileRequestActions.NeedsFileForLogin(InitFileType.Item)) + if (_fileRequestActions.NeedsFileForLogin(FileType.Eif)) { gameLoadingDialog.SetState(GameLoadingDialogState.Item); if (!await SafeGetFile(() => _fileRequestActions.GetItemFileFromServer(sessionID)).ConfigureAwait(false)) @@ -157,7 +171,7 @@ public async Task LoginToCharacter(Character character) await Task.Delay(1000).ConfigureAwait(false); } - if (_fileRequestActions.NeedsFileForLogin(InitFileType.Npc)) + if (_fileRequestActions.NeedsFileForLogin(FileType.Enf)) { gameLoadingDialog.SetState(GameLoadingDialogState.NPC); if (!await SafeGetFile(() => _fileRequestActions.GetNPCFileFromServer(sessionID)).ConfigureAwait(false)) @@ -165,7 +179,7 @@ public async Task LoginToCharacter(Character character) await Task.Delay(1000).ConfigureAwait(false); } - if (_fileRequestActions.NeedsFileForLogin(InitFileType.Spell)) + if (_fileRequestActions.NeedsFileForLogin(FileType.Esf)) { gameLoadingDialog.SetState(GameLoadingDialogState.Spell); if (!await SafeGetFile(() => _fileRequestActions.GetSpellFileFromServer(sessionID)).ConfigureAwait(false)) @@ -173,7 +187,7 @@ public async Task LoginToCharacter(Character character) await Task.Delay(1000).ConfigureAwait(false); } - if (_fileRequestActions.NeedsFileForLogin(InitFileType.Class)) + if (_fileRequestActions.NeedsFileForLogin(FileType.Ecf)) { gameLoadingDialog.SetState(GameLoadingDialogState.Class); if (!await SafeGetFile(() => _fileRequestActions.GetClassFileFromServer(sessionID)).ConfigureAwait(false)) @@ -190,7 +204,7 @@ public async Task LoginToCharacter(Character character) if (!await completeCharacterLoginOperation.Invoke().ConfigureAwait(false)) return; - if (completeCharacterLoginOperation.Result == CharacterLoginReply.RequestDenied) + if (completeCharacterLoginOperation.Result == WelcomeCode.ServerBusy) { // https://discord.com/channels/723989119503696013/787685796055482368/946634672295784509 // Sausage: 'I have WELCOME_REPLY 3 as returning a "server is busy" message if you send it and then disconnect the client' diff --git a/EndlessClient/Controllers/MainButtonController.cs b/EndlessClient/Controllers/MainButtonController.cs index 5f50375bb..1ac85b5f1 100644 --- a/EndlessClient/Controllers/MainButtonController.cs +++ b/EndlessClient/Controllers/MainButtonController.cs @@ -2,17 +2,20 @@ using EndlessClient.Dialogs.Actions; using EndlessClient.GameExecution; using EndlessClient.Rendering; +using EOLib; using EOLib.Domain; -using EOLib.Domain.Protocol; using EOLib.Net.Communication; using EOLib.Net.Connection; using EOLib.Net.PacketProcessing; +using Moffat.EndlessOnline.SDK.Packet; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System; using System.Threading; using System.Threading.Tasks; namespace EndlessClient.Controllers { - [MappedType(BaseType = typeof(IMainButtonController))] + [AutoMappedType(IsSingleton = true)] public class MainButtonController : IMainButtonController { private readonly INetworkConnectionActions _networkConnectionActions; @@ -24,6 +27,8 @@ public class MainButtonController : IMainButtonController private readonly IResetStateAction _resetStateAction; private readonly ISafeNetworkOperationFactory _networkOperationFactory; + private readonly Random _random; + private int _numberOfConnectionRequests; public MainButtonController(INetworkConnectionActions networkConnectionActions, @@ -43,6 +48,8 @@ public MainButtonController(INetworkConnectionActions networkConnectionActions, _accountDialogDisplayActions = accountDialogDisplayActions; _resetStateAction = resetStateAction; _networkOperationFactory = networkOperationFactory; + + _random = new Random(); } public void GoToInitialState() @@ -116,7 +123,7 @@ private async Task StartNetworkConnection() _backgroundReceiveActions.RunBackgroundReceiveLoop(); var beginHandshakeOperation = _networkOperationFactory.CreateSafeBlockingOperation( - _networkConnectionActions.BeginHandshake, + async () => await _networkConnectionActions.BeginHandshake(_random.Next(Constants.MaxChallenge)), ex => _errorDialogDisplayAction.ShowException(ex), ex => _errorDialogDisplayAction.ShowException(ex)); @@ -126,20 +133,21 @@ private async Task StartNetworkConnection() return false; } - var initData = beginHandshakeOperation.Result; + var serverPacket = beginHandshakeOperation.Result; - if (initData.Response != InitReply.Success) + if (serverPacket.ReplyCode != InitReply.Ok) { - _errorDialogDisplayAction.ShowError(initData); + _errorDialogDisplayAction.ShowError(serverPacket.ReplyCode, serverPacket.ReplyCodeData); StopReceivingAndDisconnect(); return false; } - _packetProcessActions.SetInitialSequenceNumber(initData[InitializationDataKey.SequenceByte1], - initData[InitializationDataKey.SequenceByte2]); - _packetProcessActions.SetEncodeMultiples(initData[InitializationDataKey.ReceiveMultiple], initData[InitializationDataKey.SendMultiple]); + var okData = (InitInitServerPacket.ReplyCodeDataOk)serverPacket.ReplyCodeData; + var sequenceStart = InitSequenceStart.FromInitValues(okData.Seq1, okData.Seq2); + _packetProcessActions.SetSequenceStart(sequenceStart); + _packetProcessActions.SetEncodeMultiples(okData.ServerEncryptionMultiple, okData.ClientEncryptionMultiple); - _networkConnectionActions.CompleteHandshake(initData); + _networkConnectionActions.CompleteHandshake(serverPacket); return true; } finally diff --git a/EndlessClient/Controllers/MapInteractionController.cs b/EndlessClient/Controllers/MapInteractionController.cs index 564cb9cf9..4e1fc6c71 100644 --- a/EndlessClient/Controllers/MapInteractionController.cs +++ b/EndlessClient/Controllers/MapInteractionController.cs @@ -127,45 +127,50 @@ public void LeftClick(IMapCellState cellState) // vanilla client prioritizes standing first, then board interaction else if (_characterProvider.MainCharacter.RenderProperties.SitState != SitState.Standing) { - _characterActions.ToggleSit(); + var mapRenderer = _hudControlProvider.GetComponent(HudControlIdentifier.MapRenderer); + _characterActions.Sit(mapRenderer.GridCoordinates); } - else if (InteractableTileSpec(cellState.TileSpec) && (cellState.TileSpec.IsBoard() || CharacterIsCloseEnough(cellState.Coordinate))) + else if (InteractableTileSpec(cellState.TileSpec) && (cellState.TileSpec.IsBoard() || cellState.TileSpec == TileSpec.Jukebox || CharacterIsCloseEnough(cellState.Coordinate))) { var unwalkableActions = _unwalkableTileActions.GetUnwalkableTileActions(cellState); foreach (var unwalkableAction in unwalkableActions) { - if (cellState.TileSpec.IsBoard()) { _mapActions.OpenBoard(cellState.TileSpec); _inGameDialogActions.ShowBoardDialog(); - continue; } - - switch (cellState.TileSpec) + else if (cellState.TileSpec.IsChair()) + { + _characterActions.Sit(cellState.Coordinate, isChair: true); + } + else { - case TileSpec.Chest: - if (unwalkableAction == UnwalkableTileAction.Chest) - { - _mapActions.OpenChest(cellState.Coordinate); - _inGameDialogActions.ShowChestDialog(); - } - break; - case TileSpec.BankVault: - if (unwalkableAction == UnwalkableTileAction.Locker) - { - _mapActions.OpenLocker(cellState.Coordinate); - _inGameDialogActions.ShowLockerDialog(); - } - break; - case TileSpec.Jukebox: - if (unwalkableAction == UnwalkableTileAction.Jukebox) - { - _mapActions.OpenJukebox(cellState.Coordinate); - _inGameDialogActions.ShowJukeboxDialog(cellState.Coordinate); - } - break; + switch (cellState.TileSpec) + { + case TileSpec.Chest: + if (unwalkableAction == UnwalkableTileAction.Chest) + { + _mapActions.OpenChest(cellState.Coordinate); + _inGameDialogActions.ShowChestDialog(); + } + break; + case TileSpec.BankVault: + if (unwalkableAction == UnwalkableTileAction.Locker) + { + _mapActions.OpenLocker(cellState.Coordinate); + _inGameDialogActions.ShowLockerDialog(); + } + break; + case TileSpec.Jukebox: + if (unwalkableAction == UnwalkableTileAction.Jukebox) + { + _mapActions.OpenJukebox(cellState.Coordinate); + _inGameDialogActions.ShowJukeboxDialog(); + } + break; + } } } } @@ -246,14 +251,6 @@ public void RightClick(ISpellTargetable target) } } - private void PlayMainCharacterWalkSfx() - { - if (_characterProvider.MainCharacter.NoWall) - _sfxPlayer.PlaySfx(SoundEffectID.NoWallWalk); - else if (IsSteppingStone(_characterProvider.MainCharacter.RenderProperties)) - _sfxPlayer.PlaySfx(SoundEffectID.JumpStone); - } - private bool IsSteppingStone(CharacterRenderProperties renderProps) { return _currentMapProvider.CurrentMap.Tiles[renderProps.MapY, renderProps.MapX] == TileSpec.Jump @@ -293,23 +290,10 @@ private void HandlePickupResult(ItemPickupResult pickupResult, MapItem item) private static bool InteractableTileSpec(TileSpec tileSpec) { - switch (tileSpec) - { - case TileSpec.Chest: - case TileSpec.BankVault: - case TileSpec.Board1: - case TileSpec.Board2: - case TileSpec.Board3: - case TileSpec.Board4: - case TileSpec.Board5: - case TileSpec.Board6: - case TileSpec.Board7: - case TileSpec.Board8: - case TileSpec.Jukebox: - return true; - default: - return false; - } + return tileSpec.IsBoard() || tileSpec.IsChair() + || tileSpec == TileSpec.Chest + || tileSpec == TileSpec.BankVault + || tileSpec == TileSpec.Jukebox; } private bool CharacterIsCloseEnough(MapCoordinate coordinate) diff --git a/EndlessClient/Dialogs/Actions/AccountDialogDisplayActions.cs b/EndlessClient/Dialogs/Actions/AccountDialogDisplayActions.cs index bb84a769e..6a7fa651b 100644 --- a/EndlessClient/Dialogs/Actions/AccountDialogDisplayActions.cs +++ b/EndlessClient/Dialogs/Actions/AccountDialogDisplayActions.cs @@ -2,6 +2,7 @@ using EndlessClient.Dialogs.Factories; using EOLib.Domain.Account; using EOLib.Localization; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using System; using System.Threading.Tasks; @@ -9,7 +10,7 @@ namespace EndlessClient.Dialogs.Actions { - [MappedType(BaseType = typeof(IAccountDialogDisplayActions))] + [AutoMappedType] public class AccountDialogDisplayActions : IAccountDialogDisplayActions { private readonly ILocalizedStringFinder _localizedStringFinder; @@ -71,7 +72,8 @@ public void ShowCreateAccountServerError(AccountReply serverError) case AccountReply.NotApproved: message = DialogResourceID.ACCOUNT_CREATE_NAME_NOT_APPROVED; break; case AccountReply.Created: message = DialogResourceID.ACCOUNT_CREATE_SUCCESS_WELCOME; break; case AccountReply.ChangeFailed: message = DialogResourceID.CHANGE_PASSWORD_MISMATCH; break; - case AccountReply.ChangeSuccess: message = DialogResourceID.CHANGE_PASSWORD_SUCCESS; break; + case AccountReply.Changed: message = DialogResourceID.CHANGE_PASSWORD_SUCCESS; break; + case AccountReply.RequestDenied: message = DialogResourceID.LOGIN_SERVER_COULD_NOT_PROCESS; break; default: throw new ArgumentOutOfRangeException(nameof(serverError), serverError, null); } diff --git a/EndlessClient/Dialogs/Actions/CharacterDialogActions.cs b/EndlessClient/Dialogs/Actions/CharacterDialogActions.cs index 465c0b411..b56924c36 100644 --- a/EndlessClient/Dialogs/Actions/CharacterDialogActions.cs +++ b/EndlessClient/Dialogs/Actions/CharacterDialogActions.cs @@ -2,6 +2,7 @@ using EndlessClient.Dialogs.Factories; using EOLib.Domain.Character; using EOLib.Localization; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using System; using System.Threading.Tasks; @@ -9,7 +10,7 @@ namespace EndlessClient.Dialogs.Actions { - [MappedType(BaseType = typeof(ICharacterDialogActions))] + [AutoMappedType] public class CharacterDialogActions : ICharacterDialogActions { private readonly IEOMessageBoxFactory _messageBoxFactory; diff --git a/EndlessClient/Dialogs/Actions/ErrorDialogDisplayAction.cs b/EndlessClient/Dialogs/Actions/ErrorDialogDisplayAction.cs index 2c8931455..2cc8d2c64 100644 --- a/EndlessClient/Dialogs/Actions/ErrorDialogDisplayAction.cs +++ b/EndlessClient/Dialogs/Actions/ErrorDialogDisplayAction.cs @@ -1,25 +1,27 @@ -using System; -using System.Net.Sockets; -using System.Runtime.InteropServices; -using AutomaticTypeMapper; +using AutomaticTypeMapper; +using EndlessClient.Audio; using EndlessClient.Dialogs.Factories; -using EOLib.Domain.Login; -using EOLib.Domain.Protocol; using EOLib.Localization; using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using System; +using System.Net.Sockets; +using System.Runtime.InteropServices; namespace EndlessClient.Dialogs.Actions { - //todo: some of this should be split into services for getting display strings - [MappedType(BaseType = typeof(IErrorDialogDisplayAction))] + [AutoMappedType] public class ErrorDialogDisplayAction : IErrorDialogDisplayAction { private readonly IEOMessageBoxFactory _messageBoxFactory; + private readonly ISfxPlayer _sfxPlayer; - public ErrorDialogDisplayAction(IEOMessageBoxFactory messageBoxFactory) + public ErrorDialogDisplayAction(IEOMessageBoxFactory messageBoxFactory, + ISfxPlayer sfxPlayer) { _messageBoxFactory = messageBoxFactory; + _sfxPlayer = sfxPlayer; } public void ShowError(ConnectResult connectResult) @@ -75,14 +77,14 @@ public void ShowError(ConnectResult connectResult) } } - public void ShowError(IInitializationData initializationData) + public void ShowError(InitReply replyCode, InitInitServerPacket.IReplyCodeData initializationData) { - switch (initializationData.Response) + switch (replyCode) { - case InitReply.ClientOutOfDate: + case InitReply.OutOfDate: { - var versionNumber = initializationData[InitializationDataKey.RequiredVersionNumber]; - var extra = $" 0.000.0{versionNumber}"; + var data = (InitInitServerPacket.ReplyCodeDataOutOfDate)initializationData; + var extra = $" {data.Version.Major:D3}.{data.Version.Minor:D3}.{data.Version.Patch:D3}"; var messageBox = _messageBoxFactory.CreateMessageBox(DialogResourceID.CONNECTION_CLIENT_OUT_OF_DATE, extra, EODialogButtons.Ok, @@ -90,19 +92,23 @@ public void ShowError(IInitializationData initializationData) messageBox.ShowDialog(); } break; - case InitReply.BannedFromServer: + case InitReply.Banned: { - var banType = (BanType)initializationData[InitializationDataKey.BanType]; - if (banType == BanType.PermanentBan) + var data = (InitInitServerPacket.ReplyCodeDataBanned)initializationData; + if (data.BanType == InitBanType.Permanent) { var messageBox = _messageBoxFactory.CreateMessageBox(DialogResourceID.CONNECTION_IP_BAN_PERM, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogLargeHeader); messageBox.ShowDialog(); } - else if (banType == BanType.TemporaryBan) + else if (data.BanType == InitBanType.Temporary || data.BanType == 0) { - var banMinutesRemaining = initializationData[InitializationDataKey.BanTimeRemaining]; + var banMinutesRemaining = data.BanTypeData is InitInitServerPacket.ReplyCodeDataBanned.BanTypeData0 dataZero + ? dataZero.MinutesRemaining + : data.BanTypeData is InitInitServerPacket.ReplyCodeDataBanned.BanTypeDataTemporary dataTemp + ? dataTemp.MinutesRemaining + : throw new ArgumentException(); var extra = $" {banMinutesRemaining} minutes."; var messageBox = _messageBoxFactory.CreateMessageBox(DialogResourceID.CONNECTION_IP_BAN_TEMP, extra, @@ -110,9 +116,11 @@ public void ShowError(IInitializationData initializationData) EOMessageBoxStyle.SmallDialogLargeHeader); messageBox.ShowDialog(); } + + _sfxPlayer.PlaySfx(SoundEffectID.Banned); } break; - case InitReply.ErrorState: + case 0: ShowError(ConnectResult.SocketError); break; default: throw new ArgumentOutOfRangeException(); @@ -139,18 +147,15 @@ public void ShowException(EmptyPacketReceivedException ex) public void ShowLoginError(LoginReply loginError) { - DialogResourceID message; - switch (loginError) + var message = loginError switch { - case LoginReply.WrongUser: message = DialogResourceID.LOGIN_ACCOUNT_NAME_NOT_FOUND; break; - case LoginReply.WrongUserPass: message = DialogResourceID.LOGIN_ACCOUNT_NAME_OR_PASSWORD_NOT_FOUND; break; - case LoginReply.AccountBanned: message = DialogResourceID.LOGIN_BANNED_FROM_SERVER; break; - case LoginReply.LoggedIn: message = DialogResourceID.LOGIN_ACCOUNT_ALREADY_LOGGED_ON; break; - case LoginReply.Busy: message = DialogResourceID.CONNECTION_SERVER_IS_FULL; break; - case LoginReply.THIS_IS_WRONG: message = DialogResourceID.LOGIN_SERVER_COULD_NOT_PROCESS; break; - default: throw new ArgumentOutOfRangeException(nameof(loginError), loginError, null); - } - + LoginReply.WrongUser => DialogResourceID.LOGIN_ACCOUNT_NAME_NOT_FOUND, + LoginReply.WrongUserPassword => DialogResourceID.LOGIN_ACCOUNT_NAME_OR_PASSWORD_NOT_FOUND, + LoginReply.Banned => DialogResourceID.LOGIN_BANNED_FROM_SERVER, + LoginReply.LoggedIn => DialogResourceID.LOGIN_ACCOUNT_ALREADY_LOGGED_ON, + LoginReply.Busy => DialogResourceID.CONNECTION_SERVER_IS_FULL, + _ => DialogResourceID.LOGIN_SERVER_COULD_NOT_PROCESS, + }; var messageBox = _messageBoxFactory.CreateMessageBox(message, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogLargeHeader); diff --git a/EndlessClient/Dialogs/Actions/IAccountDialogDisplayActions.cs b/EndlessClient/Dialogs/Actions/IAccountDialogDisplayActions.cs index 4ac29fc4f..141c30b39 100644 --- a/EndlessClient/Dialogs/Actions/IAccountDialogDisplayActions.cs +++ b/EndlessClient/Dialogs/Actions/IAccountDialogDisplayActions.cs @@ -1,7 +1,7 @@ -using System.Threading.Tasks; -using EOLib; -using EOLib.Domain.Account; +using EOLib.Domain.Account; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; +using System.Threading.Tasks; using XNAControls; namespace EndlessClient.Dialogs.Actions diff --git a/EndlessClient/Dialogs/Actions/ICharacterDialogActions.cs b/EndlessClient/Dialogs/Actions/ICharacterDialogActions.cs index 554579ec5..d09480307 100644 --- a/EndlessClient/Dialogs/Actions/ICharacterDialogActions.cs +++ b/EndlessClient/Dialogs/Actions/ICharacterDialogActions.cs @@ -1,4 +1,5 @@ using EOLib.Domain.Character; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using System.Threading.Tasks; using XNAControls; diff --git a/EndlessClient/Dialogs/Actions/IErrorDialogDisplayAction.cs b/EndlessClient/Dialogs/Actions/IErrorDialogDisplayAction.cs index 7f16bb201..9022280ce 100644 --- a/EndlessClient/Dialogs/Actions/IErrorDialogDisplayAction.cs +++ b/EndlessClient/Dialogs/Actions/IErrorDialogDisplayAction.cs @@ -1,7 +1,6 @@ -using EOLib.Domain.Login; -using EOLib.Domain.Protocol; -using EOLib.Net; +using EOLib.Net; using EOLib.Net.Communication; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; namespace EndlessClient.Dialogs.Actions { @@ -9,7 +8,7 @@ public interface IErrorDialogDisplayAction { void ShowError(ConnectResult connectResult); - void ShowError(IInitializationData initializationData); + void ShowError(InitReply replyCode, InitInitServerPacket.IReplyCodeData initializationData); void ShowException(NoDataSentException ex); diff --git a/EndlessClient/Dialogs/Actions/InGameDialogActions.cs b/EndlessClient/Dialogs/Actions/InGameDialogActions.cs index 765fa3da4..7ca9f1014 100644 --- a/EndlessClient/Dialogs/Actions/InGameDialogActions.cs +++ b/EndlessClient/Dialogs/Actions/InGameDialogActions.cs @@ -6,7 +6,6 @@ using EOLib.Domain.Interact.Quest; using EOLib.Domain.Interact.Shop; using EOLib.Domain.Interact.Skill; -using EOLib.Domain.Map; using EOLib.Localization; using Optional; using System; @@ -393,11 +392,11 @@ public void ShowBoardDialog() _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.BOARD_TOWN_BOARD_NOW_VIEWED); } - public void ShowJukeboxDialog(MapCoordinate mapCoordinate) + public void ShowJukeboxDialog() { _activeDialogRepository.JukeboxDialog.MatchNone(() => { - var dlg = _jukeboxDialogFactory.Create(mapCoordinate); + var dlg = _jukeboxDialogFactory.Create(); dlg.DialogClosed += (_, _) => _activeDialogRepository.JukeboxDialog = Option.None(); _activeDialogRepository.JukeboxDialog = Option.Some(dlg); @@ -535,7 +534,7 @@ public interface IInGameDialogActions void ShowBoardDialog(); - void ShowJukeboxDialog(MapCoordinate mapCoordinate); + void ShowJukeboxDialog(); void ShowInnkeeperDialog(); diff --git a/EndlessClient/Dialogs/Actions/NpcInteractionActions.cs b/EndlessClient/Dialogs/Actions/NpcInteractionActions.cs index f110ec531..be39af7c0 100644 --- a/EndlessClient/Dialogs/Actions/NpcInteractionActions.cs +++ b/EndlessClient/Dialogs/Actions/NpcInteractionActions.cs @@ -3,12 +3,12 @@ using EndlessClient.Dialogs.Factories; using EOLib.Domain.Interact; using EOLib.Domain.Interact.Citizen; -using EOLib.Domain.Interact.Law; using EOLib.Domain.Interact.Priest; using EOLib.Domain.Interact.Skill; using EOLib.IO; using EOLib.IO.Repositories; using EOLib.Localization; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System; using XNAControls; @@ -103,7 +103,7 @@ public void NotifyStatReset() _sfxPlayer.PlaySfx(SoundEffectID.LearnNewSpell); } - public void NotifyCitizenUnsubscribe(CitizenUnsubscribeReply reply) + public void NotifyCitizenUnsubscribe(InnUnsubscribeReply reply) { var message = EOResourceID.INN_YOU_ARE_NOT_A_CITIZEN + (int)reply; var dlg = _messageBoxFactory.CreateMessageBox(message, EOResourceID.INN_REGISTRATION_SERVICE); diff --git a/EndlessClient/Dialogs/Actions/PartyDialogActions.cs b/EndlessClient/Dialogs/Actions/PartyDialogActions.cs index e8de847f1..ece65ae9e 100644 --- a/EndlessClient/Dialogs/Actions/PartyDialogActions.cs +++ b/EndlessClient/Dialogs/Actions/PartyDialogActions.cs @@ -7,6 +7,7 @@ using EOLib.Domain.Notifiers; using EOLib.Domain.Party; using EOLib.Localization; +using Moffat.EndlessOnline.SDK.Protocol.Net; using XNAControls; namespace EndlessClient.Dialogs.Actions diff --git a/EndlessClient/Dialogs/Factories/JukeboxDialogFactory.cs b/EndlessClient/Dialogs/Factories/JukeboxDialogFactory.cs index 48a79410a..a0228e152 100644 --- a/EndlessClient/Dialogs/Factories/JukeboxDialogFactory.cs +++ b/EndlessClient/Dialogs/Factories/JukeboxDialogFactory.cs @@ -1,8 +1,8 @@ using AutomaticTypeMapper; using EndlessClient.Audio; using EndlessClient.Dialogs.Services; +using EOLib.Domain.Character; using EOLib.Domain.Interact.Jukebox; -using EOLib.Domain.Map; using EOLib.Graphics; using EOLib.Localization; @@ -19,6 +19,7 @@ public class JukeboxDialogFactory : IJukeboxDialogFactory private readonly IEOMessageBoxFactory _messageBoxFactory; private readonly IJukeboxActions _jukeboxActions; private readonly IJukeboxRepository _jukeboxRepository; + private readonly ICharacterInventoryProvider _characterInventoryProvider; private readonly ISfxPlayer _sfxPlayer; public JukeboxDialogFactory(INativeGraphicsManager nativeGraphicsManager, @@ -29,6 +30,7 @@ public JukeboxDialogFactory(INativeGraphicsManager nativeGraphicsManager, IEOMessageBoxFactory messageBoxFactory, IJukeboxActions jukeboxActions, IJukeboxRepository jukeboxRepository, + ICharacterInventoryProvider characterInventoryProvider, ISfxPlayer sfxPlayer) { _nativeGraphicsManager = nativeGraphicsManager; @@ -39,10 +41,11 @@ public JukeboxDialogFactory(INativeGraphicsManager nativeGraphicsManager, _messageBoxFactory = messageBoxFactory; _jukeboxActions = jukeboxActions; _jukeboxRepository = jukeboxRepository; + _characterInventoryProvider = characterInventoryProvider; _sfxPlayer = sfxPlayer; } - public JukeboxDialog Create(MapCoordinate mapCoordinate) + public JukeboxDialog Create() { return new JukeboxDialog(_nativeGraphicsManager, _dialogButtonService, @@ -52,13 +55,13 @@ public JukeboxDialog Create(MapCoordinate mapCoordinate) _messageBoxFactory, _jukeboxActions, _jukeboxRepository, - _sfxPlayer, - mapCoordinate); + _characterInventoryProvider, + _sfxPlayer); } } public interface IJukeboxDialogFactory { - JukeboxDialog Create(MapCoordinate mapCoordinate); + JukeboxDialog Create(); } } diff --git a/EndlessClient/Dialogs/Factories/TradeDialogFactory.cs b/EndlessClient/Dialogs/Factories/TradeDialogFactory.cs index ebaeaa872..83d56ab88 100644 --- a/EndlessClient/Dialogs/Factories/TradeDialogFactory.cs +++ b/EndlessClient/Dialogs/Factories/TradeDialogFactory.cs @@ -1,15 +1,14 @@ using AutomaticTypeMapper; +using EndlessClient.Audio; using EndlessClient.Dialogs.Services; -using EndlessClient.HUD.Inventory; using EndlessClient.HUD; +using EndlessClient.HUD.Inventory; using EndlessClient.Rendering.Map; using EOLib.Domain.Character; using EOLib.Domain.Trade; using EOLib.Graphics; using EOLib.IO.Repositories; using EOLib.Localization; -using EndlessClient.ControlSets; -using EndlessClient.HUD.Panels; namespace EndlessClient.Dialogs.Factories { @@ -27,7 +26,7 @@ public class TradeDialogFactory : ITradeDialogFactory private readonly ICharacterProvider _characterProvider; private readonly IEIFFileProvider _eifFileProvider; private readonly IMapItemGraphicProvider _mapItemGraphicProvider; - private readonly IHudControlProvider _hudControlProvider; + private readonly ISfxPlayer _sfxPlayer; public TradeDialogFactory(INativeGraphicsManager nativeGraphicsManager, ITradeActions tradeActions, @@ -40,7 +39,7 @@ public TradeDialogFactory(INativeGraphicsManager nativeGraphicsManager, ICharacterProvider characterProvider, IEIFFileProvider eifFileProvider, IMapItemGraphicProvider mapItemGraphicProvider, - IHudControlProvider hudControlProvider) + ISfxPlayer sfxPlayer) { _nativeGraphicsManager = nativeGraphicsManager; _tradeActions = tradeActions; @@ -53,7 +52,7 @@ public TradeDialogFactory(INativeGraphicsManager nativeGraphicsManager, _characterProvider = characterProvider; _eifFileProvider = eifFileProvider; _mapItemGraphicProvider = mapItemGraphicProvider; - _hudControlProvider = hudControlProvider; + _sfxPlayer = sfxPlayer; } public TradeDialog Create() @@ -69,7 +68,7 @@ public TradeDialog Create() _characterProvider, _eifFileProvider, _mapItemGraphicProvider, - _hudControlProvider.GetComponent(HUD.Controls.HudControlIdentifier.InventoryPanel)); + _sfxPlayer); } } diff --git a/EndlessClient/Dialogs/JukeboxDialog.cs b/EndlessClient/Dialogs/JukeboxDialog.cs index 92a5367d8..aa8af76ce 100644 --- a/EndlessClient/Dialogs/JukeboxDialog.cs +++ b/EndlessClient/Dialogs/JukeboxDialog.cs @@ -1,13 +1,14 @@ using EndlessClient.Audio; using EndlessClient.Dialogs.Factories; using EndlessClient.Dialogs.Services; +using EOLib.Domain.Character; using EOLib.Domain.Interact.Jukebox; -using EOLib.Domain.Map; using EOLib.Graphics; using EOLib.Localization; using Microsoft.Xna.Framework; using MonoGame.Extended.Input.InputListeners; using Optional; +using Optional.Collections; using System; using System.Collections.Generic; using XNAControls; @@ -21,10 +22,9 @@ public class JukeboxDialog : ScrollingListDialog private readonly IEOMessageBoxFactory _messageBoxFactory; private readonly IJukeboxActions _jukeboxActions; private readonly IJukeboxRepository _jukeboxRepository; + private readonly ICharacterInventoryProvider _characterInventoryProvider; private readonly ISfxPlayer _sfxPlayer; - private readonly MapCoordinate _jukeboxCoordinate; - private readonly IEDFFile _songNames; private ListDialogItem _changeSongItem, _playSongItem; @@ -42,8 +42,8 @@ public JukeboxDialog(INativeGraphicsManager nativeGraphicsManager, IEOMessageBoxFactory messageBoxFactory, IJukeboxActions jukeboxActions, IJukeboxRepository jukeboxRepository, - ISfxPlayer sfxPlayer, - MapCoordinate jukeboxCoordinate) + ICharacterInventoryProvider characterInventoryProvider, + ISfxPlayer sfxPlayer) : base(nativeGraphicsManager, dialogButtonService, DialogType.Jukebox) { _dialogIconService = dialogIconService; @@ -51,8 +51,8 @@ public JukeboxDialog(INativeGraphicsManager nativeGraphicsManager, _messageBoxFactory = messageBoxFactory; _jukeboxActions = jukeboxActions; _jukeboxRepository = jukeboxRepository; + _characterInventoryProvider = characterInventoryProvider; _sfxPlayer = sfxPlayer; - _jukeboxCoordinate = jukeboxCoordinate; ListItemType = ListDialogItem.ListItemStyle.Large; Buttons = ScrollingListDialogButtons.Cancel; @@ -141,6 +141,13 @@ private void PlaySongItem_Click(object sender, MouseEventArgs e) return; } + if (_characterInventoryProvider.ItemInventory.SingleOrNone(x => x.ItemID == 1).Map(x => x.Amount < 25).ValueOr(true)) + { + var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.WARNING_YOU_HAVE_NOT_ENOUGH, " gold"); + dlg.ShowDialog(); + return; + } + var confirmDlg = _messageBoxFactory.CreateMessageBox( $"{_localizedStringFinder.GetString(EOResourceID.JUKEBOX_REQUEST_SONG_FOR)} 25 gold?", _localizedStringFinder.GetString(EOResourceID.JUKEBOX_REQUEST_SONG), @@ -150,7 +157,7 @@ private void PlaySongItem_Click(object sender, MouseEventArgs e) { if (e.Result == XNADialogResult.OK) { - _jukeboxActions.RequestSong(_jukeboxCoordinate, _songIndex); + _jukeboxActions.RequestSong(_songIndex); _sfxPlayer.PlaySfx(SoundEffectID.BuySell); Close(XNADialogResult.NO_BUTTON_PRESSED); diff --git a/EndlessClient/Dialogs/PlayerInfoDialog.cs b/EndlessClient/Dialogs/PlayerInfoDialog.cs index 2b936bc80..8d1ff2939 100644 --- a/EndlessClient/Dialogs/PlayerInfoDialog.cs +++ b/EndlessClient/Dialogs/PlayerInfoDialog.cs @@ -7,6 +7,7 @@ using EOLib.IO.Repositories; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using Optional.Unsafe; using XNAControls; @@ -155,7 +156,7 @@ protected virtual void UpdateDisplayedData(PaperdollData paperdollData) private static string Capitalize(string input) => string.IsNullOrEmpty(input) ? string.Empty : char.ToUpper(input[0]) + input[1..].ToLower(); - private static Rectangle GetOnlineIconSourceRectangle(OnlineIcon icon) + private static Rectangle GetOnlineIconSourceRectangle(CharacterIcon icon) { var (x, y, width, height) = icon.ToChatIcon().GetChatIconRectangleBounds().ValueOrDefault(); return new Rectangle(x, y, width, height); diff --git a/EndlessClient/Dialogs/QuestDialog.cs b/EndlessClient/Dialogs/QuestDialog.cs index 861df585c..538fb1123 100644 --- a/EndlessClient/Dialogs/QuestDialog.cs +++ b/EndlessClient/Dialogs/QuestDialog.cs @@ -2,10 +2,10 @@ using EndlessClient.Dialogs.Services; using EOLib; using EOLib.Domain.Interact.Quest; -using EOLib.Domain.NPC; using EOLib.Graphics; using EOLib.IO.Repositories; using Microsoft.Xna.Framework; +using Moffat.EndlessOnline.SDK.Protocol.Net.Client; using Optional; using System; using System.Collections.Generic; diff --git a/EndlessClient/Dialogs/QuestStatusDialog.cs b/EndlessClient/Dialogs/QuestStatusDialog.cs index ab48093b1..6acff69be 100644 --- a/EndlessClient/Dialogs/QuestStatusDialog.cs +++ b/EndlessClient/Dialogs/QuestStatusDialog.cs @@ -4,6 +4,7 @@ using EOLib.Graphics; using EOLib.Localization; using Microsoft.Xna.Framework; +using Moffat.EndlessOnline.SDK.Protocol.Net; using System.Collections.Generic; namespace EndlessClient.Dialogs diff --git a/EndlessClient/Dialogs/QuestStatusListDialogItem.cs b/EndlessClient/Dialogs/QuestStatusListDialogItem.cs index b38a785ce..c708eea4a 100644 --- a/EndlessClient/Dialogs/QuestStatusListDialogItem.cs +++ b/EndlessClient/Dialogs/QuestStatusListDialogItem.cs @@ -1,8 +1,8 @@ using EOLib; -using EOLib.Domain.Interact.Quest; using EOLib.Graphics; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using Moffat.EndlessOnline.SDK.Protocol.Net; using XNAControls; namespace EndlessClient.Dialogs diff --git a/EndlessClient/Dialogs/ShopDialog.cs b/EndlessClient/Dialogs/ShopDialog.cs index 4d6ed73d4..469b06bf4 100644 --- a/EndlessClient/Dialogs/ShopDialog.cs +++ b/EndlessClient/Dialogs/ShopDialog.cs @@ -83,10 +83,10 @@ protected override void OnUpdateControl(GameTime gameTime) { _cachedShopId.MatchNone(() => { - _shopDataProvider.ShopID.SomeWhen(x => x > 0) + _shopDataProvider.SessionID.SomeWhen(x => x > 0) .MatchSome(x => { - _cachedShopId = Option.Some(_shopDataProvider.ShopID); + _cachedShopId = Option.Some(_shopDataProvider.SessionID); Title = _shopDataProvider.ShopName; diff --git a/EndlessClient/Dialogs/TradeDialog.cs b/EndlessClient/Dialogs/TradeDialog.cs index 010a96f81..33822db05 100644 --- a/EndlessClient/Dialogs/TradeDialog.cs +++ b/EndlessClient/Dialogs/TradeDialog.cs @@ -1,8 +1,8 @@ -using EndlessClient.Dialogs.Factories; +using EndlessClient.Audio; +using EndlessClient.Dialogs.Factories; using EndlessClient.Dialogs.Services; using EndlessClient.HUD; using EndlessClient.HUD.Inventory; -using EndlessClient.HUD.Panels; using EndlessClient.Rendering.Map; using EndlessClient.UIControls; using EOLib; @@ -33,7 +33,7 @@ public class TradeDialog : BaseEODialog private readonly ICharacterProvider _characterProvider; private readonly IEIFFileProvider _eifFileProvider; private readonly IMapItemGraphicProvider _mapItemGraphicProvider; - private readonly InventoryPanel _inventoryPanel; + private readonly ISfxPlayer _sfxPlayer; private readonly IXNAPanel _leftPanel, _rightPanel; private readonly IXNALabel _leftPlayerName, _rightPlayerName; @@ -64,7 +64,7 @@ public TradeDialog(INativeGraphicsManager nativeGraphicsManager, ICharacterProvider characterProvider, IEIFFileProvider eifFileProvider, IMapItemGraphicProvider mapItemGraphicProvider, - InventoryPanel inventoryPanel) + ISfxPlayer sfxPlayer) : base(nativeGraphicsManager, isInGame: true) { _tradeActions = tradeActions; @@ -76,7 +76,7 @@ public TradeDialog(INativeGraphicsManager nativeGraphicsManager, _characterProvider = characterProvider; _eifFileProvider = eifFileProvider; _mapItemGraphicProvider = mapItemGraphicProvider; - _inventoryPanel = inventoryPanel; + _sfxPlayer = sfxPlayer; BackgroundTexture = GraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 50); _leftPanel = new XNAPanel @@ -228,9 +228,12 @@ private void UpdateOffer(TradeOffer actualOffer, TradeOffer cachedOffer, List listItems, int listitemOffset) { - if ((actualOffer.PlayerName != cachedOffer.PlayerName && !string.IsNullOrEmpty(actualOffer.PlayerName)) || actualOffer.Items.Count != cachedOffer.Items.Count) + if (actualOffer.PlayerName != cachedOffer.PlayerName || actualOffer.Items.Count != cachedOffer.Items.Count) { - playerNameLabel.Text = $"{char.ToUpper(actualOffer.PlayerName[0]) + actualOffer.PlayerName[1..]}{(actualOffer.Items.Any() ? $"[{actualOffer.Items.Count}]" : "")}"; + if (!string.IsNullOrEmpty(actualOffer.PlayerName)) + { + playerNameLabel.Text = $"{char.ToUpper(actualOffer.PlayerName[0]) + actualOffer.PlayerName[1..]}{(actualOffer.Items.Any() ? $"[{actualOffer.Items.Count}]" : "")}"; + } } // todo: check if packets properly reset agrees to false when items change @@ -281,6 +284,8 @@ private void UpdateOffer(TradeOffer actualOffer, TradeOffer cachedOffer, newListItem.SetParentControl(parentPanel); listItems.Add(newListItem); + + _sfxPlayer.PlaySfx(SoundEffectID.TradeItemOfferChanged); } foreach (var removedItem in removed) @@ -291,6 +296,8 @@ private void UpdateOffer(TradeOffer actualOffer, TradeOffer cachedOffer, listItems.Remove(listItem); listItem.Dispose(); }); + + _sfxPlayer.PlaySfx(SoundEffectID.TradeItemOfferChanged); } if (cachedOffer.Items != null && actualOffer.PlayerID != 0 && actualOffer.PlayerID != _characterProvider.MainCharacter.ID) @@ -298,7 +305,7 @@ private void UpdateOffer(TradeOffer actualOffer, TradeOffer cachedOffer, _partnerItemChangeTick = Stopwatch.StartNew(); _recentPartnerItemChanges++; - if (_recentPartnerItemChanges == 3) + if (_recentPartnerItemChanges == 2) { var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.TRADE_OTHER_PLAYER_TRICK_YOU); dlg.ShowDialog(); diff --git a/EndlessClient/EndlessClient.csproj b/EndlessClient/EndlessClient.csproj index e939db84f..1ac9f1b06 100644 --- a/EndlessClient/EndlessClient.csproj +++ b/EndlessClient/EndlessClient.csproj @@ -80,6 +80,7 @@ + diff --git a/EndlessClient/GameExecution/EndlessGame.cs b/EndlessClient/GameExecution/EndlessGame.cs index c3c837b8c..8f0db67f2 100644 --- a/EndlessClient/GameExecution/EndlessGame.cs +++ b/EndlessClient/GameExecution/EndlessGame.cs @@ -120,6 +120,7 @@ protected override void Initialize() IsFixedTimeStep = false; TargetElapsedTime = TimeSpan.FromMilliseconds(FixedTimeStepRepository.TICK_TIME_MS); + InactiveSleepTime = TimeSpan.FromMilliseconds(0); _previousKeyState = Keyboard.GetState(); diff --git a/EndlessClient/HUD/Chat/ChatModeCalculator.cs b/EndlessClient/HUD/Chat/ChatModeCalculator.cs index 1511ff5d5..ea75ac74d 100644 --- a/EndlessClient/HUD/Chat/ChatModeCalculator.cs +++ b/EndlessClient/HUD/Chat/ChatModeCalculator.cs @@ -1,7 +1,7 @@ -using System; using AutomaticTypeMapper; using EndlessClient.UIControls; using EOLib.Domain.Character; +using Moffat.EndlessOnline.SDK.Protocol; namespace EndlessClient.HUD.Chat { diff --git a/EndlessClient/HUD/Controls/HudControlsFactory.cs b/EndlessClient/HUD/Controls/HudControlsFactory.cs index 754d40fdb..4d522d28e 100644 --- a/EndlessClient/HUD/Controls/HudControlsFactory.cs +++ b/EndlessClient/HUD/Controls/HudControlsFactory.cs @@ -25,7 +25,6 @@ using EOLib.Domain.Map; using EOLib.Graphics; using EOLib.Localization; -using EOLib.Net.Communication; using Microsoft.Xna.Framework; using System; using System.Collections.Generic; @@ -62,7 +61,7 @@ public class HudControlsFactory : IHudControlsFactory private readonly ICharacterActions _characterActions; private readonly IWalkValidationActions _walkValidationActions; private readonly IChatBubbleActions _chatBubbleActions; - private readonly IPacketSendService _packetSendService; + private readonly IUnknownEntitiesRequestActions _unknownEntitiesRequestActions; private readonly IUserInputTimeProvider _userInputTimeProvider; private readonly ISpellSlotDataRepository _spellSlotDataRepository; private readonly ISfxPlayer _sfxPlayer; @@ -72,6 +71,8 @@ public class HudControlsFactory : IHudControlsFactory private readonly IClickDispatcherFactory _clickDispatcherFactory; private readonly IMetadataProvider _weaponMetadataProvider; private readonly ILocalizedStringFinder _localizedStringFinder; + private readonly ICharacterRendererProvider _characterRendererProvider; + private readonly INPCRendererProvider _npcRendererProvider; private IChatController _chatController; private IMainButtonController _mainButtonController; @@ -97,7 +98,7 @@ public HudControlsFactory(IHudButtonController hudButtonController, ICharacterActions characterActions, IWalkValidationActions walkValidationActions, IChatBubbleActions chatBubbleActions, - IPacketSendService packetSendService, + IUnknownEntitiesRequestActions unknownEntitiesRequestActions, IUserInputTimeProvider userInputTimeProvider, ISpellSlotDataRepository spellSlotDataRepository, ISfxPlayer sfxPlayer, @@ -106,7 +107,9 @@ public HudControlsFactory(IHudButtonController hudButtonController, IFixedTimeStepRepository fixedTimeStepRepository, IClickDispatcherFactory clickDispatcherFactory, IMetadataProvider weaponMetadataProvider, - ILocalizedStringFinder localizedStringFinder) + ILocalizedStringFinder localizedStringFinder, + ICharacterRendererProvider characterRendererProvider, + INPCRendererProvider npcRendererProvider) { _hudButtonController = hudButtonController; _hudPanelFactory = hudPanelFactory; @@ -130,7 +133,7 @@ public HudControlsFactory(IHudButtonController hudButtonController, _characterActions = characterActions; _walkValidationActions = walkValidationActions; _chatBubbleActions = chatBubbleActions; - _packetSendService = packetSendService; + _unknownEntitiesRequestActions = unknownEntitiesRequestActions; _userInputTimeProvider = userInputTimeProvider; _spellSlotDataRepository = spellSlotDataRepository; _sfxPlayer = sfxPlayer; @@ -140,6 +143,8 @@ public HudControlsFactory(IHudButtonController hudButtonController, _clickDispatcherFactory = clickDispatcherFactory; _weaponMetadataProvider = weaponMetadataProvider; _localizedStringFinder = localizedStringFinder; + _characterRendererProvider = characterRendererProvider; + _npcRendererProvider = npcRendererProvider; } public void InjectChatController(IChatController chatController, @@ -547,7 +552,8 @@ private PeriodicStatUpdaterComponent CreatePeriodicStatUpdater() private UnknownEntitiesRequester CreateUnknownEntitiesRequester() { - return new UnknownEntitiesRequester(_endlessGameProvider, _clientWindowSizeRepository, (ICharacterProvider)_characterRepository, _currentMapStateRepository, _packetSendService); + return new UnknownEntitiesRequester(_endlessGameProvider, _clientWindowSizeRepository, (ICharacterProvider)_characterRepository, _currentMapStateRepository, + _npcRendererProvider, _characterRendererProvider, _unknownEntitiesRequestActions); } private StatusBarLabel CreateStatusLabel() diff --git a/EndlessClient/HUD/HudButtonController.cs b/EndlessClient/HUD/HudButtonController.cs index 2d9ce28af..bc7947a3a 100644 --- a/EndlessClient/HUD/HudButtonController.cs +++ b/EndlessClient/HUD/HudButtonController.cs @@ -3,6 +3,7 @@ using EOLib.Domain.Interact.Quest; using EOLib.Domain.Online; using EOLib.Localization; +using Moffat.EndlessOnline.SDK.Protocol.Net; namespace EndlessClient.HUD { diff --git a/EndlessClient/HUD/Panels/InventoryPanel.cs b/EndlessClient/HUD/Panels/InventoryPanel.cs index a83e58e9a..b2956f8b7 100644 --- a/EndlessClient/HUD/Panels/InventoryPanel.cs +++ b/EndlessClient/HUD/Panels/InventoryPanel.cs @@ -11,6 +11,7 @@ using EOLib.Domain.Character; using EOLib.Domain.Item; using EOLib.Domain.Login; +using EOLib.Domain.Map; using EOLib.Graphics; using EOLib.IO; using EOLib.IO.Extensions; @@ -20,7 +21,6 @@ using EOLib.Localization; using Microsoft.Win32; using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; using MonoGame.Extended.Input; using Optional; using Optional.Collections; @@ -173,7 +173,7 @@ protected override void OnDrawOrderChanged(object sender, EventArgs args) } } - protected override void OnUpdateControl(GameTime gameTime) + protected override void OnUnconditionalUpdateControl(GameTime gameTime) { _cachedStats.Match( some: stats => @@ -407,7 +407,7 @@ private void HandleItemDoneDragging(object sender, DragCompletedEventArgs true, + _ => false, + }; } - private static Rectangle? GetChatIconSourceRectangle(OnlineIcon icon) + private static Rectangle? GetChatIconSourceRectangle(CharacterIcon icon) { var (x, y, width, height) = icon.ToChatIcon().GetChatIconRectangleBounds().ValueOrDefault(); return new Rectangle(x, y, width, height); diff --git a/EndlessClient/HUD/Panels/PartyPanel.cs b/EndlessClient/HUD/Panels/PartyPanel.cs index 3b672f521..40bc1a4ea 100644 --- a/EndlessClient/HUD/Panels/PartyPanel.cs +++ b/EndlessClient/HUD/Panels/PartyPanel.cs @@ -82,7 +82,7 @@ protected override void OnUpdateControl(GameTime gameTime) { var added = _partyDataProvider.Members.Where(x => !_cachedParty.Any(y => y.CharacterID == x.CharacterID)).ToList(); var removed = _cachedParty.Where(x => !_partyDataProvider.Members.Any(y => y.CharacterID == x.CharacterID)).ToList(); - var updated = _cachedParty.Where(x => _partyDataProvider.Members.Any(y => y.CharacterID == x.CharacterID && !y.Equals(x))).ToList(); + var updated = _partyDataProvider.Members.Where(x => _cachedParty.Any(y => y.CharacterID == x.CharacterID && !y.Equals(x))).ToList(); _cachedParty = _partyDataProvider.Members.ToHashSet(); var mainCharacterIsLeader = _cachedParty.Any(x => x.IsLeader && x.CharacterID == _characterProvider.MainCharacter.ID); diff --git a/EndlessClient/HUD/UserInterfaceActions.cs b/EndlessClient/HUD/UserInterfaceActions.cs index 721b1571f..9fe7de27d 100644 --- a/EndlessClient/HUD/UserInterfaceActions.cs +++ b/EndlessClient/HUD/UserInterfaceActions.cs @@ -5,7 +5,7 @@ using EOLib.Domain.Notifiers; using EOLib.IO.Repositories; using EOLib.Localization; -using EOLib.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net; using System; using System.Collections.Generic; using System.Linq; @@ -35,7 +35,7 @@ public void NotifyPacketDialog(PacketFamily packetFamily) case PacketFamily.Locker: _inGameDialogActions.ShowLockerDialog(); break; case PacketFamily.Chest: _inGameDialogActions.ShowChestDialog(); break; case PacketFamily.Board: _inGameDialogActions.ShowBoardDialog(); break; - case PacketFamily.JukeBox: _inGameDialogActions.ShowJukeboxDialog(MapCoordinate.Zero); break; + case PacketFamily.Jukebox: _inGameDialogActions.ShowJukeboxDialog(); break; } } diff --git a/EndlessClient/Input/UnwalkableTileActionsHandler.cs b/EndlessClient/Input/UnwalkableTileActionsHandler.cs index 94d7963ee..0f261fe57 100644 --- a/EndlessClient/Input/UnwalkableTileActionsHandler.cs +++ b/EndlessClient/Input/UnwalkableTileActionsHandler.cs @@ -37,7 +37,7 @@ public void HandleUnwalkableTileActions(IReadOnlyList unwa _inGameDialogActions.ShowLockerDialog(); break; case UnwalkableTileAction.Chair: - _characterActions.SitInChair(); + _characterActions.Sit(cellState.Coordinate, isChair: true); break; case UnwalkableTileAction.Door: cellState.Warp.MatchSome(w => _mapActions.OpenDoor(w)); @@ -48,7 +48,7 @@ public void HandleUnwalkableTileActions(IReadOnlyList unwa break; case UnwalkableTileAction.Jukebox: _mapActions.OpenJukebox(cellState.Coordinate); - _inGameDialogActions.ShowJukeboxDialog(cellState.Coordinate); + _inGameDialogActions.ShowJukeboxDialog(); break; } } diff --git a/EndlessClient/Network/PacketHandlerGameComponent.cs b/EndlessClient/Network/PacketHandlerGameComponent.cs index ed4c587ae..57051d0db 100644 --- a/EndlessClient/Network/PacketHandlerGameComponent.cs +++ b/EndlessClient/Network/PacketHandlerGameComponent.cs @@ -2,6 +2,7 @@ using EndlessClient.Controllers; using EndlessClient.GameExecution; using EOLib.Net.Communication; +using EOLib.Net.Connection; using EOLib.Net.Handlers; using Microsoft.Xna.Framework; @@ -12,19 +13,19 @@ public class PacketHandlerGameComponent : GameComponent { private readonly IOutOfBandPacketHandler _packetHandler; private readonly INetworkClientProvider _networkClientProvider; - private readonly IGameStateProvider _gameStateProvider; + private readonly IBackgroundReceiveTaskRepository _backgroundReceiveTaskRepository; private readonly IMainButtonController _mainButtonController; public PacketHandlerGameComponent(IEndlessGame game, IOutOfBandPacketHandler packetHandler, INetworkClientProvider networkClientProvider, - IGameStateProvider gameStateProvider, + IBackgroundReceiveTaskRepository backgroundReceiveTaskRepository, IMainButtonController mainButtonController) : base((Game) game) { _packetHandler = packetHandler; _networkClientProvider = networkClientProvider; - _gameStateProvider = gameStateProvider; + _backgroundReceiveTaskRepository = backgroundReceiveTaskRepository; _mainButtonController = mainButtonController; UpdateOrder = int.MinValue; @@ -32,12 +33,15 @@ public PacketHandlerGameComponent(IEndlessGame game, public override void Update(GameTime gameTime) { - if (_networkClientProvider.NetworkClient != null && - _networkClientProvider.NetworkClient.Started && - !_networkClientProvider.NetworkClient.Connected) + if (_networkClientProvider.NetworkClient != null && _networkClientProvider.NetworkClient.Started) { - var isInGame = _gameStateProvider.CurrentState == GameStates.PlayingTheGame; - _mainButtonController.GoToInitialStateAndDisconnect(showLostConnection: true); + var connected = _networkClientProvider.NetworkClient.Connected; + var receiveLoopFaulted = _backgroundReceiveTaskRepository.Task?.IsFaulted ?? false; + + if (!connected || receiveLoopFaulted) + { + _mainButtonController.GoToInitialStateAndDisconnect(showLostConnection: true); + } } _packetHandler.PollForPacketsAndHandle(); diff --git a/EndlessClient/Network/UnknownEntitiesRequester.cs b/EndlessClient/Network/UnknownEntitiesRequester.cs index 4a66768d9..21ddb08ba 100644 --- a/EndlessClient/Network/UnknownEntitiesRequester.cs +++ b/EndlessClient/Network/UnknownEntitiesRequester.cs @@ -1,128 +1,78 @@ using EndlessClient.GameExecution; using EndlessClient.Rendering; +using EndlessClient.Rendering.Character; +using EndlessClient.Rendering.NPC; using EOLib.Domain.Character; using EOLib.Domain.Map; using EOLib.Domain.NPC; using EOLib.IO.Map; -using EOLib.Net; -using EOLib.Net.Communication; using Microsoft.Xna.Framework; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; -using System.Reflection.Metadata.Ecma335; namespace EndlessClient.Network { public class UnknownEntitiesRequester : GameComponent { - private const int UPPER_SEE_DISTANCE = 11; - private const int LOWER_SEE_DISTANCE = 14; + private const int UPPER_SEE_DISTANCE = 12; + private const int LOWER_SEE_DISTANCE = 15; - private const double REQUEST_INTERVAL_SECONDS = 1.0; + private const int REQUEST_INTERVAL_MS = 1000; private readonly IClientWindowSizeProvider _clientWindowSizeProvider; private readonly ICharacterProvider _characterProvider; private readonly ICurrentMapStateRepository _currentMapStateRepository; - private readonly IPacketSendService _packetSendService; + private readonly INPCRendererProvider _npcRendererProvider; + private readonly ICharacterRendererProvider _characterRendererProvider; + private readonly IUnknownEntitiesRequestActions _unknownEntitiesRequestActions; - private DateTime _lastRequestTime; - + private readonly Stopwatch _requestTimer; - // todo: create actions in EOLib.Domain for requesting unknown entities, instead of using packetsendservice directly public UnknownEntitiesRequester(IEndlessGameProvider gameProvider, IClientWindowSizeProvider clientWindowSizeProvider, ICharacterProvider characterProvider, ICurrentMapStateRepository currentMapStateRepository, - IPacketSendService packetSendService) + INPCRendererProvider npcRendererProvider, + ICharacterRendererProvider characterRendererProvider, + IUnknownEntitiesRequestActions unknownEntitiesRequestActions) : base((Game) gameProvider.Game) { _clientWindowSizeProvider = clientWindowSizeProvider; _characterProvider = characterProvider; _currentMapStateRepository = currentMapStateRepository; - _packetSendService = packetSendService; - _lastRequestTime = DateTime.Now; + _npcRendererProvider = npcRendererProvider; + _characterRendererProvider = characterRendererProvider; + _unknownEntitiesRequestActions = unknownEntitiesRequestActions; + _requestTimer = Stopwatch.StartNew(); } public override void Update(GameTime gameTime) { - if ((DateTime.Now - _lastRequestTime).TotalSeconds >= REQUEST_INTERVAL_SECONDS) + if (_requestTimer.ElapsedMilliseconds >= REQUEST_INTERVAL_MS) { - IPacket request = null; + ClearOutOfRangeActors(); + if (_currentMapStateRepository.UnknownNPCIndexes.Count > 0 && _currentMapStateRepository.UnknownPlayerIDs.Count > 0) { - request = CreateRequestForBoth(); + _unknownEntitiesRequestActions.RequestAll(); } else if (_currentMapStateRepository.UnknownNPCIndexes.Count > 0) { - request = CreateRequestForNPCs(); + _unknownEntitiesRequestActions.RequestUnknownNPCs(); } else if (_currentMapStateRepository.UnknownPlayerIDs.Count > 0) { - request = CreateRequestForPlayers(); - } - - try - { - if (request != null) - { - _packetSendService.SendPacket(request); - _currentMapStateRepository.UnknownNPCIndexes.Clear(); - _currentMapStateRepository.UnknownPlayerIDs.Clear(); - } - } - catch (NoDataSentException) - { } // Swallow error. Will try again on next interval - finally - { - _lastRequestTime = DateTime.Now; + _unknownEntitiesRequestActions.RequestUnknownPlayers(); } - ClearOutOfRangeActors(); + _requestTimer.Restart(); } base.Update(gameTime); } - private IPacket CreateRequestForBoth() - { - IPacketBuilder builder = new PacketBuilder(PacketFamily.MapInfo, PacketAction.Request); - foreach (var id in _currentMapStateRepository.UnknownPlayerIDs) - { - builder = builder.AddShort(id); - } - builder = builder.AddByte(0xFF); - foreach (var index in _currentMapStateRepository.UnknownNPCIndexes) - { - builder = builder.AddChar(index); - } - - return builder.Build(); - } - - private IPacket CreateRequestForNPCs() - { - IPacketBuilder builder = new PacketBuilder(PacketFamily.NPCMapInfo, PacketAction.Request) - .AddChar(_currentMapStateRepository.UnknownNPCIndexes.Count) - .AddByte(0xFF); - - foreach (var index in _currentMapStateRepository.UnknownNPCIndexes) - { - builder = builder.AddChar(index); - } - return builder.Build(); - } - - private IPacket CreateRequestForPlayers() - { - IPacketBuilder builder = new PacketBuilder(PacketFamily.CharacterMapInfo, PacketAction.Request); - foreach (var id in _currentMapStateRepository.UnknownPlayerIDs) - { - builder = builder.AddShort(id); - } - return builder.Build(); - } - private void ClearOutOfRangeActors() { var mc = _characterProvider.MainCharacter; @@ -153,9 +103,9 @@ private void ClearOutOfRangeActors() foreach (var entity in entitiesToRemove) { - if (entity is Character c) + if (entity is Character c && _characterRendererProvider.CharacterRenderers.ContainsKey(c.ID)) _currentMapStateRepository.Characters.Remove(c); - else if (entity is NPC n) + else if (entity is NPC n && _npcRendererProvider.NPCRenderers.ContainsKey(n.Index)) _currentMapStateRepository.NPCs.Remove(n); else if (entity is MapItem i) _currentMapStateRepository.MapItems.Remove(i); diff --git a/EndlessClient/Rendering/Character/CharacterAnimationActions.cs b/EndlessClient/Rendering/Character/CharacterAnimationActions.cs index 734464736..7db24db09 100644 --- a/EndlessClient/Rendering/Character/CharacterAnimationActions.cs +++ b/EndlessClient/Rendering/Character/CharacterAnimationActions.cs @@ -18,6 +18,7 @@ using EOLib.IO.Map; using EOLib.IO.Repositories; using EOLib.Localization; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using Optional; using Optional.Collections; using System; @@ -34,7 +35,6 @@ public class CharacterAnimationActions : ICharacterAnimationActions, IOtherChara private readonly ICurrentMapStateProvider _currentMapStateProvider; private readonly ICharacterRendererProvider _characterRendererProvider; private readonly ICurrentMapProvider _currentMapProvider; - private readonly ISpikeTrapActions _spikeTrapActions; private readonly IPubFileProvider _pubFileProvider; private readonly IStatusLabelSetter _statusLabelSetter; private readonly ISfxPlayer _sfxPlayer; @@ -47,7 +47,6 @@ public CharacterAnimationActions(IHudControlProvider hudControlProvider, ICurrentMapStateProvider currentMapStateProvider, ICharacterRendererProvider characterRendererProvider, ICurrentMapProvider currentMapProvider, - ISpikeTrapActions spikeTrapActions, IPubFileProvider pubFileProvider, IStatusLabelSetter statusLabelSetter, ISfxPlayer sfxPlayer, @@ -58,7 +57,6 @@ public CharacterAnimationActions(IHudControlProvider hudControlProvider, _currentMapStateProvider = currentMapStateProvider; _characterRendererProvider = characterRendererProvider; _currentMapProvider = currentMapProvider; - _spikeTrapActions = spikeTrapActions; _pubFileProvider = pubFileProvider; _statusLabelSetter = statusLabelSetter; _sfxPlayer = sfxPlayer; @@ -134,8 +132,6 @@ public void StartOtherCharacterWalkAnimation(int characterID, MapCoordinate dest Animator.StartOtherCharacterWalkAnimation(characterID, destination, direction); ShowWaterSplashiesIfNeeded(CharacterActionState.Walking, characterID); - _spikeTrapActions.HideSpikeTrap(characterID); - _spikeTrapActions.ShowSpikeTrap(characterID); if (IsSteppingStone(character.RenderProperties)) _sfxPlayer.PlaySfx(SoundEffectID.JumpStone); @@ -153,15 +149,17 @@ public void StartOtherCharacterAttackAnimation(int characterID, int noteIndex = ShowWaterSplashiesIfNeeded(CharacterActionState.Attacking, characterID); } - public void NotifyWarpLeaveEffect(int characterId, WarpAnimation anim) + public void NotifyWarpLeaveEffect(int characterId, WarpEffect anim) { - if (anim == WarpAnimation.Admin) + if (anim == WarpEffect.Admin && _characterRendererProvider.CharacterRenderers.ContainsKey(characterId)) _characterRendererProvider.CharacterRenderers[characterId].PlayEffect((int)HardCodedEffect.WarpLeave); + else if (characterId != _characterRepository.MainCharacter.ID && anim == WarpEffect.Scroll) + _sfxPlayer.PlaySfx(SoundEffectID.ScrollTeleport); } - public void NotifyWarpEnterEffect(int characterId, WarpAnimation anim) + public void NotifyWarpEnterEffect(int characterId, WarpEffect anim) { - if (anim == WarpAnimation.Admin) + if (anim == WarpEffect.Admin) { if (!_characterRendererProvider.CharacterRenderers.ContainsKey(characterId)) _characterRendererProvider.NeedsWarpArriveAnimation.Add(characterId); @@ -257,10 +255,6 @@ public void NotifyGroupSpellCast(int playerId, int spellId, int spellHp, List(HudControlIdentifier.MapRenderer); mapRenderer.StartEarthquake(strength); _sfxPlayer.PlaySfx(SoundEffectID.Earthquake); break; - case MapEffect.HPDrain: + case EOLib.IO.Map.MapEffect.HPDrain: _sfxPlayer.PlaySfx(SoundEffectID.MapEffectHPDrain); break; - case MapEffect.TPDrain: + case EOLib.IO.Map.MapEffect.TPDrain: _sfxPlayer.PlaySfx(SoundEffectID.MapEffectTPDrain); break; - case MapEffect.Spikes: + case EOLib.IO.Map.MapEffect.Spikes: _sfxPlayer.PlaySfx(SoundEffectID.Spikes); break; } diff --git a/EndlessClient/Rendering/Character/CharacterRenderer.cs b/EndlessClient/Rendering/Character/CharacterRenderer.cs index 807918a9e..6dba6e6c3 100644 --- a/EndlessClient/Rendering/Character/CharacterRenderer.cs +++ b/EndlessClient/Rendering/Character/CharacterRenderer.cs @@ -125,25 +125,14 @@ public CharacterRenderer(Game game, _chatBubble = new Lazy(() => _chatBubbleFactory.CreateChatBubble(this)); - _clientWindowSizeRepository.GameWindowSizeChanged += (_, _) => - { - lock (_rt_locker_) - { - _charRenderTarget.Dispose(); - _charRenderTarget = _renderTargetFactory.CreateRenderTarget(); - } - }; - - if (_character == _characterProvider.MainCharacter) - _clientWindowSizeRepository.GameWindowSizeChanged += (_, _) => SetToCenterScreenPosition(); + _clientWindowSizeRepository.GameWindowSizeChanged += RecreateRenderTargetEvent; } #region Game Component public override void Initialize() { - lock(_rt_locker_) - _charRenderTarget = _renderTargetFactory.CreateRenderTarget(); + RecreateRenderTarget(); _sb = new SpriteBatch(Game.GraphicsDevice); @@ -430,7 +419,7 @@ private int GetSteppingStoneOffset(CharacterRenderProperties renderProps) private void CheckForDead() { - if (_character == _characterProvider.MainCharacter && _lastIsDead != _character.RenderProperties.IsDead) + if (_lastIsDead != _character.RenderProperties.IsDead) { _lastIsDead = _character.RenderProperties.IsDead; if (_lastIsDead) @@ -446,16 +435,20 @@ private void ClipHair() _hatMetadataProvider.GetValueOrDefault(Character.RenderProperties.HatGraphic).ClipMode != HatMaskType.Standard) return; - // oof. I really need to learn how to use shaders or stencil buffer. - // https://gamedev.stackexchange.com/questions/38118/best-way-to-mask-2d-sprites-in-xna/38150#38150 - _rtColorData = new Color[_charRenderTarget.Width * _charRenderTarget.Height]; - _charRenderTarget.GetData(_rtColorData); - for (int i = 0; i < _rtColorData.Length; i++) + lock (_rt_locker_) { - if (_rtColorData[i] == Color.Black) - _rtColorData[i].A = 0; + // oof. I really need to learn how to use shaders or stencil buffer. + // https://gamedev.stackexchange.com/questions/38118/best-way-to-mask-2d-sprites-in-xna/38150#38150 + + // note: this operation causes a high number of GC events as the character's frame changes (walking/attacking) + _charRenderTarget.GetData(_rtColorData); + for (int i = 0; i < _rtColorData.Length; i++) + { + if (_rtColorData[i] == Color.Black) + _rtColorData[i].A = 0; + } + _charRenderTarget.SetData(_rtColorData); } - _charRenderTarget.SetData(_rtColorData); } #endregion @@ -516,6 +509,25 @@ public void ShowChatBubble(string message, bool isGroupChat) _chatBubble.Value.SetMessage(message, isGroupChat); } + private void RecreateRenderTarget() + { + lock (_rt_locker_) + { + _charRenderTarget?.Dispose(); + _charRenderTarget = _renderTargetFactory.CreateRenderTarget(); + + _rtColorData = new Color[_charRenderTarget.Width * _charRenderTarget.Height]; + } + } + + private void RecreateRenderTargetEvent(object sender, EventArgs e) + { + RecreateRenderTarget(); + + if (_character == _characterProvider.MainCharacter) + SetToCenterScreenPosition(); + } + protected override void Dispose(bool disposing) { if (disposing) @@ -531,6 +543,8 @@ protected override void Dispose(bool disposing) _sb?.Dispose(); + _clientWindowSizeRepository.GameWindowSizeChanged -= RecreateRenderTargetEvent; + lock(_rt_locker_) _charRenderTarget?.Dispose(); } diff --git a/EndlessClient/Rendering/ContextMenuRenderer.cs b/EndlessClient/Rendering/ContextMenuRenderer.cs index cbb7e0815..cafc92f9a 100644 --- a/EndlessClient/Rendering/ContextMenuRenderer.cs +++ b/EndlessClient/Rendering/ContextMenuRenderer.cs @@ -16,6 +16,7 @@ using EOLib.Localization; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using Moffat.EndlessOnline.SDK.Protocol.Net; using MonoGame.Extended.Input; using MonoGame.Extended.Input.InputListeners; using Optional; diff --git a/EndlessClient/Rendering/Map/DynamicMapObjectUpdater.cs b/EndlessClient/Rendering/Map/DynamicMapObjectUpdater.cs index 825744af6..3c93819a2 100644 --- a/EndlessClient/Rendering/Map/DynamicMapObjectUpdater.cs +++ b/EndlessClient/Rendering/Map/DynamicMapObjectUpdater.cs @@ -64,7 +64,6 @@ public void UpdateMapObjects(GameTime gameTime) OpenNewDoors(now); CloseExpiredDoors(now); - RemoveStaleSpikeTraps(); UpdateAmbientNoiseVolume(); HideStackedCharacterNames(); @@ -94,24 +93,6 @@ private void CloseExpiredDoors(DateTime now) } } - private void RemoveStaleSpikeTraps() - { - var staleTraps = new List(); - - foreach (var spikeTrap in _currentMapStateRepository.VisibleSpikeTraps) - { - if (_currentMapStateRepository.Characters - .Concat(new[] { _characterProvider.MainCharacter }) - .Select(x => x.RenderProperties) - .All(x => x.MapX != spikeTrap.X && x.MapY != spikeTrap.Y)) - { - staleTraps.Add(spikeTrap); - } - } - - _currentMapStateRepository.VisibleSpikeTraps.RemoveWhere(staleTraps.Contains); - } - private void UpdateAmbientNoiseVolume() { if (_cachedMap.Properties.AmbientNoise <= 0 || !_configurationProvider.SoundEnabled) @@ -121,9 +102,7 @@ private void UpdateAmbientNoiseVolume() // distance is the sum of the components of the vector from character position to closest ambient source // this is scaled from 0-25, with 0 being on top of the tile and 25 being too far away to hear the ambient sound from it var props = _characterProvider.MainCharacter.RenderProperties; - var charCoord = props.CurrentAction == CharacterActionState.Walking - ? new MapCoordinate(props.GetDestinationX(), props.GetDestinationY()) - : new MapCoordinate(props.MapX, props.MapY); + var charCoord = props.CurrentAction == CharacterActionState.Walking ? props.DestinationCoordinates() : props.Coordinates(); var shortestDistance = int.MaxValue; foreach (var coordinate in _ambientSounds) { diff --git a/EndlessClient/Rendering/Map/MapChangedActions.cs b/EndlessClient/Rendering/Map/MapChangedActions.cs index cb5962e66..9d4d40d5a 100644 --- a/EndlessClient/Rendering/Map/MapChangedActions.cs +++ b/EndlessClient/Rendering/Map/MapChangedActions.cs @@ -15,6 +15,7 @@ using EOLib.IO.Map; using EOLib.IO.Repositories; using EOLib.Localization; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; using System.Linq; namespace EndlessClient.Rendering.Map @@ -84,7 +85,7 @@ public void ActiveCharacterEnterMapForLogin() ShowPkWarning(differentMapId: true); } - public void NotifyMapChanged(WarpAnimation warpAnimation, bool differentMapID) + public void NotifyMapChanged(WarpEffect warpAnimation, bool differentMapID) { StopAllAnimations(); ClearCharacterRenderersAndCache(); @@ -93,7 +94,6 @@ public void NotifyMapChanged(WarpAnimation warpAnimation, bool differentMapID) ShowMapNameIfAvailable(differentMapID); ShowPkWarning(differentMapID); ShowMapTransition(differentMapID); - AddSpikeTraps(); ShowWarpBubbles(warpAnimation); PlayBackgroundMusic(differentMapID); PlayAmbientNoise(differentMapID); @@ -109,11 +109,9 @@ public void NotifyMapChanged(WarpAnimation warpAnimation, bool differentMapID) 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); @@ -165,11 +163,6 @@ 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)) @@ -205,20 +198,11 @@ private void ShowMapTransition(bool showMapTransition) } } - private void AddSpikeTraps() - { - foreach (var character in _currentMapStateRepository.Characters) - { - if (_currentMapProvider.CurrentMap.Tiles[character.RenderProperties.MapY, character.RenderProperties.MapX] == TileSpec.SpikesTrap) - _currentMapStateRepository.VisibleSpikeTraps.Add(new MapCoordinate(character.RenderProperties.MapX, character.RenderProperties.MapY)); - } - } - - private void ShowWarpBubbles(WarpAnimation animation) + private void ShowWarpBubbles(WarpEffect animation) { _characterRendererRepository.MainCharacterRenderer.MatchSome(r => { - if (animation == WarpAnimation.Admin) + if (animation == WarpEffect.Admin) r.PlayEffect((int)HardCodedEffect.WarpArrive); }); } diff --git a/EndlessClient/Rendering/Map/MapRenderer.cs b/EndlessClient/Rendering/Map/MapRenderer.cs index 236153146..4ce993b61 100644 --- a/EndlessClient/Rendering/Map/MapRenderer.cs +++ b/EndlessClient/Rendering/Map/MapRenderer.cs @@ -16,6 +16,7 @@ using Optional; using System; using System.Collections.Generic; +using System.Linq; namespace EndlessClient.Rendering.Map { @@ -45,7 +46,7 @@ public class MapRenderer : DrawableGameComponent, IMapRenderer private RenderTarget2D _mapBaseTarget, _mapObjectTarget; private SpriteBatch _sb; private MapTransitionState _mapTransitionState = MapTransitionState.Default; - private int? _lastMapChecksum; + private IReadOnlyList _lastMapChecksum; private bool _groundDrawn; private Option _quakeState; @@ -122,7 +123,7 @@ public override void Update(GameTime gameTime) { if (_currentMapStateProvider.IsSleepWarp) return; - if (!_lastMapChecksum.HasValue || _lastMapChecksum != _currentMapProvider.CurrentMap.Properties.ChecksumInt) + if (_lastMapChecksum == null || !_lastMapChecksum.SequenceEqual(_currentMapProvider.CurrentMap.Properties.Checksum)) { // The dimensions of the map are 0-based in the properties. Adjust to 1-based for RT creation var widthPlus1 = _currentMapProvider.CurrentMap.Properties.Width + 1; @@ -163,7 +164,7 @@ public override void Update(GameTime gameTime) } } - _lastMapChecksum = _currentMapProvider.CurrentMap.Properties.ChecksumInt; + _lastMapChecksum = _currentMapProvider.CurrentMap.Properties.Checksum; base.Update(gameTime); } @@ -270,7 +271,7 @@ private void UpdateQuakeState() private void DrawGroundLayerToRenderTarget() { - if (_groundDrawn && (!_mapTransitionState.StartTime.HasValue && _lastMapChecksum == _currentMapProvider.CurrentMap.Properties.ChecksumInt)) + if (_groundDrawn && !_mapTransitionState.StartTime.HasValue && _lastMapChecksum == _currentMapProvider.CurrentMap.Properties.Checksum) return; _groundDrawn = true; @@ -372,8 +373,10 @@ void RenderGridSpace(int row, int col) { var alpha = GetAlphaForCoordinates(col, row, immutableCharacter); - foreach (var renderer in _mapEntityRendererProvider.MapEntityRenderers) + for (int i = 0; i < _mapEntityRendererProvider.MapEntityRenderers.Count; i++) { + var renderer = _mapEntityRendererProvider.MapEntityRenderers[i]; + if (!renderer.CanRender(row, col)) continue; @@ -431,8 +434,9 @@ private void DrawBaseLayers(SpriteBatch spriteBatch) { var alpha = GetAlphaForCoordinates(col, row, _characterProvider.MainCharacter); - foreach (var renderer in _mapEntityRendererProvider.BaseRenderers) + for (int i = 0; i < _mapEntityRendererProvider.BaseRenderers.Count; i++) { + var renderer = _mapEntityRendererProvider.BaseRenderers[i]; if (renderer.CanRender(row, col)) renderer.RenderElementAt(spriteBatch, row, col, alpha, new Vector2(offset, 0)); } diff --git a/EndlessClient/Rendering/Map/MiniMapRenderer.cs b/EndlessClient/Rendering/Map/MiniMapRenderer.cs index d83895804..c6821ae5d 100644 --- a/EndlessClient/Rendering/Map/MiniMapRenderer.cs +++ b/EndlessClient/Rendering/Map/MiniMapRenderer.cs @@ -7,6 +7,7 @@ using EOLib.IO.Repositories; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using System.Collections.Generic; using System.Linq; using XNAControls; @@ -42,7 +43,7 @@ private enum MiniMapGfx private readonly Texture2D _miniMapTexture; private RenderTarget2D _miniMapTarget; - private int? _lastMapChecksum; + private IReadOnlyList _lastMapChecksum; public MiniMapRenderer(INativeGraphicsManager nativeGraphicsManager, IRenderTargetFactory renderTargetFactory, @@ -78,7 +79,7 @@ protected override bool ShouldDraw() protected override void OnUpdateControl(GameTime gameTime) { - if (_lastMapChecksum == null || _lastMapChecksum != _currentMapProvider.CurrentMap.Properties.ChecksumInt) + if (_lastMapChecksum == null || !_lastMapChecksum.SequenceEqual(_currentMapProvider.CurrentMap.Properties.Checksum)) { // The dimensions of the map are 0-based in the properties. Adjust to 1-based for RT creation var widthPlus1 = _currentMapProvider.CurrentMap.Properties.Width + 1; @@ -95,7 +96,7 @@ protected override void OnUpdateControl(GameTime gameTime) DrawFixedMapElementsToRenderTarget(); } - _lastMapChecksum = _currentMapProvider.CurrentMap.Properties.ChecksumInt; + _lastMapChecksum = _currentMapProvider.CurrentMap.Properties.Checksum; base.OnUpdateControl(gameTime); } @@ -207,7 +208,7 @@ Rectangle GetNPCSourceRectangle(EOLib.Domain.NPC.NPC npc) private void DrawFixedMapElementsToRenderTarget() { - if (_lastMapChecksum.HasValue && _lastMapChecksum == _currentMapProvider.CurrentMap.Properties.ChecksumInt) + if (_lastMapChecksum != null && _lastMapChecksum.SequenceEqual(_currentMapProvider.CurrentMap.Properties.Checksum)) return; GraphicsDevice.SetRenderTarget(_miniMapTarget); @@ -252,13 +253,10 @@ private void DrawGridBox(Vector2 loc, MiniMapGfx? edgeGfx, Rectangle gridSpaceSo private Vector2 GetMiniMapDrawCoordinates(int x, int y) { - // these are the same as in MouseCursorRenderer - var widthFactor = _clientWindowSizeProvider.Resizable - ? _clientWindowSizeProvider.Width / 2 // 288 = 640 * .45, viewport width factor - : _clientWindowSizeProvider.Width * 9 / 10; // 288 = 640 * .45, 576 = 640 * .9 + var widthFactor = _clientWindowSizeProvider.Width / 2; var heightFactor = _clientWindowSizeProvider.Resizable ? _clientWindowSizeProvider.Height / 2 // 144 = 480 * .45, viewport height factor - : _clientWindowSizeProvider.Height * 3 / 10; + : _clientWindowSizeProvider.Height * 3 / 10 - 2; var tileWidthFactor = TileWidth / 2; var tileHeightFactor = TileHeight / 2; diff --git a/EndlessClient/Rendering/Map/SpikeTrapActions.cs b/EndlessClient/Rendering/Map/SpikeTrapActions.cs deleted file mode 100644 index a15a16864..000000000 --- a/EndlessClient/Rendering/Map/SpikeTrapActions.cs +++ /dev/null @@ -1,71 +0,0 @@ -using AutomaticTypeMapper; -using EndlessClient.Audio; -using EOLib.Domain.Extensions; -using EOLib.Domain.Map; -using EOLib.IO.Map; - -namespace EndlessClient.Rendering.Map -{ - [AutoMappedType] - public class SpikeTrapActions : ISpikeTrapActions - { - private readonly ICurrentMapStateRepository _currentMapStateRepository; - private readonly ICurrentMapProvider _currentMapProvider; - private readonly ISfxPlayer _sfxPlayer; - - public SpikeTrapActions(ICurrentMapStateRepository currentMapStateRepository, - ICurrentMapProvider currentMapProvider, - ISfxPlayer sfxPlayer) - { - _currentMapStateRepository = currentMapStateRepository; - _currentMapProvider = currentMapProvider; - _sfxPlayer = sfxPlayer; - } - - public void ShowSpikeTrap(MapCoordinate coordinate, bool isMainCharacter = false) - { - if (!_currentMapStateRepository.VisibleSpikeTraps.Contains(coordinate) && - _currentMapProvider.CurrentMap.Tiles[coordinate.Y, coordinate.X] == TileSpec.SpikesTrap) - { - _currentMapStateRepository.VisibleSpikeTraps.Add(coordinate); - - if (isMainCharacter) - { - _sfxPlayer.PlaySfx(SoundEffectID.Spikes); - } - } - } - - public void ShowSpikeTrap(int characterId) - { - if (!_currentMapStateRepository.Characters.TryGetValue(characterId, out var character)) - return; - - ShowSpikeTrap(new MapCoordinate(character.X, character.Y)); - } - - public void HideSpikeTrap(MapCoordinate coordinate) - { - _currentMapStateRepository.VisibleSpikeTraps.Remove(coordinate); - } - - public void HideSpikeTrap(int characterId) - { - if (!_currentMapStateRepository.Characters.TryGetValue(characterId, out var character)) - return; - - HideSpikeTrap(new MapCoordinate(character.X, character.Y)); - } - } - - public interface ISpikeTrapActions - { - void ShowSpikeTrap(MapCoordinate coordinate, bool isMainCharacter = false); - - void ShowSpikeTrap(int characterId); - - void HideSpikeTrap(MapCoordinate coordinate); - - void HideSpikeTrap(int characterId); - } -} diff --git a/EndlessClient/Rendering/MapEntityRenderers/MainCharacterEntityRenderer.cs b/EndlessClient/Rendering/MapEntityRenderers/MainCharacterEntityRenderer.cs index b5a9814cd..f88df7d2a 100644 --- a/EndlessClient/Rendering/MapEntityRenderers/MainCharacterEntityRenderer.cs +++ b/EndlessClient/Rendering/MapEntityRenderers/MainCharacterEntityRenderer.cs @@ -31,7 +31,7 @@ public MainCharacterEntityRenderer(ICharacterProvider characterProvider, protected override bool ElementExistsAt(int row, int col) { var rp = _characterProvider.MainCharacter.RenderProperties; - if (!rp.IsActing(CharacterActionState.Walking)) + if (rp.CurrentAction != CharacterActionState.Walking) { return row == rp.MapY && col == rp.MapX; } diff --git a/EndlessClient/Rendering/MapEntityRenderers/MapItemLayerRenderer.cs b/EndlessClient/Rendering/MapEntityRenderers/MapItemLayerRenderer.cs index 24787a129..8c295783e 100644 --- a/EndlessClient/Rendering/MapEntityRenderers/MapItemLayerRenderer.cs +++ b/EndlessClient/Rendering/MapEntityRenderers/MapItemLayerRenderer.cs @@ -30,7 +30,7 @@ public MapItemLayerRenderer(ICharacterProvider characterProvider, protected override bool ElementExistsAt(int row, int col) { - return _currentMapStateProvider.MapItems.TryGetValues(new MapCoordinate(col, row), out var mapItems) && mapItems.Count > 0; + return _currentMapStateProvider.MapItems.ContainsKey(new MapCoordinate(col, row)); } public override void RenderElementAt(SpriteBatch spriteBatch, int row, int col, int alpha, Vector2 additionalOffset = default) diff --git a/EndlessClient/Rendering/MapEntityRenderers/MapObjectLayerRenderer.cs b/EndlessClient/Rendering/MapEntityRenderers/MapObjectLayerRenderer.cs index adb196a60..64c400238 100644 --- a/EndlessClient/Rendering/MapEntityRenderers/MapObjectLayerRenderer.cs +++ b/EndlessClient/Rendering/MapEntityRenderers/MapObjectLayerRenderer.cs @@ -1,17 +1,23 @@ using System; +using System.DirectoryServices.ActiveDirectory; using System.Linq; using EndlessClient.Rendering.Map; using EOLib.Domain.Character; +using EOLib.Domain.Extensions; using EOLib.Domain.Map; using EOLib.Graphics; using EOLib.IO.Map; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using DomainCharacter = EOLib.Domain.Character.Character; + namespace EndlessClient.Rendering.MapEntityRenderers { public class MapObjectLayerRenderer : BaseMapEntityRenderer { + private const int TIMED_SPIKE_DURATION_MS = 1000; + private readonly INativeGraphicsManager _nativeGraphicsManager; private readonly ICurrentMapProvider _currentMapProvider; private readonly ICurrentMapStateProvider _currentMapStateProvider; @@ -35,13 +41,37 @@ public MapObjectLayerRenderer(INativeGraphicsManager nativeGraphicsManager, protected override bool ElementExistsAt(int row, int col) { - return MapFile.GFX[MapLayer.Objects][row, col] > 0 && - (MapFile.Tiles[row, col] != TileSpec.SpikesTrap || - _currentMapStateProvider.VisibleSpikeTraps.Contains(new MapCoordinate(col, row))); + return MapFile.GFX[MapLayer.Objects][row, col] > 0; } public override void RenderElementAt(SpriteBatch spriteBatch, int row, int col, int alpha, Vector2 additionalOffset = default) { + if (MapFile.Tiles[row, col] == TileSpec.SpikesTrap) + { + var loc = new MapCoordinate(col, row); + var mainCharacterAt = CharacterAt(_characterProvider.MainCharacter, loc); + if (!mainCharacterAt && _currentMapStateProvider.Characters.ContainsKey(loc)) + { + var anyOtherCharactersAt = _currentMapStateProvider.Characters[loc].Any(x => CharacterAt(x, loc)); + if (!anyOtherCharactersAt) + { + return; + } + } + else if (!mainCharacterAt) + { + return; + } + } + else if (MapFile.Tiles[row, col] == TileSpec.SpikesTimed) + { + var shouldRender = _currentMapStateProvider.LastTimedSpikeEvent + .Map(time => (DateTime.Now - time).TotalMilliseconds <= TIMED_SPIKE_DURATION_MS) + .ValueOr(false); + if (!shouldRender) + return; + } + int gfxNum = MapFile.GFX[MapLayer.Objects][row, col]; var gfx = _nativeGraphicsManager.TextureFromResource(GFXTypes.MapObjects, gfxNum, true); @@ -52,5 +82,12 @@ public override void RenderElementAt(SpriteBatch spriteBatch, int row, int col, } private IMapFile MapFile => _currentMapProvider.CurrentMap; + + private static bool CharacterAt(DomainCharacter c, MapCoordinate tile) + { + return c.RenderProperties.CurrentAction != CharacterActionState.Walking + ? tile == c.RenderProperties.Coordinates() + : tile == c.RenderProperties.DestinationCoordinates(); + } } } diff --git a/EndlessClient/Rendering/NPC/NPCRenderer.cs b/EndlessClient/Rendering/NPC/NPCRenderer.cs index c003538f6..0ffc99ec0 100644 --- a/EndlessClient/Rendering/NPC/NPCRenderer.cs +++ b/EndlessClient/Rendering/NPC/NPCRenderer.cs @@ -93,14 +93,7 @@ public NPCRenderer(IEndlessGameProvider endlessGameProvider, _lastStandingAnimation = DateTime.Now; _fadeAwayAlpha = 255; - _clientWindowSizeProvider.GameWindowSizeChanged += (_, _) => - { - lock (_rt_locker_) - { - _npcRenderTarget.Dispose(); - _npcRenderTarget = _renderTargetFactory.CreateRenderTarget(); - } - }; + _clientWindowSizeProvider.GameWindowSizeChanged += RecreateRenderTarget; _healthBarRenderer = _healthBarRendererFactory.CreateHealthBarRenderer(this); } @@ -203,8 +196,10 @@ public void StartDying() public void ShowDamageCounter(int damage, int percentHealth, bool isHeal) { var optionalDamage = damage.SomeWhen(d => d > 0); - _healthBarRenderer.SetDamage(optionalDamage, percentHealth, () => _chatBubble?.Show()); + _healthBarRenderer.SetDamage(optionalDamage, percentHealth, ShowChatBubble); _chatBubble?.Hide(); + + void ShowChatBubble() => _chatBubble?.Show(); } public void ShowChatBubble(string message, bool isGroupChat) @@ -318,6 +313,15 @@ private void DrawToRenderTarget() } } + private void RecreateRenderTarget(object sender, EventArgs e) + { + lock (_rt_locker_) + { + _npcRenderTarget.Dispose(); + _npcRenderTarget = _renderTargetFactory.CreateRenderTarget(); + } + } + private Vector2 GetNameLabelPosition() { return new Vector2(HorizontalCenter - (_nameLabel.ActualWidth / 2f), NameLabelY); @@ -333,6 +337,8 @@ protected override void Dispose(bool disposing) lock (_rt_locker_) _npcRenderTarget?.Dispose(); + + _clientWindowSizeProvider.GameWindowSizeChanged -= RecreateRenderTarget; } base.Dispose(disposing); diff --git a/EndlessClient/Rendering/Sprites/CharacterSpriteCalculator.cs b/EndlessClient/Rendering/Sprites/CharacterSpriteCalculator.cs index 7da2d8533..e1fcfbb79 100644 --- a/EndlessClient/Rendering/Sprites/CharacterSpriteCalculator.cs +++ b/EndlessClient/Rendering/Sprites/CharacterSpriteCalculator.cs @@ -150,8 +150,7 @@ public ISpriteSheet GetHatTexture(CharacterRenderProperties characterRenderPrope var gfxNumber = baseHatValue + 1 + offset; var actualMetadata = _hatMetadataProvider.GetValueOrDefault(characterRenderProperties.HatGraphic); - var isUpOrLeft = characterRenderProperties.IsFacing(EODirection.Up, EODirection.Left); - return new SpriteSheet(_gfxManager.TextureFromResource(gfxFile, gfxNumber, transparent: true, fullTransparent: actualMetadata.ClipMode != HatMaskType.Standard || isUpOrLeft)); + return new SpriteSheet(_gfxManager.TextureFromResource(gfxFile, gfxNumber, transparent: true, fullTransparent: actualMetadata.ClipMode != HatMaskType.Standard)); } public ISpriteSheet GetShieldTexture(CharacterRenderProperties characterRenderProperties) diff --git a/EndlessClient/Subscribers/JukeboxEventSubscriber.cs b/EndlessClient/Subscribers/JukeboxEventSubscriber.cs new file mode 100644 index 000000000..bdf194b66 --- /dev/null +++ b/EndlessClient/Subscribers/JukeboxEventSubscriber.cs @@ -0,0 +1,24 @@ +using AutomaticTypeMapper; +using EndlessClient.Dialogs.Factories; +using EOLib.Domain.Notifiers; +using EOLib.Localization; + +namespace EndlessClient.Subscribers +{ + [AutoMappedType] + public class JukeboxEventSubscriber : IJukeboxNotifier + { + private readonly IEOMessageBoxFactory _messageBoxFactory; + + public JukeboxEventSubscriber(IEOMessageBoxFactory messageBoxFactory) + { + _messageBoxFactory = messageBoxFactory; + } + + public void JukeboxUnavailable() + { + var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.JUKEBOX_REQUESTED_RECENTLY); + dlg.ShowDialog(); + } + } +} diff --git a/EndlessClient/Subscribers/LockerEventSubscriber.cs b/EndlessClient/Subscribers/LockerEventSubscriber.cs new file mode 100644 index 000000000..1dd5721bd --- /dev/null +++ b/EndlessClient/Subscribers/LockerEventSubscriber.cs @@ -0,0 +1,30 @@ +using AutomaticTypeMapper; +using EndlessClient.Dialogs.Factories; +using EOLib.Domain.Notifiers; +using EOLib.Localization; + +namespace EndlessClient.Subscribers +{ + [AutoMappedType] + public class LockerEventSubscriber : ILockerEventNotifier + { + private readonly IEOMessageBoxFactory _messageBoxFactory; + private readonly ILocalizedStringFinder _localizedStringFinder; + + public LockerEventSubscriber(IEOMessageBoxFactory messageBoxFactory, + ILocalizedStringFinder localizedStringFinder) + { + _messageBoxFactory = messageBoxFactory; + _localizedStringFinder = localizedStringFinder; + } + + public void NotifyLockerFull(int maxItems) + { + var message = _localizedStringFinder.GetString(DialogResourceID.LOCKER_FULL_DIFF_ITEMS_MAX + 1); + var caption = _localizedStringFinder.GetString(DialogResourceID.LOCKER_FULL_DIFF_ITEMS_MAX); + + var dlg = _messageBoxFactory.CreateMessageBox(message.Replace("25", $"{maxItems}"), caption); + dlg.ShowDialog(); + } + } +} diff --git a/EndlessClient/UIControls/CharacterInfoPanel.cs b/EndlessClient/UIControls/CharacterInfoPanel.cs index 9fe8f1875..0ba977bd4 100644 --- a/EndlessClient/UIControls/CharacterInfoPanel.cs +++ b/EndlessClient/UIControls/CharacterInfoPanel.cs @@ -10,6 +10,7 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; +using Moffat.EndlessOnline.SDK.Protocol; using System; using System.Threading.Tasks; using XNAControls; @@ -210,10 +211,10 @@ private ISpriteSheet CreateAdminGraphic(AdminLevel adminLevel) return new EmptySpriteSheet(); case AdminLevel.Spy: return new SpriteSheet(adminGraphic, new Rectangle(252, 39, 17, 17)); - case AdminLevel.Guide: + case AdminLevel.LightGuide: case AdminLevel.Guardian: - case AdminLevel.GM: - case AdminLevel.HGM: + case AdminLevel.GameMaster: + case AdminLevel.HighGameMaster: return new SpriteSheet(adminGraphic, new Rectangle(233, 39, 17, 17)); default: throw new ArgumentOutOfRangeException(nameof(adminLevel), adminLevel, null); diff --git a/PacketDecoder/MainForm.Designer.cs b/PacketDecoder/MainForm.Designer.cs deleted file mode 100644 index d87cadfc7..000000000 --- a/PacketDecoder/MainForm.Designer.cs +++ /dev/null @@ -1,349 +0,0 @@ -namespace PacketDecoder -{ - partial class MainForm - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.txtEMulti = new System.Windows.Forms.TextBox(); - this.grpMultiples = new System.Windows.Forms.GroupBox(); - this.label2 = new System.Windows.Forms.Label(); - this.txtDMulti = new System.Windows.Forms.TextBox(); - this.label1 = new System.Windows.Forms.Label(); - this.grpData = new System.Windows.Forms.GroupBox(); - this.label4 = new System.Windows.Forms.Label(); - this.txtOffset = new System.Windows.Forms.TextBox(); - this.label3 = new System.Windows.Forms.Label(); - this.txtLength = new System.Windows.Forms.TextBox(); - this.grpInput = new System.Windows.Forms.GroupBox(); - this.txtInputData = new System.Windows.Forms.TextBox(); - this.grpOutput = new System.Windows.Forms.GroupBox(); - this.lblAction = new System.Windows.Forms.Label(); - this.lblFamily = new System.Windows.Forms.Label(); - this.lblPacketLength = new System.Windows.Forms.Label(); - this.label7 = new System.Windows.Forms.Label(); - this.txtDecoded = new System.Windows.Forms.TextBox(); - this.txtOutput = new System.Windows.Forms.TextBox(); - this.label6 = new System.Windows.Forms.Label(); - this.cmbOutputFmt = new System.Windows.Forms.ComboBox(); - this.label5 = new System.Windows.Forms.Label(); - this.btnImportMultis = new System.Windows.Forms.Button(); - this.grpMultiples.SuspendLayout(); - this.grpData.SuspendLayout(); - this.grpInput.SuspendLayout(); - this.grpOutput.SuspendLayout(); - this.SuspendLayout(); - // - // txtEMulti - // - this.txtEMulti.Location = new System.Drawing.Point(69, 19); - this.txtEMulti.Name = "txtEMulti"; - this.txtEMulti.Size = new System.Drawing.Size(43, 20); - this.txtEMulti.TabIndex = 1; - this.txtEMulti.Leave += new System.EventHandler(this.intTextValidate); - // - // grpMultiples - // - this.grpMultiples.Controls.Add(this.label2); - this.grpMultiples.Controls.Add(this.txtDMulti); - this.grpMultiples.Controls.Add(this.label1); - this.grpMultiples.Controls.Add(this.txtEMulti); - this.grpMultiples.Location = new System.Drawing.Point(12, 12); - this.grpMultiples.Name = "grpMultiples"; - this.grpMultiples.Size = new System.Drawing.Size(123, 74); - this.grpMultiples.TabIndex = 0; - this.grpMultiples.TabStop = false; - this.grpMultiples.Text = "Multiples"; - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(6, 48); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(58, 13); - this.label2.TabIndex = 2; - this.label2.Text = "Decryption"; - // - // txtDMulti - // - this.txtDMulti.Location = new System.Drawing.Point(69, 45); - this.txtDMulti.Name = "txtDMulti"; - this.txtDMulti.Size = new System.Drawing.Size(43, 20); - this.txtDMulti.TabIndex = 3; - this.txtDMulti.Leave += new System.EventHandler(this.intTextValidate); - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(6, 22); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(57, 13); - this.label1.TabIndex = 0; - this.label1.Text = "Encryption"; - // - // grpData - // - this.grpData.Controls.Add(this.label4); - this.grpData.Controls.Add(this.txtOffset); - this.grpData.Location = new System.Drawing.Point(141, 12); - this.grpData.Name = "grpData"; - this.grpData.Size = new System.Drawing.Size(123, 50); - this.grpData.TabIndex = 1; - this.grpData.TabStop = false; - this.grpData.Text = "Data"; - // - // label4 - // - this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(6, 22); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(35, 13); - this.label4.TabIndex = 0; - this.label4.Text = "Offset"; - // - // txtOffset - // - this.txtOffset.Location = new System.Drawing.Point(69, 19); - this.txtOffset.Name = "txtOffset"; - this.txtOffset.Size = new System.Drawing.Size(43, 20); - this.txtOffset.TabIndex = 1; - this.txtOffset.Leave += new System.EventHandler(this.intTextValidate); - // - // label3 - // - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(157, 22); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(40, 13); - this.label3.TabIndex = 3; - this.label3.Text = "Length"; - // - // txtLength - // - this.txtLength.Enabled = false; - this.txtLength.Location = new System.Drawing.Point(203, 19); - this.txtLength.Name = "txtLength"; - this.txtLength.Size = new System.Drawing.Size(43, 20); - this.txtLength.TabIndex = 4; - this.txtLength.TextChanged += new System.EventHandler(this.intTextValidate); - this.txtLength.Leave += new System.EventHandler(this.intTextValidate); - // - // grpInput - // - this.grpInput.Controls.Add(this.txtInputData); - this.grpInput.Location = new System.Drawing.Point(12, 92); - this.grpInput.Name = "grpInput"; - this.grpInput.Size = new System.Drawing.Size(252, 100); - this.grpInput.TabIndex = 2; - this.grpInput.TabStop = false; - this.grpInput.Text = "Packet Data"; - // - // txtInputData - // - this.txtInputData.Location = new System.Drawing.Point(6, 19); - this.txtInputData.Multiline = true; - this.txtInputData.Name = "txtInputData"; - this.txtInputData.Size = new System.Drawing.Size(240, 75); - this.txtInputData.TabIndex = 0; - // - // grpOutput - // - this.grpOutput.Controls.Add(this.lblAction); - this.grpOutput.Controls.Add(this.lblFamily); - this.grpOutput.Controls.Add(this.lblPacketLength); - this.grpOutput.Controls.Add(this.label7); - this.grpOutput.Controls.Add(this.txtDecoded); - this.grpOutput.Controls.Add(this.txtLength); - this.grpOutput.Controls.Add(this.label3); - this.grpOutput.Controls.Add(this.txtOutput); - this.grpOutput.Controls.Add(this.label6); - this.grpOutput.Controls.Add(this.cmbOutputFmt); - this.grpOutput.Controls.Add(this.label5); - this.grpOutput.Location = new System.Drawing.Point(12, 198); - this.grpOutput.Name = "grpOutput"; - this.grpOutput.Size = new System.Drawing.Size(252, 292); - this.grpOutput.TabIndex = 3; - this.grpOutput.TabStop = false; - this.grpOutput.Text = "Output"; - // - // lblAction - // - this.lblAction.AutoSize = true; - this.lblAction.Location = new System.Drawing.Point(126, 75); - this.lblAction.Name = "lblAction"; - this.lblAction.Size = new System.Drawing.Size(43, 13); - this.lblAction.TabIndex = 9; - this.lblAction.Text = "Action: "; - // - // lblFamily - // - this.lblFamily.AutoSize = true; - this.lblFamily.Location = new System.Drawing.Point(7, 75); - this.lblFamily.Name = "lblFamily"; - this.lblFamily.Size = new System.Drawing.Size(42, 13); - this.lblFamily.TabIndex = 8; - this.lblFamily.Text = "Family: "; - // - // lblPacketLength - // - this.lblPacketLength.AutoSize = true; - this.lblPacketLength.Location = new System.Drawing.Point(7, 48); - this.lblPacketLength.Name = "lblPacketLength"; - this.lblPacketLength.Size = new System.Drawing.Size(83, 13); - this.lblPacketLength.TabIndex = 7; - this.lblPacketLength.Text = "Packet Length: "; - // - // label7 - // - this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(7, 161); - this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(88, 13); - this.label7.TabIndex = 6; - this.label7.Text = "Decoded Packet"; - // - // txtDecoded - // - this.txtDecoded.HideSelection = false; - this.txtDecoded.Location = new System.Drawing.Point(6, 177); - this.txtDecoded.Multiline = true; - this.txtDecoded.Name = "txtDecoded"; - this.txtDecoded.ReadOnly = true; - this.txtDecoded.Size = new System.Drawing.Size(240, 109); - this.txtDecoded.TabIndex = 1; - // - // txtOutput - // - this.txtOutput.Location = new System.Drawing.Point(50, 101); - this.txtOutput.Multiline = true; - this.txtOutput.Name = "txtOutput"; - this.txtOutput.ReadOnly = true; - this.txtOutput.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.txtOutput.Size = new System.Drawing.Size(196, 57); - this.txtOutput.TabIndex = 5; - // - // label6 - // - this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(7, 104); - this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(37, 13); - this.label6.TabIndex = 1; - this.label6.Text = "Result"; - // - // cmbOutputFmt - // - this.cmbOutputFmt.FormattingEnabled = true; - this.cmbOutputFmt.Items.AddRange(new object[] { - "PacketFamily", - "PacketAction", - "Byte", - "Char", - "Short", - "Three", - "Int", - "BreakString", - "EndString", - "FixedString"}); - this.cmbOutputFmt.Location = new System.Drawing.Point(52, 19); - this.cmbOutputFmt.Name = "cmbOutputFmt"; - this.cmbOutputFmt.Size = new System.Drawing.Size(99, 21); - this.cmbOutputFmt.TabIndex = 2; - this.cmbOutputFmt.SelectedIndexChanged += new System.EventHandler(this.cmbOutputFmt_SelectedIndexChanged); - // - // label5 - // - this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(7, 22); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(39, 13); - this.label5.TabIndex = 0; - this.label5.Text = "Format"; - // - // btnImportMultis - // - this.btnImportMultis.Location = new System.Drawing.Point(141, 68); - this.btnImportMultis.Name = "btnImportMultis"; - this.btnImportMultis.Size = new System.Drawing.Size(123, 23); - this.btnImportMultis.TabIndex = 4; - this.btnImportMultis.Text = "Import Multiples"; - this.btnImportMultis.UseVisualStyleBackColor = true; - this.btnImportMultis.Click += new System.EventHandler(this.btnImportMultis_Click); - // - // MainForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(275, 502); - this.Controls.Add(this.btnImportMultis); - this.Controls.Add(this.grpOutput); - this.Controls.Add(this.grpInput); - this.Controls.Add(this.grpData); - this.Controls.Add(this.grpMultiples); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; - this.MaximizeBox = false; - this.Name = "MainForm"; - this.Text = "EO Packet Decoder"; - this.grpMultiples.ResumeLayout(false); - this.grpMultiples.PerformLayout(); - this.grpData.ResumeLayout(false); - this.grpData.PerformLayout(); - this.grpInput.ResumeLayout(false); - this.grpInput.PerformLayout(); - this.grpOutput.ResumeLayout(false); - this.grpOutput.PerformLayout(); - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.TextBox txtEMulti; - private System.Windows.Forms.GroupBox grpMultiples; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.TextBox txtDMulti; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.GroupBox grpData; - private System.Windows.Forms.Label label3; - private System.Windows.Forms.TextBox txtLength; - private System.Windows.Forms.Label label4; - private System.Windows.Forms.TextBox txtOffset; - private System.Windows.Forms.GroupBox grpInput; - private System.Windows.Forms.TextBox txtInputData; - private System.Windows.Forms.GroupBox grpOutput; - private System.Windows.Forms.TextBox txtOutput; - private System.Windows.Forms.Label label6; - private System.Windows.Forms.ComboBox cmbOutputFmt; - private System.Windows.Forms.Label label5; - private System.Windows.Forms.Label label7; - private System.Windows.Forms.TextBox txtDecoded; - private System.Windows.Forms.Label lblPacketLength; - private System.Windows.Forms.Label lblAction; - private System.Windows.Forms.Label lblFamily; - private System.Windows.Forms.Button btnImportMultis; - } -} - diff --git a/PacketDecoder/MainForm.cs b/PacketDecoder/MainForm.cs deleted file mode 100644 index d2a79918d..000000000 --- a/PacketDecoder/MainForm.cs +++ /dev/null @@ -1,280 +0,0 @@ -using System; -using System.Drawing; -using System.IO; -using System.Windows.Forms; -using EOLib.Config; -using EOLib.IO.Services; -using EOLib.Logger; -using EOLib.Net; -using EOLib.Net.PacketProcessing; - -namespace PacketDecoder -{ - public partial class MainForm : Form - { - private enum DataTypes - { - None = -1, - PacketFamily, - PacketAction, - Byte, - Char, - Short, - Three, - Int, - BreakString, - EndString, - FixedString, - } - - private DataTypes m_type; - private readonly IPacketProcessActions _packetProcessActions; - private readonly IPacketEncoderRepository _packetEncoderRepository; - private int m_packetOffset, m_dataLength; - private bool m_suppressEvent; - - public MainForm() - { - InitializeComponent(); - - cmbOutputFmt_SelectedIndexChanged(null, null); - - _packetEncoderRepository = new PacketEncoderRepository(); - _packetProcessActions = new PacketProcessActions(new SequenceRepository(), - _packetEncoderRepository, - new PacketEncoderService(new NumberEncoderService(), new DataEncoderService()), - new PacketSequenceService(), - new LoggerProvider(new LoggerFactory(new ConfigurationRepository()))); - } - - private void cmbOutputFmt_SelectedIndexChanged(object sender, EventArgs e) - { - m_type = (DataTypes) cmbOutputFmt.SelectedIndex; - if (m_type == DataTypes.FixedString) - { - txtLength.Enabled = true; - txtLength.Text = ""; - } - else - { - txtLength.Enabled = false; - switch (m_type) - { - case DataTypes.BreakString: - case DataTypes.EndString: - case DataTypes.None: - txtLength.Text = ""; - break; - case DataTypes.PacketFamily: - txtLength.Text = "1"; - break; - case DataTypes.PacketAction: - txtLength.Text = "1"; - break; - case DataTypes.Byte: - txtLength.Text = "1"; - break; - case DataTypes.Char: - txtLength.Text = "1"; - break; - case DataTypes.Short: - txtLength.Text = "2"; - break; - case DataTypes.Three: - txtLength.Text = "3"; - break; - case DataTypes.Int: - txtLength.Text = "4"; - break; - } - } - _checkRequiredInputs(); - } - - private void intTextValidate(object sender, EventArgs e) - { - if (m_suppressEvent) return; - - TextBox txt = sender as TextBox; - if (txt == null) - return; - - int param; - if (!int.TryParse(txt.Text, out param)) - { - if (txt == txtLength) - m_dataLength = 0; - return; - } - - if (txt == txtDMulti) - { - _packetProcessActions.SetEncodeMultiples(param, _packetEncoderRepository.SendMultiplier); - if (param < 6 || param > 12) - { - txtDMulti.BackColor = Color.FromArgb(255, 255, 128, 128); - } - else - { - txtDMulti.BackColor = Color.White; - } - } - else if (txt == txtEMulti) - { - _packetProcessActions.SetEncodeMultiples(_packetEncoderRepository.ReceiveMultiplier, param); - if (param < 6 || param > 12) - { - txtEMulti.BackColor = Color.FromArgb(255, 255, 128, 128); - } - else - { - txtEMulti.BackColor = Color.White; - } - } - else if (txt == txtOffset) - { - m_packetOffset = param; - if (param >= txtInputData.TextLength) - param = txtInputData.TextLength - 1; - } - else if (txt == txtLength) - m_dataLength = param; - - _checkRequiredInputs(); - } - - private void _checkRequiredInputs() - { - txtOutput.Text = ""; - - if (txtDMulti.TextLength == 0 || txtEMulti.TextLength == 0 || txtOffset.TextLength == 0) - return; - - if (txtLength.TextLength == 0 && m_type == DataTypes.FixedString) - return; - - string inputData = txtInputData.Text; - if (inputData.Length == 0) - return; - - //input data is copied from wireshark. colon delimited. - string bytes = inputData.Replace(":", ""); - string len = bytes.Substring(0, 4);//first 2 bytes are the length! - bytes = bytes.Substring(4); - byte[] data = new byte[bytes.Length / 2]; - - byte[] lenDat = new byte[2]; - for (int i = 0; i < len.Length; i += 2) - { - lenDat[i/2] = Convert.ToByte(len.Substring(i, 2), 16); - } - lblPacketLength.Text = "Packet Length: " + new NumberEncoderService().DecodeNumber(lenDat).ToString(); - - for (int i = 0; i < bytes.Length; i += 2) - { - data[i/2] = Convert.ToByte(bytes.Substring(i, 2), 16); - } - - var pkt = _packetProcessActions.DecodeData(data); - pkt.Seek(m_packetOffset, SeekOrigin.Begin); - - lblFamily.Text = pkt.Family.ToString(); - lblAction.Text = pkt.Action.ToString(); - - string decoded = ""; - for (int i = 0; i < pkt.Length; i++) - { - decoded += $"{pkt.RawData[i].ToString("D3")} "; - } - txtDecoded.Text = decoded; - - switch ((DataTypes) cmbOutputFmt.SelectedIndex) - { - case DataTypes.None: - txtOutput.Text = pkt.ReadEndString(); - break; - case DataTypes.PacketFamily: - txtOutput.Text = ((PacketFamily) pkt.PeekByte()).ToString(); - break; - case DataTypes.PacketAction: - txtOutput.Text = ((PacketAction)pkt.PeekByte()).ToString(); - break; - case DataTypes.Byte: - txtOutput.Text = pkt.PeekByte().ToString(); - break; - case DataTypes.Char: - txtOutput.Text = pkt.PeekChar().ToString(); - break; - case DataTypes.Short: - txtOutput.Text = pkt.PeekShort().ToString(); - break; - case DataTypes.Three: - txtOutput.Text = pkt.PeekThree().ToString(); - break; - case DataTypes.Int: - txtOutput.Text = pkt.PeekInt().ToString(); - break; - case DataTypes.BreakString: - txtOutput.Text = pkt.PeekBreakString(); - break; - case DataTypes.EndString: - txtOutput.Text = pkt.PeekEndString(); - break; - case DataTypes.FixedString: - txtOutput.Text = pkt.PeekString(m_dataLength); - break; - default: - throw new ArgumentOutOfRangeException(); - } - - int selLen; - if (m_dataLength > 0) selLen = m_dataLength; - else - switch (m_type) - { - case DataTypes.EndString: - selLen = 3*(pkt.Length - pkt.ReadPosition) - 1; - break; - case DataTypes.BreakString: - int oldPos = pkt.ReadPosition; - while (pkt.ReadByte() != 255) ; - selLen = pkt.ReadPosition - oldPos; - pkt.Seek(oldPos, SeekOrigin.Begin); - break; - default: - selLen = 0; - break; - } - txtDecoded.Select(4 * m_packetOffset, 4 * selLen - 1); - - if (m_type == DataTypes.EndString || m_type == DataTypes.BreakString) - { - m_suppressEvent = true; - txtLength.Text = selLen.ToString(); - m_suppressEvent = false; - } - } - - private void btnImportMultis_Click(object sender, EventArgs e) - { - string inp = Microsoft.VisualBasic.Interaction.InputBox("Paste the raw, colon-delimited packet data here: ", "Enter packet data"); - - if (inp.Length == 0) - return; - - inp = inp.Replace(":", ""); - if (inp.Length%2 != 0) return; - inp = inp.Substring(4); - byte[] data = new byte[inp.Length / 2]; - for (int i = 0; i < inp.Length; i += 2) - data[i/2] = Convert.ToByte(inp.Substring(i, 2), 16); - - //no need to decrypt since it's init data - var pkt = new Packet(data); - pkt.Seek(3, SeekOrigin.Current); - txtDMulti.Text = pkt.ReadByte().ToString(); - txtEMulti.Text = pkt.ReadByte().ToString(); - _packetProcessActions.SetEncodeMultiples(pkt.RawData[5], pkt.RawData[6]); - } - } -} diff --git a/PacketDecoder/MainForm.resx b/PacketDecoder/MainForm.resx deleted file mode 100644 index 1af7de150..000000000 --- a/PacketDecoder/MainForm.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/PacketDecoder/PacketDecoder.csproj b/PacketDecoder/PacketDecoder.csproj deleted file mode 100644 index 1fb6b5b7f..000000000 --- a/PacketDecoder/PacketDecoder.csproj +++ /dev/null @@ -1,27 +0,0 @@ - - - net6.0-windows - WinExe - false - ..\bin\$(Configuration)\utils\PacketDecoder - true - true - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/PacketDecoder/Program.cs b/PacketDecoder/Program.cs deleted file mode 100644 index 9e7720d8f..000000000 --- a/PacketDecoder/Program.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Windows.Forms; - -namespace PacketDecoder -{ - static class Program - { - /// - /// The main entry point for the application. - /// - [STAThread] - static void Main() - { - Application.EnableVisualStyles(); - Application.SetHighDpiMode(HighDpiMode.SystemAware); - Application.SetCompatibleTextRenderingDefault(false); - Application.Run(new MainForm()); - } - } -} diff --git a/PacketDecoder/Properties/AssemblyInfo.cs b/PacketDecoder/Properties/AssemblyInfo.cs deleted file mode 100644 index bc97849e9..000000000 --- a/PacketDecoder/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("PacketDecoder")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("PacketDecoder")] -[assembly: AssemblyCopyright("Copyright © Ethan Moffat 2014-2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("0fec5365-f6be-479f-b449-114ce0e7c977")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PacketDecoder/Properties/Resources.Designer.cs b/PacketDecoder/Properties/Resources.Designer.cs deleted file mode 100644 index 2e9aaf072..000000000 --- a/PacketDecoder/Properties/Resources.Designer.cs +++ /dev/null @@ -1,63 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace PacketDecoder.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PacketDecoder.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - } -} diff --git a/PacketDecoder/Properties/Resources.resx b/PacketDecoder/Properties/Resources.resx deleted file mode 100644 index af7dbebba..000000000 --- a/PacketDecoder/Properties/Resources.resx +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/PacketDecoder/Properties/Settings.Designer.cs b/PacketDecoder/Properties/Settings.Designer.cs deleted file mode 100644 index 662354e75..000000000 --- a/PacketDecoder/Properties/Settings.Designer.cs +++ /dev/null @@ -1,26 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace PacketDecoder.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - } -} diff --git a/PacketDecoder/Properties/Settings.settings b/PacketDecoder/Properties/Settings.settings deleted file mode 100644 index 39645652a..000000000 --- a/PacketDecoder/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - -