diff --git a/src/NosCore.Packets/Serializer.cs b/src/NosCore.Packets/Serializer.cs index ba4f812..4083fa4 100644 --- a/src/NosCore.Packets/Serializer.cs +++ b/src/NosCore.Packets/Serializer.cs @@ -18,7 +18,7 @@ public class Serializer : ISerializer { private const string InjectionKey = "IPacketToInject"; - private readonly Dictionary _packetSerializerDictionary = new Dictionary(); + private readonly Dictionary _packetSerializerDictionary = new Dictionary(); public Serializer(IEnumerable types) @@ -35,23 +35,14 @@ public void Initialize() where T : PacketBase var packetSerializerExpressionFalse = PacketSerializerExpression(); if (packetSerializerExpressionFalse != null) { - if (_packetSerializerDictionary.ContainsKey(typeof(T).Name)) - { - if (typeof(T).Namespace!.Contains("ClientPackets")) - { - return; - } - - _packetSerializerDictionary.Remove(typeof(T).Name); - } - _packetSerializerDictionary.Add(typeof(T).Name, packetSerializerExpressionFalse.Compile()); + _packetSerializerDictionary[typeof(T)] = packetSerializerExpressionFalse.Compile(); } } public string Serialize(IPacket packet) { var realType = packet.GetType(); - var deg = _packetSerializerDictionary[packet.GetType().Name]; + var deg = _packetSerializerDictionary[packet.GetType()]; var fullString = (string)deg.DynamicInvoke(packet, false)!; if (fullString.Contains(InjectionKey)) { @@ -63,7 +54,7 @@ public string Serialize(IPacket packet) fullString = fullString .Remove(place, InjectionKey.Length) .Insert(place, - (string)_packetSerializerDictionary[value!.GetType().Name].DynamicInvoke(value, true)!); + (string)_packetSerializerDictionary[value!.GetType()].DynamicInvoke(value, true)!); } } diff --git a/test/NosCore.Packets.Tests/SerializerCorpusTests.ExpressionTreeSerializerOutputIsPinnedForEveryPacket.verified.txt b/test/NosCore.Packets.Tests/SerializerCorpusTests.ExpressionTreeSerializerOutputIsPinnedForEveryPacket.verified.txt index 57a0b3c..a167144 100644 --- a/test/NosCore.Packets.Tests/SerializerCorpusTests.ExpressionTreeSerializerOutputIsPinnedForEveryPacket.verified.txt +++ b/test/NosCore.Packets.Tests/SerializerCorpusTests.ExpressionTreeSerializerOutputIsPinnedForEveryPacket.verified.txt @@ -58,8 +58,8 @@ WhisperPacket#1 => / s15521 WhisperPacket#7 => / s15674 FamilyDeputyPacket#1 => %Familydeputy s15521 FamilyDeputyPacket#7 => %Familydeputy s15674 -FamilyDismissPacket#1 => %Familydismiss s15521 -FamilyDismissPacket#7 => %Familydismiss s15674 +NosCore.Packets.ClientPackets.Commands.FamilyDismissPacket#1 => %Familydismiss s15521 +NosCore.Packets.ClientPackets.Commands.FamilyDismissPacket#7 => %Familydismiss s15674 FamilyHeadPacket#1 => %Familyhead s15521 FamilyHeadPacket#7 => %Familyhead s15674 FamilyInvitePacket#1 => %Familyinvite s15521 @@ -80,8 +80,8 @@ PartyLocationPacket#1 => $Partylocation s15521 PartyLocationPacket#7 => $Partylocation s15674 TimeSpaceInvitePacket#1 => $Accompany s15521 TimeSpaceInvitePacket#7 => $Accompany s15674 -DropPacket#1 => <> -DropPacket#7 => <> +NosCore.Packets.ClientPackets.Drops.DropPacket#1 => drop 21 44 83 53 21 1 87 55 +NosCore.Packets.ClientPackets.Drops.DropPacket#7 => drop 74 75 77 8 43 1 37 53 GetPacket#1 => get 1 44 83 53 GetPacket#7 => get 9 75 77 8 FbPacket#1 => fb s15521 @@ -106,8 +106,8 @@ CreateFamilyPacket#1 => glmk s15521 CreateFamilyPacket#7 => glmk s15674 FAuthPacket#1 => fauth 1 44 83 FAuthPacket#7 => fauth 2 75 77 -FamilyDismissPacket#1 => <> -FamilyDismissPacket#7 => <> +NosCore.Packets.ClientPackets.Families.FamilyDismissPacket#1 => glrm +NosCore.Packets.ClientPackets.Families.FamilyDismissPacket#7 => glrm FamilyManagementPacket#1 => fmg 1 44 FamilyManagementPacket#7 => fmg 2 75 FhistCtsPacket#1 => fhis_cts @@ -118,8 +118,8 @@ FwsPacket#1 => fws 21 FwsPacket#7 => fws 74 GListPacket#1 => glist 21 GListPacket#7 => glist 74 -GidxPacket#1 => <> -GidxPacket#7 => <> +NosCore.Packets.ClientPackets.Families.GidxPacket#1 => gidx 1 44 83 s15853 s14221 82 0|0 +NosCore.Packets.ClientPackets.Families.GidxPacket#7 => gidx 9 75 77 s30408 s14143 82 0|0 JoinFamilyPacket#1 => gjoin 21 44 JoinFamilyPacket#7 => gjoin 74 75 TodayPacket#1 => today_cts @@ -200,8 +200,8 @@ MinigamePacket#1 => mg 21 44 83 53 21 MinigamePacket#7 => mg 74 75 77 8 43 RmvobjPacket#1 => rmvobj 21 RmvobjPacket#7 => rmvobj 74 -UseObjPacket#1 => <> -UseObjPacket#7 => <> +NosCore.Packets.ClientPackets.Miniland.UseObjPacket#1 => useobj s15521 44 +NosCore.Packets.ClientPackets.Miniland.UseObjPacket#7 => useobj s15674 75 ClientDirPacket#1 => dir 21 9 83 ClientDirPacket#7 => dir 74 0 77 PreqPacket#1 => preq 21 @@ -226,8 +226,8 @@ BpClosePacket#1 => bp_close BpClosePacket#7 => bp_close BpOpenPacket#1 => bp_open BpOpenPacket#7 => bp_open -BpmPacket#1 => <> -BpmPacket#7 => <> +NosCore.Packets.ClientPackets.Player.BpmPacket#1 => bpm 21 1 83 53 21 82 20 1 52 90 80 24 27 24 0 90 20 18 35 +NosCore.Packets.ClientPackets.Player.BpmPacket#7 => bpm 74 0 77 8 43 82 14 0 78 12 53 59 96 14 1 58 74 95 71 BpoPacket#1 => bpo BpoPacket#7 => bpo BppPacket#1 => bpp 21 44 0 53 21 82 87 55 1 1 1 24 27 23 69 90 1 1 0 @@ -238,10 +238,10 @@ ComplPacket#1 => compl 21 ComplPacket#7 => compl 74 EquipmentInfoPacket#1 => eqinfo 21 44 83 53 EquipmentInfoPacket#7 => eqinfo 74 75 77 8 -NpInfoPacket#1 => <> -NpInfoPacket#7 => <> -RsfiPacket#1 => <> -RsfiPacket#7 => <> +NosCore.Packets.ClientPackets.Player.NpInfoPacket#1 => npinfo 21 +NosCore.Packets.ClientPackets.Player.NpInfoPacket#7 => npinfo 74 +NosCore.Packets.ClientPackets.Player.RsfiPacket#1 => rsfi 21 44 83 53 21 82 +NosCore.Packets.ClientPackets.Player.RsfiPacket#7 => rsfi 74 75 77 8 43 82 SnapPacket#1 => snap SnapPacket#7 => snap TitEqPacket#1 => tit_eq 21 44 @@ -282,8 +282,8 @@ SellListPacket#1 => sell_list 21 44.83.53 21.82.87 SellListPacket#7 => sell_list 74 75.77.8 43.82.37 SellPacket#1 => sell 21 44 83 SellPacket#7 => sell 74 75 77 -ShopClosePacket#1 => <> -ShopClosePacket#7 => <> +NosCore.Packets.ClientPackets.Shops.ShopClosePacket#1 => shopclose +NosCore.Packets.ClientPackets.Shops.ShopClosePacket#7 => shopclose ShoppingPacket#1 => shopping 21 44 3 53 ShoppingPacket#7 => shopping 74 75 2 8 SCarrierPacket#1 => s_carrier 21 44 83 @@ -292,10 +292,10 @@ SpTransformPacket#1 => sl 10 44 83 53 21 82 SpTransformPacket#7 => sl 10 75 77 8 43 82 GopPacket#1 => gop 1 1 GopPacket#7 => gop 1 0 -GuriPacket#1 => <> -GuriPacket#7 => <> -MallPacket#1 => <> -MallPacket#7 => <> +NosCore.Packets.ClientPackets.UI.GuriPacket#1 => guri 6 44 83 53 s14221 +NosCore.Packets.ClientPackets.UI.GuriPacket#7 => guri 40 75 77 8 s14143 +NosCore.Packets.ClientPackets.UI.MallPacket#1 => mall 21 +NosCore.Packets.ClientPackets.UI.MallPacket#7 => mall 74 DepositPacket#1 => deposit 1 44 83 53 0 DepositPacket#7 => deposit 2 75 77 8 0 FDepositPacket#1 => f_deposit 1 44 83 53 21 @@ -344,12 +344,16 @@ CtPacket#1 => ct 1 44 3 53 21 82 87 CtPacket#7 => ct 9 75 2 8 43 82 37 DiePacket#1 => die 1 44 3 53 DiePacket#7 => die 9 75 2 8 +DmPacket#1 => dm 1 44 83 3 +DmPacket#7 => dm 9 75 77 3 MscPacket#1 => ms_c 21 MscPacket#7 => ms_c 74 MslotPacket#1 => mslot 21 0 MslotPacket#7 => mslot 74 -1 RankCoolPacket#1 => rank_cool 21 44 83 RankCoolPacket#7 => rank_cool 74 75 77 +RcPacket#1 => rc 1 44 83 53 +RcPacket#7 => rc 9 75 77 8 RevivePacket#1 => revive 1 44 83 RevivePacket#7 => revive 9 75 77 SkillResetPacket#1 => sr 21 @@ -414,8 +418,8 @@ CatPacket#1 => ca_t 21 44 CatPacket#7 => ca_t 74 75 CharScPacket#1 => char_sc 1 44 83 CharScPacket#7 => char_sc 9 75 77 -DropPacket#1 => drop 21 44 83 53 21 1 87 -DropPacket#7 => drop 74 75 77 8 43 1 37 +NosCore.Packets.ServerPackets.Entities.DropPacket#1 => drop 21 44 83 53 21 1 87 +NosCore.Packets.ServerPackets.Entities.DropPacket#7 => drop 74 75 77 8 43 1 37 MovePacket#1 => mv 1 44 83 53 21 MovePacket#7 => mv 9 75 77 8 43 OutPacket#1 => out 1 44 @@ -432,8 +436,12 @@ DgPacket#1 => dg 21 44 83 53 DgPacket#7 => dg 74 75 77 8 EsfPacket#1 => esf 21 EsfPacket#7 => esf 74 +EventPacket#1 => evnt 10 1 83 53 +EventPacket#7 => evnt 10 0 77 8 EventbPacket#1 => evtb 21 44 83 53 21 1 87 55 52 90 80 24 27 23 69 90 20 18 35 9 75 68 79 97 1 68 41 93 EventbPacket#7 => evtb 74 75 77 8 43 1 37 53 78 12 53 59 96 45 47 58 74 95 71 58 9 5 81 27 96 55 30 7 +FbtPacket#1 => fbt 21 44 83 53 +FbtPacket#7 => fbt 74 75 77 8 RaidPacket#1 => raid 21 44 RaidPacket#7 => raid 74 75 RaidbfPacket#1 => raidbf 21 44 83 @@ -460,8 +468,8 @@ GInfoPacket#1 => ginfo s15521 s30144 1 53 21 82 87 55 0 1 1 1 0 2 0 1 s920 GInfoPacket#7 => ginfo s15674 s275 1 8 43 82 37 53 2 1 0 0 1 0 0 1 s28374 GexpPacket#1 => gexp 21|44 83|53 GexpPacket#7 => gexp 74|75 77|8 -GidxPacket#1 => gidx 1 44 83 s15853 21 1|0 -GidxPacket#7 => gidx 9 75 77 s30408 43 1|0 +NosCore.Packets.ServerPackets.Families.GidxPacket#1 => gidx 1 44 83 s15853 21 1|0 +NosCore.Packets.ServerPackets.Families.GidxPacket#7 => gidx 9 75 77 s30408 43 1|0 GmsgPacket#1 => gmsg 21|s30144 83|s15853 GmsgPacket#7 => gmsg 74|s275 77|s30408 FtptPacket#1 => ftpt 21 @@ -570,8 +578,8 @@ MlobjPacket#1 => mlobj 0 44 83 53 21 82 87 55 1 1 MlobjPacket#7 => mlobj 1 75 77 8 43 82 37 53 1 1 MlobjlstPacket#1 => mlobjlst 21.1.83.53.21.82.87.55.1.1 80.1.27.23.69.90.20.18.0.0 MlobjlstPacket#7 => mlobjlst 74.0.77.8.43.82.37.53.1.1 53.0.96.45.47.58.74.95.0.1 -UseObjPacket#1 => useobj s15521 44 -UseObjPacket#7 => useobj s15674 75 +NosCore.Packets.ServerPackets.Miniland.UseObjPacket#1 => useobj s15521 44 +NosCore.Packets.ServerPackets.Miniland.UseObjPacket#7 => useobj s15674 75 DirPacket#1 => dir 1 44 83 DirPacket#7 => dir 9 75 77 NpcReqPacket#1 => npc_req 1 44 83 @@ -584,8 +592,8 @@ PstPacket#1 => pst 1 44 83 53 21 82 87 55 0 90 80.24 PstPacket#7 => pst 9 75 77 8 43 82 37 53 0 12 53.59 BnPacket#1 => bn 21 s30144 BnPacket#7 => bn 74 s275 -BpmPacket#1 => bpm 21 44 83 -BpmPacket#7 => bpm 74 75 77 +NosCore.Packets.ServerPackets.Player.BpmPacket#1 => bpm 21 44 83 +NosCore.Packets.ServerPackets.Player.BpmPacket#7 => bpm 74 75 77 CInfoPacket#1 => c_info s15521 s30144 83 53 s14221 82 -1 1 2 90 0 24 27 23 0 90 20 1 35 9 CInfoPacket#7 => c_info s15674 s275 77 8 s14143 82 1 1 3 24 3 59 96 45 0 58 74 0 71 58 CInfoResetPacket#1 => c_info_reset @@ -610,16 +618,14 @@ LevPacket#1 => lev 21 44 83 53 21 82 87 55 52 90 80 24 LevPacket#7 => lev 74 75 77 8 43 82 37 53 78 12 53 59 LevelUpPacket#1 => levelup 21 LevelUpPacket#7 => levelup 74 -NpInfoPacket#1 => npinfo 21 -NpInfoPacket#7 => npinfo 74 +NosCore.Packets.ServerPackets.Player.NpInfoPacket#1 => npinfo 21 +NosCore.Packets.ServerPackets.Player.NpInfoPacket#7 => npinfo 74 PSexPacket#1 => p_sex 1 PSexPacket#7 => p_sex 0 RagePacket#1 => rage 21 44 RagePacket#7 => rage 74 75 -RcPacket#1 => rc 21 44 83 53 -RcPacket#7 => rc 74 75 77 8 -RsfiPacket#1 => rsfi 21 44 83 53 21 82 -RsfiPacket#7 => rsfi 74 75 77 8 43 82 +NosCore.Packets.ServerPackets.Player.RsfiPacket#1 => rsfi 21 44 83 53 21 82 +NosCore.Packets.ServerPackets.Player.RsfiPacket#7 => rsfi 74 75 77 8 43 82 ScPacket#1 => sc 21 44 83 53 21 82 87 55 52 90 80 24 27 23 69 90 20 18 35 9 75 68 79 97 ScPacket#7 => sc 74 75 77 8 43 82 37 53 78 12 53 59 96 45 47 58 74 95 71 58 9 5 81 27 ScrPacket#1 => scr 21 44 83 53 21 82 @@ -734,8 +740,8 @@ DlgiPacket#1 => dlgi #gbox^1^44^0 #gbox^1^21^1 2167 55 0 DlgiPacket#7 => dlgi #gbox^2^75^0 #gbox^0^43^1 2157 53 0 FishOpenPacket#1 => fishopen FishOpenPacket#7 => fishopen -GuriPacket#1 => guri 6 44 83 53 21 82 -GuriPacket#7 => guri 40 75 77 8 43 82 +NosCore.Packets.ServerPackets.UI.GuriPacket#1 => guri 6 44 83 53 21 82 +NosCore.Packets.ServerPackets.UI.GuriPacket#7 => guri 40 75 77 8 43 82 IconPacket#1 => icon 1 44 83 53 IconPacket#7 => icon 9 75 77 8 InfoPacket#1 => info s15521 @@ -744,8 +750,8 @@ Infoi2Packet#1 => infoi2 1371 44 0 Infoi2Packet#7 => infoi2 1524 75 0 InfoiPacket#1 => infoi 1371 0 0 44 InfoiPacket#7 => infoi 1524 0 0 75 -MallPacket#1 => mall 21 -MallPacket#7 => mall 74 +NosCore.Packets.ServerPackets.UI.MallPacket#1 => mall 21 +NosCore.Packets.ServerPackets.UI.MallPacket#7 => mall 74 ModalPacket#1 => modal 21 s30144 ModalPacket#7 => modal 74 s275 ModaliPacket#1 => modali 21 1844 83 0 0 @@ -766,8 +772,8 @@ QnaiPacket#1 => qnai #gbox^1^44^0 1703 21 0 0 QnaiPacket#7 => qnai #gbox^2^75^0 2108 43 0 0 RdiPacket#1 => rdi 21 44 RdiPacket#7 => rdi 74 75 -ShopClosePacket#1 => shopclose 21 -ShopClosePacket#7 => shopclose 74 +NosCore.Packets.ServerPackets.UI.ShopClosePacket#1 => shopclose 21 +NosCore.Packets.ServerPackets.UI.ShopClosePacket#7 => shopclose 74 TARankPacket#1 => ta_rank 21.44.83.s15853.1.0.87 55.52.90.s13380.4.1.23 s30369 TARankPacket#7 => ta_rank 74.75.77.s30408.3.0.37 53.78.12.s27953.4.0.45 s21847 TeamArenaClosePacket#1 => ta_close @@ -788,10 +794,10 @@ FStashAllPacket#1 => f_stash_all 21 44.83.53.21.82.87.55 52.90.80.24.27.23.69 FStashAllPacket#7 => f_stash_all 74 75.77.8.43.82.37.53 78.12.53.59.96.45.47 FStashClientPacket#1 => f_stash 21.44.83.53.21.82.87 55.52.90.80.24.27.23 FStashClientPacket#7 => f_stash 74.75.77.8.43.82.37 53.78.12.53.59.96.45 -PStashAllPacket#1 => p_stash_all 21 44.83.53.21.82.87.55 52.90.80.24.27.23.69 -PStashAllPacket#7 => p_stash_all 74 75.77.8.43.82.37.53 78.12.53.59.96.45.47 -PStashClientPacket#1 => p_stash 21.44.83.53.21.82.87 55.52.90.80.24.27.23 -PStashClientPacket#7 => p_stash 74.75.77.8.43.82.37 53.78.12.53.59.96.45 +PStashAllPacket#1 => pstash_all 21 44.83.53.21.82.87.55 52.90.80.24.27.23.69 +PStashAllPacket#7 => pstash_all 74 75.77.8.43.82.37.53 78.12.53.59.96.45.47 +PStashClientPacket#1 => pstash 21.44.83.53.21.82.87 55.52.90.80.24.27.23 +PStashClientPacket#7 => pstash 74.75.77.8.43.82.37 53.78.12.53.59.96.45 StashAllPacket#1 => stash_all 21 44.83.53.21.82.87.55 52.90.80.24.27.23.69 StashAllPacket#7 => stash_all 74 75.77.8.43.82.37.53 78.12.53.59.96.45.47 StashClientPacket#1 => stash 21.44.83.53.21.82.87 55.52.90.80.24.27.23 diff --git a/test/NosCore.Packets.Tests/SerializerCorpusTests.cs b/test/NosCore.Packets.Tests/SerializerCorpusTests.cs index 7a64f39..ccbf163 100644 --- a/test/NosCore.Packets.Tests/SerializerCorpusTests.cs +++ b/test/NosCore.Packets.Tests/SerializerCorpusTests.cs @@ -47,15 +47,9 @@ public Task ExpressionTreeSerializerOutputIsPinnedForEveryPacket() private static string SnapshotDirectory => Path.Combine( Directory.GetCurrentDirectory(), "..", "..", ".."); - // Serializer keys _packetSerializerDictionary by typeof(T).Name - the SIMPLE - // name - so two packets sharing a class name across namespaces overwrite each - // other, and Initialize resolves the clash by letting the non-ClientPackets one - // win. Serializing the loser then invokes the winner's delegate and throws - // ArgumentException. Each server currently registers a filtered subset of packet - // types, which is why this has not bitten in production. - // - // Pinned rather than fixed here: generated per-type methods cannot collide by - // simple name, so porting to the generator removes the failure mode outright. + // Ten packet class names exist in both a ClientPackets and a ServerPackets + // namespace. The serializer registry is keyed by Type, so both variants keep + // their own delegate; this pin only guards against new accidental duplicates. private static readonly string[] KnownSimpleNameCollisions = { "BpmPacket", "DropPacket", "FamilyDismissPacket", "GidxPacket", "GuriPacket", @@ -63,7 +57,7 @@ public Task ExpressionTreeSerializerOutputIsPinnedForEveryPacket() }; [TestMethod] - public void OnlyTheKnownSimpleNameCollisionsFailToSerialize() + public void EveryPacketSerializes() { var failures = new List(); @@ -75,18 +69,13 @@ public void OnlyTheKnownSimpleNameCollisionsFailToSerialize() } catch (Exception ex) { - failures.Add($"{type.Name}: {ex.GetType().Name} {ex.Message}"); + failures.Add($"{type.FullName}: {ex.GetType().Name} {ex.Message}"); } } - var unexpected = failures - .Where(f => !KnownSimpleNameCollisions.Any(known => - f.StartsWith(known + ":", StringComparison.Ordinal))) - .ToList(); - - Assert.AreEqual(0, unexpected.Count, - $"{unexpected.Count} packets threw for a reason other than the known name " + - $"collisions:{Environment.NewLine}{string.Join(Environment.NewLine, unexpected)}"); + Assert.AreEqual(0, failures.Count, + $"{failures.Count} packets failed to serialize:" + + $"{Environment.NewLine}{string.Join(Environment.NewLine, failures)}"); } [TestMethod] @@ -107,11 +96,15 @@ public void CollidingPacketNamesAreStillDistinctTypes() // Two seeds per packet: one exercises the populated path, the other shifts every // value so an off-by-one in separator or optional-run handling cannot hide behind - // a coincidence. + // a coincidence. Colliding simple names are disambiguated by namespace so each + // snapshot line maps to exactly one type. private static IEnumerable Corpus() { foreach (var type in PacketCorpus.PacketTypes) { + var id = KnownSimpleNameCollisions.Contains(type.Name) + ? $"{type.Namespace}.{type.Name}" + : type.Name; foreach (var seed in new[] { 1, 7 }) { string result; @@ -124,7 +117,7 @@ private static IEnumerable Corpus() result = $"<>"; } - yield return $"{type.Name}#{seed} => {result}"; + yield return $"{id}#{seed} => {result}"; } } }