fix: Fixes flaky tests, formatting, and sequential testing. (#2168)
This commit is contained in:
parent
415c7a6bfd
commit
7dbfc9d161
60 changed files with 1304 additions and 1289 deletions
|
|
@ -12,12 +12,12 @@ public class ChatPacketTests
|
|||
[InlineData("ENU", 200, "a third param", "another param")]
|
||||
public void TestSendChatMessage(string lang, int number, string param1, string param2)
|
||||
{
|
||||
var expected = new ChatMessagePacket(lang, number, param1, param2).Compile();
|
||||
var expected = new ChatMessagePacket(lang, number, param1, param2).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendChatMessage(lang, number, param1, param2);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendChatMessage(lang, number, param1, param2);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,23 +6,23 @@ public sealed class ChatMessagePacket : Packet
|
|||
{
|
||||
public ChatMessagePacket(string lang, int number, string param1, string param2) : base(0xB2)
|
||||
{
|
||||
param1 ??= string.Empty;
|
||||
param2 ??= string.Empty;
|
||||
param1 ??= string.Empty;
|
||||
param2 ??= string.Empty;
|
||||
|
||||
EnsureCapacity(13 + (param1.Length + param2.Length) * 2);
|
||||
EnsureCapacity(13 + (param1.Length + param2.Length) * 2);
|
||||
|
||||
Stream.Write((ushort)(number - 20));
|
||||
Stream.Write((ushort)(number - 20));
|
||||
|
||||
if (lang != null)
|
||||
{
|
||||
Stream.WriteAsciiFixed(lang, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream.Write(0);
|
||||
}
|
||||
|
||||
Stream.WriteBigUniNull(param1);
|
||||
Stream.WriteBigUniNull(param2);
|
||||
if (lang != null)
|
||||
{
|
||||
Stream.WriteAsciiFixed(lang, 4);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream.Write(0);
|
||||
}
|
||||
|
||||
Stream.WriteBigUniNull(param1);
|
||||
Stream.WriteBigUniNull(param2);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ using Xunit;
|
|||
|
||||
namespace UOContent.Tests;
|
||||
|
||||
[Collection("Sequential Tests")]
|
||||
[Collection("Sequential UOContent Tests")]
|
||||
public class EventSchedulerTests
|
||||
{
|
||||
// Test implementations for controlled testing
|
||||
|
|
@ -144,36 +144,39 @@ public class EventSchedulerTests
|
|||
[Fact]
|
||||
public void Scheduler_HandlesRecurringEvents()
|
||||
{
|
||||
Init();
|
||||
|
||||
try
|
||||
for (var i = 0; i < 100_000; i++)
|
||||
{
|
||||
int callCount = 0;
|
||||
Init();
|
||||
|
||||
// Create a recurrence pattern that fires every 10 seconds, up to 3 times
|
||||
var recurrence = new TestRecurrencePattern(TimeSpan.FromSeconds(10), 3);
|
||||
try
|
||||
{
|
||||
int callCount = 0;
|
||||
|
||||
var evt = new TestScheduledEvent(
|
||||
Core._now,
|
||||
() => callCount++,
|
||||
recurrence
|
||||
);
|
||||
// Create a recurrence pattern that fires every 10 seconds, up to 3 times
|
||||
var recurrence = new TestRecurrencePattern(TimeSpan.FromSeconds(10), 3);
|
||||
|
||||
EventScheduler.Shared.ScheduleEvent(evt);
|
||||
var evt = new TestScheduledEvent(
|
||||
Core._now,
|
||||
() => callCount++,
|
||||
recurrence
|
||||
);
|
||||
|
||||
// Advance time to after all occurrences should have happened
|
||||
Core._now = Core._now.AddSeconds(50);
|
||||
Timer.Slice(8);
|
||||
EventScheduler.Shared.ScheduleEvent(evt);
|
||||
|
||||
// Should have fired 4 times (3 recurrences)
|
||||
Assert.Equal(3, callCount);
|
||||
Assert.Equal(3, evt.CallCount);
|
||||
// Advance time to after all occurrences should have happened
|
||||
Core._now = Core._now.AddSeconds(50);
|
||||
Timer.Slice(8);
|
||||
|
||||
evt.Cancel();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Finish();
|
||||
// Should have fired 4 times (3 recurrences)
|
||||
Assert.Equal(3, callCount);
|
||||
Assert.Equal(3, evt.CallCount);
|
||||
|
||||
evt.Cancel();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ public class DisplayHelpTopic : Packet
|
|||
{
|
||||
public DisplayHelpTopic(int topicID, bool display) : base(0xBF)
|
||||
{
|
||||
EnsureCapacity(11);
|
||||
EnsureCapacity(11);
|
||||
|
||||
Stream.Write((short)0x17);
|
||||
Stream.Write((byte)1);
|
||||
Stream.Write(topicID);
|
||||
Stream.Write(display);
|
||||
}
|
||||
}
|
||||
Stream.Write((short)0x17);
|
||||
Stream.Write((byte)1);
|
||||
Stream.Write(topicID);
|
||||
Stream.Write(display);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@ public class TestHelpTopicPacket
|
|||
[InlineData(HelpTopic.EmptyingBowl, true)]
|
||||
public void TestDisplayHelpTopic(int topic, bool display)
|
||||
{
|
||||
var expected = new DisplayHelpTopic(topic, display).Compile();
|
||||
var expected = new DisplayHelpTopic(topic, display).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendDisplayHelpTopic(topic, display);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendDisplayHelpTopic(topic, display);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,22 +6,22 @@ public sealed class RaceChanger : Packet
|
|||
{
|
||||
public RaceChanger(bool female, Race targetRace) : base(0xBF)
|
||||
{
|
||||
EnsureCapacity(7);
|
||||
EnsureCapacity(7);
|
||||
|
||||
Stream.Write((short)0x2A);
|
||||
Stream.Write((byte)(female ? 1 : 0));
|
||||
Stream.Write((byte)(targetRace.RaceID + 1));
|
||||
}
|
||||
Stream.Write((short)0x2A);
|
||||
Stream.Write((byte)(female ? 1 : 0));
|
||||
Stream.Write((byte)(targetRace.RaceID + 1));
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CloseRaceChanger : Packet
|
||||
{
|
||||
public CloseRaceChanger() : base(0xBF)
|
||||
{
|
||||
EnsureCapacity(7);
|
||||
EnsureCapacity(7);
|
||||
|
||||
Stream.Write((short)0x2A);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)0xFF);
|
||||
}
|
||||
}
|
||||
Stream.Write((short)0x2A);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)0xFF);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,74 +6,74 @@ public sealed class PartyEmptyList : Packet
|
|||
{
|
||||
public PartyEmptyList(Serial m) : base(0xBF)
|
||||
{
|
||||
EnsureCapacity(7);
|
||||
EnsureCapacity(7);
|
||||
|
||||
Stream.Write((short)0x0006);
|
||||
Stream.Write((byte)0x02);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write(m);
|
||||
}
|
||||
Stream.Write((short)0x0006);
|
||||
Stream.Write((byte)0x02);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write(m);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class PartyMemberList : Packet
|
||||
{
|
||||
public PartyMemberList(Party p) : base(0xBF)
|
||||
{
|
||||
EnsureCapacity(7 + p.Count * 4);
|
||||
EnsureCapacity(7 + p.Count * 4);
|
||||
|
||||
Stream.Write((short)0x0006);
|
||||
Stream.Write((byte)0x01);
|
||||
Stream.Write((byte)p.Count);
|
||||
Stream.Write((short)0x0006);
|
||||
Stream.Write((byte)0x01);
|
||||
Stream.Write((byte)p.Count);
|
||||
|
||||
for (var i = 0; i < p.Count; ++i)
|
||||
{
|
||||
Stream.Write(p[i].Mobile.Serial);
|
||||
}
|
||||
for (var i = 0; i < p.Count; ++i)
|
||||
{
|
||||
Stream.Write(p[i].Mobile.Serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class PartyRemoveMember : Packet
|
||||
{
|
||||
public PartyRemoveMember(Serial removed, Party p) : base(0xBF)
|
||||
{
|
||||
EnsureCapacity(11 + p.Count * 4);
|
||||
EnsureCapacity(11 + p.Count * 4);
|
||||
|
||||
Stream.Write((short)0x0006);
|
||||
Stream.Write((byte)0x02);
|
||||
Stream.Write((byte)p.Count);
|
||||
Stream.Write((short)0x0006);
|
||||
Stream.Write((byte)0x02);
|
||||
Stream.Write((byte)p.Count);
|
||||
|
||||
Stream.Write(removed);
|
||||
Stream.Write(removed);
|
||||
|
||||
for (var i = 0; i < p.Count; ++i)
|
||||
{
|
||||
Stream.Write(p[i].Mobile.Serial);
|
||||
}
|
||||
for (var i = 0; i < p.Count; ++i)
|
||||
{
|
||||
Stream.Write(p[i].Mobile.Serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class PartyTextMessage : Packet
|
||||
{
|
||||
public PartyTextMessage(bool toAll, Serial from, string text) : base(0xBF)
|
||||
{
|
||||
text ??= "";
|
||||
text ??= "";
|
||||
|
||||
EnsureCapacity(12 + text.Length * 2);
|
||||
EnsureCapacity(12 + text.Length * 2);
|
||||
|
||||
Stream.Write((short)0x0006);
|
||||
Stream.Write((byte)(toAll ? 0x04 : 0x03));
|
||||
Stream.Write(from);
|
||||
Stream.WriteBigUniNull(text);
|
||||
}
|
||||
Stream.Write((short)0x0006);
|
||||
Stream.Write((byte)(toAll ? 0x04 : 0x03));
|
||||
Stream.Write(from);
|
||||
Stream.WriteBigUniNull(text);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class PartyInvitation : Packet
|
||||
{
|
||||
public PartyInvitation(Serial leader) : base(0xBF)
|
||||
{
|
||||
EnsureCapacity(10);
|
||||
EnsureCapacity(10);
|
||||
|
||||
Stream.Write((short)0x0006);
|
||||
Stream.Write((byte)0x07);
|
||||
Stream.Write(leader);
|
||||
}
|
||||
}
|
||||
Stream.Write((short)0x0006);
|
||||
Stream.Write((byte)0x07);
|
||||
Stream.Write(leader);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,92 +6,93 @@ using Xunit;
|
|||
|
||||
namespace UOContent.Tests;
|
||||
|
||||
public class PartyPacketTests : IClassFixture<ServerFixture>
|
||||
[Collection("Sequential UOContent Tests")]
|
||||
public class PartyPacketTests
|
||||
{
|
||||
[Fact]
|
||||
public void TestPartyEmptyList()
|
||||
{
|
||||
Serial m = (Serial)0x1024u;
|
||||
Serial m = (Serial)0x1024u;
|
||||
|
||||
var expected = new PartyEmptyList(m).Compile();
|
||||
var expected = new PartyEmptyList(m).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendPartyRemoveMember(m);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendPartyRemoveMember(m);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestPartyRemoveMember()
|
||||
{
|
||||
var leader = new Mobile((Serial)0x1024u);
|
||||
leader.DefaultMobileInit();
|
||||
var leader = new Mobile((Serial)0x1024u);
|
||||
leader.DefaultMobileInit();
|
||||
|
||||
var member = new Mobile((Serial)0x2048u);
|
||||
member.DefaultMobileInit();
|
||||
var member = new Mobile((Serial)0x2048u);
|
||||
member.DefaultMobileInit();
|
||||
|
||||
var p = new Party(leader);
|
||||
p.Add(member);
|
||||
var p = new Party(leader);
|
||||
p.Add(member);
|
||||
|
||||
var expected = new PartyRemoveMember(member.Serial, p).Compile();
|
||||
var expected = new PartyRemoveMember(member.Serial, p).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendPartyRemoveMember(member.Serial, p);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendPartyRemoveMember(member.Serial, p);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestPartyMemberList()
|
||||
{
|
||||
var leader = new Mobile((Serial)0x1024u);
|
||||
leader.DefaultMobileInit();
|
||||
var leader = new Mobile((Serial)0x1024u);
|
||||
leader.DefaultMobileInit();
|
||||
|
||||
var member = new Mobile((Serial)0x2048u);
|
||||
member.DefaultMobileInit();
|
||||
var member = new Mobile((Serial)0x2048u);
|
||||
member.DefaultMobileInit();
|
||||
|
||||
var p = new Party(leader);
|
||||
p.Add(member);
|
||||
var p = new Party(leader);
|
||||
p.Add(member);
|
||||
|
||||
var expected = new PartyMemberList(p).Compile();
|
||||
var expected = new PartyMemberList(p).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendPartyMemberList(p);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendPartyMemberList(p);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void TestPartyTextMessage(bool toAll)
|
||||
{
|
||||
Serial serial = (Serial)0x1024u;
|
||||
var text = "[Party] Stuff Happens";
|
||||
Serial serial = (Serial)0x1024u;
|
||||
var text = "[Party] Stuff Happens";
|
||||
|
||||
var expected = new PartyTextMessage(toAll, serial, text).Compile();
|
||||
var expected = new PartyTextMessage(toAll, serial, text).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendPartyTextMessage(serial, text, toAll);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendPartyTextMessage(serial, text, toAll);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestPartyInvitation()
|
||||
{
|
||||
Serial m = (Serial)0x1024u;
|
||||
Serial m = (Serial)0x1024u;
|
||||
|
||||
var expected = new PartyInvitation(m).Compile();
|
||||
var expected = new PartyInvitation(m).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendPartyInvitation(m);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendPartyInvitation(m);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@ public class CharacterStatuePacketTests
|
|||
[InlineData(0x1024u, 1, 100, 200)]
|
||||
public void TestSendStatueAnimation(uint s, int status, int anim, int frame)
|
||||
{
|
||||
var expected = new UpdateStatueAnimation((Serial)s, status, anim, frame).Compile();
|
||||
var expected = new UpdateStatueAnimation((Serial)s, status, anim, frame).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendStatueAnimation((Serial)s, status, anim, frame);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendStatueAnimation((Serial)s, status, anim, frame);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,16 +4,16 @@ public class UpdateStatueAnimation : Packet
|
|||
{
|
||||
public UpdateStatueAnimation(Serial serial, int status, int animation, int frame) : base(0xBF, 17)
|
||||
{
|
||||
Stream.Write((short)0x11);
|
||||
Stream.Write((short)0x19);
|
||||
Stream.Write((byte)0x5);
|
||||
Stream.Write(serial);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)0xFF);
|
||||
Stream.Write((byte)status);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)animation);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)frame);
|
||||
}
|
||||
}
|
||||
Stream.Write((short)0x11);
|
||||
Stream.Write((short)0x19);
|
||||
Stream.Write((byte)0x5);
|
||||
Stream.Write(serial);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)0xFF);
|
||||
Stream.Write((byte)status);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)animation);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)frame);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ using Xunit;
|
|||
|
||||
namespace Server.Tests.Gumps;
|
||||
|
||||
[Collection("Sequential Tests")]
|
||||
[Collection("Sequential UOContent Tests")]
|
||||
public class TestLayoutGumps
|
||||
{
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -15,78 +15,79 @@ public class TestBook : BaseBook
|
|||
|
||||
public TestBook(int itemID, string title, string author, int pageCount, bool writable) : base(itemID, title, author, pageCount, writable)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public TestBook(int itemID, bool writable) : base(itemID, writable)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public TestBook(Serial serial) : base(serial)
|
||||
{
|
||||
Pages = new BookPageInfo[20];
|
||||
Pages = new BookPageInfo[20];
|
||||
|
||||
for (var i = 0; i < Pages.Length; ++i)
|
||||
{
|
||||
Pages[i] = new BookPageInfo();
|
||||
}
|
||||
for (var i = 0; i < Pages.Length; ++i)
|
||||
{
|
||||
Pages[i] = new BookPageInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class BookPacketTests : IClassFixture<ServerFixture>
|
||||
[Collection("Sequential UOContent Tests")]
|
||||
public class BookPacketTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("🅵🅰🅽🅲🆈 🆃🅴🆇🆃 Author", "🅵🅰🅽🅲🆈 🆃🅴🆇🆃 Title")]
|
||||
public void TestBookCover(string author, string title)
|
||||
{
|
||||
var m = new Mobile((Serial)0x1);
|
||||
m.DefaultMobileInit();
|
||||
var m = new Mobile((Serial)0x1);
|
||||
m.DefaultMobileInit();
|
||||
|
||||
Serial serial = (Serial)0x1001;
|
||||
var book = new TestBook(serial) { Author = author, Title = title };
|
||||
Serial serial = (Serial)0x1001;
|
||||
var book = new TestBook(serial) { Author = author, Title = title };
|
||||
|
||||
var expected = new BookHeader(m, book).Compile();
|
||||
var expected = new BookHeader(m, book).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendBookCover(m, book);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendBookCover(m, book);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestBookContent()
|
||||
{
|
||||
var m = new Mobile((Serial)0x1);
|
||||
m.DefaultMobileInit();
|
||||
var m = new Mobile((Serial)0x1);
|
||||
m.DefaultMobileInit();
|
||||
|
||||
Serial serial = (Serial)0x1001;
|
||||
var book = new TestBook(serial) { Author = "Some Author", Title = "Some Title" };
|
||||
book.Pages[0].Lines = new[]
|
||||
{
|
||||
"Some books start with actual content",
|
||||
"This book does not have any actual content",
|
||||
"Instead it has several pages of useless text"
|
||||
};
|
||||
Serial serial = (Serial)0x1001;
|
||||
var book = new TestBook(serial) { Author = "Some Author", Title = "Some Title" };
|
||||
book.Pages[0].Lines = new[]
|
||||
{
|
||||
"Some books start with actual content",
|
||||
"This book does not have any actual content",
|
||||
"Instead it has several pages of useless text"
|
||||
};
|
||||
|
||||
book.Pages[1].Lines = new[]
|
||||
{
|
||||
"Another page exists but this page:",
|
||||
"Has lots of: 🅵🅰🅽🅲🆈 🆃🅴🆇🆃",
|
||||
"And just more: 🅵🅰🅽🅲🆈 🆃🅴🆇🆃",
|
||||
"So everyone can read: 🅵🅰🅽🅲🆈 🆃🅴🆇🆃"
|
||||
};
|
||||
book.Pages[1].Lines = new[]
|
||||
{
|
||||
"Another page exists but this page:",
|
||||
"Has lots of: 🅵🅰🅽🅲🆈 🆃🅴🆇🆃",
|
||||
"And just more: 🅵🅰🅽🅲🆈 🆃🅴🆇🆃",
|
||||
"So everyone can read: 🅵🅰🅽🅲🆈 🆃🅴🆇🆃"
|
||||
};
|
||||
|
||||
book.Pages[2].Lines = new[]
|
||||
{
|
||||
"The end"
|
||||
};
|
||||
book.Pages[2].Lines = new[]
|
||||
{
|
||||
"The end"
|
||||
};
|
||||
|
||||
var expected = new BookPageDetails(book).Compile();
|
||||
var expected = new BookPageDetails(book).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendBookContent(book);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendBookContent(book);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,52 +7,52 @@ public sealed class BookPageDetails : Packet
|
|||
{
|
||||
public BookPageDetails(BaseBook book) : base(0x66)
|
||||
{
|
||||
EnsureCapacity(256);
|
||||
EnsureCapacity(256);
|
||||
|
||||
Stream.Write(book.Serial);
|
||||
Stream.Write((ushort)book.PagesCount);
|
||||
Stream.Write(book.Serial);
|
||||
Stream.Write((ushort)book.PagesCount);
|
||||
|
||||
for (var i = 0; i < book.PagesCount; ++i)
|
||||
for (var i = 0; i < book.PagesCount; ++i)
|
||||
{
|
||||
var page = book.Pages[i];
|
||||
|
||||
Stream.Write((ushort)(i + 1));
|
||||
Stream.Write((ushort)page.Lines.Length);
|
||||
|
||||
for (var j = 0; j < page.Lines.Length; ++j)
|
||||
{
|
||||
var page = book.Pages[i];
|
||||
var buffer = page.Lines[j].GetBytesUtf8();
|
||||
|
||||
Stream.Write((ushort)(i + 1));
|
||||
Stream.Write((ushort)page.Lines.Length);
|
||||
|
||||
for (var j = 0; j < page.Lines.Length; ++j)
|
||||
{
|
||||
var buffer = page.Lines[j].GetBytesUtf8();
|
||||
|
||||
Stream.Write(buffer, 0, buffer.Length);
|
||||
Stream.Write((byte)0);
|
||||
}
|
||||
Stream.Write(buffer, 0, buffer.Length);
|
||||
Stream.Write((byte)0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class BookHeader : Packet
|
||||
{
|
||||
public BookHeader(Mobile from, BaseBook book) : base(0xD4)
|
||||
{
|
||||
var title = book.Title ?? "";
|
||||
var author = book.Author ?? "";
|
||||
var title = book.Title ?? "";
|
||||
var author = book.Author ?? "";
|
||||
|
||||
var titleBuffer = title.GetBytesUtf8();
|
||||
var authorBuffer = author.GetBytesUtf8();
|
||||
var titleBuffer = title.GetBytesUtf8();
|
||||
var authorBuffer = author.GetBytesUtf8();
|
||||
|
||||
EnsureCapacity(15 + titleBuffer.Length + authorBuffer.Length);
|
||||
EnsureCapacity(15 + titleBuffer.Length + authorBuffer.Length);
|
||||
|
||||
Stream.Write(book.Serial);
|
||||
Stream.Write(true);
|
||||
Stream.Write(book.Writable && from.InRange(book.GetWorldLocation(), 1));
|
||||
Stream.Write((ushort)book.PagesCount);
|
||||
Stream.Write(book.Serial);
|
||||
Stream.Write(true);
|
||||
Stream.Write(book.Writable && from.InRange(book.GetWorldLocation(), 1));
|
||||
Stream.Write((ushort)book.PagesCount);
|
||||
|
||||
Stream.Write((ushort)(titleBuffer.Length + 1));
|
||||
Stream.Write(titleBuffer, 0, titleBuffer.Length);
|
||||
Stream.Write((byte)0); // terminate
|
||||
Stream.Write((ushort)(titleBuffer.Length + 1));
|
||||
Stream.Write(titleBuffer, 0, titleBuffer.Length);
|
||||
Stream.Write((byte)0); // terminate
|
||||
|
||||
Stream.Write((ushort)(authorBuffer.Length + 1));
|
||||
Stream.Write(authorBuffer, 0, authorBuffer.Length);
|
||||
Stream.Write((byte)0); // terminate
|
||||
}
|
||||
}
|
||||
Stream.Write((ushort)(authorBuffer.Length + 1));
|
||||
Stream.Write(authorBuffer, 0, authorBuffer.Length);
|
||||
Stream.Write((byte)0); // terminate
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ using Xunit;
|
|||
|
||||
namespace UOContent.Tests;
|
||||
|
||||
[Collection("Sequential Tests")]
|
||||
public class BulletinBoardPacketTests : IClassFixture<ServerFixture>
|
||||
[Collection("Sequential UOContent Tests")]
|
||||
public class BulletinBoardPacketTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("Test Name")]
|
||||
|
|
@ -16,16 +16,16 @@ public class BulletinBoardPacketTests : IClassFixture<ServerFixture>
|
|||
[InlineData("🅵🅰🅽🅲🆈 🆃🅴🆇🆃")]
|
||||
public void TestSendBBDisplayBoard(string boardName)
|
||||
{
|
||||
var bb = new TestBulletinBoard(0x234) { BoardName = boardName };
|
||||
var bb = new TestBulletinBoard(0x234) { BoardName = boardName };
|
||||
|
||||
var expected = new BBDisplayBoard(bb).Compile();
|
||||
var expected = new BBDisplayBoard(bb).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendBBDisplayBoard(bb);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendBBDisplayBoard(bb);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("The Subject", false, "First Line", "Second Line", "Third Line")]
|
||||
|
|
@ -36,32 +36,32 @@ public class BulletinBoardPacketTests : IClassFixture<ServerFixture>
|
|||
[InlineData("🅵🅰🅽🅲🆈 🆃🅴🆇🆃", true, "First Line", "Second Line")]
|
||||
public void TestSendBBHeaderMessage(string subject, bool content, params string[] lines)
|
||||
{
|
||||
var poster = new Mobile((Serial)0x1024u) { Name = "Kamron" };
|
||||
poster.DefaultMobileInit();
|
||||
var poster = new Mobile((Serial)0x1024u) { Name = "Kamron" };
|
||||
poster.DefaultMobileInit();
|
||||
|
||||
var bb = new TestBulletinBoard(0x234);
|
||||
bb.PostMessage(poster, null, subject, lines);
|
||||
var bb = new TestBulletinBoard(0x234);
|
||||
bb.PostMessage(poster, null, subject, lines);
|
||||
|
||||
var msg = bb.Items[0] as BulletinMessage;
|
||||
var msg = bb.Items[0] as BulletinMessage;
|
||||
|
||||
var expected = (content ?
|
||||
(Packet)new BBMessageContent(bb, msg) : new BBMessageHeader(bb, msg)).Compile();
|
||||
var expected = (content ?
|
||||
(Packet)new BBMessageContent(bb, msg) : new BBMessageHeader(bb, msg)).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendBBMessage(bb, msg, content);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendBBMessage(bb, msg, content);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class TestBulletinBoard : BaseBulletinBoard
|
||||
{
|
||||
public TestBulletinBoard(int itemID) : base(itemID)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public TestBulletinBoard(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,149 +1,148 @@
|
|||
using Server.Items;
|
||||
using Server.Text;
|
||||
|
||||
namespace Server.Network
|
||||
namespace Server.Network;
|
||||
|
||||
public class BBDisplayBoard : Packet
|
||||
{
|
||||
public class BBDisplayBoard : Packet
|
||||
public BBDisplayBoard(BaseBulletinBoard board) : base(0x71)
|
||||
{
|
||||
public BBDisplayBoard(BaseBulletinBoard board) : base(0x71)
|
||||
EnsureCapacity(38);
|
||||
|
||||
var buffer = (board.BoardName ?? "").GetBytesUtf8();
|
||||
|
||||
Stream.Write((byte)0x00); // Packet ID
|
||||
Stream.Write(board.Serial); // Bulletin board serial
|
||||
|
||||
// Bulletin board name
|
||||
if (buffer.Length >= 29)
|
||||
{
|
||||
EnsureCapacity(38);
|
||||
|
||||
var buffer = (board.BoardName ?? "").GetBytesUtf8();
|
||||
|
||||
Stream.Write((byte)0x00); // Packet ID
|
||||
Stream.Write(board.Serial); // Bulletin board serial
|
||||
|
||||
// Bulletin board name
|
||||
if (buffer.Length >= 29)
|
||||
{
|
||||
Stream.Write(buffer, 0, 29);
|
||||
Stream.Write((byte)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream.Write(buffer, 0, buffer.Length);
|
||||
Stream.Fill(30 - buffer.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class BBMessageHeader : Packet
|
||||
{
|
||||
public BBMessageHeader(BaseBulletinBoard board, BulletinMessage msg) : base(0x71)
|
||||
{
|
||||
var poster = SafeString(msg.PostedName);
|
||||
var subject = SafeString(msg.Subject);
|
||||
var time = SafeString(msg.GetTimeAsString());
|
||||
|
||||
EnsureCapacity(22 + poster.Length + subject.Length + time.Length);
|
||||
|
||||
Stream.Write((byte)0x01); // Packet ID
|
||||
Stream.Write(board.Serial); // Bulletin board serial
|
||||
Stream.Write(msg.Serial); // Message serial
|
||||
|
||||
Stream.Write(msg.Thread?.Serial ?? Serial.Zero); // Thread serial--parent
|
||||
|
||||
WriteString(poster);
|
||||
WriteString(subject);
|
||||
WriteString(time);
|
||||
}
|
||||
|
||||
public void WriteString(string v)
|
||||
{
|
||||
var buffer = v.GetBytesUtf8();
|
||||
var len = buffer.Length + 1;
|
||||
|
||||
if (len > 255)
|
||||
{
|
||||
len = 255;
|
||||
}
|
||||
|
||||
Stream.Write((byte)len);
|
||||
Stream.Write(buffer, 0, len - 1);
|
||||
Stream.Write(buffer, 0, 29);
|
||||
Stream.Write((byte)0);
|
||||
}
|
||||
|
||||
public string SafeString(string v) => v ?? string.Empty;
|
||||
}
|
||||
|
||||
public class BBMessageContent : Packet
|
||||
{
|
||||
public BBMessageContent(BaseBulletinBoard board, BulletinMessage msg) : base(0x71)
|
||||
else
|
||||
{
|
||||
var poster = SafeString(msg.PostedName);
|
||||
var subject = SafeString(msg.Subject);
|
||||
var time = SafeString(msg.GetTimeAsString());
|
||||
|
||||
EnsureCapacity(22 + poster.Length + subject.Length + time.Length);
|
||||
|
||||
Stream.Write((byte)0x02); // Packet ID
|
||||
Stream.Write(board.Serial); // Bulletin board serial
|
||||
Stream.Write(msg.Serial); // Message serial
|
||||
|
||||
WriteString(poster);
|
||||
WriteString(subject);
|
||||
WriteString(time);
|
||||
|
||||
Stream.Write((short)msg.PostedBody);
|
||||
Stream.Write((short)msg.PostedHue);
|
||||
|
||||
var len = msg.PostedEquip.Length;
|
||||
|
||||
if (len > 255)
|
||||
{
|
||||
len = 255;
|
||||
}
|
||||
|
||||
Stream.Write((byte)len);
|
||||
|
||||
for (var i = 0; i < len; ++i)
|
||||
{
|
||||
var eq = msg.PostedEquip[i];
|
||||
|
||||
Stream.Write((short)eq._itemID);
|
||||
Stream.Write((short)eq._hue);
|
||||
}
|
||||
|
||||
len = msg.Lines.Length;
|
||||
|
||||
if (len > 255)
|
||||
{
|
||||
len = 255;
|
||||
}
|
||||
|
||||
Stream.Write((byte)len);
|
||||
|
||||
for (var i = 0; i < len; ++i)
|
||||
{
|
||||
WriteString(msg.Lines[i], true);
|
||||
}
|
||||
Stream.Write(buffer, 0, buffer.Length);
|
||||
Stream.Fill(30 - buffer.Length);
|
||||
}
|
||||
|
||||
public void WriteString(string v, bool padding = false)
|
||||
{
|
||||
var buffer = v.GetBytesUtf8();
|
||||
var tail = padding ? 2 : 1;
|
||||
var len = buffer.Length + tail;
|
||||
|
||||
if (len > 255)
|
||||
{
|
||||
len = 255;
|
||||
}
|
||||
|
||||
Stream.Write((byte)len);
|
||||
Stream.Write(buffer, 0, len - tail);
|
||||
|
||||
if (padding)
|
||||
{
|
||||
Stream.Write((short)0); // padding compensates for a client bug
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream.Write((byte)0);
|
||||
}
|
||||
}
|
||||
|
||||
public string SafeString(string v) => v ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public class BBMessageHeader : Packet
|
||||
{
|
||||
public BBMessageHeader(BaseBulletinBoard board, BulletinMessage msg) : base(0x71)
|
||||
{
|
||||
var poster = SafeString(msg.PostedName);
|
||||
var subject = SafeString(msg.Subject);
|
||||
var time = SafeString(msg.GetTimeAsString());
|
||||
|
||||
EnsureCapacity(22 + poster.Length + subject.Length + time.Length);
|
||||
|
||||
Stream.Write((byte)0x01); // Packet ID
|
||||
Stream.Write(board.Serial); // Bulletin board serial
|
||||
Stream.Write(msg.Serial); // Message serial
|
||||
|
||||
Stream.Write(msg.Thread?.Serial ?? Serial.Zero); // Thread serial--parent
|
||||
|
||||
WriteString(poster);
|
||||
WriteString(subject);
|
||||
WriteString(time);
|
||||
}
|
||||
|
||||
public void WriteString(string v)
|
||||
{
|
||||
var buffer = v.GetBytesUtf8();
|
||||
var len = buffer.Length + 1;
|
||||
|
||||
if (len > 255)
|
||||
{
|
||||
len = 255;
|
||||
}
|
||||
|
||||
Stream.Write((byte)len);
|
||||
Stream.Write(buffer, 0, len - 1);
|
||||
Stream.Write((byte)0);
|
||||
}
|
||||
|
||||
public string SafeString(string v) => v ?? string.Empty;
|
||||
}
|
||||
|
||||
public class BBMessageContent : Packet
|
||||
{
|
||||
public BBMessageContent(BaseBulletinBoard board, BulletinMessage msg) : base(0x71)
|
||||
{
|
||||
var poster = SafeString(msg.PostedName);
|
||||
var subject = SafeString(msg.Subject);
|
||||
var time = SafeString(msg.GetTimeAsString());
|
||||
|
||||
EnsureCapacity(22 + poster.Length + subject.Length + time.Length);
|
||||
|
||||
Stream.Write((byte)0x02); // Packet ID
|
||||
Stream.Write(board.Serial); // Bulletin board serial
|
||||
Stream.Write(msg.Serial); // Message serial
|
||||
|
||||
WriteString(poster);
|
||||
WriteString(subject);
|
||||
WriteString(time);
|
||||
|
||||
Stream.Write((short)msg.PostedBody);
|
||||
Stream.Write((short)msg.PostedHue);
|
||||
|
||||
var len = msg.PostedEquip.Length;
|
||||
|
||||
if (len > 255)
|
||||
{
|
||||
len = 255;
|
||||
}
|
||||
|
||||
Stream.Write((byte)len);
|
||||
|
||||
for (var i = 0; i < len; ++i)
|
||||
{
|
||||
var eq = msg.PostedEquip[i];
|
||||
|
||||
Stream.Write((short)eq._itemID);
|
||||
Stream.Write((short)eq._hue);
|
||||
}
|
||||
|
||||
len = msg.Lines.Length;
|
||||
|
||||
if (len > 255)
|
||||
{
|
||||
len = 255;
|
||||
}
|
||||
|
||||
Stream.Write((byte)len);
|
||||
|
||||
for (var i = 0; i < len; ++i)
|
||||
{
|
||||
WriteString(msg.Lines[i], true);
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteString(string v, bool padding = false)
|
||||
{
|
||||
var buffer = v.GetBytesUtf8();
|
||||
var tail = padding ? 2 : 1;
|
||||
var len = buffer.Length + tail;
|
||||
|
||||
if (len > 255)
|
||||
{
|
||||
len = 255;
|
||||
}
|
||||
|
||||
Stream.Write((byte)len);
|
||||
Stream.Write(buffer, 0, len - tail);
|
||||
|
||||
if (padding)
|
||||
{
|
||||
Stream.Write((short)0); // padding compensates for a client bug
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream.Write((byte)0);
|
||||
}
|
||||
}
|
||||
|
||||
public string SafeString(string v) => v ?? string.Empty;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,42 +6,42 @@ using Xunit;
|
|||
|
||||
namespace UOContent.Tests;
|
||||
|
||||
[Collection("Sequential Tests")]
|
||||
public class MahjongPacketTests : IClassFixture<ServerFixture>
|
||||
[Collection("Sequential UOContent Tests")]
|
||||
public class MahjongPacketTests
|
||||
{
|
||||
[Fact]
|
||||
public void TestMahjongJoinGame()
|
||||
{
|
||||
Serial game = (Serial)0x1024u;
|
||||
Serial game = (Serial)0x1024u;
|
||||
|
||||
var expected = new MahjongJoinGame(game).Compile();
|
||||
var expected = new MahjongJoinGame(game).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendMahjongJoinGame(game);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendMahjongJoinGame(game);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void TestMahjongPlayersInfo(bool showScores)
|
||||
{
|
||||
var m = new Mobile((Serial)0x1);
|
||||
m.DefaultMobileInit();
|
||||
var m = new Mobile((Serial)0x1);
|
||||
m.DefaultMobileInit();
|
||||
|
||||
var game = new MahjongGame { ShowScores = showScores };
|
||||
game.Players.Join(m);
|
||||
var game = new MahjongGame { ShowScores = showScores };
|
||||
game.Players.Join(m);
|
||||
|
||||
var expected = new MahjongPlayersInfo(game, m).Compile();
|
||||
var expected = new MahjongPlayersInfo(game, m).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendMahjongPlayersInfo(game, m);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendMahjongPlayersInfo(game, m);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true, true)]
|
||||
|
|
@ -50,68 +50,68 @@ public class MahjongPacketTests : IClassFixture<ServerFixture>
|
|||
[InlineData(false, false)]
|
||||
public void TestMahjongGeneralInfo(bool showScores, bool spectatorVision)
|
||||
{
|
||||
var game = new MahjongGame { ShowScores = showScores, SpectatorVision = spectatorVision};
|
||||
var game = new MahjongGame { ShowScores = showScores, SpectatorVision = spectatorVision};
|
||||
|
||||
var expected = new MahjongGeneralInfo(game).Compile();
|
||||
var expected = new MahjongGeneralInfo(game).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendMahjongGeneralInfo(game);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendMahjongGeneralInfo(game);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void TestMahjongTilesInfo(bool spectatorVision)
|
||||
{
|
||||
var m = new Mobile((Serial)0x1);
|
||||
m.DefaultMobileInit();
|
||||
var m = new Mobile((Serial)0x1);
|
||||
m.DefaultMobileInit();
|
||||
|
||||
var game = new MahjongGame { SpectatorVision = spectatorVision };
|
||||
game.Players.Join(m);
|
||||
var game = new MahjongGame { SpectatorVision = spectatorVision };
|
||||
game.Players.Join(m);
|
||||
|
||||
var expected = new MahjongTilesInfo(game, m).Compile();
|
||||
var expected = new MahjongTilesInfo(game, m).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendMahjongTilesInfo(game, m);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendMahjongTilesInfo(game, m);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void TestMahjongTileInfo(bool spectatorVision)
|
||||
{
|
||||
var m = new Mobile((Serial)0x1);
|
||||
m.DefaultMobileInit();
|
||||
var m = new Mobile((Serial)0x1);
|
||||
m.DefaultMobileInit();
|
||||
|
||||
var game = new MahjongGame { SpectatorVision = spectatorVision };
|
||||
game.Players.Join(m);
|
||||
var game = new MahjongGame { SpectatorVision = spectatorVision };
|
||||
game.Players.Join(m);
|
||||
|
||||
var expected = new MahjongTileInfo(game.Tiles[0], m).Compile();
|
||||
var expected = new MahjongTileInfo(game.Tiles[0], m).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendMahjongTileInfo(game.Tiles[0], m);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendMahjongTileInfo(game.Tiles[0], m);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestMahjongRelieve()
|
||||
{
|
||||
Serial game = (Serial)0x1024u;
|
||||
Serial game = (Serial)0x1024u;
|
||||
|
||||
var expected = new MahjongRelieve(game).Compile();
|
||||
var expected = new MahjongRelieve(game).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendMahjongRelieve(game);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendMahjongRelieve(game);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,176 +7,132 @@ public sealed class MahjongJoinGame : Packet
|
|||
{
|
||||
public MahjongJoinGame(Serial game) : base(0xDA)
|
||||
{
|
||||
EnsureCapacity(9);
|
||||
EnsureCapacity(9);
|
||||
|
||||
Stream.Write(game);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)0x19);
|
||||
}
|
||||
Stream.Write(game);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)0x19);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MahjongPlayersInfo : Packet
|
||||
{
|
||||
public MahjongPlayersInfo(MahjongGame game, Mobile to) : base(0xDA)
|
||||
{
|
||||
var players = game.Players;
|
||||
var players = game.Players;
|
||||
|
||||
EnsureCapacity(11 + 45 * players.Seats);
|
||||
EnsureCapacity(11 + 45 * players.Seats);
|
||||
|
||||
Stream.Write(game.Serial);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)0x2);
|
||||
Stream.Write(game.Serial);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)0x2);
|
||||
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)players.Seats);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)players.Seats);
|
||||
|
||||
var n = 0;
|
||||
for (var i = 0; i < players.Seats; i++)
|
||||
var n = 0;
|
||||
for (var i = 0; i < players.Seats; i++)
|
||||
{
|
||||
var mobile = players.GetPlayer(i);
|
||||
|
||||
if (mobile != null)
|
||||
{
|
||||
var mobile = players.GetPlayer(i);
|
||||
Stream.Write(mobile.Serial);
|
||||
Stream.Write(players.DealerPosition == i ? (byte)0x1 : (byte)0x2);
|
||||
Stream.Write((byte)i);
|
||||
|
||||
if (mobile != null)
|
||||
if (game.ShowScores || mobile == to)
|
||||
{
|
||||
Stream.Write(mobile.Serial);
|
||||
Stream.Write(players.DealerPosition == i ? (byte)0x1 : (byte)0x2);
|
||||
Stream.Write((byte)i);
|
||||
|
||||
if (game.ShowScores || mobile == to)
|
||||
{
|
||||
Stream.Write(players.GetScore(i));
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream.Write(0);
|
||||
}
|
||||
|
||||
Stream.Write((short)0);
|
||||
Stream.Write((byte)0);
|
||||
|
||||
Stream.Write(players.IsPublic(i));
|
||||
|
||||
Stream.WriteAsciiFixed(mobile.Name, 30);
|
||||
Stream.Write(!players.IsInGamePlayer(i));
|
||||
|
||||
n++;
|
||||
Stream.Write(players.GetScore(i));
|
||||
}
|
||||
else if (game.ShowScores)
|
||||
else
|
||||
{
|
||||
Stream.Write(0);
|
||||
Stream.Write((byte)0x2);
|
||||
Stream.Write((byte)i);
|
||||
|
||||
Stream.Write(players.GetScore(i));
|
||||
|
||||
Stream.Write((short)0);
|
||||
Stream.Write((byte)0);
|
||||
|
||||
Stream.Write(players.IsPublic(i));
|
||||
|
||||
Stream.WriteAsciiFixed("", 30);
|
||||
Stream.Write(true);
|
||||
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
if (n != players.Seats)
|
||||
Stream.Write((short)0);
|
||||
Stream.Write((byte)0);
|
||||
|
||||
Stream.Write(players.IsPublic(i));
|
||||
|
||||
Stream.WriteAsciiFixed(mobile.Name, 30);
|
||||
Stream.Write(!players.IsInGamePlayer(i));
|
||||
|
||||
n++;
|
||||
}
|
||||
else if (game.ShowScores)
|
||||
{
|
||||
Stream.Seek(10, SeekOrigin.Begin);
|
||||
Stream.Write((byte)n);
|
||||
Stream.Write(0);
|
||||
Stream.Write((byte)0x2);
|
||||
Stream.Write((byte)i);
|
||||
|
||||
Stream.Write(players.GetScore(i));
|
||||
|
||||
Stream.Write((short)0);
|
||||
Stream.Write((byte)0);
|
||||
|
||||
Stream.Write(players.IsPublic(i));
|
||||
|
||||
Stream.WriteAsciiFixed("", 30);
|
||||
Stream.Write(true);
|
||||
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
if (n != players.Seats)
|
||||
{
|
||||
Stream.Seek(10, SeekOrigin.Begin);
|
||||
Stream.Write((byte)n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MahjongGeneralInfo : Packet
|
||||
{
|
||||
public MahjongGeneralInfo(MahjongGame game) : base(0xDA)
|
||||
{
|
||||
EnsureCapacity(13);
|
||||
EnsureCapacity(13);
|
||||
|
||||
Stream.Write(game.Serial);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)0x5);
|
||||
Stream.Write(game.Serial);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)0x5);
|
||||
|
||||
Stream.Write((short)0);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((short)0);
|
||||
Stream.Write((byte)0);
|
||||
|
||||
Stream.Write((byte)((game.ShowScores ? 0x1 : 0x0) | (game.SpectatorVision ? 0x2 : 0x0)));
|
||||
Stream.Write((byte)((game.ShowScores ? 0x1 : 0x0) | (game.SpectatorVision ? 0x2 : 0x0)));
|
||||
|
||||
Stream.Write((byte)game.Dices.First);
|
||||
Stream.Write((byte)game.Dices.Second);
|
||||
Stream.Write((byte)game.Dices.First);
|
||||
Stream.Write((byte)game.Dices.Second);
|
||||
|
||||
Stream.Write((byte)game.DealerIndicator.Wind);
|
||||
Stream.Write((short)game.DealerIndicator.Position.Y);
|
||||
Stream.Write((short)game.DealerIndicator.Position.X);
|
||||
Stream.Write((byte)game.DealerIndicator.Direction);
|
||||
Stream.Write((byte)game.DealerIndicator.Wind);
|
||||
Stream.Write((short)game.DealerIndicator.Position.Y);
|
||||
Stream.Write((short)game.DealerIndicator.Position.X);
|
||||
Stream.Write((byte)game.DealerIndicator.Direction);
|
||||
|
||||
Stream.Write((short)game.WallBreakIndicator.Position.Y);
|
||||
Stream.Write((short)game.WallBreakIndicator.Position.X);
|
||||
}
|
||||
Stream.Write((short)game.WallBreakIndicator.Position.Y);
|
||||
Stream.Write((short)game.WallBreakIndicator.Position.X);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MahjongTilesInfo : Packet
|
||||
{
|
||||
public MahjongTilesInfo(MahjongGame game, Mobile to) : base(0xDA)
|
||||
{
|
||||
var tiles = game.Tiles;
|
||||
var players = game.Players;
|
||||
var tiles = game.Tiles;
|
||||
var players = game.Players;
|
||||
|
||||
EnsureCapacity(11 + 9 * tiles.Length);
|
||||
EnsureCapacity(11 + 9 * tiles.Length);
|
||||
|
||||
Stream.Write(game.Serial);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)0x4);
|
||||
Stream.Write(game.Serial);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)0x4);
|
||||
|
||||
Stream.Write((short)tiles.Length);
|
||||
|
||||
foreach (var tile in tiles)
|
||||
{
|
||||
Stream.Write((byte)tile.Number);
|
||||
|
||||
if (tile.Flipped)
|
||||
{
|
||||
var hand = tile.Dimensions.GetHandArea();
|
||||
|
||||
if (hand < 0 || players.IsPublic(hand) || players.GetPlayer(hand) == to ||
|
||||
game.SpectatorVision && players.IsSpectator(to))
|
||||
{
|
||||
Stream.Write((byte)tile.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream.Write((byte)0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream.Write((byte)0);
|
||||
}
|
||||
|
||||
Stream.Write((short)tile.Position.Y);
|
||||
Stream.Write((short)tile.Position.X);
|
||||
Stream.Write((byte)tile.StackLevel);
|
||||
Stream.Write((byte)tile.Direction);
|
||||
|
||||
Stream.Write(tile.Flipped ? (byte)0x10 : (byte)0x0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MahjongTileInfo : Packet
|
||||
{
|
||||
public MahjongTileInfo(MahjongTile tile, Mobile to) : base(0xDA)
|
||||
{
|
||||
var game = tile.Game;
|
||||
var players = game.Players;
|
||||
|
||||
EnsureCapacity(18);
|
||||
|
||||
Stream.Write(tile.Game.Serial);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)0x3);
|
||||
Stream.Write((short)tiles.Length);
|
||||
|
||||
foreach (var tile in tiles)
|
||||
{
|
||||
Stream.Write((byte)tile.Number);
|
||||
|
||||
if (tile.Flipped)
|
||||
|
|
@ -205,16 +161,60 @@ public sealed class MahjongTileInfo : Packet
|
|||
|
||||
Stream.Write(tile.Flipped ? (byte)0x10 : (byte)0x0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MahjongTileInfo : Packet
|
||||
{
|
||||
public MahjongTileInfo(MahjongTile tile, Mobile to) : base(0xDA)
|
||||
{
|
||||
var game = tile.Game;
|
||||
var players = game.Players;
|
||||
|
||||
EnsureCapacity(18);
|
||||
|
||||
Stream.Write(tile.Game.Serial);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)0x3);
|
||||
|
||||
Stream.Write((byte)tile.Number);
|
||||
|
||||
if (tile.Flipped)
|
||||
{
|
||||
var hand = tile.Dimensions.GetHandArea();
|
||||
|
||||
if (hand < 0 || players.IsPublic(hand) || players.GetPlayer(hand) == to ||
|
||||
game.SpectatorVision && players.IsSpectator(to))
|
||||
{
|
||||
Stream.Write((byte)tile.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream.Write((byte)0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream.Write((byte)0);
|
||||
}
|
||||
|
||||
Stream.Write((short)tile.Position.Y);
|
||||
Stream.Write((short)tile.Position.X);
|
||||
Stream.Write((byte)tile.StackLevel);
|
||||
Stream.Write((byte)tile.Direction);
|
||||
|
||||
Stream.Write(tile.Flipped ? (byte)0x10 : (byte)0x0);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MahjongRelieve : Packet
|
||||
{
|
||||
public MahjongRelieve(Serial game) : base(0xDA)
|
||||
{
|
||||
EnsureCapacity(9);
|
||||
EnsureCapacity(9);
|
||||
|
||||
Stream.Write(game);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)0x1A);
|
||||
}
|
||||
}
|
||||
Stream.Write(game);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)0x1A);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,62 +6,62 @@ public sealed class MapDetails : Packet
|
|||
{
|
||||
public MapDetails(MapItem map) : base(0x90, 19)
|
||||
{
|
||||
Stream.Write(map.Serial);
|
||||
Stream.Write((short)0x139D);
|
||||
Stream.Write((short)map.Bounds.Start.X);
|
||||
Stream.Write((short)map.Bounds.Start.Y);
|
||||
Stream.Write((short)map.Bounds.End.X);
|
||||
Stream.Write((short)map.Bounds.End.Y);
|
||||
Stream.Write((short)map.Width);
|
||||
Stream.Write((short)map.Height);
|
||||
}
|
||||
Stream.Write(map.Serial);
|
||||
Stream.Write((short)0x139D);
|
||||
Stream.Write((short)map.Bounds.Start.X);
|
||||
Stream.Write((short)map.Bounds.Start.Y);
|
||||
Stream.Write((short)map.Bounds.End.X);
|
||||
Stream.Write((short)map.Bounds.End.Y);
|
||||
Stream.Write((short)map.Width);
|
||||
Stream.Write((short)map.Height);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MapDetailsNew : Packet
|
||||
{
|
||||
public MapDetailsNew(MapItem map) : base(0xF5, 21)
|
||||
{
|
||||
Stream.Write(map.Serial);
|
||||
Stream.Write((short)0x139D);
|
||||
Stream.Write((short)map.Bounds.Start.X);
|
||||
Stream.Write((short)map.Bounds.Start.Y);
|
||||
Stream.Write((short)map.Bounds.End.X);
|
||||
Stream.Write((short)map.Bounds.End.Y);
|
||||
Stream.Write((short)map.Width);
|
||||
Stream.Write((short)map.Height);
|
||||
Stream.Write((short)(map.Facet?.MapID ?? 0));
|
||||
}
|
||||
Stream.Write(map.Serial);
|
||||
Stream.Write((short)0x139D);
|
||||
Stream.Write((short)map.Bounds.Start.X);
|
||||
Stream.Write((short)map.Bounds.Start.Y);
|
||||
Stream.Write((short)map.Bounds.End.X);
|
||||
Stream.Write((short)map.Bounds.End.Y);
|
||||
Stream.Write((short)map.Width);
|
||||
Stream.Write((short)map.Height);
|
||||
Stream.Write((short)(map.Facet?.MapID ?? 0));
|
||||
}
|
||||
}
|
||||
|
||||
public class MapCommand : Packet
|
||||
{
|
||||
public MapCommand(MapItem map, int command, int number, int x, int y) : base(0x56, 11)
|
||||
{
|
||||
Stream.Write(map.Serial);
|
||||
Stream.Write((byte)command);
|
||||
Stream.Write((byte)number);
|
||||
Stream.Write((short)x);
|
||||
Stream.Write((short)y);
|
||||
}
|
||||
Stream.Write(map.Serial);
|
||||
Stream.Write((byte)command);
|
||||
Stream.Write((byte)number);
|
||||
Stream.Write((short)x);
|
||||
Stream.Write((short)y);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MapDisplay : MapCommand
|
||||
{
|
||||
public MapDisplay(MapItem map) : base(map, 5, 0, 0, 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MapAddPin : MapCommand
|
||||
{
|
||||
public MapAddPin(MapItem map, Point2D point) : base(map, 1, 0, point.X, point.Y)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MapSetEditable : MapCommand
|
||||
{
|
||||
public MapSetEditable(MapItem map, bool editable) : base(map, 7, editable ? 1 : 0, 0, 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,26 +7,26 @@ using Xunit;
|
|||
|
||||
namespace UOContent.Tests;
|
||||
|
||||
[Collection("Sequential Tests")]
|
||||
public class TestMapItemPackets : IClassFixture<ServerFixture>
|
||||
[Collection("Sequential UOContent Tests")]
|
||||
public class TestMapItemPackets
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(ProtocolChanges.NewCharacterList)]
|
||||
[InlineData(ProtocolChanges.None)]
|
||||
public void TestSendMapDetails(ProtocolChanges changes)
|
||||
{
|
||||
var mapItem = new MapItem(Map.Trammel);
|
||||
var mapItem = new MapItem(Map.Trammel);
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.ProtocolChanges = changes;
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.ProtocolChanges = changes;
|
||||
|
||||
var expected = (ns.NewCharacterList ?
|
||||
(Packet)new MapDetailsNew(mapItem) : new MapDetails(mapItem)).Compile();
|
||||
ns.SendMapDetails(mapItem);
|
||||
var expected = (ns.NewCharacterList ?
|
||||
(Packet)new MapDetailsNew(mapItem) : new MapDetails(mapItem)).Compile();
|
||||
ns.SendMapDetails(mapItem);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(5, 0, 0, 0)]
|
||||
|
|
@ -35,14 +35,14 @@ public class TestMapItemPackets : IClassFixture<ServerFixture>
|
|||
[InlineData(7, 0, 0, 0)]
|
||||
public void TestSendMapCommand(int command, int number, int x, int y)
|
||||
{
|
||||
var mapItem = new MapItem(Map.Trammel);
|
||||
var mapItem = new MapItem(Map.Trammel);
|
||||
|
||||
var expected = new MapCommand(mapItem, command, number, x, y).Compile();
|
||||
var expected = new MapCommand(mapItem, command, number, x, y).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendMapCommand(mapItem, command, x, y, number > 0);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendMapCommand(mapItem, command, x, y, number > 0);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,50 +7,50 @@ using Xunit;
|
|||
|
||||
namespace UOContent.Tests;
|
||||
|
||||
[Collection("Sequential Tests")]
|
||||
public class CorpsePacketTests : IClassFixture<ServerFixture>
|
||||
[Collection("Sequential UOContent Tests")]
|
||||
public class CorpsePacketTests
|
||||
{
|
||||
[Fact]
|
||||
public void TestCorpseEquipPacket()
|
||||
{
|
||||
var m = new Mobile((Serial)0x1);
|
||||
m.DefaultMobileInit();
|
||||
var m = new Mobile((Serial)0x1);
|
||||
m.DefaultMobileInit();
|
||||
|
||||
var weapon = new VikingSword();
|
||||
m.EquipItem(weapon);
|
||||
var weapon = new VikingSword();
|
||||
m.EquipItem(weapon);
|
||||
|
||||
var c = new Corpse(m, m.Items);
|
||||
var c = new Corpse(m, m.Items);
|
||||
|
||||
var expected = new CorpseEquip(m, c).Compile();
|
||||
var expected = new CorpseEquip(m, c).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendCorpseEquip(m, c);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendCorpseEquip(m, c);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(ProtocolChanges.None)]
|
||||
[InlineData(ProtocolChanges.ContainerGridLines)]
|
||||
public void TestCorpseContainerPacket(ProtocolChanges changes)
|
||||
{
|
||||
var m = new Mobile((Serial)0x1);
|
||||
m.DefaultMobileInit();
|
||||
var m = new Mobile((Serial)0x1);
|
||||
m.DefaultMobileInit();
|
||||
|
||||
var weapon = new VikingSword();
|
||||
m.EquipItem(weapon);
|
||||
var weapon = new VikingSword();
|
||||
m.EquipItem(weapon);
|
||||
|
||||
var c = new Corpse(m, m.Items);
|
||||
var c = new Corpse(m, m.Items);
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.ProtocolChanges = changes;
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.ProtocolChanges = changes;
|
||||
|
||||
var expected = (ns.ContainerGridLines ? (Packet)new CorpseContent6017(m, c) : new CorpseContent(m, c)).Compile();
|
||||
var expected = (ns.ContainerGridLines ? (Packet)new CorpseContent6017(m, c) : new CorpseContent(m, c)).Compile();
|
||||
|
||||
ns.SendCorpseContent(m, c);
|
||||
ns.SendCorpseContent(m, c);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,24 +14,24 @@ public class WeaponAbilityPacketTests
|
|||
[InlineData(1000, false)]
|
||||
public void TestSpecialAbility(int abilityId, bool active)
|
||||
{
|
||||
var expected = new ToggleSpecialAbility(abilityId, active).Compile();
|
||||
var expected = new ToggleSpecialAbility(abilityId, active).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendToggleSpecialAbility(abilityId, active);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendToggleSpecialAbility(abilityId, active);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestClearAbility()
|
||||
{
|
||||
var expected = new ClearWeaponAbility().Compile();
|
||||
var expected = new ClearWeaponAbility().Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendClearWeaponAbility();
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendClearWeaponAbility();
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@ public sealed class ToggleSpecialAbility : Packet
|
|||
{
|
||||
public ToggleSpecialAbility(int abilityID, bool active) : base(0xBF)
|
||||
{
|
||||
EnsureCapacity(7);
|
||||
EnsureCapacity(7);
|
||||
|
||||
Stream.Write((short)0x25);
|
||||
Stream.Write((short)0x25);
|
||||
|
||||
Stream.Write((short)abilityID);
|
||||
Stream.Write(active);
|
||||
}
|
||||
Stream.Write((short)abilityID);
|
||||
Stream.Write(active);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ClearWeaponAbility : Packet
|
||||
|
|
@ -21,8 +21,8 @@ public sealed class ClearWeaponAbility : Packet
|
|||
|
||||
public ClearWeaponAbility() : base(0xBF)
|
||||
{
|
||||
EnsureCapacity(5);
|
||||
EnsureCapacity(5);
|
||||
|
||||
Stream.Write((short)0x21);
|
||||
}
|
||||
}
|
||||
Stream.Write((short)0x21);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ using Xunit;
|
|||
|
||||
namespace UOContent.Tests;
|
||||
|
||||
public class BoatPacketTests : IClassFixture<ServerFixture>
|
||||
[Collection("Sequential UOContent Tests")]
|
||||
public class BoatPacketTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(Direction.West, 10, 100, 200)]
|
||||
|
|
|
|||
|
|
@ -15,117 +15,117 @@ public sealed class MoveBoatHS : Packet
|
|||
int yOffset
|
||||
) : base(0xF6)
|
||||
{
|
||||
EnsureCapacity(3 + 15 + ents.Count * 10);
|
||||
EnsureCapacity(3 + 15 + ents.Count * 10);
|
||||
|
||||
Stream.Write(boat.Serial);
|
||||
Stream.Write((byte)speed);
|
||||
Stream.Write((byte)d);
|
||||
Stream.Write((byte)boat.Facing);
|
||||
Stream.Write((short)(boat.X + xOffset));
|
||||
Stream.Write((short)(boat.Y + yOffset));
|
||||
Stream.Write((short)boat.Z);
|
||||
Stream.Write((short)0); // count placeholder
|
||||
Stream.Write(boat.Serial);
|
||||
Stream.Write((byte)speed);
|
||||
Stream.Write((byte)d);
|
||||
Stream.Write((byte)boat.Facing);
|
||||
Stream.Write((short)(boat.X + xOffset));
|
||||
Stream.Write((short)(boat.Y + yOffset));
|
||||
Stream.Write((short)boat.Z);
|
||||
Stream.Write((short)0); // count placeholder
|
||||
|
||||
var count = 0;
|
||||
var count = 0;
|
||||
|
||||
foreach (var ent in ents)
|
||||
{
|
||||
Stream.Write(ent.Serial);
|
||||
Stream.Write((short)(ent.X + xOffset));
|
||||
Stream.Write((short)(ent.Y + yOffset));
|
||||
Stream.Write((short)ent.Z);
|
||||
++count;
|
||||
}
|
||||
|
||||
Stream.Seek(16, SeekOrigin.Begin);
|
||||
Stream.Write((short)count);
|
||||
foreach (var ent in ents)
|
||||
{
|
||||
Stream.Write(ent.Serial);
|
||||
Stream.Write((short)(ent.X + xOffset));
|
||||
Stream.Write((short)(ent.Y + yOffset));
|
||||
Stream.Write((short)ent.Z);
|
||||
++count;
|
||||
}
|
||||
|
||||
Stream.Seek(16, SeekOrigin.Begin);
|
||||
Stream.Write((short)count);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DisplayBoatHS : Packet
|
||||
{
|
||||
public DisplayBoatHS(Mobile beholder, BaseBoat boat) : base(0xF7)
|
||||
{
|
||||
var ents = boat.GetMovingEntities(true);
|
||||
var ents = boat.GetMovingEntities(true);
|
||||
|
||||
EnsureCapacity(3 + 2 + 5 * 26);
|
||||
EnsureCapacity(3 + 2 + 5 * 26);
|
||||
|
||||
Stream.Write((short)0); // count placeholder
|
||||
Stream.Write((short)0); // count placeholder
|
||||
|
||||
var count = 0;
|
||||
var count = 0;
|
||||
|
||||
foreach (var ent in ents)
|
||||
foreach (var ent in ents)
|
||||
{
|
||||
if (!beholder.CanSee(ent))
|
||||
{
|
||||
if (!beholder.CanSee(ent))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Embedded WorldItemHS packets
|
||||
Stream.Write((byte)0xF3);
|
||||
Stream.Write((short)0x1);
|
||||
|
||||
if (ent is BaseMulti bm)
|
||||
{
|
||||
Stream.Write((byte)0x02);
|
||||
Stream.Write(bm.Serial);
|
||||
// TODO: Mask no longer needed, merge with Item case?
|
||||
Stream.Write((ushort)(bm.ItemID & 0x3FFF));
|
||||
Stream.Write((byte)0);
|
||||
|
||||
Stream.Write((short)bm.Amount);
|
||||
Stream.Write((short)bm.Amount);
|
||||
|
||||
Stream.Write((short)(bm.X & 0x7FFF));
|
||||
Stream.Write((short)(bm.Y & 0x3FFF));
|
||||
Stream.Write((sbyte)bm.Z);
|
||||
|
||||
Stream.Write((byte)bm.Light);
|
||||
Stream.Write((short)bm.Hue);
|
||||
Stream.Write((byte)bm.GetPacketFlags());
|
||||
}
|
||||
else if (ent is Mobile m)
|
||||
{
|
||||
Stream.Write((byte)0x01);
|
||||
Stream.Write(m.Serial);
|
||||
Stream.Write((short)m.Body);
|
||||
Stream.Write((byte)0);
|
||||
|
||||
Stream.Write((short)1);
|
||||
Stream.Write((short)1);
|
||||
|
||||
Stream.Write((short)(m.X & 0x7FFF));
|
||||
Stream.Write((short)(m.Y & 0x3FFF));
|
||||
Stream.Write((sbyte)m.Z);
|
||||
|
||||
Stream.Write((byte)m.Direction);
|
||||
Stream.Write((short)m.Hue);
|
||||
Stream.Write((byte)m.GetPacketFlags(true));
|
||||
}
|
||||
else if (ent is Item item)
|
||||
{
|
||||
Stream.Write((byte)0x00);
|
||||
Stream.Write(item.Serial);
|
||||
Stream.Write((ushort)(item.ItemID & 0xFFFF));
|
||||
Stream.Write((byte)0);
|
||||
|
||||
Stream.Write((short)item.Amount);
|
||||
Stream.Write((short)item.Amount);
|
||||
|
||||
Stream.Write((short)(item.X & 0x7FFF));
|
||||
Stream.Write((short)(item.Y & 0x3FFF));
|
||||
Stream.Write((sbyte)item.Z);
|
||||
|
||||
Stream.Write((byte)item.Light);
|
||||
Stream.Write((short)item.Hue);
|
||||
Stream.Write((byte)item.GetPacketFlags());
|
||||
}
|
||||
|
||||
Stream.Write((short)0x00);
|
||||
++count;
|
||||
continue;
|
||||
}
|
||||
|
||||
Stream.Seek(3, SeekOrigin.Begin);
|
||||
Stream.Write((short)count);
|
||||
// Embedded WorldItemHS packets
|
||||
Stream.Write((byte)0xF3);
|
||||
Stream.Write((short)0x1);
|
||||
|
||||
if (ent is BaseMulti bm)
|
||||
{
|
||||
Stream.Write((byte)0x02);
|
||||
Stream.Write(bm.Serial);
|
||||
// TODO: Mask no longer needed, merge with Item case?
|
||||
Stream.Write((ushort)(bm.ItemID & 0x3FFF));
|
||||
Stream.Write((byte)0);
|
||||
|
||||
Stream.Write((short)bm.Amount);
|
||||
Stream.Write((short)bm.Amount);
|
||||
|
||||
Stream.Write((short)(bm.X & 0x7FFF));
|
||||
Stream.Write((short)(bm.Y & 0x3FFF));
|
||||
Stream.Write((sbyte)bm.Z);
|
||||
|
||||
Stream.Write((byte)bm.Light);
|
||||
Stream.Write((short)bm.Hue);
|
||||
Stream.Write((byte)bm.GetPacketFlags());
|
||||
}
|
||||
else if (ent is Mobile m)
|
||||
{
|
||||
Stream.Write((byte)0x01);
|
||||
Stream.Write(m.Serial);
|
||||
Stream.Write((short)m.Body);
|
||||
Stream.Write((byte)0);
|
||||
|
||||
Stream.Write((short)1);
|
||||
Stream.Write((short)1);
|
||||
|
||||
Stream.Write((short)(m.X & 0x7FFF));
|
||||
Stream.Write((short)(m.Y & 0x3FFF));
|
||||
Stream.Write((sbyte)m.Z);
|
||||
|
||||
Stream.Write((byte)m.Direction);
|
||||
Stream.Write((short)m.Hue);
|
||||
Stream.Write((byte)m.GetPacketFlags(true));
|
||||
}
|
||||
else if (ent is Item item)
|
||||
{
|
||||
Stream.Write((byte)0x00);
|
||||
Stream.Write(item.Serial);
|
||||
Stream.Write((ushort)(item.ItemID & 0xFFFF));
|
||||
Stream.Write((byte)0);
|
||||
|
||||
Stream.Write((short)item.Amount);
|
||||
Stream.Write((short)item.Amount);
|
||||
|
||||
Stream.Write((short)(item.X & 0x7FFF));
|
||||
Stream.Write((short)(item.Y & 0x3FFF));
|
||||
Stream.Write((sbyte)item.Z);
|
||||
|
||||
Stream.Write((byte)item.Light);
|
||||
Stream.Write((short)item.Hue);
|
||||
Stream.Write((byte)item.GetPacketFlags());
|
||||
}
|
||||
|
||||
Stream.Write((short)0x00);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
Stream.Seek(3, SeekOrigin.Begin);
|
||||
Stream.Write((short)count);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,66 +14,66 @@ public class HousePacketTests
|
|||
[InlineData(0x1001u)]
|
||||
public void TestBeginHouseCustomization(uint serial)
|
||||
{
|
||||
var expected = new BeginHouseCustomization((Serial)serial).Compile();
|
||||
var expected = new BeginHouseCustomization((Serial)serial).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendBeginHouseCustomization((Serial)serial);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendBeginHouseCustomization((Serial)serial);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0x1001u)]
|
||||
public void TestEndHouseCustomization(uint serial)
|
||||
{
|
||||
var expected = new EndHouseCustomization((Serial)serial).Compile();
|
||||
var expected = new EndHouseCustomization((Serial)serial).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendEndHouseCustomization((Serial)serial);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendEndHouseCustomization((Serial)serial);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0x1001u, 0)]
|
||||
[InlineData(0x1001u, 100)]
|
||||
public void TestDesignStateGeneral(uint serial, int revision)
|
||||
{
|
||||
var expected = new DesignStateGeneral((Serial)serial, revision).Compile();
|
||||
var expected = new DesignStateGeneral((Serial)serial, revision).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendDesignStateGeneral((Serial)serial, revision);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendDesignStateGeneral((Serial)serial, revision);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestHouseDesignStateDetailed()
|
||||
{
|
||||
Serial serial = (Serial)0x40000001;
|
||||
var revision = 10;
|
||||
var tiles = new MultiTileEntry[250];
|
||||
for (var i = 0; i < tiles.Length; i++)
|
||||
{
|
||||
tiles[i] = new MultiTileEntry(
|
||||
(ushort)i,
|
||||
(byte)i,
|
||||
(byte)i,
|
||||
(byte)(i / 50),
|
||||
TileFlag.None
|
||||
);
|
||||
}
|
||||
var mcl = new MultiComponentList(tiles.ToList());
|
||||
|
||||
var expected = new DesignStateDetailed(
|
||||
serial, revision, mcl.Min.X, mcl.Min.Y, mcl.Max.X, mcl.Max.Y, tiles
|
||||
).Compile();
|
||||
|
||||
var actual = HousePackets.CreateHouseDesignStateDetailed(serial, revision, mcl);
|
||||
|
||||
AssertThat.Equal(actual, expected);
|
||||
Serial serial = (Serial)0x40000001;
|
||||
var revision = 10;
|
||||
var tiles = new MultiTileEntry[250];
|
||||
for (var i = 0; i < tiles.Length; i++)
|
||||
{
|
||||
tiles[i] = new MultiTileEntry(
|
||||
(ushort)i,
|
||||
(byte)i,
|
||||
(byte)i,
|
||||
(byte)(i / 50),
|
||||
TileFlag.None
|
||||
);
|
||||
}
|
||||
}
|
||||
var mcl = new MultiComponentList(tiles.ToList());
|
||||
|
||||
var expected = new DesignStateDetailed(
|
||||
serial, revision, mcl.Min.X, mcl.Min.Y, mcl.Max.X, mcl.Max.Y, tiles
|
||||
).Compile();
|
||||
|
||||
var actual = HousePackets.CreateHouseDesignStateDetailed(serial, revision, mcl);
|
||||
|
||||
AssertThat.Equal(actual, expected);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,320 +3,319 @@ using System.Buffers;
|
|||
using System.IO;
|
||||
using Server.Compression;
|
||||
|
||||
namespace Server.Network
|
||||
namespace Server.Network;
|
||||
|
||||
public class BeginHouseCustomization : Packet
|
||||
{
|
||||
public class BeginHouseCustomization : Packet
|
||||
public BeginHouseCustomization(Serial house) : base(0xBF)
|
||||
{
|
||||
public BeginHouseCustomization(Serial house) : base(0xBF)
|
||||
{
|
||||
EnsureCapacity(17);
|
||||
EnsureCapacity(17);
|
||||
|
||||
Stream.Write((short)0x20);
|
||||
Stream.Write(house);
|
||||
Stream.Write((byte)0x04);
|
||||
Stream.Write((ushort)0x0000);
|
||||
Stream.Write((ushort)0xFFFF);
|
||||
Stream.Write((ushort)0xFFFF);
|
||||
Stream.Write((byte)0xFF);
|
||||
Stream.Write((short)0x20);
|
||||
Stream.Write(house);
|
||||
Stream.Write((byte)0x04);
|
||||
Stream.Write((ushort)0x0000);
|
||||
Stream.Write((ushort)0xFFFF);
|
||||
Stream.Write((ushort)0xFFFF);
|
||||
Stream.Write((byte)0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
public class EndHouseCustomization : Packet
|
||||
{
|
||||
public EndHouseCustomization(Serial house) : base(0xBF)
|
||||
{
|
||||
EnsureCapacity(17);
|
||||
|
||||
Stream.Write((short)0x20);
|
||||
Stream.Write(house);
|
||||
Stream.Write((byte)0x05);
|
||||
Stream.Write((ushort)0x0000);
|
||||
Stream.Write((ushort)0xFFFF);
|
||||
Stream.Write((ushort)0xFFFF);
|
||||
Stream.Write((byte)0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DesignStateGeneral : Packet
|
||||
{
|
||||
public DesignStateGeneral(Serial house, int revision) : base(0xBF)
|
||||
{
|
||||
EnsureCapacity(13);
|
||||
|
||||
Stream.Write((short)0x1D);
|
||||
Stream.Write(house);
|
||||
Stream.Write(revision);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DesignStateDetailed : Packet
|
||||
{
|
||||
public const int MaxItemsPerStairBuffer = 750;
|
||||
|
||||
private readonly bool[] m_PlaneUsed = new bool[9];
|
||||
private readonly byte[] m_PrimBuffer = new byte[4];
|
||||
|
||||
public DesignStateDetailed(Serial serial, int revision, int xMin, int yMin, int xMax, int yMax, MultiTileEntry[] tiles)
|
||||
: base(0xD8)
|
||||
{
|
||||
EnsureCapacity(17 + tiles.Length * 5);
|
||||
|
||||
Write((byte)0x03); // Compression Type
|
||||
Write((byte)0x00); // Unknown
|
||||
Write(serial.Value);
|
||||
Write(revision);
|
||||
Write((short)tiles.Length);
|
||||
Write((short)0); // Buffer length : reserved
|
||||
Write((byte)0); // Plane count : reserved
|
||||
|
||||
var totalLength = 1; // includes plane count
|
||||
|
||||
var width = xMax - xMin + 1;
|
||||
var height = yMax - yMin + 1;
|
||||
|
||||
var planeBuffers = new byte[9][];
|
||||
|
||||
for (var i = 0; i < planeBuffers.Length; ++i)
|
||||
{
|
||||
planeBuffers[i] = ArrayPool<byte>.Shared.Rent(0x400);
|
||||
}
|
||||
|
||||
var stairBuffers = new byte[6][];
|
||||
|
||||
for (var i = 0; i < stairBuffers.Length; ++i)
|
||||
{
|
||||
stairBuffers[i] = ArrayPool<byte>.Shared.Rent(MaxItemsPerStairBuffer * 5);
|
||||
}
|
||||
|
||||
Clear(planeBuffers[0], width * height * 2);
|
||||
|
||||
for (var i = 0; i < 4; ++i)
|
||||
{
|
||||
Clear(planeBuffers[1 + i], (width - 1) * (height - 2) * 2);
|
||||
Clear(planeBuffers[5 + i], width * (height - 1) * 2);
|
||||
}
|
||||
|
||||
var totalStairsUsed = 0;
|
||||
|
||||
for (var i = 0; i < tiles.Length; ++i)
|
||||
{
|
||||
var mte = tiles[i];
|
||||
var x = mte.OffsetX - xMin;
|
||||
var y = mte.OffsetY - yMin;
|
||||
int z = mte.OffsetZ;
|
||||
var floor = TileData.ItemTable[mte.ItemId & TileData.MaxItemValue].Height <= 0;
|
||||
int plane, size;
|
||||
|
||||
switch (z)
|
||||
{
|
||||
case 0:
|
||||
plane = 0;
|
||||
break;
|
||||
case 7:
|
||||
plane = 1;
|
||||
break;
|
||||
case 27:
|
||||
plane = 2;
|
||||
break;
|
||||
case 47:
|
||||
plane = 3;
|
||||
break;
|
||||
case 67:
|
||||
plane = 4;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
var stairBufferIndex = totalStairsUsed / MaxItemsPerStairBuffer;
|
||||
var stairBuffer = stairBuffers[stairBufferIndex];
|
||||
|
||||
var byteIndex = totalStairsUsed % MaxItemsPerStairBuffer * 5;
|
||||
|
||||
stairBuffer[byteIndex++] = (byte)(mte.ItemId >> 8);
|
||||
stairBuffer[byteIndex++] = (byte)mte.ItemId;
|
||||
|
||||
stairBuffer[byteIndex++] = (byte)mte.OffsetX;
|
||||
stairBuffer[byteIndex++] = (byte)mte.OffsetY;
|
||||
stairBuffer[byteIndex] = (byte)mte.OffsetZ;
|
||||
|
||||
++totalStairsUsed;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (plane == 0)
|
||||
{
|
||||
size = height;
|
||||
}
|
||||
else if (floor)
|
||||
{
|
||||
size = height - 2;
|
||||
x -= 1;
|
||||
y -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = height - 1;
|
||||
plane += 4;
|
||||
}
|
||||
|
||||
var index = (x * size + y) * 2;
|
||||
|
||||
if (x < 0 || y < 0 || y >= size || index + 1 >= 0x400)
|
||||
{
|
||||
var stairBufferIndex = totalStairsUsed / MaxItemsPerStairBuffer;
|
||||
var stairBuffer = stairBuffers[stairBufferIndex];
|
||||
|
||||
var byteIndex = totalStairsUsed % MaxItemsPerStairBuffer * 5;
|
||||
|
||||
stairBuffer[byteIndex++] = (byte)(mte.ItemId >> 8);
|
||||
stairBuffer[byteIndex++] = (byte)mte.ItemId;
|
||||
|
||||
stairBuffer[byteIndex++] = (byte)mte.OffsetX;
|
||||
stairBuffer[byteIndex++] = (byte)mte.OffsetY;
|
||||
stairBuffer[byteIndex] = (byte)mte.OffsetZ;
|
||||
|
||||
++totalStairsUsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_PlaneUsed[plane] = true;
|
||||
planeBuffers[plane][index] = (byte)(mte.ItemId >> 8);
|
||||
planeBuffers[plane][index + 1] = (byte)mte.ItemId;
|
||||
}
|
||||
}
|
||||
|
||||
var planeCount = 0;
|
||||
|
||||
var deflatedBuffer = ArrayPool<byte>.Shared.Rent(0x2000);
|
||||
|
||||
for (var i = 0; i < planeBuffers.Length; ++i)
|
||||
{
|
||||
if (!m_PlaneUsed[i])
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(planeBuffers[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
++planeCount;
|
||||
|
||||
int size = i switch
|
||||
{
|
||||
0 => width * height * 2,
|
||||
< 5 => (width - 1) * (height - 2) * 2,
|
||||
_ => width * (height - 1) * 2
|
||||
};
|
||||
|
||||
var inflatedBuffer = planeBuffers[i];
|
||||
|
||||
var deflatedLength = Deflate.Standard.Pack(
|
||||
deflatedBuffer,
|
||||
inflatedBuffer.AsSpan(0, size)
|
||||
);
|
||||
|
||||
if (deflatedLength == 0)
|
||||
{
|
||||
Console.WriteLine("Compression error");
|
||||
}
|
||||
|
||||
Write((byte)(0x20 | i));
|
||||
Write((byte)size);
|
||||
Write((byte)deflatedLength);
|
||||
Write((byte)(((size >> 4) & 0xF0) | ((deflatedLength >> 8) & 0xF)));
|
||||
Write(deflatedBuffer, 0, deflatedLength);
|
||||
|
||||
totalLength += 4 + deflatedLength;
|
||||
ArrayPool<byte>.Shared.Return(inflatedBuffer);
|
||||
}
|
||||
|
||||
var totalStairBuffersUsed = (totalStairsUsed + (MaxItemsPerStairBuffer - 1)) / MaxItemsPerStairBuffer;
|
||||
|
||||
for (var i = 0; i < totalStairBuffersUsed; ++i)
|
||||
{
|
||||
++planeCount;
|
||||
|
||||
var count = Math.Min(MaxItemsPerStairBuffer, totalStairsUsed - i * MaxItemsPerStairBuffer);
|
||||
|
||||
var size = count * 5;
|
||||
|
||||
var inflatedBuffer = stairBuffers[i];
|
||||
|
||||
var deflatedLength = Deflate.Standard.Pack(
|
||||
deflatedBuffer,
|
||||
inflatedBuffer.AsSpan(0, size)
|
||||
);
|
||||
|
||||
if (deflatedLength == 0)
|
||||
{
|
||||
Console.WriteLine("Compression error");
|
||||
}
|
||||
|
||||
Write((byte)(9 + i));
|
||||
Write((byte)size);
|
||||
Write((byte)deflatedLength);
|
||||
Write((byte)(((size >> 4) & 0xF0) | ((deflatedLength >> 8) & 0xF)));
|
||||
Write(deflatedBuffer, 0, deflatedLength);
|
||||
|
||||
totalLength += 4 + deflatedLength;
|
||||
}
|
||||
|
||||
for (var i = 0; i < stairBuffers.Length; ++i)
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(stairBuffers[i]);
|
||||
}
|
||||
|
||||
ArrayPool<byte>.Shared.Return(deflatedBuffer);
|
||||
|
||||
Stream.Seek(15, SeekOrigin.Begin);
|
||||
|
||||
Write((short)totalLength); // Buffer length
|
||||
Write((byte)planeCount); // Plane count
|
||||
}
|
||||
|
||||
public class EndHouseCustomization : Packet
|
||||
public void Write(int value)
|
||||
{
|
||||
public EndHouseCustomization(Serial house) : base(0xBF)
|
||||
{
|
||||
EnsureCapacity(17);
|
||||
m_PrimBuffer[0] = (byte)(value >> 24);
|
||||
m_PrimBuffer[1] = (byte)(value >> 16);
|
||||
m_PrimBuffer[2] = (byte)(value >> 8);
|
||||
m_PrimBuffer[3] = (byte)value;
|
||||
|
||||
Stream.Write((short)0x20);
|
||||
Stream.Write(house);
|
||||
Stream.Write((byte)0x05);
|
||||
Stream.Write((ushort)0x0000);
|
||||
Stream.Write((ushort)0xFFFF);
|
||||
Stream.Write((ushort)0xFFFF);
|
||||
Stream.Write((byte)0xFF);
|
||||
}
|
||||
Stream.UnderlyingStream.Write(m_PrimBuffer, 0, 4);
|
||||
}
|
||||
|
||||
public sealed class DesignStateGeneral : Packet
|
||||
public void Write(uint value)
|
||||
{
|
||||
public DesignStateGeneral(Serial house, int revision) : base(0xBF)
|
||||
{
|
||||
EnsureCapacity(13);
|
||||
m_PrimBuffer[0] = (byte)(value >> 24);
|
||||
m_PrimBuffer[1] = (byte)(value >> 16);
|
||||
m_PrimBuffer[2] = (byte)(value >> 8);
|
||||
m_PrimBuffer[3] = (byte)value;
|
||||
|
||||
Stream.Write((short)0x1D);
|
||||
Stream.Write(house);
|
||||
Stream.Write(revision);
|
||||
}
|
||||
Stream.UnderlyingStream.Write(m_PrimBuffer, 0, 4);
|
||||
}
|
||||
|
||||
public sealed class DesignStateDetailed : Packet
|
||||
public void Write(short value)
|
||||
{
|
||||
public const int MaxItemsPerStairBuffer = 750;
|
||||
m_PrimBuffer[0] = (byte)(value >> 8);
|
||||
m_PrimBuffer[1] = (byte)value;
|
||||
|
||||
private readonly bool[] m_PlaneUsed = new bool[9];
|
||||
private readonly byte[] m_PrimBuffer = new byte[4];
|
||||
Stream.UnderlyingStream.Write(m_PrimBuffer, 0, 2);
|
||||
}
|
||||
|
||||
public DesignStateDetailed(Serial serial, int revision, int xMin, int yMin, int xMax, int yMax, MultiTileEntry[] tiles)
|
||||
: base(0xD8)
|
||||
public void Write(byte value)
|
||||
{
|
||||
Stream.UnderlyingStream.WriteByte(value);
|
||||
}
|
||||
|
||||
public void Write(byte[] buffer, int offset, int size)
|
||||
{
|
||||
Stream.UnderlyingStream.Write(buffer, offset, size);
|
||||
}
|
||||
|
||||
public static void Clear(byte[] buffer, int size)
|
||||
{
|
||||
for (var i = 0; i < size; ++i)
|
||||
{
|
||||
EnsureCapacity(17 + tiles.Length * 5);
|
||||
|
||||
Write((byte)0x03); // Compression Type
|
||||
Write((byte)0x00); // Unknown
|
||||
Write(serial.Value);
|
||||
Write(revision);
|
||||
Write((short)tiles.Length);
|
||||
Write((short)0); // Buffer length : reserved
|
||||
Write((byte)0); // Plane count : reserved
|
||||
|
||||
var totalLength = 1; // includes plane count
|
||||
|
||||
var width = xMax - xMin + 1;
|
||||
var height = yMax - yMin + 1;
|
||||
|
||||
var planeBuffers = new byte[9][];
|
||||
|
||||
for (var i = 0; i < planeBuffers.Length; ++i)
|
||||
{
|
||||
planeBuffers[i] = ArrayPool<byte>.Shared.Rent(0x400);
|
||||
}
|
||||
|
||||
var stairBuffers = new byte[6][];
|
||||
|
||||
for (var i = 0; i < stairBuffers.Length; ++i)
|
||||
{
|
||||
stairBuffers[i] = ArrayPool<byte>.Shared.Rent(MaxItemsPerStairBuffer * 5);
|
||||
}
|
||||
|
||||
Clear(planeBuffers[0], width * height * 2);
|
||||
|
||||
for (var i = 0; i < 4; ++i)
|
||||
{
|
||||
Clear(planeBuffers[1 + i], (width - 1) * (height - 2) * 2);
|
||||
Clear(planeBuffers[5 + i], width * (height - 1) * 2);
|
||||
}
|
||||
|
||||
var totalStairsUsed = 0;
|
||||
|
||||
for (var i = 0; i < tiles.Length; ++i)
|
||||
{
|
||||
var mte = tiles[i];
|
||||
var x = mte.OffsetX - xMin;
|
||||
var y = mte.OffsetY - yMin;
|
||||
int z = mte.OffsetZ;
|
||||
var floor = TileData.ItemTable[mte.ItemId & TileData.MaxItemValue].Height <= 0;
|
||||
int plane, size;
|
||||
|
||||
switch (z)
|
||||
{
|
||||
case 0:
|
||||
plane = 0;
|
||||
break;
|
||||
case 7:
|
||||
plane = 1;
|
||||
break;
|
||||
case 27:
|
||||
plane = 2;
|
||||
break;
|
||||
case 47:
|
||||
plane = 3;
|
||||
break;
|
||||
case 67:
|
||||
plane = 4;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
var stairBufferIndex = totalStairsUsed / MaxItemsPerStairBuffer;
|
||||
var stairBuffer = stairBuffers[stairBufferIndex];
|
||||
|
||||
var byteIndex = totalStairsUsed % MaxItemsPerStairBuffer * 5;
|
||||
|
||||
stairBuffer[byteIndex++] = (byte)(mte.ItemId >> 8);
|
||||
stairBuffer[byteIndex++] = (byte)mte.ItemId;
|
||||
|
||||
stairBuffer[byteIndex++] = (byte)mte.OffsetX;
|
||||
stairBuffer[byteIndex++] = (byte)mte.OffsetY;
|
||||
stairBuffer[byteIndex] = (byte)mte.OffsetZ;
|
||||
|
||||
++totalStairsUsed;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (plane == 0)
|
||||
{
|
||||
size = height;
|
||||
}
|
||||
else if (floor)
|
||||
{
|
||||
size = height - 2;
|
||||
x -= 1;
|
||||
y -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = height - 1;
|
||||
plane += 4;
|
||||
}
|
||||
|
||||
var index = (x * size + y) * 2;
|
||||
|
||||
if (x < 0 || y < 0 || y >= size || index + 1 >= 0x400)
|
||||
{
|
||||
var stairBufferIndex = totalStairsUsed / MaxItemsPerStairBuffer;
|
||||
var stairBuffer = stairBuffers[stairBufferIndex];
|
||||
|
||||
var byteIndex = totalStairsUsed % MaxItemsPerStairBuffer * 5;
|
||||
|
||||
stairBuffer[byteIndex++] = (byte)(mte.ItemId >> 8);
|
||||
stairBuffer[byteIndex++] = (byte)mte.ItemId;
|
||||
|
||||
stairBuffer[byteIndex++] = (byte)mte.OffsetX;
|
||||
stairBuffer[byteIndex++] = (byte)mte.OffsetY;
|
||||
stairBuffer[byteIndex] = (byte)mte.OffsetZ;
|
||||
|
||||
++totalStairsUsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_PlaneUsed[plane] = true;
|
||||
planeBuffers[plane][index] = (byte)(mte.ItemId >> 8);
|
||||
planeBuffers[plane][index + 1] = (byte)mte.ItemId;
|
||||
}
|
||||
}
|
||||
|
||||
var planeCount = 0;
|
||||
|
||||
var deflatedBuffer = ArrayPool<byte>.Shared.Rent(0x2000);
|
||||
|
||||
for (var i = 0; i < planeBuffers.Length; ++i)
|
||||
{
|
||||
if (!m_PlaneUsed[i])
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(planeBuffers[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
++planeCount;
|
||||
|
||||
int size = i switch
|
||||
{
|
||||
0 => width * height * 2,
|
||||
< 5 => (width - 1) * (height - 2) * 2,
|
||||
_ => width * (height - 1) * 2
|
||||
};
|
||||
|
||||
var inflatedBuffer = planeBuffers[i];
|
||||
|
||||
var deflatedLength = Deflate.Standard.Pack(
|
||||
deflatedBuffer,
|
||||
inflatedBuffer.AsSpan(0, size)
|
||||
);
|
||||
|
||||
if (deflatedLength == 0)
|
||||
{
|
||||
Console.WriteLine("Compression error");
|
||||
}
|
||||
|
||||
Write((byte)(0x20 | i));
|
||||
Write((byte)size);
|
||||
Write((byte)deflatedLength);
|
||||
Write((byte)(((size >> 4) & 0xF0) | ((deflatedLength >> 8) & 0xF)));
|
||||
Write(deflatedBuffer, 0, deflatedLength);
|
||||
|
||||
totalLength += 4 + deflatedLength;
|
||||
ArrayPool<byte>.Shared.Return(inflatedBuffer);
|
||||
}
|
||||
|
||||
var totalStairBuffersUsed = (totalStairsUsed + (MaxItemsPerStairBuffer - 1)) / MaxItemsPerStairBuffer;
|
||||
|
||||
for (var i = 0; i < totalStairBuffersUsed; ++i)
|
||||
{
|
||||
++planeCount;
|
||||
|
||||
var count = Math.Min(MaxItemsPerStairBuffer, totalStairsUsed - i * MaxItemsPerStairBuffer);
|
||||
|
||||
var size = count * 5;
|
||||
|
||||
var inflatedBuffer = stairBuffers[i];
|
||||
|
||||
var deflatedLength = Deflate.Standard.Pack(
|
||||
deflatedBuffer,
|
||||
inflatedBuffer.AsSpan(0, size)
|
||||
);
|
||||
|
||||
if (deflatedLength == 0)
|
||||
{
|
||||
Console.WriteLine("Compression error");
|
||||
}
|
||||
|
||||
Write((byte)(9 + i));
|
||||
Write((byte)size);
|
||||
Write((byte)deflatedLength);
|
||||
Write((byte)(((size >> 4) & 0xF0) | ((deflatedLength >> 8) & 0xF)));
|
||||
Write(deflatedBuffer, 0, deflatedLength);
|
||||
|
||||
totalLength += 4 + deflatedLength;
|
||||
}
|
||||
|
||||
for (var i = 0; i < stairBuffers.Length; ++i)
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(stairBuffers[i]);
|
||||
}
|
||||
|
||||
ArrayPool<byte>.Shared.Return(deflatedBuffer);
|
||||
|
||||
Stream.Seek(15, SeekOrigin.Begin);
|
||||
|
||||
Write((short)totalLength); // Buffer length
|
||||
Write((byte)planeCount); // Plane count
|
||||
}
|
||||
|
||||
public void Write(int value)
|
||||
{
|
||||
m_PrimBuffer[0] = (byte)(value >> 24);
|
||||
m_PrimBuffer[1] = (byte)(value >> 16);
|
||||
m_PrimBuffer[2] = (byte)(value >> 8);
|
||||
m_PrimBuffer[3] = (byte)value;
|
||||
|
||||
Stream.UnderlyingStream.Write(m_PrimBuffer, 0, 4);
|
||||
}
|
||||
|
||||
public void Write(uint value)
|
||||
{
|
||||
m_PrimBuffer[0] = (byte)(value >> 24);
|
||||
m_PrimBuffer[1] = (byte)(value >> 16);
|
||||
m_PrimBuffer[2] = (byte)(value >> 8);
|
||||
m_PrimBuffer[3] = (byte)value;
|
||||
|
||||
Stream.UnderlyingStream.Write(m_PrimBuffer, 0, 4);
|
||||
}
|
||||
|
||||
public void Write(short value)
|
||||
{
|
||||
m_PrimBuffer[0] = (byte)(value >> 8);
|
||||
m_PrimBuffer[1] = (byte)value;
|
||||
|
||||
Stream.UnderlyingStream.Write(m_PrimBuffer, 0, 2);
|
||||
}
|
||||
|
||||
public void Write(byte value)
|
||||
{
|
||||
Stream.UnderlyingStream.WriteByte(value);
|
||||
}
|
||||
|
||||
public void Write(byte[] buffer, int offset, int size)
|
||||
{
|
||||
Stream.UnderlyingStream.Write(buffer, offset, size);
|
||||
}
|
||||
|
||||
public static void Clear(byte[] buffer, int size)
|
||||
{
|
||||
for (var i = 0; i < size; ++i)
|
||||
{
|
||||
buffer[i] = 0;
|
||||
}
|
||||
buffer[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ public class ArrowPacketTests
|
|||
[Fact]
|
||||
public void TestCancelArrow()
|
||||
{
|
||||
var expected = new CancelArrow().Compile();
|
||||
var expected = new CancelArrow().Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendCancelArrow(0, 0, Serial.Zero);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendCancelArrow(0, 0, Serial.Zero);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0)]
|
||||
|
|
@ -23,14 +23,14 @@ public class ArrowPacketTests
|
|||
[InlineData(100000, 100000)]
|
||||
public void TestSetArrow(int x, int y)
|
||||
{
|
||||
var expected = new SetArrow(x, y).Compile();
|
||||
var expected = new SetArrow(x, y).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendSetArrow(x, y, Serial.Zero);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendSetArrow(x, y, Serial.Zero);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0)]
|
||||
|
|
@ -38,17 +38,17 @@ public class ArrowPacketTests
|
|||
[InlineData(100000, 100000)]
|
||||
public void TestCancelArrowHS(int x, int y)
|
||||
{
|
||||
Serial serial = (Serial)0x1024;
|
||||
Serial serial = (Serial)0x1024;
|
||||
|
||||
var expected = new CancelArrowHS(x, y, serial).Compile();
|
||||
var expected = new CancelArrowHS(x, y, serial).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.ProtocolChanges = ProtocolChanges.HighSeas;
|
||||
ns.SendCancelArrow(x, y, serial);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.ProtocolChanges = ProtocolChanges.HighSeas;
|
||||
ns.SendCancelArrow(x, y, serial);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0)]
|
||||
|
|
@ -56,15 +56,15 @@ public class ArrowPacketTests
|
|||
[InlineData(100000, 100000)]
|
||||
public void TestSetArrowHS(int x, int y)
|
||||
{
|
||||
Serial serial = (Serial)0x1024;
|
||||
Serial serial = (Serial)0x1024;
|
||||
|
||||
var expected = new SetArrowHS(x, y, serial).Compile();
|
||||
var expected = new SetArrowHS(x, y, serial).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.ProtocolChanges = ProtocolChanges.HighSeas;
|
||||
ns.SendSetArrow(x, y, serial);
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.ProtocolChanges = ProtocolChanges.HighSeas;
|
||||
ns.SendSetArrow(x, y, serial);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,40 +4,40 @@ public sealed class CancelArrow : Packet
|
|||
{
|
||||
public CancelArrow() : base(0xBA, 6)
|
||||
{
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((short)-1);
|
||||
Stream.Write((short)-1);
|
||||
}
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((short)-1);
|
||||
Stream.Write((short)-1);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SetArrow : Packet
|
||||
{
|
||||
public SetArrow(int x, int y) : base(0xBA, 6)
|
||||
{
|
||||
Stream.Write((byte)1);
|
||||
Stream.Write((short)x);
|
||||
Stream.Write((short)y);
|
||||
}
|
||||
Stream.Write((byte)1);
|
||||
Stream.Write((short)x);
|
||||
Stream.Write((short)y);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CancelArrowHS : Packet
|
||||
{
|
||||
public CancelArrowHS(int x, int y, Serial s) : base(0xBA, 10)
|
||||
{
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((short)x);
|
||||
Stream.Write((short)y);
|
||||
Stream.Write(s);
|
||||
}
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((short)x);
|
||||
Stream.Write((short)y);
|
||||
Stream.Write(s);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SetArrowHS : Packet
|
||||
{
|
||||
public SetArrowHS(int x, int y, Serial s) : base(0xBA, 10)
|
||||
{
|
||||
Stream.Write((byte)1);
|
||||
Stream.Write((short)x);
|
||||
Stream.Write((short)y);
|
||||
Stream.Write(s);
|
||||
}
|
||||
}
|
||||
Stream.Write((byte)1);
|
||||
Stream.Write((short)x);
|
||||
Stream.Write((short)y);
|
||||
Stream.Write(s);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,84 +1,83 @@
|
|||
using System;
|
||||
using Server.Engines.BuffIcons;
|
||||
|
||||
namespace Server.Network
|
||||
namespace Server.Network;
|
||||
|
||||
public sealed class AddBuffPacket : Packet
|
||||
{
|
||||
public sealed class AddBuffPacket : Packet
|
||||
{
|
||||
public AddBuffPacket(Serial m, BuffInfo info)
|
||||
: this(
|
||||
m,
|
||||
info.ID,
|
||||
info.TitleCliloc,
|
||||
info.SecondaryCliloc,
|
||||
info.Args,
|
||||
info.Duration
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public AddBuffPacket(
|
||||
Serial mob, BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args,
|
||||
TimeSpan length
|
||||
public AddBuffPacket(Serial m, BuffInfo info)
|
||||
: this(
|
||||
m,
|
||||
info.ID,
|
||||
info.TitleCliloc,
|
||||
info.SecondaryCliloc,
|
||||
info.Args,
|
||||
info.Duration
|
||||
)
|
||||
: base(0xDF)
|
||||
{
|
||||
var hasArgs = args != null;
|
||||
|
||||
EnsureCapacity(hasArgs ? 48 + args.ToString().Length * 2 : 44);
|
||||
Stream.Write(mob);
|
||||
|
||||
Stream.Write((short)iconID); // ID
|
||||
Stream.Write((short)0x1); // Type 0 for removal. 1 for add 2 for Data
|
||||
|
||||
Stream.Fill(4);
|
||||
|
||||
Stream.Write((short)iconID); // ID
|
||||
Stream.Write((short)0x01); // Type 0 for removal. 1 for add 2 for Data
|
||||
|
||||
Stream.Fill(4);
|
||||
|
||||
Stream.Write((short)Math.Max(length.TotalSeconds, 0)); // Time in seconds
|
||||
|
||||
Stream.Fill(3);
|
||||
Stream.Write(titleCliloc);
|
||||
Stream.Write(secondaryCliloc);
|
||||
|
||||
if (!hasArgs)
|
||||
{
|
||||
// m_Stream.Fill( 2 );
|
||||
Stream.Fill(10);
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream.Fill(4);
|
||||
Stream.Write((short)0x1); // Unknown -> Possibly something saying 'hey, I have more data!'?
|
||||
Stream.Fill(2);
|
||||
|
||||
// m_Stream.WriteLittleUniNull( "\t#1018280" );
|
||||
Stream.WriteLittleUniNull($"\t{args}");
|
||||
|
||||
Stream.Write((short)0x1); // Even more Unknown -> Possibly something saying 'hey, I have more data!'?
|
||||
Stream.Fill(2);
|
||||
}
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
public sealed class RemoveBuffPacket : Packet
|
||||
public AddBuffPacket(
|
||||
Serial mob, BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args,
|
||||
TimeSpan length
|
||||
)
|
||||
: base(0xDF)
|
||||
{
|
||||
public RemoveBuffPacket(Serial mob, BuffInfo info) : this(mob, info.ID)
|
||||
var hasArgs = args != null;
|
||||
|
||||
EnsureCapacity(hasArgs ? 48 + args.ToString().Length * 2 : 44);
|
||||
Stream.Write(mob);
|
||||
|
||||
Stream.Write((short)iconID); // ID
|
||||
Stream.Write((short)0x1); // Type 0 for removal. 1 for add 2 for Data
|
||||
|
||||
Stream.Fill(4);
|
||||
|
||||
Stream.Write((short)iconID); // ID
|
||||
Stream.Write((short)0x01); // Type 0 for removal. 1 for add 2 for Data
|
||||
|
||||
Stream.Fill(4);
|
||||
|
||||
Stream.Write((short)Math.Max(length.TotalSeconds, 0)); // Time in seconds
|
||||
|
||||
Stream.Fill(3);
|
||||
Stream.Write(titleCliloc);
|
||||
Stream.Write(secondaryCliloc);
|
||||
|
||||
if (!hasArgs)
|
||||
{
|
||||
// m_Stream.Fill( 2 );
|
||||
Stream.Fill(10);
|
||||
}
|
||||
|
||||
public RemoveBuffPacket(Serial mob, BuffIcon iconID) : base(0xDF)
|
||||
else
|
||||
{
|
||||
EnsureCapacity(13);
|
||||
Stream.Write(mob);
|
||||
|
||||
Stream.Write((short)iconID); // ID
|
||||
Stream.Write((short)0x0); // Type 0 for removal. 1 for add 2 for Data
|
||||
|
||||
Stream.Fill(4);
|
||||
Stream.Write((short)0x1); // Unknown -> Possibly something saying 'hey, I have more data!'?
|
||||
Stream.Fill(2);
|
||||
|
||||
// m_Stream.WriteLittleUniNull( "\t#1018280" );
|
||||
Stream.WriteLittleUniNull($"\t{args}");
|
||||
|
||||
Stream.Write((short)0x1); // Even more Unknown -> Possibly something saying 'hey, I have more data!'?
|
||||
Stream.Fill(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class RemoveBuffPacket : Packet
|
||||
{
|
||||
public RemoveBuffPacket(Serial mob, BuffInfo info) : this(mob, info.ID)
|
||||
{
|
||||
}
|
||||
|
||||
public RemoveBuffPacket(Serial mob, BuffIcon iconID) : base(0xDF)
|
||||
{
|
||||
EnsureCapacity(13);
|
||||
Stream.Write(mob);
|
||||
|
||||
Stream.Write((short)iconID); // ID
|
||||
Stream.Write((short)0x0); // Type 0 for removal. 1 for add 2 for Data
|
||||
|
||||
Stream.Fill(4);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ using Xunit;
|
|||
|
||||
namespace UOContent.Tests;
|
||||
|
||||
public class SkillPacketsTests : IClassFixture<ServerFixture>
|
||||
[Collection("Sequential UOContent Tests")]
|
||||
public class SkillPacketsTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(SkillName.Alchemy, 0, 1)]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue