diff --git a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/DisplayHuePickerTests.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/DisplayHuePickerTests.cs deleted file mode 100644 index a696f9302..000000000 --- a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/DisplayHuePickerTests.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Buffers; -using Server.HuePickers; -using Server.Network; -using Xunit; - -namespace Server.Tests.Network -{ - public class DisplayHuePickerTests - { - [Fact] - public void TestDisplayHuePicker() - { - const ushort itemID = 0xFF01; - var huePicker = new HuePicker(itemID); - - var data = new DisplayHuePicker(huePicker).Compile(); - - Span expectedData = stackalloc byte[9]; - var pos = 0; - - expectedData.Write(ref pos, (byte)0x95); - expectedData.Write(ref pos, huePicker.Serial); -#if NO_LOCAL_INIT - expectedData.Write(ref pos, (ushort)0); -#else - pos += 2; -#endif - expectedData.Write(ref pos, itemID); - - AssertThat.Equal(data, expectedData); - } - } -} diff --git a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPacketTests.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPacketTests.cs index 90c5c3788..c8f7201de 100644 --- a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPacketTests.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPacketTests.cs @@ -1,5 +1,6 @@ using System; using System.Buffers; +using Server.HuePickers; using Server.Network; using Xunit; @@ -127,87 +128,60 @@ namespace Server.Tests.Network AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Fact] - public void TestServerChange() + [Theory] + [InlineData(100, 1000, 1, 0)] + public void TestServerChange(int x, int y, int z, int mapID) { - var p = new Point3D(100, 1000, 1); - var map = Map.Felucca; - var data = new ServerChange(p, map).Compile(); + var p = new Point3D(x, y, z); + var map = Map.Maps[mapID]; + var expected = new ServerChange(p, map).Compile(); - Span expectedData = stackalloc byte[16]; - var pos = 0; + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendServerChange(p, map); - expectedData.Write(ref pos, (byte)0x76); // Packet ID - expectedData.Write(ref pos, (ushort)p.X); - expectedData.Write(ref pos, (ushort)p.Y); - expectedData.Write(ref pos, (short)p.Z); -#if NO_LOCAL_INIT - expectedData.Write(ref pos, (byte)0); // Unknown - expectedData.Write(ref pos, 0); // Server X, Server Y -#else - pos += 5; -#endif - expectedData.Write(ref pos, (ushort)map.Width); // Server Width - expectedData.Write(ref pos, (ushort)map.Height); // Server Height - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } [Fact] - public void TestSkillUpdate() + public void TestSkillsUpdate() { var m = new Mobile(0x1); m.DefaultMobileInit(); var skills = m.Skills; - m.Skills[SkillName.Alchemy].BaseFixedPoint = 1000; // GM Alchemy + m.Skills[Utility.RandomSkill()].BaseFixedPoint = 1000; - var data = new SkillUpdate(skills).Compile(); + var expected = new SkillUpdate(skills).Compile(); - var length = 6 + skills.Length * 9; - Span expectedData = stackalloc byte[length]; - var pos = 0; + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendSkillsUpdate(skills); - expectedData.Write(ref pos, (byte)0x3A); // Packet ID - expectedData.Write(ref pos, (ushort)length); // Length - expectedData.Write(ref pos, (byte)0x02); // type: absolute, capped - - for (var i = 0; i < skills.Length; i++) - { - var s = skills[i]; - - var v = s.NonRacialValue; - var uv = Math.Clamp((int)(v * 10), 0, 0xFFFF); - - expectedData.Write(ref pos, (ushort)(s.Info.SkillID + 1)); - expectedData.Write(ref pos, (ushort)uv); - expectedData.Write(ref pos, (ushort)s.BaseFixedPoint); - expectedData.Write(ref pos, (byte)s.Lock); - expectedData.Write(ref pos, (ushort)s.CapFixedPoint); - } - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Theory, InlineData(0), InlineData(10), InlineData(255)] + [Theory] + [InlineData(0)] + [InlineData(10)] + [InlineData(255)] public void TestSequence(byte num) { - var data = new Sequence(num).Compile(); + var expected = new Sequence(num).Compile(); - Span expectedData = stackalloc byte[2]; - var pos = 0; + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendSequence(num); - expectedData.Write(ref pos, (byte)0x7B); // Packet ID - expectedData.Write(ref pos, num); - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Theory, InlineData(SkillName.Alchemy, 0, 1), InlineData(SkillName.Archery, 10, 1000), - InlineData(SkillName.Begging, 100000, 1000)] + [Theory] + [InlineData(SkillName.Alchemy, 0, 1)] + [InlineData(SkillName.Archery, 10, 1000)] + [InlineData(SkillName.Begging, 100000, 1000)] public void TestSkillChange(SkillName skillName, int baseFixedPoint, int capFixedPoint) { - // TODO: Eliminate all of this and just create a Skill directly var m = new Mobile(0x1); m.DefaultMobileInit(); @@ -215,217 +189,181 @@ namespace Server.Tests.Network skill.BaseFixedPoint = baseFixedPoint; skill.CapFixedPoint = capFixedPoint; - var data = new SkillChange(skill).Compile(); + var expected = new SkillChange(skill).Compile(); - Span expectedData = stackalloc byte[13]; - var pos = 0; + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendSkillChange(skill); - expectedData.Write(ref pos, (byte)0x3A); // Packet ID - expectedData.Write(ref pos, (ushort)13); // Length - expectedData.Write(ref pos, (byte)0xDF); // type: delta, capped - - var v = skill.NonRacialValue; - var uv = Math.Clamp((int)(v * 10), 0, 0xFFFF); - - expectedData.Write(ref pos, (ushort)skill.Info.SkillID); - expectedData.Write(ref pos, (ushort)uv); - expectedData.Write(ref pos, (ushort)skill.BaseFixedPoint); - expectedData.Write(ref pos, (byte)skill.Lock); - expectedData.Write(ref pos, (ushort)skill.CapFixedPoint); - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Theory, InlineData(null), InlineData(""), InlineData("This is a URL, I promise")] - public void TestLaunchBrowser(string url) + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData("This is a URL, I promise")] + [InlineData("https://www.modernuo.com")] + public void TestLaunchBrowser(string uri) { - var data = new LaunchBrowser(url).Compile(); + var expected = new LaunchBrowser(uri).Compile(); - url ??= ""; + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendLaunchBrowser(uri); - var length = 4 + url.Length; - Span expectedData = stackalloc byte[length]; - var pos = 0; - - expectedData.Write(ref pos, (byte)0xA5); // Packet ID - expectedData.Write(ref pos, (ushort)length); // Length - expectedData.WriteAsciiNull(ref pos, url); // Note: use punycode for unicode URLs - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Fact] - public void TestDragEffect() + [Theory] + [InlineData(0x1000u, 1000, 100, 10, 0x2000u, 1125, 125, 5, 0x384, 1024, 25)] + public void TestDragEffect( + uint srcSerial, int srcX, int srcY, int srcZ, + uint trgSerial, int trgX, int trgY, int trgZ, + int itemId, int hue, int amount + ) { - var src = new Entity(0x1, new Point3D(1000, 100, 10), Map.Felucca); - var targ = new Entity(0x2, new Point3D(1125, 125, 5), Map.Felucca); - var itemID = 0x384; - var hue = 1024; - var amount = 25; + var src = new Entity(srcSerial, new Point3D(srcX, srcY, srcZ), null); + var targ = new Entity(trgSerial, new Point3D(trgX, trgY, trgZ), null); - var data = new DragEffect(src, targ, itemID, hue, amount).Compile(); + var expected = new DragEffect(src, targ, itemId, hue, amount).Compile(); - Span expectedData = stackalloc byte[26]; - var pos = 0; + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendDragEffect( + src.Serial, src.Location, + targ.Serial, targ.Location, + itemId, hue, amount + ); - expectedData.Write(ref pos, (byte)0x23); // Packet ID - expectedData.Write(ref pos, (ushort)itemID); - -#if NO_LOCAL_INIT - expectedData.Write(ref pos, (byte)0); -#else - pos++; -#endif - - expectedData.Write(ref pos, (ushort)hue); - expectedData.Write(ref pos, (ushort)amount); - expectedData.Write(ref pos, src.Serial); - expectedData.Write(ref pos, src.Location); - expectedData.Write(ref pos, targ.Serial); - expectedData.Write(ref pos, targ.Location); - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Theory, InlineData(1, false), InlineData(2, true)] + [Theory] + [InlineData(1, false)] + [InlineData(2, true)] public void TestSeasonChange(int season, bool playSound) { - var data = new SeasonChange(season, playSound).Compile(); + var expected = new SeasonChange(season, playSound).Compile(); - Span expectedData = stackalloc byte[3]; - var pos = 0; + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendSeasonChange((byte)season, playSound); - expectedData.Write(ref pos, (byte)0xBC); // Packet ID - expectedData.Write(ref pos, (byte)season); - expectedData.Write(ref pos, playSound); - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Theory, InlineData(0x1024, "Test Title", true, true), InlineData(0x1024, "Test Title", false, true), - InlineData(0x1024, "Test Title", true, false)] + [Theory] + [InlineData(0x1024u, "Test Title", true, true)] + [InlineData(0x1024u, "Test Title", false, true)] + [InlineData(0x1024u, "Test Title", true, false)] public void TestDisplayPaperdoll(uint m, string title, bool warmode, bool canLift) { - var data = new DisplayPaperdoll(m, title, warmode, canLift).Compile(); + var expected = new DisplayPaperdoll(m, title, warmode, canLift).Compile(); - Span expectedData = stackalloc byte[66]; - var pos = 0; + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendDisplayPaperdoll(m, title, warmode, canLift); - expectedData.Write(ref pos, (byte)0x88); // Packet ID - expectedData.Write(ref pos, m); - expectedData.WriteAsciiFixed(ref pos, title, 60); - byte flags = 0x00; - if (warmode) - { - flags |= 0x01; - } - - if (canLift) - { - flags |= 0x02; - } - - expectedData.Write(ref pos, flags); - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Theory, InlineData(MusicName.Approach), InlineData(MusicName.Combat1), InlineData(MusicName.ValoriaShips)] + [Theory] + [InlineData(MusicName.Approach)] + [InlineData(MusicName.Combat1)] + [InlineData(MusicName.ValoriaShips)] public void TestPlayMusic(MusicName music) { - var data = new PlayMusic(music).Compile(); + var expected = new PlayMusic(music).Compile(); - Span expectedData = stackalloc byte[3]; - var pos = 0; + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendPlayMusic(music); - expectedData.Write(ref pos, (byte)0x6D); // Packet ID - expectedData.Write(ref pos, (ushort)music); // Flags - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Theory, InlineData(10, 1, "Some text"), InlineData(100, 10, "Some more text")] + [Theory] + [InlineData(10, 1, "Some text")] + [InlineData(100, 10, "Some more text")] public void TestScrollMessage(int type, int tip, string text) { - var data = new ScrollMessage(type, tip, text).Compile(); + var expected = new ScrollMessage(type, tip, text).Compile(); - text ??= ""; - var length = 10 + text.Length; - Span expectedData = stackalloc byte[length]; - var pos = 0; + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendScrollMessage(type, tip ,text); - expectedData.Write(ref pos, (byte)0xA6); // Packet ID - expectedData.Write(ref pos, (ushort)length); // Length - expectedData.Write(ref pos, (byte)type); - expectedData.Write(ref pos, tip); - expectedData.Write(ref pos, (ushort)text.Length); - expectedData.WriteAscii(ref pos, text); - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Fact] - public void TestCurrentTime() + [Theory] + [InlineData(14, 10, 05)] + public void TestCurrentTime(int hour, int minute, int second) { - var date = DateTime.Parse("2020-01-01 14:10:05"); + var date = new DateTime(2020, 1, 1, hour, minute, second); + var expected = new CurrentTime(date).Compile(); - var data = new CurrentTime(date).Compile(); + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendCurrentTime(date); - Span expectedData = stackalloc byte[4]; - var pos = 0; - - expectedData.Write(ref pos, (byte)0x5B); // Packet ID - expectedData.Write(ref pos, (byte)date.Hour); - expectedData.Write(ref pos, (byte)date.Minute); - expectedData.Write(ref pos, (byte)date.Second); - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Fact] - public void TestPathfindMessage() + [Theory] + [InlineData(1000, 10, 1)] + public void TestPathfindMessage(int x, int y, int z) { - var p = new Point3D(1000, 10, 1); - var data = new PathfindMessage(p).Compile(); + var p = new Point3D(x, y, z); + var expected = new PathfindMessage(p).Compile(); - Span expectedData = stackalloc byte[7]; - var pos = 0; + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendPathfindMessage(p); - expectedData.Write(ref pos, (byte)0x38); // Packet ID - expectedData.Write(ref pos, (ushort)p.X); - expectedData.Write(ref pos, (ushort)p.Y); - expectedData.Write(ref pos, (short)p.Z); - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Theory, InlineData(0), InlineData(10), InlineData(100)] + [Theory] + [InlineData(0)] + [InlineData(10)] + [InlineData(100)] public void TestPingAck(byte ping) { - var data = new PingAck(ping).Compile(); + var expected = new PingAck(ping).Compile(); - Span expectedData = stackalloc byte[2]; - var pos = 0; + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendPingAck(ping); - expectedData.Write(ref pos, (byte)0x73); // Packet ID - expectedData.Write(ref pos, ping); - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } [Fact] public void TestClearAbility() { - var data = new ClearWeaponAbility().Compile(); + var expected = new ClearWeaponAbility().Compile(); - Span expectedData = stackalloc byte[5]; - var pos = 0; + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendClearWeaponAbility(); - expectedData.Write(ref pos, (byte)0xBF); // Packet ID - expectedData.Write(ref pos, (ushort)5); // Length - expectedData.Write(ref pos, (ushort)0x21); // Sub-packet + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); + } - AssertThat.Equal(data, expectedData); + [Theory] + [InlineData(0xFF01)] + public void TestDisplayHuePicker(int itemID) + { + var huePicker = new HuePicker(itemID); + + var expected = new DisplayHuePicker(huePicker).Compile(); + + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendDisplayHuePicker(huePicker.Serial, huePicker.ItemID); + + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } } } diff --git a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPackets.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPackets.cs index 82dbd892d..f304c3b69 100644 --- a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPackets.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPackets.cs @@ -1,3 +1,6 @@ +using System; +using Server.HuePickers; + namespace Server.Network { public sealed class StatLockInfo : Packet @@ -109,4 +112,287 @@ namespace Server.Network Stream.Write((byte)temp); } } + + public sealed class ServerChange : Packet + { + public ServerChange(Point3D p, Map map) : base(0x76, 16) + { + Stream.Write((short)p.X); + Stream.Write((short)p.Y); + Stream.Write((short)p.Z); + Stream.Write((byte)0); + Stream.Write((short)0); + Stream.Write((short)0); + Stream.Write((short)map.Width); + Stream.Write((short)map.Height); + } + } + + public sealed class SkillUpdate : Packet + { + public SkillUpdate(Skills skills) : base(0x3A) + { + EnsureCapacity(6 + skills.Length * 9); + + Stream.Write((byte)0x02); // type: absolute, capped + + for (var i = 0; i < skills.Length; ++i) + { + var s = skills[i]; + + var v = s.NonRacialValue; + var uv = Math.Clamp((int)(v * 10), 0, 0xFFFF); + + Stream.Write((ushort)(s.Info.SkillID + 1)); + Stream.Write((ushort)uv); + Stream.Write((ushort)s.BaseFixedPoint); + Stream.Write((byte)s.Lock); + Stream.Write((ushort)s.CapFixedPoint); + } + + Stream.Write((short)0); // terminate + } + } + + public sealed class Sequence : Packet + { + public Sequence(int num) : base(0x7B, 2) + { + Stream.Write((byte)num); + } + } + + public sealed class SkillChange : Packet + { + public SkillChange(Skill skill) : base(0x3A) + { + EnsureCapacity(13); + + var v = skill.NonRacialValue; + var uv = Math.Clamp((int)(v * 10), 0, 0xFFFF); + + Stream.Write((byte)0xDF); // type: delta, capped + Stream.Write((ushort)skill.Info.SkillID); + Stream.Write((ushort)uv); + Stream.Write((ushort)skill.BaseFixedPoint); + Stream.Write((byte)skill.Lock); + Stream.Write((ushort)skill.CapFixedPoint); + } + } + + public sealed class LaunchBrowser : Packet + { + public LaunchBrowser(string url) : base(0xA5) + { + url ??= ""; + + EnsureCapacity(4 + url.Length); + + Stream.WriteAsciiNull(url); + } + } + + public sealed class DragEffect : Packet + { + public DragEffect(IEntity src, IEntity trg, int itemID, int hue, int amount) : base(0x23, 26) + { + Stream.Write((short)itemID); + Stream.Write((byte)0); + Stream.Write((short)hue); + Stream.Write((short)amount); + Stream.Write(src.Serial); + Stream.Write((short)src.X); + Stream.Write((short)src.Y); + Stream.Write((sbyte)src.Z); + Stream.Write(trg.Serial); + Stream.Write((short)trg.X); + Stream.Write((short)trg.Y); + Stream.Write((sbyte)trg.Z); + } + } + + public sealed class SeasonChange : Packet + { + private static readonly SeasonChange[][] m_Cache = + { + new SeasonChange[2], + new SeasonChange[2], + new SeasonChange[2], + new SeasonChange[2], + new SeasonChange[2] + }; + + public SeasonChange(int season, bool playSound = true) : base(0xBC, 3) + { + Stream.Write((byte)season); + Stream.Write(playSound); + } + + public static SeasonChange Instantiate(int season) => Instantiate(season, true); + + public static SeasonChange Instantiate(int season, bool playSound) + { + if (season >= 0 && season < m_Cache.Length) + { + var idx = playSound ? 1 : 0; + + var p = m_Cache[season][idx]; + + if (p == null) + { + m_Cache[season][idx] = p = new SeasonChange(season, playSound); + p.SetStatic(); + } + + return p; + } + + return new SeasonChange(season, playSound); + } + } + + public sealed class DisplayPaperdoll : Packet + { + public DisplayPaperdoll(Serial m, string title, bool warmode, bool canLift) : base(0x88, 66) + { + byte flags = 0x00; + + if (warmode) + { + flags |= 0x01; + } + + if (canLift) + { + flags |= 0x02; + } + + Stream.Write(m); + Stream.WriteAsciiFixed(title, 60); + Stream.Write(flags); + } + } + + public sealed class PlayMusic : Packet + { + public static readonly Packet InvalidInstance = SetStatic(new PlayMusic(MusicName.Invalid)); + + private static readonly Packet[] m_Instances = new Packet[60]; + + public PlayMusic(MusicName name) : base(0x6D, 3) + { + Stream.Write((short)name); + } + + public static Packet GetInstance(MusicName name) + { + if (name == MusicName.Invalid) + { + return InvalidInstance; + } + + var v = (int)name; + Packet p; + + if (v >= 0 && v < m_Instances.Length) + { + p = m_Instances[v]; + + if (p == null) + { + m_Instances[v] = p = SetStatic(new PlayMusic(name)); + } + } + else + { + p = new PlayMusic(name); + } + + return p; + } + } + + public sealed class ScrollMessage : Packet + { + public ScrollMessage(int type, int tip, string text) : base(0xA6) + { + text ??= ""; + + EnsureCapacity(10 + text.Length); + + Stream.Write((byte)type); + Stream.Write(tip); + Stream.Write((ushort)text.Length); + Stream.WriteAsciiFixed(text, text.Length); + } + } + + public sealed class CurrentTime : Packet + { + public CurrentTime() : this(DateTime.Now) + { + } + + public CurrentTime(DateTime date) : base(0x5B, 4) + { + Stream.Write((byte)date.Hour); + Stream.Write((byte)date.Minute); + Stream.Write((byte)date.Second); + } + } + + public sealed class PathfindMessage : Packet + { + public PathfindMessage(Point3D p) : base(0x38, 7) + { + Stream.Write((short)p.X); + Stream.Write((short)p.Y); + Stream.Write((short)p.Z); + } + } + + public sealed class PingAck : Packet + { + private static readonly PingAck[] m_Cache = new PingAck[0x100]; + + public PingAck(byte ping) : base(0x73, 2) + { + Stream.Write(ping); + } + + public static PingAck Instantiate(byte ping) + { + var p = m_Cache[ping]; + + if (p == null) + { + m_Cache[ping] = p = new PingAck(ping); + p.SetStatic(); + } + + return p; + } + } + + public sealed class ClearWeaponAbility : Packet + { + public static readonly Packet Instance = SetStatic(new ClearWeaponAbility()); + + public ClearWeaponAbility() : base(0xBF) + { + EnsureCapacity(5); + + Stream.Write((short)0x21); + } + } + + public sealed class DisplayHuePicker : Packet + { + public DisplayHuePicker(HuePicker huePicker) : base(0x95, 9) + { + Stream.Write(huePicker.Serial); + Stream.Write((short)0); + Stream.Write((short)huePicker.ItemID); + } + } } diff --git a/Projects/Server/HuePicker.cs b/Projects/Server/HuePicker.cs index 1d549467d..dc5408834 100644 --- a/Projects/Server/HuePicker.cs +++ b/Projects/Server/HuePicker.cs @@ -4,7 +4,7 @@ namespace Server.HuePickers { public class HuePicker { - private static int m_NextSerial = 1; + private static Serial m_NextSerial = 1; public HuePicker(int itemID) { @@ -16,7 +16,7 @@ namespace Server.HuePickers ItemID = itemID; } - public int Serial { get; } + public Serial Serial { get; } public int ItemID { get; } @@ -26,7 +26,7 @@ namespace Server.HuePickers public void SendTo(NetState state) { - state.Send(new DisplayHuePicker(this)); + state.SendDisplayHuePicker(Serial, ItemID); state.AddHuePicker(this); } } diff --git a/Projects/Server/Mobiles/Mobile.cs b/Projects/Server/Mobiles/Mobile.cs index e8ca1ca8c..defa27f83 100644 --- a/Projects/Server/Mobiles/Mobile.cs +++ b/Projects/Server/Mobiles/Mobile.cs @@ -2815,10 +2815,10 @@ namespace Server ns.SendMapPatches(); } - ns.Send(SeasonChange.Instantiate(GetSeason(), true)); + ns.SendSeasonChange((byte)GetSeason(), true); ns.SendMobileUpdate(this); - Send(new ServerChange(m_Location, m_Map)); + ns.SendServerChange(m_Location, m_Map); } ns.SendMobileIncoming(this, this); @@ -5288,31 +5288,34 @@ namespace Server if (DragEffects && map != null && (root == null || root is Item)) { var eable = map.GetClientsInRange(from.Location); - Packet p = null; var rootItem = root as Item; + Span buffer = stackalloc byte[OutgoingPlayerPackets.DragEffectPacketLength]; + buffer.InitializePacket(); + foreach (var ns in eable) { if (ns.Mobile != from && ns.Mobile.CanSee(from) && ns.Mobile.InLOS(from) && ns.Mobile.CanSee(root)) { - if (p == null) + if (buffer[0] == 0) { - IEntity src = new Entity( + OutgoingPlayerPackets.CreateDragEffect( + buffer, rootItem?.Serial ?? Serial.Zero, rootItem?.Location ?? item.Location, - map + from.Serial, + from.Location, + item.ItemID, + item.Hue, + amount ); - - p = Packet.Acquire(new DragEffect(src, from, item.ItemID, item.Hue, amount)); } - ns.Send(p); + ns.Send(buffer); } } - Packet.Release(p); - eable.Free(); } @@ -5430,46 +5433,53 @@ namespace Server public virtual void SendDropEffect(Item item) { - if (DragEffects && !item.Deleted) + if (!DragEffects || item.Deleted) { - var map = m_Map; - var root = item.RootParent; + return; + } - if (map != null && (root == null || root is Item)) + var map = m_Map; + var root = item.RootParent; + var rootItem = root as Item; + + if (map == null || root != null && rootItem == null) + { + return; + } + + var eable = map.GetClientsInRange(m_Location); + + Span buffer = stackalloc byte[OutgoingPlayerPackets.DragEffectPacketLength]; + buffer.InitializePacket(); + + foreach (var ns in eable) + { + if (ns.StygianAbyss) { - var eable = map.GetClientsInRange(m_Location); - Packet p = null; - var rootItem = root as Item; + continue; + } - foreach (var ns in eable) + if (ns.Mobile != this && ns.Mobile.CanSee(this) && ns.Mobile.InLOS(this) && ns.Mobile.CanSee(root)) + { + if (buffer[0] == 0) { - if (ns.StygianAbyss) - { - continue; - } - - if (ns.Mobile != this && ns.Mobile.CanSee(this) && ns.Mobile.InLOS(this) && ns.Mobile.CanSee(root)) - { - if (p == null) - { - IEntity trg = new Entity( - rootItem?.Serial ?? Serial.Zero, - rootItem?.Location ?? item.Location, - map - ); - - p = Packet.Acquire(new DragEffect(this, trg, item.ItemID, item.Hue, item.Amount)); - } - - ns.Send(p); - } + OutgoingPlayerPackets.CreateDragEffect( + buffer, + Serial, + Location, + rootItem?.Serial ?? Serial.Zero, + rootItem?.Location ?? item.Location, + item.ItemID, + item.Hue, + item.Amount + ); } - Packet.Release(p); - - eable.Free(); + ns.Send(buffer); } } + + eable.Free(); } public virtual bool Drop(Item to, Point3D loc) @@ -8116,7 +8126,7 @@ namespace Server { if (from == this) { - Send(new SkillUpdate(Skills)); + m_NetState.SendSkillsUpdate(Skills); } } diff --git a/Projects/Server/Network/NetState/NetState.cs b/Projects/Server/Network/NetState/NetState.cs index ad9afb8c6..ab823521a 100644 --- a/Projects/Server/Network/NetState/NetState.cs +++ b/Projects/Server/Network/NetState/NetState.cs @@ -354,7 +354,7 @@ namespace Server.Network public void LaunchBrowser(string url) { this.SendMessageLocalized(Serial.MinusOne, -1, MessageType.Label, 0x35, 3, 501231); - Send(new LaunchBrowser(url)); + this.SendLaunchBrowser(url); } public override string ToString() => m_ToString; diff --git a/Projects/Server/Network/Packets/IncomingAccountPackets.cs b/Projects/Server/Network/Packets/IncomingAccountPackets.cs index 71eaf48ef..23d9d4dd6 100644 --- a/Projects/Server/Network/Packets/IncomingAccountPackets.cs +++ b/Projects/Server/Network/Packets/IncomingAccountPackets.cs @@ -310,7 +310,7 @@ namespace Server.Network state.SendMapPatches(); } - state.Send(SeasonChange.Instantiate(m.GetSeason(), true)); + state.SendSeasonChange((byte)m.GetSeason(), true); state.SendSupportedFeature(); @@ -338,8 +338,8 @@ namespace Server.Network state.SendMobileIncoming(m, m); state.SendLoginComplete(); - state.Send(new CurrentTime()); - state.Send(SeasonChange.Instantiate(m.GetSeason(), true)); + state.SendCurrentTime(); + state.SendSeasonChange((byte)m.GetSeason(), true); state.SendMapChange(m.Map); EventSink.InvokeLogin(m); diff --git a/Projects/Server/Network/Packets/IncomingPlayerPackets.cs b/Projects/Server/Network/Packets/IncomingPlayerPackets.cs index 4fa23259f..24621a6b4 100644 --- a/Projects/Server/Network/Packets/IncomingPlayerPackets.cs +++ b/Projects/Server/Network/Packets/IncomingPlayerPackets.cs @@ -483,7 +483,7 @@ namespace Server.Network public static void PingReq(NetState state, CircularBufferReader reader) { - state.Send(PingAck.Instantiate(reader.ReadByte())); + state.SendPingAck(reader.ReadByte()); } public static void SetUpdateRange(NetState state, CircularBufferReader reader) diff --git a/Projects/Server/Network/Packets/OutgoingPlayerPackets.cs b/Projects/Server/Network/Packets/OutgoingPlayerPackets.cs index 07317c76d..2724f81f5 100644 --- a/Projects/Server/Network/Packets/OutgoingPlayerPackets.cs +++ b/Projects/Server/Network/Packets/OutgoingPlayerPackets.cs @@ -13,9 +13,11 @@ * along with this program. If not, see . * *************************************************************************/ +using System; using System.Buffers; using System.IO; using System.Runtime.CompilerServices; +using Server.HuePickers; namespace Server.Network { @@ -31,6 +33,8 @@ namespace Server.Network public static class OutgoingPlayerPackets { + public const int DragEffectPacketLength = 26; + public static void SendStatLockInfo(this NetState ns, Mobile m) { if (ns == null || !ns.GetSendBuffer(out var buffer)) @@ -122,5 +126,269 @@ namespace Server.Network { ns?.Send(stackalloc byte[] { 0x65, type, density, temp }); } + + public static void SendServerChange(this NetState ns, Point3D p, Map map) + { + if (ns == null || !ns.GetSendBuffer(out var buffer)) + { + return; + } + + var writer = new CircularBufferWriter(buffer); + writer.Write((byte)0x76); // Packet ID + writer.Write((short)p.X); + writer.Write((short)p.Y); + writer.Write((short)p.Z); + writer.Write((byte)0); + writer.Write((short)0); + writer.Write((short)0); + writer.Write((short)map.Width); + writer.Write((short)map.Height); + + ns.Send(ref buffer, writer.Position); + } + + public static void SendSkillsUpdate(this NetState ns, Skills skills) + { + if (ns == null || !ns.GetSendBuffer(out var buffer)) + { + return; + } + + var writer = new CircularBufferWriter(buffer); + writer.Write((byte)0x3A); // Packet ID + writer.Seek(2, SeekOrigin.Current); + + writer.Write((byte)0x02); // type: absolute, capped + + for (var i = 0; i < skills.Length; ++i) + { + var s = skills[i]; + + var v = s.NonRacialValue; + var uv = Math.Clamp((int)(v * 10), 0, 0xFFFF); + + writer.Write((ushort)(s.Info.SkillID + 1)); + writer.Write((ushort)uv); + writer.Write((ushort)s.BaseFixedPoint); + writer.Write((byte)s.Lock); + writer.Write((ushort)s.CapFixedPoint); + } + + writer.Write((short)0); // terminate + + writer.WritePacketLength(); + ns.Send(ref buffer, writer.Position); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SendSequence(this NetState ns, byte sequence) + { + ns?.Send(stackalloc byte[] { 0x7B, sequence }); + } + + public static void SendSkillChange(this NetState ns, Skill skill) + { + if (ns == null || !ns.GetSendBuffer(out var buffer)) + { + return; + } + + var writer = new CircularBufferWriter(buffer); + writer.Write((byte)0x3A); // Packet ID + writer.Write((ushort)13); + + var v = skill.NonRacialValue; + var uv = Math.Clamp((int)(v * 10), 0, 0xFFFF); + + writer.Write((byte)0xDF); // type: delta, capped + writer.Write((ushort)skill.Info.SkillID); + writer.Write((ushort)uv); + writer.Write((ushort)skill.BaseFixedPoint); + writer.Write((byte)skill.Lock); + writer.Write((ushort)skill.CapFixedPoint); + + ns.Send(ref buffer, writer.Position); + } + + public static void SendLaunchBrowser(this NetState ns, string uri) + { + if (ns == null || !ns.GetSendBuffer(out var buffer)) + { + return; + } + + var writer = new CircularBufferWriter(buffer); + writer.Write((byte)0xA5); // Packet ID + writer.Seek(2, SeekOrigin.Current); + writer.WriteAsciiNull(uri ?? ""); + + writer.WritePacketLength(); + + ns.Send(ref buffer, writer.Position); + } + + public static void CreateDragEffect( + Span buffer, + Serial srcSerial, Point3D srcLocation, + Serial trgSerial, Point3D trgLocation, + int itemID, int hue, int amount + ) + { + var writer = new SpanWriter(buffer); + writer.Write((byte)0x23); // Packet ID + writer.Write((short)itemID); + writer.Write((byte)0); + writer.Write((short)hue); + writer.Write((short)amount); + writer.Write(srcSerial); + writer.Write((short)srcLocation.X); + writer.Write((short)srcLocation.Y); + writer.Write((sbyte)srcLocation.Z); + writer.Write(trgSerial); + writer.Write((short)trgLocation.X); + writer.Write((short)trgLocation.Y); + writer.Write((sbyte)trgLocation.Z); + } + + public static void SendDragEffect( + this NetState ns, + Serial srcSerial, Point3D srcLocation, + Serial trgSerial, Point3D trgLocation, + int itemID, int hue, int amount + ) + { + if (ns == null) + { + return; + } + + Span span = stackalloc byte[DragEffectPacketLength]; + CreateDragEffect(span, srcSerial, srcLocation, trgSerial, trgLocation, itemID, hue, amount); + ns.Send(span); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void SendSeasonChange(this NetState ns, byte season, bool playSound) + { + ns?.Send(stackalloc byte[]{ 0xBC, season, *(byte*)&playSound }); + } + + public static void SendDisplayPaperdoll(this NetState ns, Serial m, string title, bool warmode, bool canLift) + { + if (ns == null || !ns.GetSendBuffer(out var buffer)) + { + return; + } + + byte flags = 0x00; + + if (warmode) + { + flags |= 0x01; + } + + if (canLift) + { + flags |= 0x02; + } + + var writer = new CircularBufferWriter(buffer); + writer.Write((byte)0x88); // Packet ID + writer.Write(m); + writer.WriteAscii(title, 60); + writer.Write(flags); + + ns.Send(ref buffer, writer.Position); + } + + public static void SendPlayMusic(this NetState ns, MusicName music) + { + if (ns == null || !ns.GetSendBuffer(out var buffer)) + { + return; + } + + var writer = new CircularBufferWriter(buffer); + writer.Write((byte)0x6D); // Packet ID + writer.Write((short)music); + + ns.Send(ref buffer, writer.Position); + } + + public static void SendScrollMessage(this NetState ns, int type, int tip, string text) + { + if (ns == null || !ns.GetSendBuffer(out var buffer)) + { + return; + } + + text ??= ""; + + var writer = new CircularBufferWriter(buffer); + writer.Write((byte)0xA6); // Packet ID + writer.Seek(2, SeekOrigin.Current); + writer.Write((byte)type); + writer.Write(tip); + writer.Write((ushort)text.Length); + writer.WriteAscii(text); + + writer.WritePacketLength(); + ns.Send(ref buffer, writer.Position); + } + + // TODO: Use DateTime caching against core loop + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SendCurrentTime(this NetState ns) => ns.SendCurrentTime(DateTime.UtcNow); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SendCurrentTime(this NetState ns, DateTime date) + { + ns?.Send(stackalloc byte[] { 0x5B, (byte)date.Hour, (byte)date.Minute, (byte)date.Second }); + } + + public static void SendPathfindMessage(this NetState ns, Point3D p) + { + if (ns == null || !ns.GetSendBuffer(out var buffer)) + { + return; + } + + var writer = new CircularBufferWriter(buffer); + writer.Write((byte)0x38); // Packet ID + writer.Write((short)p.X); + writer.Write((short)p.Y); + writer.Write((short)p.Z); + + ns.Send(ref buffer, writer.Position); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SendPingAck(this NetState ns, byte ping) + { + ns?.Send(stackalloc byte[] { 0x73, ping }); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SendClearWeaponAbility(this NetState ns) + { + ns?.Send(stackalloc byte[] { 0xBF, 0x00, 0x5, 0x00, 0x21 }); + } + + public static void SendDisplayHuePicker(this NetState ns, Serial huePickerSerial, int huePickerItemID) + { + if (ns == null || !ns.GetSendBuffer(out var buffer)) + { + return; + } + + var writer = new CircularBufferWriter(buffer); + writer.Write((byte)0x95); // Packet ID + writer.Write(huePickerSerial); + writer.Write((short)0); + writer.Write((short)huePickerItemID); + + ns.Send(ref buffer, writer.Position); + } } } diff --git a/Projects/Server/Network/Packets/PlayerPackets.cs b/Projects/Server/Network/Packets/PlayerPackets.cs deleted file mode 100644 index e7ec0f628..000000000 --- a/Projects/Server/Network/Packets/PlayerPackets.cs +++ /dev/null @@ -1,288 +0,0 @@ -using System; -using Server.HuePickers; - -namespace Server.Network -{ - public sealed class ServerChange : Packet - { - public ServerChange(Point3D p, Map map) : base(0x76, 16) - { - Stream.Write((short)p.X); - Stream.Write((short)p.Y); - Stream.Write((short)p.Z); - Stream.Write((byte)0); - Stream.Write((short)0); - Stream.Write((short)0); - Stream.Write((short)map.Width); - Stream.Write((short)map.Height); - } - } - - public sealed class SkillUpdate : Packet - { - public SkillUpdate(Skills skills) : base(0x3A) - { - EnsureCapacity(6 + skills.Length * 9); - - Stream.Write((byte)0x02); // type: absolute, capped - - for (var i = 0; i < skills.Length; ++i) - { - var s = skills[i]; - - var v = s.NonRacialValue; - var uv = Math.Clamp((int)(v * 10), 0, 0xFFFF); - - Stream.Write((ushort)(s.Info.SkillID + 1)); - Stream.Write((ushort)uv); - Stream.Write((ushort)s.BaseFixedPoint); - Stream.Write((byte)s.Lock); - Stream.Write((ushort)s.CapFixedPoint); - } - - Stream.Write((short)0); // terminate - } - } - - public sealed class Sequence : Packet - { - public Sequence(int num) : base(0x7B, 2) - { - Stream.Write((byte)num); - } - } - - public sealed class SkillChange : Packet - { - public SkillChange(Skill skill) : base(0x3A) - { - EnsureCapacity(13); - - var v = skill.NonRacialValue; - var uv = Math.Clamp((int)(v * 10), 0, 0xFFFF); - - Stream.Write((byte)0xDF); // type: delta, capped - Stream.Write((ushort)skill.Info.SkillID); - Stream.Write((ushort)uv); - Stream.Write((ushort)skill.BaseFixedPoint); - Stream.Write((byte)skill.Lock); - Stream.Write((ushort)skill.CapFixedPoint); - } - } - - public sealed class LaunchBrowser : Packet - { - public LaunchBrowser(string url) : base(0xA5) - { - url ??= ""; - - EnsureCapacity(4 + url.Length); - - Stream.WriteAsciiNull(url); - } - } - - public sealed class DragEffect : Packet - { - public DragEffect(IEntity src, IEntity trg, int itemID, int hue, int amount) : base(0x23, 26) - { - Stream.Write((short)itemID); - Stream.Write((byte)0); - Stream.Write((short)hue); - Stream.Write((short)amount); - Stream.Write(src.Serial); - Stream.Write((short)src.X); - Stream.Write((short)src.Y); - Stream.Write((sbyte)src.Z); - Stream.Write(trg.Serial); - Stream.Write((short)trg.X); - Stream.Write((short)trg.Y); - Stream.Write((sbyte)trg.Z); - } - } - - public sealed class SeasonChange : Packet - { - private static readonly SeasonChange[][] m_Cache = - { - new SeasonChange[2], - new SeasonChange[2], - new SeasonChange[2], - new SeasonChange[2], - new SeasonChange[2] - }; - - public SeasonChange(int season, bool playSound = true) : base(0xBC, 3) - { - Stream.Write((byte)season); - Stream.Write(playSound); - } - - public static SeasonChange Instantiate(int season) => Instantiate(season, true); - - public static SeasonChange Instantiate(int season, bool playSound) - { - if (season >= 0 && season < m_Cache.Length) - { - var idx = playSound ? 1 : 0; - - var p = m_Cache[season][idx]; - - if (p == null) - { - m_Cache[season][idx] = p = new SeasonChange(season, playSound); - p.SetStatic(); - } - - return p; - } - - return new SeasonChange(season, playSound); - } - } - - public sealed class DisplayPaperdoll : Packet - { - public DisplayPaperdoll(Serial m, string title, bool warmode, bool canLift) : base(0x88, 66) - { - byte flags = 0x00; - - if (warmode) - { - flags |= 0x01; - } - - if (canLift) - { - flags |= 0x02; - } - - Stream.Write(m); - Stream.WriteAsciiFixed(title, 60); - Stream.Write(flags); - } - } - - public sealed class PlayMusic : Packet - { - public static readonly Packet InvalidInstance = SetStatic(new PlayMusic(MusicName.Invalid)); - - private static readonly Packet[] m_Instances = new Packet[60]; - - public PlayMusic(MusicName name) : base(0x6D, 3) - { - Stream.Write((short)name); - } - - public static Packet GetInstance(MusicName name) - { - if (name == MusicName.Invalid) - { - return InvalidInstance; - } - - var v = (int)name; - Packet p; - - if (v >= 0 && v < m_Instances.Length) - { - p = m_Instances[v]; - - if (p == null) - { - m_Instances[v] = p = SetStatic(new PlayMusic(name)); - } - } - else - { - p = new PlayMusic(name); - } - - return p; - } - } - - public sealed class ScrollMessage : Packet - { - public ScrollMessage(int type, int tip, string text) : base(0xA6) - { - text ??= ""; - - EnsureCapacity(10 + text.Length); - - Stream.Write((byte)type); - Stream.Write(tip); - Stream.Write((ushort)text.Length); - Stream.WriteAsciiFixed(text, text.Length); - } - } - - public sealed class CurrentTime : Packet - { - public CurrentTime() : this(DateTime.Now) - { - } - - public CurrentTime(DateTime date) : base(0x5B, 4) - { - Stream.Write((byte)date.Hour); - Stream.Write((byte)date.Minute); - Stream.Write((byte)date.Second); - } - } - - public sealed class PathfindMessage : Packet - { - public PathfindMessage(Point3D p) : base(0x38, 7) - { - Stream.Write((short)p.X); - Stream.Write((short)p.Y); - Stream.Write((short)p.Z); - } - } - - public sealed class PingAck : Packet - { - private static readonly PingAck[] m_Cache = new PingAck[0x100]; - - public PingAck(byte ping) : base(0x73, 2) - { - Stream.Write(ping); - } - - public static PingAck Instantiate(byte ping) - { - var p = m_Cache[ping]; - - if (p == null) - { - m_Cache[ping] = p = new PingAck(ping); - p.SetStatic(); - } - - return p; - } - } - - public sealed class ClearWeaponAbility : Packet - { - public static readonly Packet Instance = SetStatic(new ClearWeaponAbility()); - - public ClearWeaponAbility() : base(0xBF) - { - EnsureCapacity(5); - - Stream.Write((short)0x21); - } - } - - public sealed class DisplayHuePicker : Packet - { - public DisplayHuePicker(HuePicker huePicker) : base(0x95, 9) - { - Stream.Write(huePicker.Serial); - Stream.Write((short)0); - Stream.Write((short)huePicker.ItemID); - } - } -} diff --git a/Projects/Server/Regions/Region.cs b/Projects/Server/Regions/Region.cs index eedfa3380..9d0604b39 100644 --- a/Projects/Server/Regions/Region.cs +++ b/Projects/Server/Regions/Region.cs @@ -774,7 +774,7 @@ namespace Server if (oldRegion == null || oldRegion.Music != newRegion.Music) { - m.Send(PlayMusic.GetInstance(newRegion.Music)); + m.NetState.SendPlayMusic(newRegion.Music); } } diff --git a/Projects/Server/Skills.cs b/Projects/Server/Skills.cs index 0bf9cdcac..d49a196f2 100644 --- a/Projects/Server/Skills.cs +++ b/Projects/Server/Skills.cs @@ -505,9 +505,6 @@ namespace Server var info = SkillInfo.Table; m_Skills = new Skill[info.Length]; - - // for ( int i = 0; i < info.Length; ++i ) - // m_Skills[i] = new Skill( this, info[i], 0, 1000, SkillLock.Up ); } public Skills(Mobile owner, IGenericReader reader) @@ -897,13 +894,13 @@ namespace Server { m_Highest = null; } - else if (m_Highest != null && skill.BaseFixedPoint > m_Highest.BaseFixedPoint) + else if (skill.BaseFixedPoint > m_Highest?.BaseFixedPoint) { m_Highest = skill; } Owner.OnSkillInvalidated(skill); - Owner.NetState?.Send(new SkillChange(skill)); + Owner.NetState.SendSkillChange(skill); } } } diff --git a/Projects/UOContent/Engines/Virtues/VirtueInfoGump.cs b/Projects/UOContent/Engines/Virtues/VirtueInfoGump.cs index 6e683e545..eb4af7f2d 100644 --- a/Projects/UOContent/Engines/Virtues/VirtueInfoGump.cs +++ b/Projects/UOContent/Engines/Virtues/VirtueInfoGump.cs @@ -121,7 +121,7 @@ namespace Server if (m_Page != null) { - state.Send(new LaunchBrowser(m_Page)); // No message about web browser starting on OSI + state.SendLaunchBrowser(m_Page); // No message about web browser starting on OSI } break; diff --git a/Projects/UOContent/Gumps/DawnsMusicBoxGump.cs b/Projects/UOContent/Gumps/DawnsMusicBoxGump.cs index d65b46df0..b3197cf97 100644 --- a/Projects/UOContent/Gumps/DawnsMusicBoxGump.cs +++ b/Projects/UOContent/Gumps/DawnsMusicBoxGump.cs @@ -82,7 +82,7 @@ namespace Server.Gumps 1061856 ); // You must have the item in your backpack or locked down in order to use it. } - else if (m_Box.IsLockedDown && !m_Box.HasAccces(m)) + else if (m_Box.IsLockedDown && !m_Box.HasAccess(m)) { m.SendLocalizedMessage(502691); // You must be the owner to use this. } diff --git a/Projects/UOContent/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicBox.cs b/Projects/UOContent/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicBox.cs index 8120aa8e9..b14929273 100644 --- a/Projects/UOContent/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicBox.cs +++ b/Projects/UOContent/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicBox.cs @@ -20,9 +20,66 @@ namespace Server.Items [Flippable(0x2AF9, 0x2AFD)] public class DawnsMusicBox : Item, ISecurable { - private static Dictionary m_Info; + private static readonly Dictionary m_Info = new() + { + { MusicName.Samlethe, new DawnsMusicInfo(1075152, DawnsMusicRarity.Common) }, + { MusicName.Sailing, new DawnsMusicInfo(1075163, DawnsMusicRarity.Common) }, + { MusicName.Britain2, new DawnsMusicInfo(1075145, DawnsMusicRarity.Common) }, + { MusicName.Britain1, new DawnsMusicInfo(1075144, DawnsMusicRarity.Common) }, + { MusicName.Bucsden, new DawnsMusicInfo(1075146, DawnsMusicRarity.Common) }, + { MusicName.Forest_a, new DawnsMusicInfo(1075161, DawnsMusicRarity.Common) }, + { MusicName.Cove, new DawnsMusicInfo(1075176, DawnsMusicRarity.Common) }, + { MusicName.Death, new DawnsMusicInfo(1075171, DawnsMusicRarity.Common) }, + { MusicName.Dungeon9, new DawnsMusicInfo(1075160, DawnsMusicRarity.Common) }, + { MusicName.Dungeon2, new DawnsMusicInfo(1075175, DawnsMusicRarity.Common) }, + { MusicName.Cave01, new DawnsMusicInfo(1075159, DawnsMusicRarity.Common) }, + { MusicName.Combat3, new DawnsMusicInfo(1075170, DawnsMusicRarity.Common) }, + { MusicName.Combat1, new DawnsMusicInfo(1075168, DawnsMusicRarity.Common) }, + { MusicName.Combat2, new DawnsMusicInfo(1075169, DawnsMusicRarity.Common) }, + { MusicName.Jhelom, new DawnsMusicInfo(1075147, DawnsMusicRarity.Common) }, + { MusicName.Linelle, new DawnsMusicInfo(1075185, DawnsMusicRarity.Common) }, + { MusicName.LBCastle, new DawnsMusicInfo(1075148, DawnsMusicRarity.Common) }, + { MusicName.Minoc, new DawnsMusicInfo(1075150, DawnsMusicRarity.Common) }, + { MusicName.Moonglow, new DawnsMusicInfo(1075177, DawnsMusicRarity.Common) }, + { MusicName.Magincia, new DawnsMusicInfo(1075149, DawnsMusicRarity.Common) }, + { MusicName.Nujelm, new DawnsMusicInfo(1075174, DawnsMusicRarity.Common) }, + { MusicName.BTCastle, new DawnsMusicInfo(1075173, DawnsMusicRarity.Common) }, + { MusicName.Tavern04, new DawnsMusicInfo(1075167, DawnsMusicRarity.Common) }, + { MusicName.Skarabra, new DawnsMusicInfo(1075154, DawnsMusicRarity.Common) }, + { MusicName.Stones2, new DawnsMusicInfo(1075143, DawnsMusicRarity.Common) }, + { MusicName.Serpents, new DawnsMusicInfo(1075153, DawnsMusicRarity.Common) }, + { MusicName.Taiko, new DawnsMusicInfo(1075180, DawnsMusicRarity.Common) }, + { MusicName.Tavern01, new DawnsMusicInfo(1075164, DawnsMusicRarity.Common) }, + { MusicName.Tavern02, new DawnsMusicInfo(1075165, DawnsMusicRarity.Common) }, + { MusicName.Tavern03, new DawnsMusicInfo(1075166, DawnsMusicRarity.Common) }, + { MusicName.TokunoDungeon, new DawnsMusicInfo(1075179, DawnsMusicRarity.Common) }, + { MusicName.Trinsic, new DawnsMusicInfo(1075155, DawnsMusicRarity.Common) }, + { MusicName.OldUlt01, new DawnsMusicInfo(1075142, DawnsMusicRarity.Common) }, + { MusicName.Ocllo, new DawnsMusicInfo(1075151, DawnsMusicRarity.Common) }, + { MusicName.Vesper, new DawnsMusicInfo(1075156, DawnsMusicRarity.Common) }, + { MusicName.Victory, new DawnsMusicInfo(1075172, DawnsMusicRarity.Common) }, + { MusicName.Mountn_a, new DawnsMusicInfo(1075162, DawnsMusicRarity.Common) }, + { MusicName.Wind, new DawnsMusicInfo(1075157, DawnsMusicRarity.Common) }, + { MusicName.Yew, new DawnsMusicInfo(1075158, DawnsMusicRarity.Common) }, + { MusicName.Zento, new DawnsMusicInfo(1075178, DawnsMusicRarity.Common) }, + { MusicName.GwennoConversation, new DawnsMusicInfo(1075131, DawnsMusicRarity.Uncommon) }, + { MusicName.DreadHornArea, new DawnsMusicInfo(1075181, DawnsMusicRarity.Uncommon) }, + { MusicName.ElfCity, new DawnsMusicInfo(1075182, DawnsMusicRarity.Uncommon) }, + { MusicName.GoodEndGame, new DawnsMusicInfo(1075132, DawnsMusicRarity.Uncommon) }, + { MusicName.GoodVsEvil, new DawnsMusicInfo(1075133, DawnsMusicRarity.Uncommon) }, + { MusicName.GreatEarthSerpents, new DawnsMusicInfo(1075134, DawnsMusicRarity.Uncommon) }, + { MusicName.GrizzleDungeon, new DawnsMusicInfo(1075186, DawnsMusicRarity.Uncommon) }, + { MusicName.Humanoids_U9, new DawnsMusicInfo(1075135, DawnsMusicRarity.Uncommon) }, + { MusicName.MelisandesLair, new DawnsMusicInfo(1075183, DawnsMusicRarity.Uncommon) }, + { MusicName.MinocNegative, new DawnsMusicInfo(1075136, DawnsMusicRarity.Uncommon) }, + { MusicName.ParoxysmusLair, new DawnsMusicInfo(1075184, DawnsMusicRarity.Uncommon) }, + { MusicName.Paws, new DawnsMusicInfo(1075137, DawnsMusicRarity.Uncommon) }, + { MusicName.SelimsBar, new DawnsMusicInfo(1075138, DawnsMusicRarity.Rare) }, + { MusicName.SerpentIsleCombat_U7, new DawnsMusicInfo(1075139, DawnsMusicRarity.Rare) }, + { MusicName.ValoriaShips, new DawnsMusicInfo(1075140, DawnsMusicRarity.Rare) } + }; - public static MusicName[] m_CommonTracks = + public static readonly MusicName[] m_CommonTracks = { MusicName.Samlethe, MusicName.Sailing, MusicName.Britain2, MusicName.Britain1, MusicName.Bucsden, MusicName.Forest_a, MusicName.Cove, MusicName.Death, @@ -36,7 +93,7 @@ namespace Server.Items MusicName.Mountn_a, MusicName.Wind, MusicName.Yew, MusicName.Zento }; - public static MusicName[] m_UncommonTracks = + public static readonly MusicName[] m_UncommonTracks = { MusicName.GwennoConversation, MusicName.DreadHornArea, MusicName.ElfCity, MusicName.GoodEndGame, MusicName.GoodVsEvil, MusicName.GreatEarthSerpents, @@ -44,7 +101,7 @@ namespace Server.Items MusicName.MinocNegative, MusicName.ParoxysmusLair, MusicName.Paws }; - public static MusicName[] m_RareTracks = + public static readonly MusicName[] m_RareTracks = { MusicName.SelimsBar, MusicName.SerpentIsleCombat_U7, MusicName.ValoriaShips }; @@ -151,7 +208,7 @@ namespace Server.Items 1061856 ); // You must have the item in your backpack or locked down in order to use it. } - else if (IsLockedDown && !HasAccces(from)) + else if (IsLockedDown && !HasAccess(from)) { from.SendLocalizedMessage(502436); // That is not accessible. } @@ -162,7 +219,7 @@ namespace Server.Items } } - public bool HasAccces(Mobile m) => + public bool HasAccess(Mobile m) => m.AccessLevel >= AccessLevel.GameMaster || BaseHouse.FindHouseAt(this)?.HasAccess(m) == true; public void PlayMusic(Mobile m, MusicName music) @@ -176,7 +233,7 @@ namespace Server.Items m_ItemID = ItemID; } - m.Send(new PlayMusic(music)); + m.NetState.SendPlayMusic(music); m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5), 4, Animate); } @@ -247,68 +304,6 @@ namespace Server.Items m_ItemID = reader.ReadInt(); } - public static void Initialize() - { - m_Info = new Dictionary - { - { MusicName.Samlethe, new DawnsMusicInfo(1075152, DawnsMusicRarity.Common) }, - { MusicName.Sailing, new DawnsMusicInfo(1075163, DawnsMusicRarity.Common) }, - { MusicName.Britain2, new DawnsMusicInfo(1075145, DawnsMusicRarity.Common) }, - { MusicName.Britain1, new DawnsMusicInfo(1075144, DawnsMusicRarity.Common) }, - { MusicName.Bucsden, new DawnsMusicInfo(1075146, DawnsMusicRarity.Common) }, - { MusicName.Forest_a, new DawnsMusicInfo(1075161, DawnsMusicRarity.Common) }, - { MusicName.Cove, new DawnsMusicInfo(1075176, DawnsMusicRarity.Common) }, - { MusicName.Death, new DawnsMusicInfo(1075171, DawnsMusicRarity.Common) }, - { MusicName.Dungeon9, new DawnsMusicInfo(1075160, DawnsMusicRarity.Common) }, - { MusicName.Dungeon2, new DawnsMusicInfo(1075175, DawnsMusicRarity.Common) }, - { MusicName.Cave01, new DawnsMusicInfo(1075159, DawnsMusicRarity.Common) }, - { MusicName.Combat3, new DawnsMusicInfo(1075170, DawnsMusicRarity.Common) }, - { MusicName.Combat1, new DawnsMusicInfo(1075168, DawnsMusicRarity.Common) }, - { MusicName.Combat2, new DawnsMusicInfo(1075169, DawnsMusicRarity.Common) }, - { MusicName.Jhelom, new DawnsMusicInfo(1075147, DawnsMusicRarity.Common) }, - { MusicName.Linelle, new DawnsMusicInfo(1075185, DawnsMusicRarity.Common) }, - { MusicName.LBCastle, new DawnsMusicInfo(1075148, DawnsMusicRarity.Common) }, - { MusicName.Minoc, new DawnsMusicInfo(1075150, DawnsMusicRarity.Common) }, - { MusicName.Moonglow, new DawnsMusicInfo(1075177, DawnsMusicRarity.Common) }, - { MusicName.Magincia, new DawnsMusicInfo(1075149, DawnsMusicRarity.Common) }, - { MusicName.Nujelm, new DawnsMusicInfo(1075174, DawnsMusicRarity.Common) }, - { MusicName.BTCastle, new DawnsMusicInfo(1075173, DawnsMusicRarity.Common) }, - { MusicName.Tavern04, new DawnsMusicInfo(1075167, DawnsMusicRarity.Common) }, - { MusicName.Skarabra, new DawnsMusicInfo(1075154, DawnsMusicRarity.Common) }, - { MusicName.Stones2, new DawnsMusicInfo(1075143, DawnsMusicRarity.Common) }, - { MusicName.Serpents, new DawnsMusicInfo(1075153, DawnsMusicRarity.Common) }, - { MusicName.Taiko, new DawnsMusicInfo(1075180, DawnsMusicRarity.Common) }, - { MusicName.Tavern01, new DawnsMusicInfo(1075164, DawnsMusicRarity.Common) }, - { MusicName.Tavern02, new DawnsMusicInfo(1075165, DawnsMusicRarity.Common) }, - { MusicName.Tavern03, new DawnsMusicInfo(1075166, DawnsMusicRarity.Common) }, - { MusicName.TokunoDungeon, new DawnsMusicInfo(1075179, DawnsMusicRarity.Common) }, - { MusicName.Trinsic, new DawnsMusicInfo(1075155, DawnsMusicRarity.Common) }, - { MusicName.OldUlt01, new DawnsMusicInfo(1075142, DawnsMusicRarity.Common) }, - { MusicName.Ocllo, new DawnsMusicInfo(1075151, DawnsMusicRarity.Common) }, - { MusicName.Vesper, new DawnsMusicInfo(1075156, DawnsMusicRarity.Common) }, - { MusicName.Victory, new DawnsMusicInfo(1075172, DawnsMusicRarity.Common) }, - { MusicName.Mountn_a, new DawnsMusicInfo(1075162, DawnsMusicRarity.Common) }, - { MusicName.Wind, new DawnsMusicInfo(1075157, DawnsMusicRarity.Common) }, - { MusicName.Yew, new DawnsMusicInfo(1075158, DawnsMusicRarity.Common) }, - { MusicName.Zento, new DawnsMusicInfo(1075178, DawnsMusicRarity.Common) }, - { MusicName.GwennoConversation, new DawnsMusicInfo(1075131, DawnsMusicRarity.Uncommon) }, - { MusicName.DreadHornArea, new DawnsMusicInfo(1075181, DawnsMusicRarity.Uncommon) }, - { MusicName.ElfCity, new DawnsMusicInfo(1075182, DawnsMusicRarity.Uncommon) }, - { MusicName.GoodEndGame, new DawnsMusicInfo(1075132, DawnsMusicRarity.Uncommon) }, - { MusicName.GoodVsEvil, new DawnsMusicInfo(1075133, DawnsMusicRarity.Uncommon) }, - { MusicName.GreatEarthSerpents, new DawnsMusicInfo(1075134, DawnsMusicRarity.Uncommon) }, - { MusicName.GrizzleDungeon, new DawnsMusicInfo(1075186, DawnsMusicRarity.Uncommon) }, - { MusicName.Humanoids_U9, new DawnsMusicInfo(1075135, DawnsMusicRarity.Uncommon) }, - { MusicName.MelisandesLair, new DawnsMusicInfo(1075183, DawnsMusicRarity.Uncommon) }, - { MusicName.MinocNegative, new DawnsMusicInfo(1075136, DawnsMusicRarity.Uncommon) }, - { MusicName.ParoxysmusLair, new DawnsMusicInfo(1075184, DawnsMusicRarity.Uncommon) }, - { MusicName.Paws, new DawnsMusicInfo(1075137, DawnsMusicRarity.Uncommon) }, - { MusicName.SelimsBar, new DawnsMusicInfo(1075138, DawnsMusicRarity.Rare) }, - { MusicName.SerpentIsleCombat_U7, new DawnsMusicInfo(1075139, DawnsMusicRarity.Rare) }, - { MusicName.ValoriaShips, new DawnsMusicInfo(1075140, DawnsMusicRarity.Rare) } - }; - } - public static DawnsMusicInfo GetInfo(MusicName name) { if (m_Info == null) // sanity diff --git a/Projects/UOContent/Items/Weapons/Abilities/WeaponAbility.cs b/Projects/UOContent/Items/Weapons/Abilities/WeaponAbility.cs index d348dbe4f..7c93af3d6 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/WeaponAbility.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/WeaponAbility.cs @@ -396,9 +396,9 @@ namespace Server.Items { Table.Remove(m); - if (Core.AOS && m.NetState != null) + if (Core.AOS) { - m.Send(ClearWeaponAbility.Instance); + m.NetState.SendClearWeaponAbility(); } } diff --git a/Projects/UOContent/Misc/Paperdoll.cs b/Projects/UOContent/Misc/Paperdoll.cs index c147997a9..5f3ca0d64 100644 --- a/Projects/UOContent/Misc/Paperdoll.cs +++ b/Projects/UOContent/Misc/Paperdoll.cs @@ -11,13 +11,11 @@ namespace Server.Misc public static void EventSink_PaperdollRequest(Mobile beholder, Mobile beheld) { - beholder.Send( - new DisplayPaperdoll( - beheld.Serial, - Titles.ComputeTitle(beholder, beheld), - beheld.Warmode, - beheld.AllowEquipFrom(beholder) - ) + beholder.NetState.SendDisplayPaperdoll( + beheld.Serial, + Titles.ComputeTitle(beholder, beheld), + beheld.Warmode, + beheld.AllowEquipFrom(beholder) ); for (var i = 0; i < beheld.Items.Count; ++i)