Adds more packet tests (#166)

This commit is contained in:
Kamron Batman 2020-07-03 19:03:10 -07:00 committed by GitHub
parent ee06eb4407
commit e17195ca80
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 1203 additions and 277 deletions

View file

@ -0,0 +1,40 @@
using System;
using System.IO.Compression;
using System.Text;
namespace Server.Tests.Network.Packets
{
public class GumpUtilities
{
public static readonly byte[] NoMoveBuffer = Encoding.ASCII.GetBytes("{ nomove }");
public static readonly byte[] NoCloseBuffer = Encoding.ASCII.GetBytes("{ noclose }");
public static readonly byte[] NoDisposeBuffer = Encoding.ASCII.GetBytes("{ nodispose }");
public static readonly byte[] NoResizeBuffer = Encoding.ASCII.GetBytes("{ noresize }");
public const string NoMove = "{ nomove }";
public const string NoClose = "{ noclose }";
public const string NoDispose = "{ nodispose }";
public const string NoResize = "{ noresize }";
public static int WritePacked(ReadOnlySpan<byte> source, Span<byte> dest)
{
int length = source.Length;
if (length == 0)
{
dest.Slice(0, 4).Clear();
return 4;
}
ulong packLength = (ulong)dest.Length - 8;
ZlibError ce = Zlib.Pack(dest.Slice(8), ref packLength, source, ZlibQuality.Default);
if (ce != ZlibError.Okay) Console.WriteLine("ZLib error: {0} (#{1})", ce, (int)ce);
((int)(4 + packLength)).CopyTo(dest.Slice(0, 4));
length.CopyTo(dest.Slice(4, 4));
return (int)(8 + packLength);
}
}
}

View file

@ -114,10 +114,10 @@ namespace Server.Tests.Network.Packets
Span<byte> expectedData = stackalloc byte[5 + account.Length * 60];
int pos = 0;
expectedData[pos++] = 0x81; // Packet ID
((byte)0x81).CopyTo(ref pos, expectedData); // Packet ID
((ushort)expectedData.Length).CopyTo(ref pos, expectedData); // Length
expectedData[pos++] = 1; // Count of non-null characters
expectedData[pos++] = 0;
((byte)1).CopyTo(ref pos, expectedData); // Count of non-null characters
((byte)0).CopyTo(ref pos, expectedData);
for (var i = 0; i < account.Length; ++i)
{
@ -183,13 +183,19 @@ namespace Server.Tests.Network.Packets
[InlineData(ProtocolChanges.Version6000)]
public void TestSupportedFeatures(ProtocolChanges protocolChanges)
{
var firstMobile = new Mobile(0x1);
firstMobile.DefaultMobileInit();
firstMobile.Name = "Test Mobile";
var account = new TestAccount(new[] {firstMobile, null, null, null, null});
NetState ns = new NetState(new TestConnectionContext
{
RemoteEndPoint = IPEndPoint.Parse("127.0.0.1")
});
ns.ProtocolChanges = protocolChanges;
ns.Account = new TestAccount(new Mobile[0]);
})
{
Account = account
};
Span<byte> data = new SupportedFeatures(ns).Compile();
@ -257,7 +263,7 @@ namespace Server.Tests.Network.Packets
((ushort)m.X).CopyTo(ref pos, expectedData);
((ushort)m.Y).CopyTo(ref pos, expectedData);
((ushort)m.Z).CopyTo(ref pos, expectedData);
expectedData[pos++] = (byte)m.Direction;
((byte)m.Direction).CopyTo(ref pos, expectedData);
pos += 9;
var map = m.Map;
@ -297,7 +303,7 @@ namespace Server.Tests.Network.Packets
Span<byte> expectedData = stackalloc byte[4 + account.Length * 60];
int pos = 0;
expectedData[pos++] = 0x86; // Packet ID
((byte)0x86).CopyTo(ref pos, expectedData); // Packet ID
((ushort)expectedData.Length).CopyTo(ref pos, expectedData); // Length
int highSlot = -1;
@ -309,7 +315,7 @@ namespace Server.Tests.Network.Packets
}
int count = Math.Max(Math.Max(highSlot + 1, account.Limit), 5);
expectedData[pos++] = (byte)count;
((byte)count).CopyTo(ref pos, expectedData);
for (int i = 0; i < count; i++)
{
@ -346,7 +352,7 @@ namespace Server.Tests.Network.Packets
Span<byte> expectedData = stackalloc byte[11 + account.Length * 60 + info.Length * 89];
int pos = 0;
expectedData[pos++] = 0xA9; // Packet ID
((byte)0xA9).CopyTo(ref pos, expectedData); // Packet ID
((ushort)expectedData.Length).CopyTo(ref pos, expectedData); // Length
int highSlot = -1;
@ -358,7 +364,7 @@ namespace Server.Tests.Network.Packets
}
int count = Math.Max(Math.Max(highSlot + 1, account.Limit), 5);
expectedData[pos++] = (byte)count;
((byte)count).CopyTo(ref pos, expectedData);
for (int i = 0; i < count; i++)
{
@ -374,12 +380,12 @@ namespace Server.Tests.Network.Packets
}
}
expectedData[pos++] = (byte)info.Length;
((byte)info.Length).CopyTo(ref pos, expectedData);
for (int i = 0; i < info.Length; i++)
{
var ci = info[i];
expectedData[pos++] = (byte)i;
((byte)i).CopyTo(ref pos, expectedData);
ci.City.CopyASCIIFixedTo(ref pos, 32, expectedData);
ci.Building.CopyASCIIFixedTo(ref pos, 32, expectedData);
ci.X.CopyTo(ref pos, expectedData);
@ -424,7 +430,7 @@ namespace Server.Tests.Network.Packets
Span<byte> expectedData = stackalloc byte[9 + account.Length * 60 + info.Length * 63];
int pos = 0;
expectedData[pos++] = 0xA9; // Packet ID
((byte)0xA9).CopyTo(ref pos, expectedData); // Packet ID
((ushort)expectedData.Length).CopyTo(ref pos, expectedData); // Length
int highSlot = -1;
@ -436,7 +442,7 @@ namespace Server.Tests.Network.Packets
}
int count = Math.Max(Math.Max(highSlot + 1, account.Limit), 5);
expectedData[pos++] = (byte)count;
((byte)count).CopyTo(ref pos, expectedData);
for (int i = 0; i < count; i++)
{
@ -452,12 +458,12 @@ namespace Server.Tests.Network.Packets
}
}
expectedData[pos++] = (byte)info.Length;
((byte)info.Length).CopyTo(ref pos, expectedData);
for (int i = 0; i < info.Length; i++)
{
var ci = info[i];
expectedData[pos++] = (byte)i;
((byte)i).CopyTo(ref pos, expectedData);
ci.City.CopyASCIIFixedTo(ref pos, 31, expectedData);
ci.Building.CopyASCIIFixedTo(ref pos, 31, expectedData);
}
@ -505,9 +511,9 @@ namespace Server.Tests.Network.Packets
Span<byte> expectedData = stackalloc byte[6 + info.Length * 40];
int pos = 0;
expectedData[pos++] = 0xA8; // Packet ID
((byte)0xA8).CopyTo(ref pos, expectedData); // Packet ID
((ushort)expectedData.Length).CopyTo(ref pos, expectedData);
expectedData[pos++] = 0x5D; // Unknown
((byte)0x5D).CopyTo(ref pos, expectedData); // Unknown
((ushort)info.Length).CopyTo(ref pos, expectedData);
for (int i = 0; i < info.Length; i++)
@ -515,8 +521,8 @@ namespace Server.Tests.Network.Packets
var si = info[i];
((ushort)i).CopyTo(ref pos, expectedData);
si.Name.CopyASCIIFixedTo(ref pos, 32, expectedData);
expectedData[pos++] = (byte)si.FullPercent;
expectedData[pos++] = (byte)si.TimeZone;
((byte)si.FullPercent).CopyTo(ref pos, expectedData);
((byte)si.TimeZone).CopyTo(ref pos, expectedData);
Utility.GetAddressValue(si.Address.Address).CopyTo(ref pos, expectedData);
}

View file

