diff --git a/documentation/DocumentationTest.PacketsDocumentation.verified.md b/documentation/DocumentationTest.PacketsDocumentation.verified.md
index 167c6d22..4f224bd4 100644
--- a/documentation/DocumentationTest.PacketsDocumentation.verified.md
+++ b/documentation/DocumentationTest.PacketsDocumentation.verified.md
@@ -75,7 +75,7 @@
- [treq](../src/NosCore.Packets/ClientPackets/Event/TreqPacket.cs) *InGame*
### Exchanges
-- [req_exc](../src/NosCore.Packets/ClientPackets/Exchanges/ExchangeRequestPacket.cs) *InGame*
+- [req_exc](../src/NosCore.Packets/ClientPackets/Exchanges/ExchangeRequestPacket.cs) *InTrade | InGame*
- [exc_list](../src/NosCore.Packets/ClientPackets/Exchanges/ExcListPacket.cs) *InTrade | InGame*
### Families
diff --git a/src/NosCore.Packets/ClientPackets/Exchanges/ExchangeRequestPacket.cs b/src/NosCore.Packets/ClientPackets/Exchanges/ExchangeRequestPacket.cs
index 1d75cc97..675e3d61 100644
--- a/src/NosCore.Packets/ClientPackets/Exchanges/ExchangeRequestPacket.cs
+++ b/src/NosCore.Packets/ClientPackets/Exchanges/ExchangeRequestPacket.cs
@@ -10,7 +10,7 @@
namespace NosCore.Packets.ClientPackets.Exchanges
{
- [PacketHeader("req_exc", Scope.InGame)]
+ [PacketHeader("req_exc", Scope.InGame | Scope.InTrade)]
public class ExchangeRequestPacket : PacketBase
{
[PacketIndex(0)]
diff --git a/src/NosCore.Packets/Deserializer.cs b/src/NosCore.Packets/Deserializer.cs
index 06e652b0..8ef6b6a0 100644
--- a/src/NosCore.Packets/Deserializer.cs
+++ b/src/NosCore.Packets/Deserializer.cs
@@ -346,7 +346,15 @@ public IPacket Deserialize(string packetContent)
}
if (isMaxIndex && string.IsNullOrWhiteSpace(separator))
{
- length = (sbyte)(matches.Length - currentIndex);
+ var remainingTokens = matches.Length - currentIndex;
+ // Sub-packets whose fields are space-separated span several tokens each
+ // (exc_list's "type slot amount"), so the item count is tokens / fields.
+ var subPacketCreator = typeof(IPacket).IsAssignableFrom(subType) && remainingTokens > 0
+ && !matches[currentIndex].Contains(packetIndexAttribute.SpecialSeparator ?? ".")
+ ? _packetDeserializerDictionary.Values.FirstOrDefault(s => s.PacketType == subType)
+ : null;
+ var tokensPerItem = subPacketCreator == null ? 1 : subPacketCreator.PropertyAmount + 1;
+ length = (sbyte)((remainingTokens + tokensPerItem - 1) / tokensPerItem);
}
if (!string.IsNullOrWhiteSpace(separator))
diff --git a/src/NosCore.Packets/NosCore.Packets.csproj b/src/NosCore.Packets/NosCore.Packets.csproj
index e85a71e2..07a612d4 100644
--- a/src/NosCore.Packets/NosCore.Packets.csproj
+++ b/src/NosCore.Packets/NosCore.Packets.csproj
@@ -12,7 +12,7 @@
https://github.com/NosCoreIO/NosCore.Packets.git
nostale, noscore, chickenapi, nostale private server source, nostale emulator
- 21.1.2
+ 21.1.3
false
NosCore's Packets (Nostale packets) defined over classes
MIT
diff --git a/test/NosCore.Packets.Tests/DeserializerTest.cs b/test/NosCore.Packets.Tests/DeserializerTest.cs
index 1ef9a685..d3e41c57 100644
--- a/test/NosCore.Packets.Tests/DeserializerTest.cs
+++ b/test/NosCore.Packets.Tests/DeserializerTest.cs
@@ -5,6 +5,9 @@
// -----------------------------------
using NosCore.Packets.ClientPackets.Chat;
+using NosCore.Packets.ClientPackets.Exchanges;
+using NosCore.Packets.Attributes;
+using System.Reflection;
using NosCore.Packets.ClientPackets.Inventory;
using NosCore.Packets.ClientPackets.Login;
using NosCore.Packets.ClientPackets.Movement;
@@ -63,6 +66,8 @@ public class DeserializerTest
typeof(CBListPacket),
typeof(CScalcPacket),
typeof(CreateFamilyPacket),
+ typeof(ExcListPacket),
+ typeof(ExcListSubPacket),
typeof(UnresolvedPacket)
});
@@ -495,5 +500,36 @@ public void PacketWithEmptySpecialSeparatorSplitsEachCharIntoField()
Assert.AreEqual((byte)3, packet.ArmorUpgradeRareSubPacket!.Upgrade);
Assert.AreEqual((sbyte)5, packet.ArmorUpgradeRareSubPacket.Rare);
}
+
+ [TestMethod]
+ public void DeserializeSpaceSeparatedSubPacketListYieldsOneItemPerSubPacket()
+ {
+ var packet = (ExcListPacket)Deserializer.Deserialize("exc_list 21 44 10 53 21 2 87 55");
+ Assert.AreEqual(21, packet.Gold);
+ Assert.AreEqual(44, packet.BankGold);
+ Assert.HasCount(2, packet.SubPackets!);
+ Assert.AreEqual(PocketType.Raid, packet.SubPackets![0]!.PocketType);
+ Assert.AreEqual(53, packet.SubPackets[0]!.Slot);
+ Assert.AreEqual(21, packet.SubPackets[0]!.Amount);
+ Assert.AreEqual(PocketType.Etc, packet.SubPackets[1]!.PocketType);
+ Assert.AreEqual(87, packet.SubPackets[1]!.Slot);
+ Assert.AreEqual(55, packet.SubPackets[1]!.Amount);
+ }
+
+ [TestMethod]
+ public void DeserializeSpaceSeparatedSubPacketListWithASingleSubPacket()
+ {
+ var packet = (ExcListPacket)Deserializer.Deserialize("exc_list 5000 0 0 3 2");
+ Assert.HasCount(1, packet.SubPackets!);
+ Assert.AreEqual(3, packet.SubPackets![0]!.Slot);
+ Assert.AreEqual(2, packet.SubPackets[0]!.Amount);
+ }
+
+ [TestMethod]
+ public void ExchangeRequestIsAcceptedWhileTrading()
+ {
+ var scopes = typeof(ExchangeRequestPacket).GetCustomAttribute()!.Scopes;
+ Assert.IsTrue(scopes.HasFlag(Scope.InTrade));
+ }
}
}