fix: Fixes flaky tests, formatting, and sequential testing. (#2168)

This commit is contained in:
Kamron Batman 2025-04-30 16:42:38 -07:00 committed by GitHub
parent 415c7a6bfd
commit 7dbfc9d161
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
60 changed files with 1304 additions and 1289 deletions

View file

@ -1,12 +1,13 @@
using System;
using System.Reflection;
using Xunit;
namespace Server.Tests;
internal class ServerFixture : IDisposable
[CollectionDefinition("Sequential Server Tests", DisableParallelization = true)]
public class ServerFixture : ICollectionFixture<ServerFixture>, IDisposable
{
// Global setup
static ServerFixture()
public ServerFixture()
{
Core.ApplicationAssembly = Assembly.GetExecutingAssembly(); // Server.Tests.dll

View file

@ -1,34 +1,33 @@
namespace Server
namespace Server.Tests;
public static class TestMapDefinitions
{
public static class TestMapDefinitions
public static void ConfigureTestMapDefinitions()
{
public static void ConfigureTestMapDefinitions()
{
RegisterMap(0, 0, 0, 7168, 4096, 4, "Felucca", MapRules.FeluccaRules);
RegisterMap(1, 1, 1, 7168, 4096, 0, "Trammel", MapRules.TrammelRules);
RegisterMap(2, 2, 2, 2304, 1600, 1, "Ilshenar", MapRules.TrammelRules);
RegisterMap(3, 3, 3, 2560, 2048, 1, "Malas", MapRules.TrammelRules);
RegisterMap(4, 4, 4, 1448, 1448, 1, "Tokuno", MapRules.TrammelRules);
RegisterMap(5, 5, 5, 1280, 4096, 1, "TerMur", MapRules.TrammelRules);
RegisterMap(0, 0, 0, 7168, 4096, 4, "Felucca", MapRules.FeluccaRules);
RegisterMap(1, 1, 1, 7168, 4096, 0, "Trammel", MapRules.TrammelRules);
RegisterMap(2, 2, 2, 2304, 1600, 1, "Ilshenar", MapRules.TrammelRules);
RegisterMap(3, 3, 3, 2560, 2048, 1, "Malas", MapRules.TrammelRules);
RegisterMap(4, 4, 4, 1448, 1448, 1, "Tokuno", MapRules.TrammelRules);
RegisterMap(5, 5, 5, 1280, 4096, 1, "TerMur", MapRules.TrammelRules);
RegisterMap(0x7F, 0x7F, 0x7F, Map.SectorSize, Map.SectorSize, 1, "Internal", MapRules.Internal);
}
RegisterMap(0x7F, 0x7F, 0x7F, Map.SectorSize, Map.SectorSize, 1, "Internal", MapRules.Internal);
}
private static void RegisterMap(
int mapIndex,
int mapID,
int fileIndex,
int width,
int height,
int season,
string name,
MapRules rules
)
{
var newMap = new Map(mapID, mapIndex, fileIndex, width, height, season, name, rules);
private static void RegisterMap(
int mapIndex,
int mapID,
int fileIndex,
int width,
int height,
int season,
string name,
MapRules rules
)
{
var newMap = new Map(mapID, mapIndex, fileIndex, width, height, season, name, rules);
Map.Maps[mapIndex] = newMap;
Map.AllMaps.Add(newMap);
}
Map.Maps[mapIndex] = newMap;
Map.AllMaps.Add(newMap);
}
}

View file

@ -1,9 +0,0 @@
using Xunit;
namespace Server.Tests
{
[CollectionDefinition("Sequential Tests", DisableParallelization = true)]
public class SequentialTestCollectionDefinition
{
}
}

View file

@ -4,7 +4,7 @@ using Xunit;
namespace Server.Tests.Tests.Buffers;
[Collection("Sequential Tests")]
[Collection("Sequential Server Tests")]
public class STArrayPoolTests
{
[Theory]

View file

@ -3,7 +3,7 @@ using Xunit;
namespace Server.Tests.Buffers;
[Collection("Sequential Tests")]
[Collection("Sequential Server Tests")]
public class ValueStringBuilderTests
{
[Theory]

View file

@ -2,7 +2,7 @@ using Xunit;
namespace Server.Tests.Network;
[Collection("Sequential Tests")]
[Collection("Sequential Server Tests")]
public class ClientVersionTests
{
[Theory]

View file

@ -3,7 +3,8 @@ using Xunit;
namespace Server.Tests;
public sealed class WorldLocationTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public sealed class WorldLocationTests
{
private static Map CreateMap(string name) => new(0, 0, 0, 1, 1, 0, name, MapRules.Internal);

View file

@ -5,7 +5,8 @@ using Xunit;
namespace Server.Tests;
public class ContainerTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public class ContainerTests
{
[Fact]
public void TestFindItemsByType()

View file

@ -2,7 +2,7 @@ using Xunit;
namespace Server.Tests;
[Collection("Sequential Tests")]
[Collection("Sequential Server Tests")]
public class LocalizationEntryTests
{
[Fact]

View file

@ -7,7 +7,8 @@ using Xunit;
namespace Server.Tests.Network;
public class AccountPacketTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public class AccountPacketTests
{
private class MockedAccount : IAccount
{

View file

@ -4,8 +4,8 @@ using Xunit;
namespace Server.Tests.Network
{
[Collection("Sequential Tests")]
public class ContainerPacketTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public class ContainerPacketTests
{
[Fact]

View file

@ -3,7 +3,8 @@ using Xunit;
namespace Server.Tests.Network
{
public class DamagePacketTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public class DamagePacketTests
{
[Theory, InlineData(10), InlineData(-5), InlineData(1024)]
public void TestDamagePacketOld(int inputAmount)

View file

@ -4,7 +4,8 @@ using Xunit;
namespace Server.Tests.Network
{
public class EquipmentPacketTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public class EquipmentPacketTests
{
[Theory]
[InlineData(null, false)]

View file

@ -3,8 +3,8 @@ using Xunit;
namespace Server.Tests.Network;
[Collection("Sequential Tests")]
public class GumpPacketTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public class GumpPacketTests
{
[Theory]
[InlineData(100, 10)]

View file

@ -3,7 +3,8 @@ using Xunit;
namespace Server.Tests.Network
{
public class ItemPacketTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public class ItemPacketTests
{
[Fact]
public void TestWorldItemPacket()

View file

@ -3,7 +3,8 @@ using Xunit;
namespace Server.Tests.Network
{
public class MapPatchesTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public class MapPatchesTests
{
[Fact]
public void TestMapPatches()

View file

@ -27,8 +27,8 @@ namespace Server.Tests.Network
}
}
[Collection("Sequential Tests")]
public class MenuPacketTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public class MenuPacketTests
{
[Fact]
public void TestDisplayItemListMenu()

View file

@ -3,8 +3,8 @@ using Xunit;
namespace Server.Tests.Network;
[Collection("Sequential Tests")]
public class MobilePacketTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public class MobilePacketTests
{
[Fact]
public void TestDeathAnimation()

View file

@ -3,7 +3,8 @@ using Xunit;
namespace Server.Tests.Network
{
public class MovementPacketTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public class MovementPacketTests
{
[Theory]
[InlineData(0)]

View file

@ -5,8 +5,8 @@ using Xunit;
namespace Server.Tests.Network
{
[Collection("Sequential Tests")]
public class PlayerPacketTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public class PlayerPacketTests
{
[Theory]
[InlineData(StatLockType.Down, StatLockType.Up, StatLockType.Locked)]

View file

@ -4,7 +4,8 @@ using Xunit;
namespace Server.Tests.Network
{
public class SecureTradePacketTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public class SecureTradePacketTests
{
[Theory]
[InlineData("short-name")]

View file

@ -5,8 +5,8 @@ using Xunit;
namespace Server.Tests.Network
{
[Collection("Sequential Tests")]
public class VendorBuyPacketTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public class VendorBuyPacketTests
{
[Theory]
[InlineData(ProtocolChanges.None)]

View file

@ -5,8 +5,8 @@ using Xunit;
namespace Server.Tests.Network
{
[Collection("Sequential Tests")]
public class VendorSellPacketTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public class VendorSellPacketTests
{
[Fact]
public void TestVendorSellList()

View file

@ -2,40 +2,40 @@ using Server.Network;
using Server.Tests.Network;
using Xunit;
namespace Server.Tests
namespace Server.Tests;
[Collection("Sequential Server Tests")]
public class VirtualHairPacketTests
{
public class VirtualHairPacketTests: IClassFixture<ServerFixture>
[Fact]
public void TestSendVirtualHairUpdate()
{
[Fact]
public void TestSendVirtualHairUpdate()
{
var m = new Mobile((Serial)0x1024u);
m.DefaultMobileInit();
m.HairHue = 0x1000;
m.HairItemID = 0x2000;
var m = new Mobile((Serial)0x1024u);
m.DefaultMobileInit();
m.HairHue = 0x1000;
m.HairItemID = 0x2000;
var expected = new HairEquipUpdate(m).Compile();
var expected = new HairEquipUpdate(m).Compile();
var ns = PacketTestUtilities.CreateTestNetState();
ns.SendHairEquipUpdatePacket(m, (uint)m.Hair.VirtualSerial, m.Hair.ItemId, m.Hair.Hue, Layer.Hair);
var ns = PacketTestUtilities.CreateTestNetState();
ns.SendHairEquipUpdatePacket(m, (uint)m.Hair.VirtualSerial, m.Hair.ItemId, m.Hair.Hue, Layer.Hair);
var result = ns.SendPipe.Reader.AvailableToRead();
AssertThat.Equal(result, expected);
}
var result = ns.SendPipe.Reader.AvailableToRead();
AssertThat.Equal(result, expected);
}
[Fact]
public void TestSendRemoveVirtualHair()
{
var m = new Mobile((Serial)0x1024u);
m.DefaultMobileInit();
[Fact]
public void TestSendRemoveVirtualHair()
{
var m = new Mobile((Serial)0x1024u);
m.DefaultMobileInit();
var expected = new RemoveHair(m).Compile();
var expected = new RemoveHair(m).Compile();
var ns = PacketTestUtilities.CreateTestNetState();
ns.SendRemoveHairPacket((uint) m.Hair.VirtualSerial);
var ns = PacketTestUtilities.CreateTestNetState();
ns.SendRemoveHairPacket((uint) m.Hair.VirtualSerial);
var result = ns.SendPipe.Reader.AvailableToRead();
AssertThat.Equal(result, expected);
}
var result = ns.SendPipe.Reader.AvailableToRead();
AssertThat.Equal(result, expected);
}
}

View file

@ -8,7 +8,8 @@ using Xunit;
namespace Server.Tests;
public class TypeConverterTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public class TypeConverterTests
{
[Fact]
public void TestReadAfterWrite()

View file

@ -3,8 +3,8 @@ using Xunit;
namespace Server.Tests;
[Collection("Sequential Tests")]
public class TimerTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public class TimerTests
{
[Theory]
[InlineData(0L, 8L)]

View file

@ -4,7 +4,7 @@ using Xunit;
namespace Server.Tests;
[Collection("Sequential Tests")]
[Collection("Sequential Server Tests")]
public class TestStringHelpers
{
[Theory]

View file

@ -2,8 +2,8 @@ using Xunit;
namespace Server.Tests;
[Collection("Sequential Tests")]
public class VirtualSerialTests : IClassFixture<ServerFixture>
[Collection("Sequential Server Tests")]
public class VirtualSerialTests
{
[Fact]
public void TestNewVirtualGetsAndRollover()

View file

@ -1,13 +1,14 @@
using System;
using System.Reflection;
using Server.Misc;
using Xunit;
namespace Server.Tests;
internal class ServerFixture : IDisposable
[CollectionDefinition("Sequential UOContent Tests", DisableParallelization = true)]
public class UOContentFixture : ICollectionFixture<UOContentFixture>, IDisposable
{
// Global setup
static ServerFixture()
public UOContentFixture()
{
Core.ApplicationAssembly = Assembly.GetExecutingAssembly();
Core.LoopContext = new EventLoopContext();
@ -40,8 +41,16 @@ internal class ServerFixture : IDisposable
World.ExitSerializationThreads();
}
private static int _counter;
public void Dispose()
{
_counter++;
if (_counter > 1)
{
throw new Exception("NO!");
}
Timer.Init(0);
}
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}

View file

@ -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();
}
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}

View file

@ -7,7 +7,7 @@ using Xunit;
namespace Server.Tests.Gumps;
[Collection("Sequential Tests")]
[Collection("Sequential UOContent Tests")]
public class TestLayoutGumps
{
[Fact]

View file

@ -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);
}
}
}

View file

@ -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
}
}

View file

@ -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)
{
}
}
}
}

View file

@ -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;
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}

View file

@ -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)
{
}
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}

View file

@ -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)]

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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)]

View file

@ -10,7 +10,8 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<ProjectReference Include="..\Application\Application.csproj" />
<ProjectReference Include="..\Server\Server.csproj" />
<ProjectReference Include="..\UOContent\UOContent.csproj" />
<ProjectReference Include="..\Server.Tests\Server.Tests.csproj" />
<DataFiles Include="$(SolutionDir)\Distribution\Data\**" />
</ItemGroup>