@ -0,0 +1,178 @@
using System;
using Server.Network;
using Xunit;
namespace Server.Tests.Network.Packets
{
public class EffectPackets
{
[Fact]
public void TestParticleEffect()
{
EffectType effectType = EffectType.Moving;
Serial serial = 0x4000;
Serial from = 0x1000;
Serial to = 0x2000;
var itemId = 0x100;
Point3D fromPoint = new Point3D(1000, 100, -10);
Point3D toPoint = new Point3D(1500, 500, 0);
byte speed = 3;
byte duration = 2;
bool direction = false;
bool explode = false;
int hue = 0x1024;
int renderMode = 1;
ushort effect = 3;
ushort explodeEffect = 0;
ushort explodeSound = 0;
byte layer = 9;
ushort unknown = 0;
Span<byte> data = new ParticleEffect(
effectType, from, to, itemId,
fromPoint, toPoint, speed, duration,
direction, explode, hue, renderMode,
effect, explodeEffect, explodeSound, serial,
layer, unknown
).Compile();
Span<byte> expectedData = stackalloc byte[49];
int pos = 0;
((byte)0xC7).CopyTo(ref pos, expectedData); // Packet ID
((byte)effectType).CopyTo(ref pos, expectedData);
from.CopyTo(ref pos, expectedData);
to.CopyTo(ref pos, expectedData);
((ushort)itemId).CopyTo(ref pos, expectedData);
((ushort)fromPoint.X).CopyTo(ref pos, expectedData);
((ushort)fromPoint.Y).CopyTo(ref pos, expectedData);
((byte)fromPoint.Z).CopyTo(ref pos, expectedData);
((ushort)toPoint.X).CopyTo(ref pos, expectedData);
((ushort)toPoint.Y).CopyTo(ref pos, expectedData);
((byte)toPoint.Z).CopyTo(ref pos, expectedData);
speed.CopyTo(ref pos, expectedData);
duration.CopyTo(ref pos, expectedData);
expectedData.Clear(ref pos, 2);
direction.CopyTo(ref pos, expectedData);
explode.CopyTo(ref pos, expectedData);
hue.CopyTo(ref pos, expectedData);
renderMode.CopyTo(ref pos, expectedData);
effect.CopyTo(ref pos, expectedData);
explodeEffect.CopyTo(ref pos, expectedData);
explodeSound.CopyTo(ref pos, expectedData);
serial.CopyTo(ref pos, expectedData);
layer.CopyTo(ref pos, expectedData);
unknown.CopyTo(ref pos, expectedData);
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestHuedEffect()
{
EffectType effectType = EffectType.Moving;
Serial serial = 0x4000;
Serial from = 0x1000;
Serial to = 0x2000;
var itemId = 0x100;
Point3D fromPoint = new Point3D(1000, 100, -10);
Point3D toPoint = new Point3D(1500, 500, 0);
byte speed = 3;
byte duration = 2;
bool direction = false;
bool explode = false;
int hue = 0x1024;
int renderMode = 1;
Span<byte> data = new HuedEffect(
effectType, from, to, itemId,
fromPoint, toPoint, speed, duration,
direction, explode, hue, renderMode
).Compile();
Span<byte> expectedData = stackalloc byte[36];
int pos = 0;
((byte)0xC0).CopyTo(ref pos, expectedData); // Packet ID
((byte)effectType).CopyTo(ref pos, expectedData);
from.CopyTo(ref pos, expectedData);
to.CopyTo(ref pos, expectedData);
((ushort)itemId).CopyTo(ref pos, expectedData);
((ushort)fromPoint.X).CopyTo(ref pos, expectedData);
((ushort)fromPoint.Y).CopyTo(ref pos, expectedData);
((byte)fromPoint.Z).CopyTo(ref pos, expectedData);
((ushort)toPoint.X).CopyTo(ref pos, expectedData);
((ushort)toPoint.Y).CopyTo(ref pos, expectedData);
((byte)toPoint.Z).CopyTo(ref pos, expectedData);
speed.CopyTo(ref pos, expectedData);
duration.CopyTo(ref pos, expectedData);
expectedData.Clear(ref pos, 2);
direction.CopyTo(ref pos, expectedData);
explode.CopyTo(ref pos, expectedData);
hue.CopyTo(ref pos, expectedData);
renderMode.CopyTo(ref pos, expectedData);
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestScreenEffect()
{
var type = ScreenEffectType.FadeOut;
Span<byte> data = new ScreenEffect(type).Compile();
Span<byte> expectedData = stackalloc byte[28]
{
0x70, // Packet ID
0x04,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, // Screen Effect Type
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
((ushort)type).CopyTo(expectedData.Slice(10, 2));
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestBoltEffect()
{
IEntity entity = new Entity(0x1000, new Point3D(1000, 100, -10), Map.Felucca);
var hue = 0x1024;
Span<byte> data = new BoltEffect(entity, hue).Compile();
Span<byte> expectedData = stackalloc byte[36]
{
0xC0, // Packet ID
0x01, // Effect
0x00, 0x00, 0x00, 0x00, // From Serial
0x00, 0x00, 0x00, 0x00, // To Serial
0x00, 0x00, // Item ID
0x00, 0x00, 0x00, 0x00, 0x00, // From Point
0x00, 0x00, 0x00, 0x00, 0x00, // To Point
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, // Hue
0x00, 0x00, 0x00, 0x00
};
int pos = 2;
entity.Serial.CopyTo(ref pos, expectedData);
pos += 6;
((ushort)entity.X).CopyTo(ref pos, expectedData);
((ushort)entity.Y).CopyTo(ref pos, expectedData);
((byte)entity.Z).CopyTo(ref pos, expectedData);
((ushort)entity.X).CopyTo(ref pos, expectedData);
((ushort)entity.Y).CopyTo(ref pos, expectedData);
((byte)entity.Z).CopyTo(ref pos, expectedData);
pos += 6;
hue.CopyTo(ref pos, expectedData);
AssertThat.Equal(data, expectedData);
}
}
}

View file

@ -37,7 +37,7 @@ namespace Server.Tests.Network.Packets
int pos = 0;
expectedData[pos++] = 0xBF; // Packet ID
((byte)0xBF).CopyTo(ref pos, expectedData); // Packet ID
((ushort)length).CopyTo(ref pos, expectedData); // Length
((ushort)0x10).CopyTo(ref pos, expectedData); // Subcommand
item.Serial.CopyTo(ref pos, expectedData);
@ -46,7 +46,6 @@ namespace Server.Tests.Network.Packets
{
var name = info.Crafter.Name ?? "";
(-3).CopyTo(ref pos, expectedData);
((ushort)name.Length).CopyTo(ref pos, expectedData);
name.CopyASCIITo(ref pos, expectedData);
}

View file

@ -0,0 +1,244 @@
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Server.Gumps;
using Server.Network;
using Xunit;
namespace Server.Tests.Network.Packets
{
public class GumpPacketTests
{
[Fact]
public void TestCloseGump()
{
var typeId = 100;
var buttonId = 10;
Span<byte> data = new CloseGump(typeId, buttonId).Compile();
Span<byte> expectedData = stackalloc byte[]
{
0xBF, // Packet ID
0x00, 0xD, // Length
0x00, 0x04, // Close
0x00, 0x00, 0x00, 0x00, // Type Id
0x00, 0x00, 0x00, 0x00, // Button Id
};
typeId.CopyTo(expectedData.Slice(5, 4));
buttonId.CopyTo(expectedData.Slice(9, 4));
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestDisplaySignGump()
{
Serial gumpSerial = 0x1000;
var gumpId = 100;
var unknownString = "This is an unknown string";
var caption = "This is a caption";
Span<byte> data = new DisplaySignGump(gumpSerial, gumpId, unknownString, caption).Compile();
Span<byte> expectedData = stackalloc byte[15 + unknownString.Length + caption.Length];
int pos = 0;
((byte)0x8B).CopyTo(ref pos, expectedData);
((ushort)expectedData.Length).CopyTo(ref pos, expectedData);
gumpSerial.CopyTo(ref pos, expectedData);
((ushort)gumpId).CopyTo(ref pos, expectedData);
unknownString.CopyASCIINullTo(ref pos, expectedData);
caption.CopyASCIINullTo(ref pos, expectedData);
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestFastGumpPacket()
{
NetState ns = new NetState(new AccountPacketTests.TestConnectionContext
{
RemoteEndPoint = IPEndPoint.Parse("127.0.0.1"),
});
var gump = new ResurrectGump(2);
Span<byte> data = gump.Compile(ns).Compile();
Span<byte> expectedData = stackalloc byte[0x1000];
int pos = 0;
expectedData[pos++] = 0xB0; // Packet ID
pos += 2; // Length
gump.Serial.CopyTo(ref pos, expectedData);
gump.TypeID.CopyTo(ref pos, expectedData);
gump.X.CopyTo(ref pos, expectedData);
gump.Y.CopyTo(ref pos, expectedData);
pos += 2; // Layout Length
int layoutLength = 0;
if (!gump.Draggable)
{
GumpUtilities.NoMoveBuffer.CopyTo(ref pos, expectedData);
layoutLength += GumpUtilities.NoMove.Length;
}
if (!gump.Closable)
{
GumpUtilities.NoCloseBuffer.CopyTo(ref pos, expectedData);
layoutLength += GumpUtilities.NoClose.Length;
}
if (!gump.Disposable)
{
GumpUtilities.NoDisposeBuffer.CopyTo(ref pos, expectedData);
layoutLength += GumpUtilities.NoDispose.Length;
}
if (!gump.Resizable)
{
GumpUtilities.NoResizeBuffer.CopyTo(ref pos, expectedData);
layoutLength += GumpUtilities.NoResize.Length;
}
foreach (var entry in gump.Entries)
{
var str = entry.Compile(ns);
str.CopyRawASCIITo(ref pos, expectedData);
layoutLength += str.Length; // ASCII so 1:1
}
((ushort)layoutLength).CopyTo(expectedData.Slice(19, 2));
((ushort)gump.Strings.Count).CopyTo(ref pos, expectedData);
for (var i = 0; i < gump.Strings.Count; ++i)
(gump.Strings[i] ?? "").CopyUnicodeBigEndianTo(ref pos, expectedData);
((ushort)pos).CopyTo(expectedData.Slice(1, 2));
expectedData = expectedData.Slice(0, pos);
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestPackedGumpPacket()
{
NetState ns = new NetState(new AccountPacketTests.TestConnectionContext
{
RemoteEndPoint = IPEndPoint.Parse("127.0.0.1"),
});
ns.ProtocolChanges = ProtocolChanges.Unpack;
var gump = new ResurrectGump(2);
Span<byte> data = gump.Compile(ns).Compile();
Span<byte> expectedData = stackalloc byte[0x1000];
int pos = 0;
expectedData[pos++] = 0xDD; // Packet ID
pos += 2; // Length
gump.Serial.CopyTo(ref pos, expectedData);
gump.TypeID.CopyTo(ref pos, expectedData);
gump.X.CopyTo(ref pos, expectedData);
gump.Y.CopyTo(ref pos, expectedData);
var layoutList = new List<string>();
int bufferLength = 1; // Null terminated
if (!gump.Draggable)
{
layoutList.Add(GumpUtilities.NoMove);
bufferLength += GumpUtilities.NoMove.Length;
}
if (!gump.Closable)
{
layoutList.Add(GumpUtilities.NoClose);
bufferLength += GumpUtilities.NoClose.Length;
}
if (!gump.Disposable)
{
layoutList.Add(GumpUtilities.NoDispose);
bufferLength += GumpUtilities.NoDispose.Length;
}
if (!gump.Resizable)
{
layoutList.Add(GumpUtilities.NoResize);
bufferLength += GumpUtilities.NoResize.Length;
}
foreach (var entry in gump.Entries)
{
var str = entry.Compile(ns);
bufferLength += str.Length;
layoutList.Add(str);
}
IMemoryOwner<byte> memOwner = SlabMemoryPool.Shared.Rent(bufferLength);
Span<byte> buffer = memOwner.Memory.Span;
int bufferPos = 0;
foreach (var layout in layoutList)
layout.CopyRawASCIITo(ref bufferPos, buffer);
pos += GumpUtilities.WritePacked(buffer.Slice(0, bufferPos + 1), expectedData.Slice(pos));
memOwner.Dispose();
gump.Strings.Count.CopyTo(ref pos, expectedData);
bufferLength = gump.Strings.Sum(str => 2 + str.Length * 2);
memOwner = SlabMemoryPool.Shared.Rent(bufferLength);
buffer = memOwner.Memory.Span;
bufferPos = 0;
foreach (var str in gump.Strings)
str.CopyUnicodeBigEndianTo(ref bufferPos, buffer);
pos += GumpUtilities.WritePacked(buffer.Slice(0, bufferPos), expectedData.Slice(pos));
// Length
((ushort)pos).CopyTo(expectedData.Slice(1, 2));
expectedData = expectedData.Slice(0, pos);
AssertThat.Equal(data, expectedData);
}
}
public class ResurrectGump : Gump
{
public ResurrectGump(int msg) : base(100, 0)
{
AddPage(0);
AddBackground(0, 0, 400, 350, 2600);
AddHtmlLocalized(0, 20, 400, 35, 1011022); // <center>Resurrection</center>
/* It is possible for you to be resurrected here by this healer. Do you wish to try?<br>
* CONTINUE - You chose to try to come back to life now.<br>
* CANCEL - You prefer to remain a ghost for now.
*/
AddHtmlLocalized(50, 55, 300, 140, 1011023 + msg, true, true);
AddButton(200, 227, 4005, 4007, 0);
AddHtmlLocalized(235, 230, 110, 35, 1011012); // CANCEL
AddButton(65, 227, 4005, 4007, 1);
AddHtmlLocalized(100, 230, 110, 35, 1011011); // CONTINUE
}
}
}

View file

@ -0,0 +1,388 @@
using System;
using Server.Items;
using Server.Network;
using Xunit;
namespace Server.Tests.Network.Packets
{
public class ItemPacketTests
{
[Fact]
public void TestWorldItemPacket()
{
Serial serial = 0x1000;
var itemId = 1;
// Move to fixture
TileData.ItemTable[itemId] = new ItemData(
"Test Item Data", TileFlag.Generic, 1, 1, 1, 1, 1
);
Item item = new Item(serial)
{
ItemID = itemId,
Hue = 0x1024,
Amount = 10,
Location = new Point3D(1000, 100, -10),
Direction = Direction.Left
};
Span<byte> data = new WorldItem(item).Compile();
Span<byte> expectedData = stackalloc byte[20]; // Max size
int pos = 0;
((byte)0x1A).CopyTo(ref pos, expectedData);
pos += 2; // Length
if (item.Amount != 0)
(serial | 0x80000000).CopyTo(ref pos, expectedData);
else
(serial & 0x7FFFFFFF).CopyTo(ref pos, expectedData);
if (item is BaseMulti)
((ushort)(item.ItemID | 0x4000)).CopyTo(ref pos, expectedData);
else
((ushort)item.ItemID).CopyTo(ref pos, expectedData);
if (item.Amount != 0)
((ushort)item.Amount).CopyTo(ref pos, expectedData);
byte direction = (byte)item.Direction;
ushort x = (ushort)(item.X & 0x7FFF);
if (direction != 0)
x |= 0x8000;
x.CopyTo(ref pos, expectedData);
int hue = item.Hue;
int flags = item.GetPacketFlags();
ushort y = (ushort)(item.Y & 0x3FFF);
if (hue != 0) y |= 0x8000;
if (flags != 0) y |= 0x4000;
y.CopyTo(ref pos, expectedData);
if (direction != 0)
direction.CopyTo(ref pos, expectedData);
((byte)item.Z).CopyTo(ref pos, expectedData);
if (hue != 0)
((ushort)hue).CopyTo(ref pos, expectedData);
if (flags != 0)
((byte)flags).CopyTo(ref pos, expectedData);
// Length
((ushort)pos).CopyTo(expectedData.Slice(1, 2));
// Slice the data to match in size
data = data.Slice(0, pos);
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestWorldItemSAPacket()
{
Serial serial = 0x1000;
ushort itemId = 1;
// Move to fixture
TileData.ItemTable[itemId] = new ItemData(
"Test Item Data", TileFlag.Generic, 1, 1, 1, 1, 1
);
Item item = new Item(serial)
{
ItemID = itemId,
Hue = 0x1024,
Amount = 10,
Location = new Point3D(1000, 100, -10)
};
var loc = item.Location;
var isMulti = item is BaseMulti;
Span<byte> data = new WorldItemSA(item).Compile();
Span<byte> expectedData = stackalloc byte[]
{
0xF3, // Packet ID
0x00, 0x01,
(byte)(isMulti ? 0x02 : 0x00), // Item Type (Regular, or Multi)
0x00, 0x00, 0x00, 0x00, // Serial
0x00, 0x00, // Item ID
0x00,
0x00, 0x00, // Amount (min?)
0x00, 0x00, // Amount (max?)
0x00, 0x00, // X
0x00, 0x00, // Y
(byte)loc.Z, // Z
(byte)item.Light, // Light
0x00, 0x00, // Hue
(byte)item.GetPacketFlags() // Flags
};
serial.CopyTo(expectedData.Slice(4, 4));
((ushort)(itemId & (isMulti ? 0x3FFF : 0xFFFF))).CopyTo(expectedData.Slice(8, 2));
ushort amount = (ushort)item.Amount;
amount.CopyTo(expectedData.Slice(11, 2));
amount.CopyTo(expectedData.Slice(13, 2));
((ushort)loc.X).CopyTo(expectedData.Slice(15, 2));
((ushort)loc.Y).CopyTo(expectedData.Slice(17, 2));
((ushort)item.Hue).CopyTo(expectedData.Slice(21, 2));
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestWorldItemHSPacket()
{
Serial serial = 0x1000;
var itemId = 1;
// Move to fixture
TileData.ItemTable[itemId] = new ItemData(
"Test Item Data", TileFlag.Generic, 1, 1, 1, 1, 1
);
Item item = new Item(serial)
{
ItemID = itemId,
Hue = 0x1024,
Amount = 10,
Location = new Point3D(1000, 100, -10)
};
var loc = item.Location;
var isMulti = item is BaseMulti;
Span<byte> data = new WorldItemHS(item).Compile();
Span<byte> expectedData = stackalloc byte[]
{
0xF3, // Packet ID
0x00, 0x01,
(byte)(isMulti ? 0x02 : 0x00), // Item Type (Regular, or Multi)
0x00, 0x00, 0x00, 0x00, // Serial
0x00, 0x00, // Item ID
0x00,
0x00, 0x00, // Amount (min?)
0x00, 0x00, // Amount (max?)
0x00, 0x00, // X
0x00, 0x00, // Y
(byte)loc.Z, // Z
(byte)item.Light, // Light
0x00, 0x00, // Hue
(byte)item.GetPacketFlags(), // Flags
00, 00 // ???
};
serial.CopyTo(expectedData.Slice(4, 4));
((ushort)(itemId & (isMulti ? 0x3FFF : 0xFFFF))).CopyTo(expectedData.Slice(8, 2));
ushort amount = (ushort)item.Amount;
amount.CopyTo(expectedData.Slice(11, 2));
amount.CopyTo(expectedData.Slice(13, 2));
((ushort)loc.X).CopyTo(expectedData.Slice(15, 2));
((ushort)loc.Y).CopyTo(expectedData.Slice(17, 2));
((ushort)item.Hue).CopyTo(expectedData.Slice(21, 2));
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestContainerDisplay()
{
Serial serial = 0x1000;
ushort gumpId = 100;
Span<byte> data = new ContainerDisplay(serial, gumpId).Compile();
Span<byte> expectedData = stackalloc byte[]
{
0x24, // Packet ID
0x00, 0x00, 0x00, 0x00, // Serial
0x00, 0x00 // Gump ID
};
serial.CopyTo(expectedData.Slice(1, 4));
gumpId.CopyTo(expectedData.Slice(5, 2));
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestContainerDisplayHS()
{
Serial serial = 0x1000;
ushort gumpId = 100;
Span<byte> data = new ContainerDisplayHS(serial, gumpId).Compile();
Span<byte> expectedData = stackalloc byte[]
{
0x24, // Packet ID
0x00, 0x00, 0x00, 0x00, // Serial
0x00, 0x00, // Gump ID
0x00, 0x7D // Max Items?
};
serial.CopyTo(expectedData.Slice(1, 4));
gumpId.CopyTo(expectedData.Slice(5, 2));
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestDisplaySpellbook()
{
Serial serial = 0x1000;
Span<byte> data = new DisplaySpellbook(serial).Compile();
Span<byte> expectedData = stackalloc byte[]
{
0x24, // Packet ID
0x00, 0x00, 0x00, 0x00, // Serial
0xFF, 0xFF // Gump ID
};
serial.CopyTo(expectedData.Slice(1, 4));
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestDisplaySpellbookHS()
{
Serial serial = 0x1000;
Span<byte> data = new DisplaySpellbookHS(serial).Compile();
Span<byte> expectedData = stackalloc byte[]
{
0x24, // Packet ID
0x00, 0x00, 0x00, 0x00, // Serial
0xFF, 0xFF, // Gump ID
0x00, 0x7D // Max Items?
};
serial.CopyTo(expectedData.Slice(1, 4));
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestNewSpellbookContent()
{
Serial serial = 0x1000;
ushort graphic = 100;
ushort offset = 10;
ulong content = 0x123456789ABCDEF0;
Span<byte> data = new NewSpellbookContent(serial, graphic, offset, content).Compile();
Span<byte> expectedData = stackalloc byte[]
{
0xBF, // Packet ID
0x00, 0x17, // Length
0x00, 0x1B, // Sub-packet
0x00, 0x01,
0x00, 0x00, 0x00, 0x00, // Serial
0x00, 0x00, // Graphic
0x00, 0x00, // Offset
0x00, 0x00, 0x00, 0x00, // Content
0x00, 0x00, 0x00, 0x00 // Content
};
serial.CopyTo(expectedData.Slice(7, 4));
graphic.CopyTo(expectedData.Slice(11, 2));
offset.CopyTo(expectedData.Slice(13, 2));
content.CopyToLE(expectedData.Slice(15, 8));
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestSpellbookContent()
{
Serial serial = 0x1000;
ushort offset = 10;
ulong content = 0x123456789ABCDEF0;
Span<byte> data = new SpellbookContent(serial, offset, content).Compile();
Span<byte> expectedData = stackalloc byte[5 + 64 * 19]; // Max size
int pos = 0;
((byte)0x3C).CopyTo(ref pos, expectedData);
pos += 4; // Length + spell count
ushort count = 0;
for (var i = 0; i < 64; i++)
if ((content & (1ul << i)) != 0)
{
(0x7FFFFFFF - i).CopyTo(ref pos, expectedData);
expectedData.Clear(ref pos, 3);
((ushort)(i + offset)).CopyTo(ref pos, expectedData);
expectedData.Clear(ref pos, 4); // X, Y
serial.CopyTo(ref pos, expectedData);
expectedData.Clear(ref pos, 2);
count++;
}
((ushort)pos).CopyTo(expectedData.Slice(1, 2));
count.CopyTo(expectedData.Slice(3, 2));
expectedData = expectedData.Slice(0, pos);
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestSpellbookContent6017()
{
Serial serial = 0x1000;
ushort offset = 10;
ulong content = 0x123456789ABCDEF0;
Span<byte> data = new SpellbookContent6017(serial, offset, content).Compile();
Span<byte> expectedData = stackalloc byte[5 + 64 * 19]; // Max size
int pos = 0;
((byte)0x3C).CopyTo(ref pos, expectedData);
pos += 4; // Length + spell count
ushort count = 0;
for (var i = 0; i < 64; i++)
if ((content & (1ul << i)) != 0)
{
(0x7FFFFFFF - i).CopyTo(ref pos, expectedData);
expectedData.Clear(ref pos, 3);
((ushort)(i + offset)).CopyTo(ref pos, expectedData);
expectedData.Clear(ref pos, 5); // X, Y, Grid Location
serial.CopyTo(ref pos, expectedData);
expectedData.Clear(ref pos, 2);
count++;
}
((ushort)pos).CopyTo(expectedData.Slice(1, 2));
count.CopyTo(expectedData.Slice(3, 2));
expectedData = expectedData.Slice(0, pos);
AssertThat.Equal(data, expectedData);
}
}
}

View file

@ -51,22 +51,18 @@ namespace Server.Tests.Network.Packets
int pos = 0;
expectedData[pos++] = 0x7C; // Packet ID
((byte)0x7C).CopyTo(ref pos, expectedData); // Packet ID
((ushort)length).CopyTo(ref pos, expectedData);
menu.Serial.CopyTo(ref pos, expectedData);
pos += 2; // ((ushort)0x00).CopyTo(ref pos, expectedData);
expectedData[pos++] = (byte)questionLength;
question.CopyASCIITo(ref pos, expectedData);
expectedData[pos++] = (byte)menu.Entries.Length;
((ushort)0x00).CopyTo(ref pos, expectedData);
question.CopySmallASCIITo(ref pos, expectedData);
((byte)menu.Entries.Length).CopyTo(ref pos, expectedData);
for (int i = 0; i < menu.Entries.Length; i++)
{
var entry = menu.Entries[i];
((ushort)entry.ItemID).CopyTo(ref pos, expectedData);
((ushort)entry.Hue).CopyTo(ref pos, expectedData);
string name = entry.Name?.Trim() ?? "";
expectedData[pos++] = (byte)name.Length;
name.CopyASCIITo(ref pos, expectedData);
(entry.Name?.Trim() ?? "").CopySmallASCIITo(ref pos, expectedData);
}
AssertThat.Equal(data, expectedData);
@ -96,19 +92,16 @@ namespace Server.Tests.Network.Packets
int pos = 0;
expectedData[pos++] = 0x7C; // Packet ID
((byte)0x7C).CopyTo(ref pos, expectedData); // Packet ID
((ushort)length).CopyTo(ref pos, expectedData);
menu.Serial.CopyTo(ref pos, expectedData);
pos += 2; // ((ushort)0x00).CopyTo(ref pos, expectedData);
expectedData[pos++] = (byte)questionLength;
question?.CopyASCIITo(ref pos, expectedData);
expectedData[pos++] = (byte)menu.Answers.Length;
((ushort)0x00).CopyTo(ref pos, expectedData);
question.CopySmallASCIITo(ref pos, expectedData);
((byte)menu.Answers.Length).CopyTo(ref pos, expectedData);
for (int i = 0; i < menu.Answers.Length; i++)
{
pos += 4; // 0x0.CopyTo(ref pos, expectedData);
var answer = menu.Answers[i]?.Trim() ?? "";
expectedData[pos++] = (byte)answer.Length;
answer.CopyASCIITo(ref pos, expectedData);
0x0.CopyTo(ref pos, expectedData);
(menu.Answers[i]?.Trim() ?? "").CopySmallASCIITo(ref pos, expectedData);
}
AssertThat.Equal(data, expectedData);
@ -130,14 +123,14 @@ namespace Server.Tests.Network.Packets
Span<byte> expectedData = stackalloc byte[length];
int pos = 0;
expectedData[pos++] = 0xBF; // Packet ID
((byte)0xBF).CopyTo(ref pos, expectedData); // Packet ID
((ushort)length).CopyTo(ref pos, expectedData); // Length
((ushort)0x14).CopyTo(ref pos, expectedData); // Command
((ushort)0x02).CopyTo(ref pos, expectedData); // Subcommand
menu.Target.Serial.CopyTo(ref pos, expectedData);
var entries = menu.Entries;
expectedData[pos++] = (byte)entries.Length;
((byte)entries.Length).CopyTo(ref pos, expectedData);
for (int i = 0; i < entries.Length; i++)
{
@ -177,14 +170,14 @@ namespace Server.Tests.Network.Packets
Span<byte> expectedData = stackalloc byte[length];
int pos = 0;
expectedData[pos++] = 0xBF; // Packet ID
((byte)0xBF).CopyTo(ref pos, expectedData); // Packet ID
((ushort)length).CopyTo(ref pos, expectedData); // Length
((ushort)0x14).CopyTo(ref pos, expectedData); // Command
((ushort)0x01).CopyTo(ref pos, expectedData); // Subcommand
menu.Target.Serial.CopyTo(ref pos, expectedData);
var entries = menu.Entries;
expectedData[pos++] = (byte)entries.Length;
((byte)entries.Length).CopyTo(ref pos, expectedData);
for (int i = 0; i < entries.Length; i++)
{

View file

@ -141,7 +141,7 @@ namespace Server.Tests.Network.Packets
int pos = 1;
itemInCont.Serial.CopyTo(ref pos, expectedData);
((short)itemInCont.ItemID).CopyTo(ref pos, expectedData);
pos++; // expectedData[pos++] = 0x0;
pos++;
((short)itemInCont.Amount).CopyTo(ref pos, expectedData);
((short)itemInCont.X).CopyTo(ref pos, expectedData);
((short)itemInCont.Y).CopyTo(ref pos, expectedData);

View file

@ -27,7 +27,7 @@ namespace Server.Tests.Network.Packets
int pos = 0;
expectedData[pos++] = 0x3C; // Packet ID
((byte)0x3C).CopyTo(ref pos, expectedData); // Packet ID
((ushort)expectedData.Length).CopyTo(ref pos, expectedData); // Length
((ushort)buyStates.Count).CopyTo(ref pos, expectedData); // Count
@ -40,8 +40,8 @@ namespace Server.Tests.Network.Packets
pos++; // ItemID Offset
((ushort)buyState.Amount).CopyTo(ref pos, expectedData);
((ushort)(i + 1)).CopyTo(ref pos, expectedData); // X
expectedData[pos++] = 0;
expectedData[pos++] = 1; // Y
((byte)0).CopyTo(ref pos, expectedData);
((byte)1).CopyTo(ref pos, expectedData); // Y
buyState.ContainerSerial.CopyTo(ref pos, expectedData);
((ushort)buyState.Hue).CopyTo(ref pos, expectedData);
}
@ -67,7 +67,7 @@ namespace Server.Tests.Network.Packets
int pos = 0;
expectedData[pos++] = 0x3C; // Packet ID
((byte)0x3C).CopyTo(ref pos, expectedData); // Packet ID
((ushort)expectedData.Length).CopyTo(ref pos, expectedData); // Length
((ushort)buyStates.Count).CopyTo(ref pos, expectedData); // Count
@ -80,9 +80,9 @@ namespace Server.Tests.Network.Packets
pos++; // ItemID Offset
((ushort)buyState.Amount).CopyTo(ref pos, expectedData);
((ushort)(i + 1)).CopyTo(ref pos, expectedData); // X
expectedData[pos++] = 0;
expectedData[pos++] = 1; // Y
expectedData[pos++] = 0; // Grid Location
((byte)0).CopyTo(ref pos, expectedData);
((byte)1).CopyTo(ref pos, expectedData); // Y
((byte)0).CopyTo(ref pos, expectedData); // Grid Location
buyState.ContainerSerial.CopyTo(ref pos, expectedData);
((ushort)buyState.Hue).CopyTo(ref pos, expectedData);
}
@ -148,25 +148,22 @@ namespace Server.Tests.Network.Packets
Span<byte> data = new VendorBuyList(vendor, buyStates).Compile();
int length = 8 + 5 * 3 + buyStates.Sum(state => state.Description.Length + 1);
int length = 8 + buyStates.Sum(state => 6 + state.Description.Length);
Span<byte> expectedData = stackalloc byte[length];
int pos = 0;
expectedData[pos++] = 0x74; // Packet ID
((byte)0x74).CopyTo(ref pos, expectedData); // Packet ID
((ushort)expectedData.Length).CopyTo(ref pos, expectedData); // Length
Serial.MinusOne.CopyTo(ref pos, expectedData); // Vendor Buy Pack Serial or -1
expectedData[pos++] = (byte)buyStates.Count;
((byte)buyStates.Count).CopyTo(ref pos, expectedData);
for (int i = 0; i < buyStates.Count; i++)
{
BuyItemState state = buyStates[i];
state.Price.CopyTo(ref pos, expectedData);
string desc = state.Description ?? "";
expectedData[pos++] = (byte)(desc.Length + 1);
desc.CopyASCIITo(ref pos, expectedData);
pos++;
(state.Description ?? "").CopySmallASCIINullTo(ref pos, expectedData);
}
AssertThat.Equal(data, expectedData);

View file

@ -34,7 +34,7 @@ namespace Server.Tests.Network.Packets
Span<byte> expectedData = stackalloc byte[length];
int pos = 0;
expectedData[pos++] = 0x9E; // Packet ID
((byte)0x9E).CopyTo(ref pos, expectedData); // Packet ID
((ushort)length).CopyTo(ref pos, expectedData);
vendor.Serial.CopyTo(ref pos, expectedData);
((ushort)sellStates.Count).CopyTo(ref pos, expectedData);
@ -48,7 +48,6 @@ namespace Server.Tests.Network.Packets
((ushort)state.Item.Amount).CopyTo(ref pos, expectedData);
((ushort)state.Price).CopyTo(ref pos, expectedData);
string name = string.IsNullOrWhiteSpace(state.Item.Name) ? state.Name ?? "" : state.Item.Name.Trim();
((ushort)name.Length).CopyTo(ref pos, expectedData);
name.CopyASCIITo(ref pos, expectedData);
}

View file

@ -12,6 +12,12 @@ namespace Server.Tests.Network.Packets
public static Span<byte> Compile(this Packet p) =>
p.Compile(false, out int length).AsSpan(0, length);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyTo(this byte value, Span<byte> bytes) => bytes[0] = value;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyTo(this bool value, Span<byte> bytes) => bytes[0] = (byte)(value ? 0x1 : 0x0);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyTo(this ushort number, Span<byte> bytes) => BinaryPrimitives.WriteUInt16BigEndian(bytes, number);
@ -28,12 +34,39 @@ namespace Server.Tests.Network.Packets
public static void CopyTo(this int number, Span<byte> bytes) => BinaryPrimitives.WriteInt32BigEndian(bytes, number);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyASCIITo(this string str, Span<byte> bytes) => Encoding.ASCII.GetBytes(str.AsSpan(), bytes);
public static void CopyTo(this ulong number, Span<byte> bytes) => BinaryPrimitives.WriteUInt64BigEndian(bytes, number);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyASCIITo(this string str, int max, Span<byte> bytes) => Encoding.ASCII.GetBytes(str.AsSpan(0, Math.Min(str.Length, max)), bytes);
public static void CopyTo(this long number, Span<byte> bytes) => BinaryPrimitives.WriteInt64BigEndian(bytes, number);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyToLE(this ushort number, Span<byte> bytes) => BinaryPrimitives.WriteUInt16LittleEndian(bytes, number);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyToLE(this short number, Span<byte> bytes) => BinaryPrimitives.WriteInt16LittleEndian(bytes, number);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyToLE(this Serial s, Span<byte> bytes) => BinaryPrimitives.WriteUInt32LittleEndian(bytes, s);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyToLE(this uint number, Span<byte> bytes) => BinaryPrimitives.WriteUInt32LittleEndian(bytes, number);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyToLE(this int number, Span<byte> bytes) => BinaryPrimitives.WriteInt32LittleEndian(bytes, number);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyToLE(this ulong number, Span<byte> bytes) => BinaryPrimitives.WriteUInt64LittleEndian(bytes, number);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyToLE(this long number, Span<byte> bytes) => BinaryPrimitives.WriteInt64LittleEndian(bytes, number);
// With Position Reference
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyTo(this byte value, ref int pos, Span<byte> bytes) => bytes[pos++] = value;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyTo(this bool value, ref int pos, Span<byte> bytes) => bytes[pos++] = (byte)(value ? 0x1 : 0x0);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyTo(this ushort number, ref int pos, Span<byte> bytes)
{
@ -70,17 +103,97 @@ namespace Server.Tests.Network.Packets
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyASCIITo(this string str, ref int pos, Span<byte> bytes)
public static void CopyTo(this ulong number, ref int pos, Span<byte> bytes)
{
BinaryPrimitives.WriteUInt64BigEndian(bytes.Slice(pos, 8), number);
pos += 8;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyTo(this long number, ref int pos, Span<byte> bytes)
{
BinaryPrimitives.WriteInt64BigEndian(bytes.Slice(pos, 8), number);
pos += 8;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyRawASCIITo(this string str, ref int pos, Span<byte> bytes)
{
pos += Encoding.ASCII.GetBytes(str.AsSpan(), bytes.Slice(pos));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyASCIITo(this string str, ref int pos, int max, Span<byte> bytes)
public static void CopyRawASCIITo(this string str, ref int pos, int max, Span<byte> bytes)
{
pos += Encoding.ASCII.GetBytes(str.AsSpan(0, Math.Min(str.Length, max)), bytes.Slice(pos));
}
// Ascii prepended with two-byte length
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyASCIITo(this string str, ref int pos, Span<byte> bytes)
{
BinaryPrimitives.WriteUInt16BigEndian(bytes.Slice(pos, 2), (ushort)str.Length);
pos += 2 + Encoding.ASCII.GetBytes(str.AsSpan(), bytes.Slice(pos + 2));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyASCIITo(this string str, ref int pos, int max, Span<byte> bytes)
{
var length = Math.Min(str.Length, max);
BinaryPrimitives.WriteUInt16BigEndian(bytes.Slice(pos, 2), (ushort)length);
pos += 2 + Encoding.ASCII.GetBytes(str.AsSpan(0, length), bytes.Slice(pos + 2));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyASCIINullTo(this string str, ref int pos, Span<byte> bytes)
{
BinaryPrimitives.WriteUInt16BigEndian(bytes.Slice(pos, 2), (ushort)(str.Length + 1));
pos += 3 + Encoding.ASCII.GetBytes(str.AsSpan(), bytes.Slice(pos + 2));
bytes[pos - 1] = 0; // null terminator
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyASCIINullTo(this string str, ref int pos, int max, Span<byte> bytes)
{
var length = Math.Min(str.Length, max - 1);
BinaryPrimitives.WriteUInt16BigEndian(bytes.Slice(pos, 2), (ushort)(length + 1));
pos += 3 + Encoding.ASCII.GetBytes(str.AsSpan(0, length), bytes.Slice(pos + 2));
bytes[pos - 1] = 0; // null terminator
}
// Ascii prepended with one-byte length
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopySmallASCIITo(this string str, ref int pos, Span<byte> bytes)
{
bytes[pos++] = (byte)str.Length;
pos += Encoding.ASCII.GetBytes(str.AsSpan(), bytes.Slice(pos));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopySmallASCIITo(this string str, ref int pos, int max, Span<byte> bytes)
{
var length = Math.Min(255, Math.Min(str.Length, max));
bytes[pos++] = (byte)length;
pos += Encoding.ASCII.GetBytes(str.AsSpan(0, length), bytes.Slice(pos));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopySmallASCIINullTo(this string str, ref int pos, Span<byte> bytes)
{
bytes[pos++] = (byte)(str.Length + 1);
pos += Encoding.ASCII.GetBytes(str.AsSpan(), bytes.Slice(pos));
bytes[pos++] = 0; // null terminator
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopySmallASCIINullTo(this string str, ref int pos, int max, Span<byte> bytes)
{
var length = Math.Min(255, Math.Min(str.Length, max));
bytes[pos++] = (byte)length;
pos += Encoding.ASCII.GetBytes(str.AsSpan(0, length), bytes.Slice(pos));
bytes[pos++] = 0; // null terminator
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyASCIIFixedTo(this string str, ref int pos, int max, Span<byte> bytes)
{
@ -93,6 +206,38 @@ namespace Server.Tests.Network.Packets
pos += max;
}
// Unicode prepended with two-byte length
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyUnicodeBigEndianTo(this string str, ref int pos, Span<byte> bytes)
{
BinaryPrimitives.WriteUInt16BigEndian(bytes.Slice(pos, 2), (ushort)str.Length);
pos += 2 + Encoding.BigEndianUnicode.GetBytes(str.AsSpan(), bytes.Slice(pos + 2));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyTo(this byte[] src, ref int pos, Span<byte> bytes) =>
src.CopyTo(bytes.Slice(pos, src.Length));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyTo(this byte[] src, ref int pos, int max, Span<byte> bytes) =>
src.CopyTo(bytes.Slice(pos, Math.Min(max, src.Length)));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyTo(this Span<byte> src, ref int pos, Span<byte> bytes) =>
src.CopyTo(bytes.Slice(pos, src.Length));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyTo(this Span<byte> src, ref int pos, int max, Span<byte> bytes) =>
src.CopyTo(bytes.Slice(pos, Math.Min(max, src.Length)));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyTo(this ReadOnlySpan<byte> src, ref int pos, Span<byte> bytes) =>
src.CopyTo(bytes.Slice(pos, src.Length));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyTo(this ReadOnlySpan<byte> src, ref int pos, int max, Span<byte> bytes) =>
src.CopyTo(bytes.Slice(pos, Math.Min(max, src.Length)));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Clear(this Span<byte> span, ref int pos, int amount)
{

View file

@ -7,6 +7,7 @@
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.2" />
<PackageReference Include="coverlet.collector" Version="1.3.0" />
<PackageReference Include="Zlib.Bindings" Version="1.1.0" />
<ProjectReference Include="..\Server\Server.csproj" />
</ItemGroup>
</Project>

View file

@ -35,6 +35,12 @@
"resolved": "2.4.2",
"contentHash": "Trt9multph2KE3U0p9oBt0k4Fq6lUv4btUcONaQEeuFnMCak2k/b7PAArbLtMFW7HO1jxlBHUgIPKEqci3Y1dg=="
},
"Zlib.Bindings": {
"type": "Direct",
"requested": "[1.1.0, )",
"resolved": "1.1.0",
"contentHash": "hLmHUTlZR3rnJ95FboiyJdLR8MJbfHdmapnRZHWLvkxB48jDgRBBJG1w5NYRiNBteVY4uksacXM7/V8nu1byBw=="
},
"Libuv": {
"type": "Transitive",
"resolved": "1.10.0",
@ -1181,11 +1187,6 @@
"xunit.extensibility.core": "[2.4.1]"
}
},
"Zlib.Bindings": {
"type": "Transitive",
"resolved": "1.1.0",
"contentHash": "hLmHUTlZR3rnJ95FboiyJdLR8MJbfHdmapnRZHWLvkxB48jDgRBBJG1w5NYRiNBteVY4uksacXM7/V8nu1byBw=="
},
"ModernUO": {
"type": "Project",
"dependencies": {
@ -1198,6 +1199,12 @@
}
},
".NETCoreApp,Version=v3.1/centos.7-x64": {
"Zlib.Bindings": {
"type": "Direct",
"requested": "[1.1.0, )",
"resolved": "1.1.0",
"contentHash": "hLmHUTlZR3rnJ95FboiyJdLR8MJbfHdmapnRZHWLvkxB48jDgRBBJG1w5NYRiNBteVY4uksacXM7/V8nu1byBw=="
},
"Libuv": {
"type": "Transitive",
"resolved": "1.10.0",
@ -2109,14 +2116,15 @@
"System.Runtime": "4.3.0",
"runtime.any.System.Threading.Timer": "4.3.0"
}
},
"Zlib.Bindings": {
"type": "Transitive",
"resolved": "1.1.0",
"contentHash": "hLmHUTlZR3rnJ95FboiyJdLR8MJbfHdmapnRZHWLvkxB48jDgRBBJG1w5NYRiNBteVY4uksacXM7/V8nu1byBw=="
}
},
".NETCoreApp,Version=v3.1/centos.8-x64": {
"Zlib.Bindings": {
"type": "Direct",
"requested": "[1.1.0, )",
"resolved": "1.1.0",
"contentHash": "hLmHUTlZR3rnJ95FboiyJdLR8MJbfHdmapnRZHWLvkxB48jDgRBBJG1w5NYRiNBteVY4uksacXM7/V8nu1byBw=="
},
"Libuv": {
"type": "Transitive",
"resolved": "1.10.0",
@ -2983,14 +2991,15 @@
"System.Runtime": "4.3.0",
"runtime.any.System.Threading.Timer": "4.3.0"
}
},
"Zlib.Bindings": {
"type": "Transitive",
"resolved": "1.1.0",
"contentHash": "hLmHUTlZR3rnJ95FboiyJdLR8MJbfHdmapnRZHWLvkxB48jDgRBBJG1w5NYRiNBteVY4uksacXM7/V8nu1byBw=="
}
},
".NETCoreApp,Version=v3.1/debian.10-x64": {
"Zlib.Bindings": {
"type": "Direct",
"requested": "[1.1.0, )",
"resolved": "1.1.0",
"contentHash": "hLmHUTlZR3rnJ95FboiyJdLR8MJbfHdmapnRZHWLvkxB48jDgRBBJG1w5NYRiNBteVY4uksacXM7/V8nu1byBw=="
},
"Libuv": {
"type": "Transitive",
"resolved": "1.10.0",
@ -3857,14 +3866,15 @@
"System.Runtime": "4.3.0",
"runtime.any.System.Threading.Timer": "4.3.0"
}
},
"Zlib.Bindings": {
"type": "Transitive",
"resolved": "1.1.0",
"contentHash": "hLmHUTlZR3rnJ95FboiyJdLR8MJbfHdmapnRZHWLvkxB48jDgRBBJG1w5NYRiNBteVY4uksacXM7/V8nu1byBw=="
}
},
".NETCoreApp,Version=v3.1/debian.9-x64": {
"Zlib.Bindings": {
"type": "Direct",
"requested": "[1.1.0, )",
"resolved": "1.1.0",
"contentHash": "hLmHUTlZR3rnJ95FboiyJdLR8MJbfHdmapnRZHWLvkxB48jDgRBBJG1w5NYRiNBteVY4uksacXM7/V8nu1byBw=="
},
"Libuv": {
"type": "Transitive",
"resolved": "1.10.0",
@ -4731,14 +4741,15 @@
"System.Runtime": "4.3.0",
"runtime.any.System.Threading.Timer": "4.3.0"
}
},
"Zlib.Bindings": {
"type": "Transitive",
"resolved": "1.1.0",
"contentHash": "hLmHUTlZR3rnJ95FboiyJdLR8MJbfHdmapnRZHWLvkxB48jDgRBBJG1w5NYRiNBteVY4uksacXM7/V8nu1byBw=="
}
},
".NETCoreApp,Version=v3.1/osx-x64": {
"Zlib.Bindings": {
"type": "Direct",
"requested": "[1.1.0, )",
"resolved": "1.1.0",
"contentHash": "hLmHUTlZR3rnJ95FboiyJdLR8MJbfHdmapnRZHWLvkxB48jDgRBBJG1w5NYRiNBteVY4uksacXM7/V8nu1byBw=="
},
"Libuv": {
"type": "Transitive",
"resolved": "1.10.0",
@ -5605,14 +5616,15 @@
"System.Runtime": "4.3.0",
"runtime.any.System.Threading.Timer": "4.3.0"
}
},
"Zlib.Bindings": {
"type": "Transitive",
"resolved": "1.1.0",
"contentHash": "hLmHUTlZR3rnJ95FboiyJdLR8MJbfHdmapnRZHWLvkxB48jDgRBBJG1w5NYRiNBteVY4uksacXM7/V8nu1byBw=="
}
},
".NETCoreApp,Version=v3.1/ubuntu.16.04-x64": {
"Zlib.Bindings": {
"type": "Direct",
"requested": "[1.1.0, )",
"resolved": "1.1.0",
"contentHash": "hLmHUTlZR3rnJ95FboiyJdLR8MJbfHdmapnRZHWLvkxB48jDgRBBJG1w5NYRiNBteVY4uksacXM7/V8nu1byBw=="
},
"Libuv": {
"type": "Transitive",
"resolved": "1.10.0",
@ -6524,14 +6536,15 @@
"System.Runtime": "4.3.0",
"runtime.any.System.Threading.Timer": "4.3.0"
}
},
"Zlib.Bindings": {
"type": "Transitive",
"resolved": "1.1.0",
"contentHash": "hLmHUTlZR3rnJ95FboiyJdLR8MJbfHdmapnRZHWLvkxB48jDgRBBJG1w5NYRiNBteVY4uksacXM7/V8nu1byBw=="
}
},
".NETCoreApp,Version=v3.1/ubuntu.18.04-x64": {
"Zlib.Bindings": {
"type": "Direct",
"requested": "[1.1.0, )",
"resolved": "1.1.0",
"contentHash": "hLmHUTlZR3rnJ95FboiyJdLR8MJbfHdmapnRZHWLvkxB48jDgRBBJG1w5NYRiNBteVY4uksacXM7/V8nu1byBw=="
},
"Libuv": {
"type": "Transitive",
"resolved": "1.10.0",
@ -7398,14 +7411,15 @@
"System.Runtime": "4.3.0",
"runtime.any.System.Threading.Timer": "4.3.0"
}
},
"Zlib.Bindings": {
"type": "Transitive",
"resolved": "1.1.0",
"contentHash": "hLmHUTlZR3rnJ95FboiyJdLR8MJbfHdmapnRZHWLvkxB48jDgRBBJG1w5NYRiNBteVY4uksacXM7/V8nu1byBw=="
}
},
".NETCoreApp,Version=v3.1/win-x64": {
"Zlib.Bindings": {
"type": "Direct",
"requested": "[1.1.0, )",
"resolved": "1.1.0",
"contentHash": "hLmHUTlZR3rnJ95FboiyJdLR8MJbfHdmapnRZHWLvkxB48jDgRBBJG1w5NYRiNBteVY4uksacXM7/V8nu1byBw=="
},
"Libuv": {
"type": "Transitive",
"resolved": "1.10.0",
@ -8255,11 +8269,6 @@
"System.Runtime": "4.3.0",
"runtime.any.System.Threading.Timer": "4.3.0"
}
},
"Zlib.Bindings": {
"type": "Transitive",
"resolved": "1.1.0",
"contentHash": "hLmHUTlZR3rnJ95FboiyJdLR8MJbfHdmapnRZHWLvkxB48jDgRBBJG1w5NYRiNBteVY4uksacXM7/V8nu1byBw=="
}
}
}

View file

@ -37,7 +37,7 @@ namespace Server.Gumps
private static readonly byte[] m_NoDispose = StringToBuffer("{ nodispose }");
private static readonly byte[] m_NoResize = StringToBuffer("{ noresize }");
private readonly List<string> m_Strings;
public List<string> Strings { get; }
internal int m_TextEntries, m_Switches;
@ -54,7 +54,7 @@ namespace Server.Gumps
TypeID = GetTypeID(GetType());
Entries = new List<GumpEntry>();
m_Strings = new List<string>();
Strings = new List<string>();
}
public int TypeID { get; }
@ -206,13 +206,9 @@ namespace Server.Gumps
public void Add(GumpEntry g)
{
if (g.Parent != this)
{
g.Parent = this;
}
else if (!Entries.Contains(g))
{
Entries.Add(g);
}
}
public void Remove(GumpEntry g)
@ -226,12 +222,12 @@ namespace Server.Gumps
public int Intern(string value)
{
var indexOf = m_Strings.IndexOf(value);
var indexOf = Strings.IndexOf(value);
if (indexOf >= 0) return indexOf;
m_Strings.Add(value);
return m_Strings.Count - 1;
Strings.Add(value);
return Strings.Count - 1;
}
public void SendTo(NetState state)
@ -242,7 +238,7 @@ namespace Server.Gumps
public static byte[] StringToBuffer(string str) => Encoding.ASCII.GetBytes(str);
private Packet Compile(NetState ns = null)
public Packet Compile(NetState ns = null)
{
IGumpWriter disp;
@ -274,7 +270,7 @@ namespace Server.Gumps
disp.AppendLayout(m_EndLayout);
}
disp.WriteStrings(m_Strings);
disp.WriteStrings(Strings);
disp.Flush();

View file

@ -634,9 +634,9 @@ namespace Server.Items
if (ns != null)
{
if (ns.HighSeas)
to.Send(new ContainerDisplayHS(this));
to.Send(new ContainerDisplayHS(Serial, GumpID));
else
to.Send(new ContainerDisplay(this));
to.Send(new ContainerDisplay(Serial, GumpID));
SendContentTo(ns);

View file

@ -47,6 +47,11 @@ namespace Server
private static bool m_Profiling;
private static DateTime m_ProfileStart;
private static TimeSpan m_ProfileTime;
private static bool? m_IsRunningFromXUnit;
public static bool IsRunningFromXUnit =>
m_IsRunningFromXUnit ??= AppDomain.CurrentDomain.GetAssemblies().Any(
a => a.FullName?.ToLowerInvariant().StartsWith("xunit") ?? false);
/*
* DateTime.Now and DateTime.UtcNow are based on actual system clock time.

View file

@ -331,14 +331,14 @@ namespace Server.Network
unknown ??= "";
caption ??= "";
EnsureCapacity(16 + unknown.Length + caption.Length);
EnsureCapacity(15 + unknown.Length + caption.Length);
Stream.Write(serial);
Stream.Write((short)gumpID);
Stream.Write((short)unknown.Length);
Stream.WriteAsciiFixed(unknown, unknown.Length);
Stream.Write((short)(unknown.Length + 1));
Stream.WriteAsciiNull(unknown);
Stream.Write((short)(caption.Length + 1));
Stream.WriteAsciiFixed(caption, caption.Length + 1);
Stream.WriteAsciiNull(caption);
}
}
}

View file

@ -105,14 +105,6 @@ namespace Server.Network
Stream.Write((short)itemID);
Stream.Write((byte)0);
/*} else if ( ) {
m_Stream.Write( (byte) 0x01 );
m_Stream.Write( (int) item.Serial );
m_Stream.Write( (short) itemID );
m_Stream.Write( (byte) item.Direction );*/
}
else
{
@ -132,10 +124,8 @@ namespace Server.Network
Stream.Write((short)amount);
var loc = item.Location;
var x = loc.m_X & 0x7FFF;
var y = loc.m_Y & 0x3FFF;
Stream.Write((short)x);
Stream.Write((short)y);
Stream.Write((short)loc.m_X);
Stream.Write((short)loc.m_Y);
Stream.Write((sbyte)loc.m_Z);
Stream.Write((byte)item.Light);
@ -163,14 +153,6 @@ namespace Server.Network
Stream.Write((ushort)itemID);
Stream.Write((byte)0);
/*} else if ( ) {
m_Stream.Write( (byte) 0x01 );
m_Stream.Write( (int) item.Serial );
m_Stream.Write( (ushort) itemID );
m_Stream.Write( (byte) item.Direction );*/
}
else
{
@ -190,10 +172,8 @@ namespace Server.Network
Stream.Write((short)amount);
var loc = item.Location;
var x = loc.m_X & 0x7FFF;
var y = loc.m_Y & 0x3FFF;
Stream.Write((short)x);
Stream.Write((short)y);
Stream.Write((short)loc.m_X);
Stream.Write((short)loc.m_Y);
Stream.Write((sbyte)loc.m_Z);
Stream.Write((byte)item.Light);
@ -206,18 +186,18 @@ namespace Server.Network
public sealed class DisplaySpellbook : Packet
{
public DisplaySpellbook(Item book) : base(0x24, 7)
public DisplaySpellbook(Serial book) : base(0x24, 7)
{
Stream.Write(book.Serial);
Stream.Write(book);
Stream.Write((short)-1);
}
}
public sealed class DisplaySpellbookHS : Packet
{
public DisplaySpellbookHS(Item book) : base(0x24, 9)
public DisplaySpellbookHS(Serial book) : base(0x24, 9)
{
Stream.Write(book.Serial);
Stream.Write(book);
Stream.Write((short)-1);
Stream.Write((short)0x7D);
}
@ -225,14 +205,14 @@ namespace Server.Network
public sealed class NewSpellbookContent : Packet
{
public NewSpellbookContent(Item item, int graphic, int offset, ulong content) : base(0xBF)
public NewSpellbookContent(Serial spellbook, int graphic, int offset, ulong content) : base(0xBF)
{
EnsureCapacity(23);
Stream.Write((short)0x1B);
Stream.Write((short)0x01);
Stream.Write(item.Serial);
Stream.Write(spellbook);
Stream.Write((short)graphic);
Stream.Write((short)offset);
@ -243,9 +223,9 @@ namespace Server.Network
public sealed class SpellbookContent : Packet
{
public SpellbookContent(int count, int offset, ulong content, Item item) : base(0x3C)
public SpellbookContent(Serial spellbook, int offset, ulong content) : base(0x3C)
{
EnsureCapacity(5 + count * 19);
EnsureCapacity(5 + 64 * 19);
var written = 0;
@ -262,7 +242,7 @@ namespace Server.Network
Stream.Write((ushort)(i + offset));
Stream.Write((short)0);
Stream.Write((short)0);
Stream.Write(item.Serial);
Stream.Write(spellbook);
Stream.Write((short)0);
++written;
@ -275,9 +255,9 @@ namespace Server.Network
public sealed class SpellbookContent6017 : Packet
{
public SpellbookContent6017(int count, int offset, ulong content, Item item) : base(0x3C)
public SpellbookContent6017(Serial spellbook, int offset, ulong content) : base(0x3C)
{
EnsureCapacity(5 + count * 20);
EnsureCapacity(5 + 64 * 20);
var written = 0;
@ -295,7 +275,7 @@ namespace Server.Network
Stream.Write((short)0);
Stream.Write((short)0);
Stream.Write((byte)0); // Grid Location?
Stream.Write(item.Serial);
Stream.Write(spellbook);
Stream.Write((short)0);
++written;
@ -308,19 +288,19 @@ namespace Server.Network
public sealed class ContainerDisplay : Packet
{
public ContainerDisplay(Container c) : base(0x24, 7)
public ContainerDisplay(Serial cont, int gumpId) : base(0x24, 7)
{
Stream.Write(c.Serial);
Stream.Write((short)c.GumpID);
Stream.Write(cont);
Stream.Write((short)gumpId);
}
}
public sealed class ContainerDisplayHS : Packet
{
public ContainerDisplayHS(Container c) : base(0x24, 9)
public ContainerDisplayHS(Serial cont, int gumpId) : base(0x24, 9)
{
Stream.Write(c.Serial);
Stream.Write((short)c.GumpID);
Stream.Write(cont);
Stream.Write((short)gumpId);
Stream.Write((short)0x7D);
}
}

View file

@ -20,6 +20,7 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
namespace Server
@ -181,108 +182,56 @@ namespace Server
static TileData()
{
ItemTable = new ItemData[0x10000];
LandTable = new LandData[0x4000];
if (Core.IsRunningFromXUnit) return;
var filePath = Core.FindDataFile("tiledata.mul");
using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
var bin = new BinaryReader(fs);
if (fs.Length == 3188736)
var is7090 = fs.Length == 3188736;
bool is7000 = fs.Length == 1644544;
for (var i = 0; i < 0x4000; i++)
{
// 7.0.9.0
LandTable = new LandData[0x4000];
for (var i = 0; i < 0x4000; ++i)
// header
if (is7090)
{
if (i == 1 || i > 0 && (i & 0x1F) == 0) bin.ReadInt32(); // header
var flags = (TileFlag)bin.ReadInt64();
bin.ReadInt16(); // skip 2 bytes -- textureID
LandTable[i] = new LandData(ReadNameString(bin), flags);
if (i == 1 || i > 0 && (i & 0x1F) == 0)
bin.ReadInt32();
}
ItemTable = new ItemData[0x10000];
for (var i = 0; i < 0x10000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
var flags = (TileFlag)bin.ReadInt64();
int weight = bin.ReadByte();
int quality = bin.ReadByte();
bin.ReadInt16();
bin.ReadByte();
int quantity = bin.ReadByte();
else if ((i & 0x1F) == 0)
bin.ReadInt32();
bin.ReadByte();
int value = bin.ReadByte();
int height = bin.ReadByte();
ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value,
height);
}
var flags = (TileFlag)(is7090 ? bin.ReadInt64() : bin.ReadInt32());
bin.ReadInt16(); // skip 2 bytes -- textureID
LandTable[i] = new LandData(ReadNameString(bin), flags);
}
else
int length = is7090 ? 0x10000 : is7000 ? 0x8000 : 0x4000;
for (var i = 0; i < length; i++)
{
LandTable = new LandData[0x4000];
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
for (var i = 0; i < 0x4000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
var flags = (TileFlag)(is7090 ? bin.ReadInt64() : bin.ReadInt32());
int weight = bin.ReadByte();
int quality = bin.ReadByte();
bin.ReadInt16();
bin.ReadByte();
int quantity = bin.ReadByte();
bin.ReadInt32();
bin.ReadByte();
int value = bin.ReadByte();
int height = bin.ReadByte();
var flags = (TileFlag)bin.ReadInt32();
bin.ReadInt16(); // skip 2 bytes -- textureID
LandTable[i] = new LandData(ReadNameString(bin), flags);
}
if (fs.Length == 1644544)
{
// 7.0.0.0
ItemTable = new ItemData[0x8000];
for (var i = 0; i < 0x8000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
var flags = (TileFlag)bin.ReadInt32();
int weight = bin.ReadByte();
int quality = bin.ReadByte();
bin.ReadInt16();
bin.ReadByte();
int quantity = bin.ReadByte();
bin.ReadInt32();
bin.ReadByte();
int value = bin.ReadByte();
int height = bin.ReadByte();
ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value,
height);
}
}
else
{
ItemTable = new ItemData[0x4000];
for (var i = 0; i < 0x4000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
var flags = (TileFlag)bin.ReadInt32();
int weight = bin.ReadByte();
int quality = bin.ReadByte();
bin.ReadInt16();
bin.ReadByte();
int quantity = bin.ReadByte();
bin.ReadInt32();
bin.ReadByte();
int value = bin.ReadByte();
int height = bin.ReadByte();
ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value,
height);
}
}
ItemTable[i] = new ItemData(
ReadNameString(bin), flags, weight, quality, quantity, value, height
);
}
MaxLandValue = LandTable.Length - 1;

View file

@ -5,8 +5,8 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
<PackageReference Include="coverlet.collector" Version="1.2.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.2" />
<PackageReference Include="coverlet.collector" Version="1.3.0" />
<ProjectReference Include="..\Server\Server.csproj" />
<ProjectReference Include="..\UOContent\UOContent.csproj" />
</ItemGroup>

View file

@ -4,9 +4,9 @@
".NETCoreApp,Version=v3.1": {
"coverlet.collector": {
"type": "Direct",
"requested": "[1.2.1, )",
"resolved": "1.2.1",
"contentHash": "a4JYYZbEXk2UsrTEHlKrQxBVROeQkAg/Qwrf/XgZHGDXNctIrIu9MCihNKpFXC6cgj6wuXmWcPN++T9wOnhskA=="
"requested": "[1.3.0, )",
"resolved": "1.3.0",
"contentHash": "t8pnf5SX2ya0RX4vjoxsbhDMQCZJcpPun2neHKJ4FouMmObylo25FvoOydvf3Bl+l+IzWw7u2vjEeCBHnleB9g=="
},
"Microsoft.NET.Test.Sdk": {
"type": "Direct",
@ -31,12 +31,9 @@
},
"xunit.runner.visualstudio": {
"type": "Direct",
"requested": "[2.4.1, )",
"resolved": "2.4.1",
"contentHash": "mBXd1lp1TQr4to2nFv+c4Tf+RnPoQPKglzwLdbdirOUxRaJsCUNDUx2y7E6j9ajgISlTTp1CydFBZCRCUIrwDg==",
"dependencies": {
"Microsoft.NET.Test.Sdk": "15.0.0"
}
"requested": "[2.4.2, )",
"resolved": "2.4.2",
"contentHash": "Trt9multph2KE3U0p9oBt0k4Fq6lUv4btUcONaQEeuFnMCak2k/b7PAArbLtMFW7HO1jxlBHUgIPKEqci3Y1dg=="
},
"Argon2.Bindings": {
"type": "Transitive",

View file

@ -603,30 +603,30 @@ namespace Server.Items
}
if (ns.HighSeas)
to.Send(new DisplaySpellbookHS(this));
to.Send(new DisplaySpellbookHS(Serial));
else
to.Send(new DisplaySpellbook(this));
to.Send(new DisplaySpellbook(Serial));
if (ObjectPropertyList.Enabled)
{
if (ns.NewSpellbook)
{
to.Send(new NewSpellbookContent(this, ItemID, BookOffset + 1, m_Content));
to.Send(new NewSpellbookContent(Serial, ItemID, BookOffset + 1, m_Content));
}
else
{
if (ns.ContainerGridLines)
to.Send(new SpellbookContent6017(SpellCount, BookOffset + 1, m_Content, this));
to.Send(new SpellbookContent6017(Serial, BookOffset + 1, m_Content));
else
to.Send(new SpellbookContent(SpellCount, BookOffset + 1, m_Content, this));
to.Send(new SpellbookContent(Serial, BookOffset + 1, m_Content));
}
}
else
{
if (ns.ContainerGridLines)
to.Send(new SpellbookContent6017(SpellCount, BookOffset + 1, m_Content, this));
to.Send(new SpellbookContent6017(Serial, BookOffset + 1, m_Content));
else
to.Send(new SpellbookContent(SpellCount, BookOffset + 1, m_Content, this));
to.Send(new SpellbookContent(Serial, BookOffset + 1, m_Content));
}
}