Adds more unit tests (#133)

This commit is contained in:
Kamron Batman 2020-05-08 20:32:59 -07:00 committed by GitHub
parent e138706536
commit 8278694105
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 1406 additions and 996 deletions

View file

@ -1,12 +0,0 @@
6b0276b603e867108643104978963ddd2e599e58 ../Projects/Argon2/Argon2.csproj
214715e88298b66715dee7c06080fc083f2c9e26 ../Projects/Argon2/Argon2.cs
1e89625abe364f895346d0c5753f3ca6653cf7df ../Projects/Argon2/Argon2Context.cs
abbb34d85f55ca1d78a400b4d46afbd6965f642b ../Projects/Argon2/Argon2Error.cs
00ef35a6809d4959bdda1de01f45e39ff388270f ../Projects/Argon2/Argon2Exception.cs
58979ca359777ae45a6233264f0741ba23203959 ../Projects/Argon2/Argon2PasswordHasher.cs
a137d2fe0478d065d478366168f80ab9eaaa9c3a ../Projects/Argon2/Argon2Type.cs
c09f7a2f9690d56ca838aafb28640c09950c5a8c ../Projects/Argon2/HashMetadata.cs
c9fb8b37bd035c6597047d4279f9b6e6384db944 ../Projects/Argon2/Utility.cs
c9fb8b37bd035c6597047d4279f9b6e6384db944 ../Projects/ZLib/Utility.cs
a4c3595dada3e596ab3131886616d5c27107ec7f ../Projects/ZLib/ZLib.cs
d129d82f8607e97090088a6e1956706d886e8294 ../Projects/ZLib/ZLib.csproj

View file

@ -17,84 +17,35 @@ jobs:
steps: steps:
- run: rm -rf ~/project/.git # CircleCI git caching is likely broken - run: rm -rf ~/project/.git # CircleCI git caching is likely broken
- checkout - checkout
- restore_cache:
keys:
- dotnet-packages-v1-{{ arch }}-{{ checksum ".circleci/checksum.txt" }}
- run: - run:
name: Build native libraries name: Building ModernUO for Linux
command: /mnt/ramdisk/Tools/build-native-libraries.sh command: Tools/publish.cmd linux
- save_cache:
paths:
- /mnt/ramdisk/packages
key: dotnet-packages-v1-{{ arch }}-{{ checksum ".circleci/checksum.txt" }}
- run:
name: Install ModernUO dependencies
command: dotnet restore
- run:
name: Building ModernUO for Linux (Debug)
command: dotnet build -c Debug -r linux-x64
build_windows: build_windows:
description: Build application description: Build application
executor: win/default executor: win/default
steps: steps:
- checkout - checkout
- restore_cache:
keys:
- dotnet-packages-v1-{{ arch }}-{{ checksum ".circleci/checksum.txt" }}
- run: - run:
name: Build native libraries name: Building ModernUO for Windows
command: Tools\build-native-libraries.cmd command: Tools/publish.cmd win
- save_cache:
paths:
- packages
key: dotnet-packages-v1-{{ arch }}-{{ checksum ".circleci/checksum.txt" }}
- run:
name: Install ModernUO dependencies
command: dotnet restore
- run:
name: Building ModernUO for Windows (Debug)
command: dotnet build -c Debug -r win-x64
code_styling: code_styling:
description: Code analysis description: Code analysis
executor: linux-build executor: linux-build
steps: steps:
- run: rm -rf ~/project/.git # CircleCI git caching is likely broken - run: rm -rf ~/project/.git # CircleCI git caching is likely broken
- checkout - checkout
- restore_cache:
keys:
- dotnet-packages-v1-{{ arch }}-{{ checksum ".circleci/checksum.txt" }}
- run:
name: Build native libraries
command: /mnt/ramdisk/Tools/build-native-libraries.sh
- save_cache:
paths:
- /mnt/ramdisk/packages
key: dotnet-packages-v1-{{ arch }}-{{ checksum ".circleci/checksum.txt" }}
- run:
name: Install ModernUO dependencies
command: dotnet restore
- run: - run:
name: Building with Analyzers name: Building with Analyzers
command: dotnet build -c Analyze -r linux-x64 command: Tools/publish.cmd linux Analyze
tests: tests:
description: Unit Tests description: Unit Tests
executor: linux-build executor: linux-build
steps: steps:
- run: rm -rf ~/project/.git # CircleCI git caching is likely broken - run: rm -rf ~/project/.git # CircleCI git caching is likely broken
- checkout - checkout
- restore_cache:
keys:
- dotnet-packages-v1-{{ arch }}-{{ checksum ".circleci/checksum.txt" }}
- run: - run:
name: Build native libraries name: Build native libraries
command: /mnt/ramdisk/Tools/build-native-libraries.sh command: /mnt/ramdisk/Tools/build-native-libraries.sh
- save_cache:
paths:
- /mnt/ramdisk/packages
key: dotnet-packages-v1-{{ arch }}-{{ checksum ".circleci/checksum.txt" }}
- run:
name: Install ModernUO dependencies
command: dotnet restore
- run: - run:
name: Running unit tests name: Running unit tests
command: dotnet test -r linux-x64 command: dotnet test -r linux-x64

View file

@ -1 +0,0 @@
sha1sum ../Projects/Argon2/*.csproj ../Projects/Argon2/*.cs ../Projects/ZLib/*.cs ../Projects/ZLib/*.csproj > "checksum.txt"

View file

@ -3036,7 +3036,7 @@ namespace Server.Mobiles
IsDeadPet = false; IsDeadPet = false;
Effects.SendPacket(Location, Map, new BondedStatus(0, Serial, 0)); Effects.SendPacket(Location, Map, new BondedStatus(Serial, false));
SendIncomingPacket(); SendIncomingPacket();
SendIncomingPacket(); SendIncomingPacket();

View file

@ -14,8 +14,8 @@
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
<LangVersion>8.0</LangVersion> <LangVersion>8.0</LangVersion>
<OutDir>$(SolutionDir)\Distribution\Assemblies</OutDir> <!-- <OutDir>$(SolutionDir)\Distribution\Assemblies</OutDir>-->
<OutputPath>$(SolutionDir)\Distribution\Assemblies</OutputPath> <!-- <OutputPath>$(SolutionDir)\Distribution\Assemblies</OutputPath>-->
<PublishDir>$(SolutionDir)\Distribution\Assemblies</PublishDir> <PublishDir>$(SolutionDir)\Distribution\Assemblies</PublishDir>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Configurations>Debug;Release;Analyze</Configurations> <Configurations>Debug;Release;Analyze</Configurations>

View file

@ -15,7 +15,7 @@ namespace Server.Tests
return builder.ToString(); return builder.ToString();
} }
public static void Equal(ReadOnlySpan<byte> expected, ReadOnlySpan<byte> actual) => public static void Equal(ReadOnlySpan<byte> actual, ReadOnlySpan<byte> expected) =>
Xunit.Assert.True( Xunit.Assert.True(
MemoryExtensions.SequenceEqual(expected, actual), MemoryExtensions.SequenceEqual(expected, actual),
$"Expected does not match actual.\nExpected:\t{SpanToString(expected)}\nActual:\t\t{SpanToString(actual)}" $"Expected does not match actual.\nExpected:\t{SpanToString(expected)}\nActual:\t\t{SpanToString(actual)}"

View file

@ -11,7 +11,8 @@ namespace Server.Tests.Network.Packets
{ {
Span<byte> data = new CancelArrow().Compile(); Span<byte> data = new CancelArrow().Compile();
Span<byte> expectedData = stackalloc byte[] { Span<byte> expectedData = stackalloc byte[]
{
0xBA, // Packet 0xBA, // Packet
0x00, // Command 0x00, // Command
0xFF, 0xFF, // X 0xFF, 0xFF, // X
@ -29,7 +30,8 @@ namespace Server.Tests.Network.Packets
{ {
Span<byte> data = new SetArrow(x, y).Compile(); Span<byte> data = new SetArrow(x, y).Compile();
Span<byte> expectedData = stackalloc byte[] { Span<byte> expectedData = stackalloc byte[]
{
0xBA, // Packet 0xBA, // Packet
0x01, // Command 0x01, // Command
0x00, 0x00, // X 0x00, 0x00, // X
@ -50,7 +52,8 @@ namespace Server.Tests.Network.Packets
{ {
Span<byte> data = new CancelArrowHS(x, y, 0x1).Compile(); Span<byte> data = new CancelArrowHS(x, y, 0x1).Compile();
Span<byte> expectedData = stackalloc byte[] { Span<byte> expectedData = stackalloc byte[]
{
0xBA, // Packet 0xBA, // Packet
0x00, // Command 0x00, // Command
0x00, 0x00, // X 0x00, 0x00, // X
@ -72,7 +75,8 @@ namespace Server.Tests.Network.Packets
{ {
Span<byte> data = new SetArrowHS(x, y, 0x1).Compile(); Span<byte> data = new SetArrowHS(x, y, 0x1).Compile();
Span<byte> expectedData = stackalloc byte[] { Span<byte> expectedData = stackalloc byte[]
{
0xBA, // Packet 0xBA, // Packet
0x01, // Command 0x01, // Command
0x00, 0x00, // X 0x00, 0x00, // X

View file

@ -6,19 +6,19 @@ namespace Server.Tests.Network.Packets
{ {
public class DamagePacketTests : IClassFixture<ServerFixture> public class DamagePacketTests : IClassFixture<ServerFixture>
{ {
private readonly Mobile mobile;
public DamagePacketTests(ServerFixture fixture) => mobile = fixture.fromMobile;
[Theory] [Theory]
[InlineData(10, 10)] [InlineData(10, 10)]
[InlineData(-5, 0)] [InlineData(-5, 0)]
[InlineData(1024, 0xFF)] [InlineData(1024, 0xFF)]
public void TestDamagePacketOld(int inputAmount, byte expectedAmount) public void TestDamagePacketOld(int inputAmount, byte expectedAmount)
{ {
Span<byte> data = new DamagePacketOld(mobile, inputAmount).Compile(); var m = new Mobile(0x1);
m.DefaultMobileInit();
Span<byte> expectedData = stackalloc byte[] { Span<byte> data = new DamagePacketOld(m, inputAmount).Compile();
Span<byte> expectedData = stackalloc byte[]
{
0xBF, // Packet 0xBF, // Packet
0x00, 0x0B, // Length 0x00, 0x0B, // Length
0x00, 0x22, // Sub-packet 0x00, 0x22, // Sub-packet
@ -27,7 +27,7 @@ namespace Server.Tests.Network.Packets
expectedAmount // Amount expectedAmount // Amount
}; };
mobile.Serial.CopyTo(expectedData.Slice(6, 4)); m.Serial.CopyTo(expectedData.Slice(6, 4));
AssertThat.Equal(data, expectedData); AssertThat.Equal(data, expectedData);
} }
@ -38,15 +38,19 @@ namespace Server.Tests.Network.Packets
[InlineData(100000, 0xFFFF)] [InlineData(100000, 0xFFFF)]
public void TestDamagePacket(int inputAmount, ushort expectedAmount) public void TestDamagePacket(int inputAmount, ushort expectedAmount)
{ {
Span<byte> data = new DamagePacket(mobile, inputAmount).Compile(); var m = new Mobile(0x1);
m.DefaultMobileInit();
Span<byte> expectedData = stackalloc byte[] { Span<byte> data = new DamagePacket(m, inputAmount).Compile();
Span<byte> expectedData = stackalloc byte[]
{
0x0B, // Packet 0x0B, // Packet
0x00, 0x00, 0x00, 0x00, // Mobile Serial 0x00, 0x00, 0x00, 0x00, // Mobile Serial
0x00, 0x00 // Amount 0x00, 0x00 // Amount
}; };
mobile.Serial.CopyTo(expectedData.Slice(1, 4)); m.Serial.CopyTo(expectedData.Slice(1, 4));
expectedAmount.CopyTo(expectedData.Slice(5, 2)); expectedAmount.CopyTo(expectedData.Slice(5, 2));
AssertThat.Equal(data, expectedData); AssertThat.Equal(data, expectedData);

View file

@ -0,0 +1,32 @@
using System;
using Server.HuePickers;
using Server.Network;
using Xunit;
namespace Server.Tests.Network.Packets
{
public class DisplayHuePickerTests
{
[Fact]
public void TestDisplayHuePicker()
{
ushort itemID = 0xFF01;
var huePicker = new HuePicker(itemID);
Span<byte> data = new DisplayHuePicker(huePicker).Compile();
Span<byte> expectedData = stackalloc byte[]
{
0x95, // Packet ID
0x00, 0x00, 0x00, 0x00, // Hue Picker Serial
0x00, 0x00, // Nothing
0x00, 0x00 // Item ID
};
huePicker.Serial.CopyTo(expectedData.Slice(1, 4));
itemID.CopyTo(expectedData.Slice(7, 2));
AssertThat.Equal(data, expectedData);
}
}
}

View file

@ -11,7 +11,8 @@ namespace Server.Tests.Network.Packets
{ {
Span<byte> data = new MapPatches().Compile(); Span<byte> data = new MapPatches().Compile();
Span<byte> expectedData = stackalloc byte[] { Span<byte> expectedData = stackalloc byte[]
{
0xBF, // Packet 0xBF, // Packet
0x00, 0x29, // Length 0x00, 0x29, // Length
0x00, 0x18, // Sub-packet 0x00, 0x18, // Sub-packet
@ -28,5 +29,18 @@ namespace Server.Tests.Network.Packets
AssertThat.Equal(data, expectedData); AssertThat.Equal(data, expectedData);
} }
[Fact]
public void TestInvalidMapEnable()
{
Span<byte> data = new InvalidMapEnable().Compile();
Span<byte> expectedData = stackalloc byte[]
{
0xC6 // Packet ID
};
AssertThat.Equal(data, expectedData);
}
} }
} }

View file

@ -0,0 +1,219 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Server.ContextMenus;
using Server.Menus.ItemLists;
using Server.Menus.Questions;
using Server.Network;
using Xunit;
namespace Server.Tests.Network.Packets
{
internal class ContextMenuItem : Item
{
public override void GetContextMenuEntries(Mobile from, List<ContextMenuEntry> list)
{
base.GetContextMenuEntries(from, list);
list.Add(new ContextMenuEntry(500000));
list.Add(new ContextMenuEntry(500001));
list.Add(new ContextMenuEntry(500002));
}
public ContextMenuItem(Serial serial) : base(serial)
{
}
}
public class MenuPacketTests : IClassFixture<ServerFixture>
{
[Fact]
public void TestDisplayItemListMenu()
{
var menu = new ItemListMenu(
"Which item would you choose?",
new[]
{
new ItemListEntry("Item 1", 0x01),
new ItemListEntry("Item 2", 0x100),
new ItemListEntry("Item 3", 0x1000, 250)
}
);
string question = menu.Question?.Trim() ?? "";
int questionLength = Math.Min(255, question.Length);
int length = 11 + questionLength + menu.Entries.Sum(entry => 5 + entry.Name?.Trim().Length ?? 0);
Span<byte> data = new DisplayItemListMenu(menu).Compile();
Span<byte> expectedData = stackalloc byte[length];
int pos = 0;
expectedData[pos++] = 0x7C; // 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;
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);
}
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestDisplayQuestionMenu()
{
var menu = new QuestionMenu(
"Which option would you choose?",
new[]
{
"Option 1",
"Option 2",
"Option 3"
}
);
string question = menu.Question?.Trim() ?? "";
int questionLength = Math.Min(255, question.Length);
int length = 11 + questionLength + menu.Answers.Sum(answer => 5 + answer?.Trim().Length ?? 0);
Span<byte> data = new DisplayQuestionMenu(menu).Compile();
Span<byte> expectedData = stackalloc byte[length];
int pos = 0;
expectedData[pos++] = 0x7C; // 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;
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);
}
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestDisplayContextMenu()
{
var m = new Mobile(0x1);
m.DefaultMobileInit();
var item = new ContextMenuItem(Serial.LastItem + 1);
var menu = new ContextMenu(m, item);
Span<byte> data = new DisplayContextMenu(menu).Compile();
int length = 12 + menu.Entries.Length * 8;
Span<byte> expectedData = stackalloc byte[length];
int pos = 0;
expectedData[pos++] = 0xBF; // 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;
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
entry.Number.CopyTo(ref pos, expectedData);
((ushort)i).CopyTo(ref pos, expectedData);
var flags = entry.Flags;
var range = entry.Range;
if (range == -1)
range = 18;
if (!(entry.Enabled && menu.From.InRange(item.GetWorldLocation(), range)))
flags |= CMEFlags.Disabled;
((ushort)flags).CopyTo(ref pos, expectedData);
}
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestDisplayContextMenuOld()
{
var m = new Mobile(0x1);
m.DefaultMobileInit();
var item = new ContextMenuItem(Serial.LastItem + 1);
var menu = new ContextMenu(m, item);
Span<byte> data = new DisplayContextMenuOld(menu).Compile();
int length = 12 + menu.Entries.Sum(entry => 6 + ((entry.Color & 0xFFFF) != 0xFFFF ? 2 : 0));
Span<byte> expectedData = stackalloc byte[length];
int pos = 0;
expectedData[pos++] = 0xBF; // 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;
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
((ushort)i).CopyTo(ref pos, expectedData);
((ushort)(entry.Number - 3000000)).CopyTo(ref pos, expectedData);
var flags = entry.Flags;
var color = entry.Color & 0xFFFF;
if (color != 0xFFFF)
flags |= CMEFlags.Colored;
var range = entry.Range;
if (range == -1)
range = 18;
if (!(entry.Enabled && menu.From.InRange(item.GetWorldLocation(), range)))
flags |= CMEFlags.Disabled;
((ushort)flags).CopyTo(ref pos, expectedData);
if ((flags & CMEFlags.Colored) != 0)
((ushort)color).CopyTo(ref pos, expectedData);
}
AssertThat.Equal(data, expectedData);
}
}
}

View file

@ -7,25 +7,18 @@ namespace Server.Tests.Network.Packets
{ {
public class SecureTradePacketTests : IClassFixture<ServerFixture> public class SecureTradePacketTests : IClassFixture<ServerFixture>
{ {
private readonly Mobile to;
private readonly Container firstCont;
private readonly Container secondCont;
private readonly Item itemInFirstCont;
public SecureTradePacketTests(ServerFixture fixture)
{
to = fixture.toMobile;
firstCont = fixture.fromCont;
secondCont = fixture.toCont;
itemInFirstCont = fixture.itemInFromCont;
}
[Theory] [Theory]
[InlineData("short-name")] [InlineData("short-name")]
[InlineData("this is a really long name that is more than 30 characters, probably")] [InlineData("this is a really long name that is more than 30 characters, probably")]
public void TestDisplaySecureTrade(string name) public void TestDisplaySecureTrade(string name)
{ {
Span<byte> data = new DisplaySecureTrade(to, firstCont, secondCont, name).Compile(); var m = new Mobile(0x1);
m.DefaultMobileInit();
var firstCont = new Container(Serial.LastItem + 1);
var secondCont = new Container(Serial.LastItem + 2);
Span<byte> data = new DisplaySecureTrade(m, firstCont, secondCont, name).Compile();
Span<byte> expectedData = stackalloc byte[] Span<byte> expectedData = stackalloc byte[]
{ {
@ -42,7 +35,7 @@ namespace Server.Tests.Network.Packets
}; };
int pos = 4; int pos = 4;
to.Serial.CopyTo(ref pos, expectedData); m.Serial.CopyTo(ref pos, expectedData);
firstCont.Serial.CopyTo(ref pos, expectedData); firstCont.Serial.CopyTo(ref pos, expectedData);
secondCont.Serial.CopyTo(ref pos, expectedData); secondCont.Serial.CopyTo(ref pos, expectedData);
pos++; pos++;
@ -54,7 +47,9 @@ namespace Server.Tests.Network.Packets
[Fact] [Fact]
public void TestCloseSecureTrade() public void TestCloseSecureTrade()
{ {
Span<byte> data = new CloseSecureTrade(firstCont).Compile(); var cont = new Container(Serial.LastItem + 1);
Span<byte> data = new CloseSecureTrade(cont).Compile();
Span<byte> expectedData = stackalloc byte[] Span<byte> expectedData = stackalloc byte[]
{ {
@ -64,7 +59,7 @@ namespace Server.Tests.Network.Packets
0x00, 0x00, 0x00, 0x00 // Container Serial 0x00, 0x00, 0x00, 0x00 // Container Serial
}; };
firstCont.Serial.CopyTo(expectedData.Slice(4, 4)); cont.Serial.CopyTo(expectedData.Slice(4, 4));
AssertThat.Equal(data, expectedData); AssertThat.Equal(data, expectedData);
} }
@ -74,6 +69,9 @@ namespace Server.Tests.Network.Packets
[InlineData(false, true)] // Update second [InlineData(false, true)] // Update second
public void TestUpdateSecureTrade(bool first, bool second) public void TestUpdateSecureTrade(bool first, bool second)
{ {
var firstCont = new Container(Serial.LastItem + 1);
var secondCont = new Container(Serial.LastItem + 2);
Container cont = first ? firstCont : secondCont; Container cont = first ? firstCont : secondCont;
Span<byte> data = new UpdateSecureTrade(cont, first, second).Compile(); Span<byte> data = new UpdateSecureTrade(cont, first, second).Compile();
@ -97,7 +95,8 @@ namespace Server.Tests.Network.Packets
[InlineData(250000, 50000, TradeFlag.UpdateLedger)] [InlineData(250000, 50000, TradeFlag.UpdateLedger)]
public void TestUpdateGoldSecureTrade(int gold, int plat, TradeFlag flag) public void TestUpdateGoldSecureTrade(int gold, int plat, TradeFlag flag)
{ {
Span<byte> data = new UpdateSecureTrade(firstCont, flag, gold, plat).Compile(); var cont = new Container(Serial.LastItem + 1);
Span<byte> data = new UpdateSecureTrade(cont, flag, gold, plat).Compile();
Span<byte> expectedData = stackalloc byte[] Span<byte> expectedData = stackalloc byte[]
{ {
0x6F, // Packet ID 0x6F, // Packet ID
@ -109,7 +108,7 @@ namespace Server.Tests.Network.Packets
}; };
int pos = 4; int pos = 4;
firstCont.Serial.CopyTo(ref pos, expectedData); cont.Serial.CopyTo(ref pos, expectedData);
gold.CopyTo(ref pos, expectedData); gold.CopyTo(ref pos, expectedData);
plat.CopyTo(ref pos, expectedData); plat.CopyTo(ref pos, expectedData);
@ -119,7 +118,13 @@ namespace Server.Tests.Network.Packets
[Fact] [Fact]
public void TestSecureTradeEquip() public void TestSecureTradeEquip()
{ {
Span<byte> data = new SecureTradeEquip(itemInFirstCont, to).Compile(); var m = new Mobile(0x1);
m.DefaultMobileInit();
var cont = new Container(Serial.LastItem + 1);
var itemInCont = new Item(Serial.LastItem + 2) { Parent = cont };
Span<byte> data = new SecureTradeEquip(itemInCont, m).Compile();
Span<byte> expectedData = stackalloc byte[] Span<byte> expectedData = stackalloc byte[]
{ {
0x25, // Packet ID 0x25, // Packet ID
@ -134,14 +139,14 @@ namespace Server.Tests.Network.Packets
}; };
int pos = 1; int pos = 1;
itemInFirstCont.Serial.CopyTo(ref pos, expectedData); itemInCont.Serial.CopyTo(ref pos, expectedData);
((short)itemInFirstCont.ItemID).CopyTo(ref pos, expectedData); ((short)itemInCont.ItemID).CopyTo(ref pos, expectedData);
pos++; pos++; // expectedData[pos++] = 0x0;
((short)itemInFirstCont.Amount).CopyTo(ref pos, expectedData); ((short)itemInCont.Amount).CopyTo(ref pos, expectedData);
((short)itemInFirstCont.X).CopyTo(ref pos, expectedData); ((short)itemInCont.X).CopyTo(ref pos, expectedData);
((short)itemInFirstCont.Y).CopyTo(ref pos, expectedData); ((short)itemInCont.Y).CopyTo(ref pos, expectedData);
to.Serial.CopyTo(ref pos, expectedData); m.Serial.CopyTo(ref pos, expectedData);
((short)itemInFirstCont.Hue).CopyTo(ref pos, expectedData); ((short)itemInCont.Hue).CopyTo(ref pos, expectedData);
AssertThat.Equal(data, expectedData); AssertThat.Equal(data, expectedData);
} }
@ -149,7 +154,13 @@ namespace Server.Tests.Network.Packets
[Fact] [Fact]
public void TestSecureTradeEquip6017() public void TestSecureTradeEquip6017()
{ {
Span<byte> data = new SecureTradeEquip6017(itemInFirstCont, to).Compile(); var m = new Mobile(0x1);
m.DefaultMobileInit();
var cont = new Container(Serial.LastItem + 1);
var itemInCont = new Item(Serial.LastItem + 2) { Parent = cont };
Span<byte> data = new SecureTradeEquip6017(itemInCont, m).Compile();
Span<byte> expectedData = stackalloc byte[] Span<byte> expectedData = stackalloc byte[]
{ {
0x25, // Packet ID 0x25, // Packet ID
@ -165,15 +176,15 @@ namespace Server.Tests.Network.Packets
}; };
int pos = 1; int pos = 1;
itemInFirstCont.Serial.CopyTo(ref pos, expectedData); itemInCont.Serial.CopyTo(ref pos, expectedData);
((short)itemInFirstCont.ItemID).CopyTo(ref pos, expectedData); ((short)itemInCont.ItemID).CopyTo(ref pos, expectedData);
pos++; pos++;
((short)itemInFirstCont.Amount).CopyTo(ref pos, expectedData); ((short)itemInCont.Amount).CopyTo(ref pos, expectedData);
((short)itemInFirstCont.X).CopyTo(ref pos, expectedData); ((short)itemInCont.X).CopyTo(ref pos, expectedData);
((short)itemInFirstCont.Y).CopyTo(ref pos, expectedData); ((short)itemInCont.Y).CopyTo(ref pos, expectedData);
pos++; pos++;
to.Serial.CopyTo(ref pos, expectedData); m.Serial.CopyTo(ref pos, expectedData);
((short)itemInFirstCont.Hue).CopyTo(ref pos, expectedData); ((short)itemInCont.Hue).CopyTo(ref pos, expectedData);
AssertThat.Equal(data, expectedData); AssertThat.Equal(data, expectedData);
} }

View file

@ -0,0 +1,95 @@
using System;
using Server.Network;
using Xunit;
namespace Server.Tests.Network.Packets
{
public class TestEquipmentPackets : IClassFixture<ServerFixture>
{
[Fact]
public void TestDisplayEquipmentInfo()
{
var m = new Mobile(0x1);
m.DefaultMobileInit();
var item = new Item(Serial.LastItem + 1);
var info = new EquipmentInfo(
500000,
m,
false,
new []
{
new EquipInfoAttribute(500001, 1),
new EquipInfoAttribute(500002, 2),
new EquipInfoAttribute(500002, 3)
}
);
Span<byte> data = new DisplayEquipmentInfo(item, info).Compile();
var attrs = info.Attributes;
int length = 17 + (info.Unidentified ? 4 : 0) + attrs.Length * 6;
if (info.Crafter != null) length += 6 + (info.Crafter.Name?.Length ?? 0);
Span<byte> expectedData = stackalloc byte[length];
int pos = 0;
expectedData[pos++] = 0xBF; // Packet ID
((ushort)length).CopyTo(ref pos, expectedData); // Length
((ushort)0x10).CopyTo(ref pos, expectedData); // Subcommand
item.Serial.CopyTo(ref pos, expectedData);
info.Number.CopyTo(ref pos, expectedData);
if (info.Crafter != null)
{
var name = info.Crafter.Name ?? "";
(-3).CopyTo(ref pos, expectedData);
((ushort)name.Length).CopyTo(ref pos, expectedData);
name.CopyASCIITo(ref pos, expectedData);
}
if (info.Unidentified) (-4).CopyTo(ref pos, expectedData);
for (var i = 0; i < attrs.Length; i++)
{
var attr = attrs[i];
attr.Number.CopyTo(ref pos, expectedData);
((ushort)attr.Charges).CopyTo(ref pos, expectedData);
}
(-1).CopyTo(ref pos, expectedData);
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestEquipUpdate()
{
var m = new Mobile(0x1);
m.DefaultMobileInit();
var item = new Item(Serial.LastItem + 1) { Parent = m };
Span<byte> data = new EquipUpdate(item).Compile();
Span<byte> expectedData = stackalloc byte[]
{
0x2E, // Packet ID
0x00, 0x00, 0x00, 0x00, // Serial
0x00, 0x00, // Item ID
0x00, (byte)item.Layer,
0x00, 0x00, 0x00, 0x00, // Parent Serial
0x00, 0x00, // Hue
};
item.Serial.CopyTo(expectedData.Slice(1, 4));
((ushort)item.ItemID).CopyTo(expectedData.Slice(5, 2));
item.Parent.Serial.CopyTo(expectedData.Slice(9, 4));
((ushort)item.Hue).CopyTo(expectedData.Slice(13, 2));
AssertThat.Equal(data, expectedData);
}
}
}

View file

@ -0,0 +1,37 @@
using System;
using Server.Network;
using Server.Prompts;
using Xunit;
namespace Server.Tests.Network.Packets
{
internal class TestPrompt : Prompt
{
}
public class UnicodePromptTests
{
[Fact]
public void TestUnicodePrompt()
{
var prompt = new TestPrompt();
Span<byte> data = new UnicodePrompt(prompt).Compile();
Span<byte> expectedData = stackalloc byte[]
{
0xC2, // Packet ID
0x00, 0x15, // Length
0x00, 0x00, 0x00, 0x00, // Serial
0x00, 0x00, 0x00, 0x00, // Prompt Serial
0x00, 0x00, 0x00, 0x00, // Unused
0x00, 0x00, 0x00, 0x00, // Unused
0x00, 0x00 // Unused
};
prompt.Serial.CopyTo(expectedData.Slice(3, 4));
prompt.Serial.CopyTo(expectedData.Slice(7, 4));
AssertThat.Equal(data, expectedData);
}
}
}

View file

@ -4,33 +4,23 @@ using System.Linq;
using Server.Items; using Server.Items;
using Server.Network; using Server.Network;
using Xunit; using Xunit;
using Xunit.Abstractions;
namespace Server.Tests.Network.Packets namespace Server.Tests.Network.Packets
{ {
public class VendorBuyPacketTests : IClassFixture<ServerFixture> public class VendorBuyPacketTests : IClassFixture<ServerFixture>
{ {
private readonly Mobile vendor; [Fact]
private readonly Container cont; public void TestVendorBuyContent()
private readonly List<BuyItemState> buyStates;
public VendorBuyPacketTests(ServerFixture fixture)
{ {
vendor = fixture.fromMobile; var cont = new Container(Serial.LastItem + 1);
cont = fixture.fromCont;
buyStates = new List<BuyItemState> var buyStates = new List<BuyItemState>
{ {
new BuyItemState("First Item", cont.Serial, Serial.NewItem, 10, 1, 0x01, 0), new BuyItemState("First Item", cont.Serial, Serial.NewItem, 10, 1, 0x01, 0),
new BuyItemState("Second Item", cont.Serial, Serial.NewItem, 20, 2, 0x0A, 0), new BuyItemState("Second Item", cont.Serial, Serial.NewItem, 20, 2, 0x0A, 0),
new BuyItemState("Third Item", cont.Serial, Serial.NewItem, 30, 10, 0x0F, 0) new BuyItemState("Third Item", cont.Serial, Serial.NewItem, 30, 10, 0x0F, 0)
}; };
}
[Fact]
public void TestVendorBuyContent()
{
Span<byte> data = new VendorBuyContent(buyStates).Compile(); Span<byte> data = new VendorBuyContent(buyStates).Compile();
Span<byte> expectedData = stackalloc byte[5 + buyStates.Count * 19]; Span<byte> expectedData = stackalloc byte[5 + buyStates.Count * 19];
@ -62,6 +52,15 @@ namespace Server.Tests.Network.Packets
[Fact] [Fact]
public void TestVendorBuyContent6017() public void TestVendorBuyContent6017()
{ {
var cont = new Container(Serial.LastItem + 1);
var buyStates = new List<BuyItemState>
{
new BuyItemState("First Item", cont.Serial, Serial.NewItem, 10, 1, 0x01, 0),
new BuyItemState("Second Item", cont.Serial, Serial.NewItem, 20, 2, 0x0A, 0),
new BuyItemState("Third Item", cont.Serial, Serial.NewItem, 30, 10, 0x0F, 0)
};
Span<byte> data = new VendorBuyContent6017(buyStates).Compile(); Span<byte> data = new VendorBuyContent6017(buyStates).Compile();
Span<byte> expectedData = stackalloc byte[5 + buyStates.Count * 20]; Span<byte> expectedData = stackalloc byte[5 + buyStates.Count * 20];
@ -94,6 +93,9 @@ namespace Server.Tests.Network.Packets
[Fact] [Fact]
public void TestDisplayBuyList() public void TestDisplayBuyList()
{ {
var vendor = new Mobile(0x1);
vendor.DefaultMobileInit();
Span<byte> data = new DisplayBuyList(vendor).Compile(); Span<byte> data = new DisplayBuyList(vendor).Compile();
Span<byte> expectedData = stackalloc byte[] Span<byte> expectedData = stackalloc byte[]
@ -111,6 +113,9 @@ namespace Server.Tests.Network.Packets
[Fact] [Fact]
public void TestDisplayBuyListHS() public void TestDisplayBuyListHS()
{ {
var vendor = new Mobile(0x1);
vendor.DefaultMobileInit();
Span<byte> data = new DisplayBuyListHS(vendor).Compile(); Span<byte> data = new DisplayBuyListHS(vendor).Compile();
Span<byte> expectedData = stackalloc byte[] Span<byte> expectedData = stackalloc byte[]
@ -129,6 +134,18 @@ namespace Server.Tests.Network.Packets
[Fact] [Fact]
public void TestVendorBuyList() public void TestVendorBuyList()
{ {
var vendor = new Mobile(0x1);
vendor.DefaultMobileInit();
var cont = new Container(Serial.LastItem + 1);
var buyStates = new List<BuyItemState>
{
new BuyItemState("First Item", cont.Serial, Serial.NewItem, 10, 1, 0x01, 0),
new BuyItemState("Second Item", cont.Serial, Serial.NewItem, 20, 2, 0x0A, 0),
new BuyItemState("Third Item", cont.Serial, Serial.NewItem, 30, 10, 0x0F, 0)
};
Span<byte> data = new VendorBuyList(vendor, buyStates).Compile(); Span<byte> data = new VendorBuyList(vendor, buyStates).Compile();
int length = 8 + 5 * 3 + buyStates.Sum(state => state.Description.Length + 1); int length = 8 + 5 * 3 + buyStates.Sum(state => state.Description.Length + 1);
@ -154,5 +171,26 @@ namespace Server.Tests.Network.Packets
AssertThat.Equal(data, expectedData); AssertThat.Equal(data, expectedData);
} }
[Fact]
public void TestEndVendorBuy()
{
var vendor = new Mobile(0x1);
vendor.DefaultMobileInit();
Span<byte> data = new EndVendorBuy(vendor).Compile();
Span<byte> expectedData = stackalloc byte[]
{
0x3B, // Packet ID
0x00, 0x08, // Length
0x00, 0x00, 0x00, 0x00, // Vendor Serial
0x00
};
vendor.Serial.CopyTo(expectedData.Slice(3, 4));
AssertThat.Equal(data, expectedData);
}
} }
} }

View file

@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Server.Network;
using Xunit;
namespace Server.Tests.Network.Packets
{
public class VendorSellPacketTests : IClassFixture<ServerFixture>
{
[Fact]
public void TestVendorSellList()
{
var vendor = new Mobile(0x1);
vendor.DefaultMobileInit();
var item1 = new Item(Serial.LastItem + 1);
var item2 = new Item(Serial.LastItem + 2) { Name = "Second Item" };
var item3 = new Item(Serial.LastItem + 3);
var sellStates = new List<SellItemState>
{
new SellItemState(item1, 100, "Item 1"),
new SellItemState(item2, 100000, "Item 2"),
new SellItemState(item3, 1, "Item 3")
};
Span<byte> data = new VendorSellList(vendor, sellStates).Compile();
int length = 9 + 14 * 3 + sellStates.Sum(state =>
(string.IsNullOrWhiteSpace(state.Item.Name) ? state.Name ?? "" : state.Item.Name.Trim()).Length
);
Span<byte> expectedData = stackalloc byte[length];
int pos = 0;
expectedData[pos++] = 0x9E; // Packet ID
((ushort)length).CopyTo(ref pos, expectedData);
vendor.Serial.CopyTo(ref pos, expectedData);
((ushort)sellStates.Count).CopyTo(ref pos, expectedData);
for (int i = 0; i < sellStates.Count; i++)
{
SellItemState state = sellStates[i];
state.Item.Serial.CopyTo(ref pos, expectedData);
((ushort)state.Item.ItemID).CopyTo(ref pos, expectedData);
((ushort)state.Item.Hue).CopyTo(ref pos, expectedData);
((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);
}
AssertThat.Equal(data, expectedData);
}
[Fact]
public void TestEndVendorSell()
{
var vendor = new Mobile(0x1);
vendor.DefaultMobileInit();
Span<byte> data = new EndVendorBuy(vendor).Compile();
Span<byte> expectedData = stackalloc byte[]
{
0x3B, // Packet ID
0x00, 0x08, // Length
0x00, 0x00, 0x00, 0x00, // Vendor Serial
0x00
};
vendor.Serial.CopyTo(expectedData.Slice(3, 4));
AssertThat.Equal(data, expectedData);
}
}
}

View file

@ -6,11 +6,6 @@ namespace Server.Tests
{ {
public class ServerFixture : IDisposable public class ServerFixture : IDisposable
{ {
private static Mobile m_FromMobile;
private static Mobile m_ToMobile;
private static Container m_FromCont;
private static Container m_ToCont;
private static Item m_ItemInFromCont;
// Global setup // Global setup
static ServerFixture() static ServerFixture()
@ -23,24 +18,8 @@ namespace Server.Tests
// Load the world // Load the world
World.Load(); World.Load();
m_FromMobile = new Mobile(Serial.NewMobile);
m_FromMobile.DefaultMobileInit();
m_ToMobile = new Mobile(Serial.NewMobile);
m_ToMobile.DefaultMobileInit();
m_FromCont = new Container(Serial.NewItem);
m_ToCont = new Container(Serial.NewItem);
m_ItemInFromCont = new Item(Serial.NewItem) { Parent = m_FromCont };
} }
public Mobile fromMobile => m_FromMobile;
public Mobile toMobile => m_ToMobile;
public Container fromCont => m_FromCont;
public Container toCont => m_ToCont;
public Item itemInFromCont => m_ItemInFromCont;
public void Dispose() public void Dispose()
{ {
} }

View file

@ -19,6 +19,7 @@
***************************************************************************/ ***************************************************************************/
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace Server.ContextMenus namespace Server.ContextMenus
{ {
@ -40,7 +41,7 @@ namespace Server.ContextMenus
/// The <see cref="Mobile" /> or <see cref="Item" /> for which this ContextMenu is on. /// The <see cref="Mobile" /> or <see cref="Item" /> for which this ContextMenu is on.
/// <seealso cref="Target" /> /// <seealso cref="Target" />
/// </param> /// </param>
public ContextMenu(Mobile from, object target) public ContextMenu(Mobile from, IEntity target)
{ {
From = from; From = from;
Target = target; Target = target;
@ -52,8 +53,6 @@ namespace Server.ContextMenus
else if (target is Item item) else if (target is Item item)
item.GetContextMenuEntries(from, list); item.GetContextMenuEntries(from, list);
// m_Entries = (ContextMenuEntry[])list.ToArray( typeof( ContextMenuEntry ) );
Entries = list.ToArray(); Entries = list.ToArray();
for (var i = 0; i < Entries.Length; ++i) for (var i = 0; i < Entries.Length; ++i)
@ -68,7 +67,7 @@ namespace Server.ContextMenus
/// <summary> /// <summary>
/// Gets an object of the <see cref="Mobile" /> or <see cref="Item" /> for which this ContextMenu is on. /// Gets an object of the <see cref="Mobile" /> or <see cref="Item" /> for which this ContextMenu is on.
/// </summary> /// </summary>
public object Target { get; } public IEntity Target { get; }
/// <summary> /// <summary>
/// Gets the list of <see cref="ContextMenuEntry">entries</see> contained in this ContextMenu. /// Gets the list of <see cref="ContextMenuEntry">entries</see> contained in this ContextMenu.
@ -78,16 +77,7 @@ namespace Server.ContextMenus
/// <summary> /// <summary>
/// Returns true if this ContextMenu requires packet version 2. /// Returns true if this ContextMenu requires packet version 2.
/// </summary> /// </summary>
public bool RequiresNewPacket public bool RequiresNewPacket =>
{ Entries.Any(t => t.Number < 3000000 || t.Number > 3032767);
get
{
for (var i = 0; i < Entries.Length; ++i)
if (Entries[i].Number < 3000000 || Entries[i].Number > 3032767)
return true;
return false;
}
}
} }
} }

View file

@ -889,7 +889,7 @@ namespace Server
++m_ChangingCombatant; ++m_ChangingCombatant;
m_Combatant = value; m_Combatant = value;
if ((m_Combatant != null && !CanBeHarmful(m_Combatant, false)) || if (m_Combatant != null && !CanBeHarmful(m_Combatant, false) ||
!Region.OnCombatantChange(this, old, m_Combatant)) !Region.OnCombatantChange(this, old, m_Combatant))
{ {
m_Combatant = old; m_Combatant = old;
@ -2519,7 +2519,7 @@ namespace Server
if (m.IsDeadBondedPet) if (m.IsDeadBondedPet)
{ {
deadPacket ??= Packet.Acquire(new BondedStatus(0, m.Serial, 1)); deadPacket ??= Packet.Acquire(new BondedStatus(m.Serial, true));
state.Send(deadPacket); state.Send(deadPacket);
} }
@ -6231,7 +6231,7 @@ namespace Server
} }
if (m.IsDeadBondedPet) if (m.IsDeadBondedPet)
ns.Send(new BondedStatus(0, m.Serial, 1)); ns.Send(new BondedStatus(m.Serial, true));
if (ObjectPropertyList.Enabled) ns.Send(m.OPLPacket); if (ObjectPropertyList.Enabled) ns.Send(m.OPLPacket);
} }
@ -6356,7 +6356,7 @@ namespace Server
state.Send(MobileIncoming.Create(state, state.Mobile, this)); state.Send(MobileIncoming.Create(state, state.Mobile, this));
if (IsDeadBondedPet) if (IsDeadBondedPet)
state.Send(new BondedStatus(0, Serial, 1)); state.Send(new BondedStatus(Serial, true));
if (ObjectPropertyList.Enabled) state.Send(OPLPacket); if (ObjectPropertyList.Enabled) state.Send(OPLPacket);
} }
@ -6594,7 +6594,7 @@ namespace Server
} }
if (IsDeadBondedPet) if (IsDeadBondedPet)
m.m_NetState.Send(new BondedStatus(0, Serial, 1)); m.m_NetState.Send(new BondedStatus(Serial, true));
if (ObjectPropertyList.Enabled) m.m_NetState.Send(OPLPacket); if (ObjectPropertyList.Enabled) m.m_NetState.Send(OPLPacket);
} }
@ -6614,7 +6614,7 @@ namespace Server
} }
if (m.IsDeadBondedPet) if (m.IsDeadBondedPet)
ourState.Send(new BondedStatus(0, m.Serial, 1)); ourState.Send(new BondedStatus(m.Serial, true));
if (ObjectPropertyList.Enabled) ourState.Send(m.OPLPacket); if (ObjectPropertyList.Enabled) ourState.Send(m.OPLPacket);
} }
@ -6642,7 +6642,7 @@ namespace Server
} }
if (IsDeadBondedPet) if (IsDeadBondedPet)
ns.Send(new BondedStatus(0, Serial, 1)); ns.Send(new BondedStatus(Serial, true));
if (ObjectPropertyList.Enabled) ns.Send(OPLPacket); if (ObjectPropertyList.Enabled) ns.Send(OPLPacket);
} }
@ -6712,7 +6712,7 @@ namespace Server
} }
if (IsDeadBondedPet) if (IsDeadBondedPet)
state.Send(new BondedStatus(0, Serial, 1)); state.Send(new BondedStatus(Serial, true));
if (ObjectPropertyList.Enabled) state.Send(OPLPacket); if (ObjectPropertyList.Enabled) state.Send(OPLPacket);
} }

View file

@ -636,7 +636,7 @@ namespace Server.Network
public static void HuePickerResponse(NetState state, PacketReader pvSrc) public static void HuePickerResponse(NetState state, PacketReader pvSrc)
{ {
var serial = pvSrc.ReadUInt32(); var serial = pvSrc.ReadUInt32();
int value = pvSrc.ReadInt16(); _ = pvSrc.ReadInt16(); // Item ID
var hue = pvSrc.ReadInt16() & 0x3FFF; var hue = pvSrc.ReadInt16() & 0x3FFF;
hue = Utility.ClipDyedHue(hue); hue = Utility.ClipDyedHue(hue);

View file

@ -29,7 +29,6 @@ using Server.Accounting;
using Server.Compression; using Server.Compression;
using Server.ContextMenus; using Server.ContextMenus;
using Server.Gumps; using Server.Gumps;
using Server.HuePickers;
using Server.Items; using Server.Items;
using Server.Menus; using Server.Menus;
using Server.Menus.ItemLists; using Server.Menus.ItemLists;
@ -58,474 +57,6 @@ namespace Server.Network
Inspecific = 5 Inspecific = 5
} }
public sealed class VendorSellList : Packet
{
public VendorSellList(Mobile shopkeeper, ICollection<SellItemState> sis) : base(0x9E)
{
EnsureCapacity(256);
Stream.Write(shopkeeper.Serial);
Stream.Write((ushort)sis.Count);
foreach (var state in sis)
{
Stream.Write(state.Item.Serial);
Stream.Write((ushort)state.Item.ItemID);
Stream.Write((ushort)state.Item.Hue);
Stream.Write((ushort)state.Item.Amount);
Stream.Write((ushort)state.Price);
var name = state.Item.Name?.Trim();
if (string.IsNullOrWhiteSpace(name))
name = state.Name ?? "";
Stream.Write((ushort)name.Length);
Stream.WriteAsciiFixed(name, (ushort)name.Length);
}
}
}
public sealed class EndVendorSell : Packet
{
public EndVendorSell(Mobile vendor) : base(0x3B, 8)
{
Stream.Write((ushort)8); // length
Stream.Write(vendor.Serial);
Stream.Write((byte)0);
}
}
public sealed class EndVendorBuy : Packet
{
public EndVendorBuy(Mobile vendor) : base(0x3B, 8)
{
Stream.Write((ushort)8); // length
Stream.Write(vendor.Serial);
Stream.Write((byte)0);
}
}
public sealed class DeathAnimation : Packet
{
public DeathAnimation(Mobile killed, Item corpse) : base(0xAF, 13)
{
Stream.Write(killed.Serial);
Stream.Write(corpse?.Serial ?? Serial.Zero);
Stream.Write(0);
}
}
public sealed class StatLockInfo : Packet
{
public StatLockInfo(Mobile m) : base(0xBF)
{
EnsureCapacity(12);
Stream.Write((short)0x19);
Stream.Write((byte)2);
Stream.Write(m.Serial);
Stream.Write((byte)0);
var lockBits = ((int)m.StrLock << 4) | ((int)m.DexLock << 2) | (int)m.IntLock;
Stream.Write((byte)lockBits);
}
}
public class EquipInfoAttribute
{
public EquipInfoAttribute(int number, int charges = -1)
{
Number = number;
Charges = charges;
}
public int Number { get; }
public int Charges { get; }
}
public class EquipmentInfo
{
public EquipmentInfo(int number, Mobile crafter, bool unidentified, EquipInfoAttribute[] attributes)
{
Number = number;
Crafter = crafter;
Unidentified = unidentified;
Attributes = attributes;
}
public int Number { get; }
public Mobile Crafter { get; }
public bool Unidentified { get; }
public EquipInfoAttribute[] Attributes { get; }
}
public sealed class DisplayEquipmentInfo : Packet
{
public DisplayEquipmentInfo(Item item, EquipmentInfo info) : base(0xBF)
{
var attrs = info.Attributes;
EnsureCapacity(17 + (info.Crafter?.Name.Length ?? 0) +
(info.Unidentified ? 4 : 0) + attrs.Length * 6);
Stream.Write((short)0x10);
Stream.Write(item.Serial);
Stream.Write(info.Number);
if (info.Crafter != null)
{
var name = info.Crafter.Name;
Stream.Write(-3);
if (name == null)
{
Stream.Write((ushort)0);
}
else
{
var length = name.Length;
Stream.Write((ushort)length);
Stream.WriteAsciiFixed(name, length);
}
}
if (info.Unidentified) Stream.Write(-4);
for (var i = 0; i < attrs.Length; ++i)
{
Stream.Write(attrs[i].Number);
Stream.Write((short)attrs[i].Charges);
}
Stream.Write(-1);
}
}
public sealed class ChangeUpdateRange : Packet
{
private static readonly ChangeUpdateRange[] m_Cache = new ChangeUpdateRange[0x100];
public ChangeUpdateRange(int range) : base(0xC8, 2)
{
Stream.Write((byte)range);
}
public static ChangeUpdateRange Instantiate(int range)
{
var idx = (byte)range;
var p = m_Cache[idx];
if (p == null)
{
m_Cache[idx] = p = new ChangeUpdateRange(range);
p.SetStatic();
}
return p;
}
}
public sealed class ChangeCombatant : Packet
{
public ChangeCombatant(Mobile combatant) : base(0xAA, 5)
{
Stream.Write(combatant?.Serial ?? Serial.Zero);
}
}
public sealed class DisplayHuePicker : Packet
{
public DisplayHuePicker(HuePicker huePicker) : base(0x95, 9)
{
Stream.Write(huePicker.Serial);
Stream.Write((short)0);
Stream.Write((short)huePicker.ItemID);
}
}
public sealed class TripTimeResponse : Packet
{
public TripTimeResponse(int unk) : base(0xC9, 6)
{
Stream.Write((byte)unk);
Stream.Write(Environment.TickCount);
}
}
public sealed class UTripTimeResponse : Packet
{
public UTripTimeResponse(int unk) : base(0xCA, 6)
{
Stream.Write((byte)unk);
Stream.Write(Environment.TickCount);
}
}
public sealed class UnicodePrompt : Packet
{
public UnicodePrompt(Prompt prompt) : base(0xC2)
{
EnsureCapacity(21);
Stream.Write(prompt.Serial);
Stream.Write(prompt.Serial);
Stream.Write(0);
Stream.Write(0);
Stream.Write((short)0);
}
}
public sealed class ChangeCharacter : Packet
{
public ChangeCharacter(IAccount a) : base(0x81)
{
EnsureCapacity(305);
var count = 0;
for (var i = 0; i < a.Length; ++i)
if (a[i] != null)
++count;
Stream.Write((byte)count);
Stream.Write((byte)0);
for (var i = 0; i < a.Length; ++i)
if (a[i] != null)
{
var name = a[i].Name;
if (name == null)
name = "-null-";
else if ((name = name.Trim()).Length == 0)
name = "-empty-";
Stream.WriteAsciiFixed(name, 30);
Stream.Fill(30); // password
}
else
{
Stream.Fill(60);
}
}
}
public sealed class DeathStatus : Packet
{
public static readonly Packet Dead = SetStatic(new DeathStatus(true));
public static readonly Packet Alive = SetStatic(new DeathStatus(false));
public DeathStatus(bool dead) : base(0x2C, 2)
{
Stream.Write((byte)(dead ? 0 : 2));
}
public static Packet Instantiate(bool dead) => dead ? Dead : Alive;
}
public sealed class SpeedControl : Packet
{
public static readonly Packet WalkSpeed = SetStatic(new SpeedControl(2));
public static readonly Packet MountSpeed = SetStatic(new SpeedControl(1));
public static readonly Packet Disable = SetStatic(new SpeedControl(0));
public SpeedControl(int speedControl)
: base(0xBF)
{
EnsureCapacity(3);
Stream.Write((short)0x26);
Stream.Write((byte)speedControl);
}
}
public sealed class InvalidMapEnable : Packet
{
public InvalidMapEnable() : base(0xC6, 1)
{
}
}
public sealed class BondedStatus : Packet
{
public BondedStatus(int val1, Serial serial, int val2) : base(0xBF)
{
EnsureCapacity(11);
Stream.Write((short)0x19);
Stream.Write((byte)val1);
Stream.Write(serial);
Stream.Write((byte)val2);
}
}
public sealed class ToggleSpecialAbility : Packet
{
public ToggleSpecialAbility(int abilityID, bool active)
: base(0xBF)
{
EnsureCapacity(7);
Stream.Write((short)0x25);
Stream.Write((short)abilityID);
Stream.Write(active);
}
}
public sealed class DisplayItemListMenu : Packet
{
public DisplayItemListMenu(ItemListMenu menu) : base(0x7C)
{
EnsureCapacity(256);
Stream.Write(((IMenu)menu).Serial);
Stream.Write((short)0);
var question = menu.Question;
if (question == null)
{
Stream.Write((byte)0);
}
else
{
var questionLength = question.Length;
Stream.Write((byte)questionLength);
Stream.WriteAsciiFixed(question, questionLength);
}
var entries = menu.Entries;
int entriesLength = (byte)entries.Length;
Stream.Write((byte)entriesLength);
for (var i = 0; i < entriesLength; ++i)
{
var e = entries[i];
Stream.Write((ushort)e.ItemID);
Stream.Write((short)e.Hue);
var name = e.Name;
if (name == null)
{
Stream.Write((byte)0);
}
else
{
var nameLength = name.Length;
Stream.Write((byte)nameLength);
Stream.WriteAsciiFixed(name, nameLength);
}
}
}
}
public sealed class DisplayQuestionMenu : Packet
{
public DisplayQuestionMenu(QuestionMenu menu) : base(0x7C)
{
EnsureCapacity(256);
Stream.Write(((IMenu)menu).Serial);
Stream.Write((short)0);
var question = menu.Question;
if (question == null)
{
Stream.Write((byte)0);
}
else
{
var questionLength = question.Length;
Stream.Write((byte)questionLength);
Stream.WriteAsciiFixed(question, questionLength);
}
var answers = menu.Answers;
int answersLength = (byte)answers.Length;
Stream.Write((byte)answersLength);
for (var i = 0; i < answersLength; ++i)
{
Stream.Write(0);
var answer = answers[i];
if (answer == null)
{
Stream.Write((byte)0);
}
else
{
var answerLength = answer.Length;
Stream.Write((byte)answerLength);
Stream.WriteAsciiFixed(answer, answerLength);
}
}
}
}
public sealed class GlobalLightLevel : Packet
{
private static readonly GlobalLightLevel[] m_Cache = new GlobalLightLevel[0x100];
public GlobalLightLevel(int level) : base(0x4F, 2)
{
Stream.Write((sbyte)level);
}
public static GlobalLightLevel Instantiate(int level)
{
var lvl = (byte)level;
var p = m_Cache[lvl];
if (p == null)
{
m_Cache[lvl] = p = new GlobalLightLevel(level);
p.SetStatic();
}
return p;
}
}
public sealed class PersonalLightLevel : Packet
{
public PersonalLightLevel(Mobile m) : this(m, m.LightLevel)
{
}
public PersonalLightLevel(Mobile m, int level) : base(0x4E, 6)
{
Stream.Write(m.Serial);
Stream.Write((sbyte)level);
}
}
public sealed class PersonalLightLevelZero : Packet
{
public PersonalLightLevelZero(Mobile m) : base(0x4E, 6)
{
Stream.Write(m.Serial);
Stream.Write((sbyte)0);
}
}
[Flags] [Flags]
public enum CMEFlags public enum CMEFlags
{ {
@ -536,112 +67,6 @@ namespace Server.Network
Colored = 0x20 Colored = 0x20
} }
public sealed class DisplayContextMenu : Packet
{
public DisplayContextMenu(ContextMenu menu) : base(0xBF)
{
var entries = menu.Entries;
int length = (byte)entries.Length;
EnsureCapacity(12 + length * 8);
Stream.Write((short)0x14);
Stream.Write((short)0x02);
var target = menu.Target as IEntity;
Stream.Write(target?.Serial ?? Serial.MinusOne);
Stream.Write((byte)length);
Point3D p;
if (target is Mobile)
p = target.Location;
else if (target is Item item)
p = item.GetWorldLocation();
else
p = Point3D.Zero;
for (var i = 0; i < length; ++i)
{
var e = entries[i];
Stream.Write(e.Number);
Stream.Write((short)i);
var range = e.Range;
if (range == -1)
range = 18;
var flags = e.Enabled && menu.From.InRange(p, range) ? CMEFlags.None : CMEFlags.Disabled;
flags |= e.Flags;
Stream.Write((short)flags);
}
}
}
public sealed class DisplayContextMenuOld : Packet
{
public DisplayContextMenuOld(ContextMenu menu) : base(0xBF)
{
var entries = menu.Entries;
int length = (byte)entries.Length;
EnsureCapacity(12 + length * 8);
Stream.Write((short)0x14);
Stream.Write((short)0x01);
var target = menu.Target as IEntity;
Stream.Write(target?.Serial ?? Serial.MinusOne);
Stream.Write((byte)length);
Point3D p;
if (target is Mobile)
p = target.Location;
else if (target is Item item)
p = item.GetWorldLocation();
else
p = Point3D.Zero;
for (var i = 0; i < length; ++i)
{
var e = entries[i];
Stream.Write((short)i);
Stream.Write((ushort)(e.Number - 3000000));
var range = e.Range;
if (range == -1)
range = 18;
var flags = e.Enabled && menu.From.InRange(p, range) ? CMEFlags.None : CMEFlags.Disabled;
var color = e.Color & 0xFFFF;
if (color != 0xFFFF)
flags |= CMEFlags.Colored;
flags |= e.Flags;
Stream.Write((short)flags);
if ((flags & CMEFlags.Colored) != 0)
Stream.Write((short)color);
}
}
}
public sealed class DisplayProfile : Packet public sealed class DisplayProfile : Packet
{ {
public DisplayProfile(bool realSerial, Mobile m, string header, string body, string footer) : base(0xB8) public DisplayProfile(bool realSerial, Mobile m, string header, string body, string footer) : base(0xB8)
@ -671,38 +96,6 @@ namespace Server.Network
} }
} }
public sealed class EquipUpdate : Packet
{
public EquipUpdate(Item item) : base(0x2E, 15)
{
Serial parentSerial;
var parent = item.Parent as Mobile;
if (parent != null)
{
parentSerial = parent.Serial;
}
else
{
Console.WriteLine("Warning: EquipUpdate on item with !(parent is Mobile)");
parentSerial = Serial.Zero;
}
var hue = item.Hue;
if (parent?.SolidHueOverride >= 0)
hue = parent.SolidHueOverride;
Stream.Write(item.Serial);
Stream.Write((short)item.ItemID);
Stream.Write((byte)0);
Stream.Write((byte)item.Layer);
Stream.Write(parentSerial);
Stream.Write((short)hue);
}
}
public sealed class WorldItem : Packet public sealed class WorldItem : Packet
{ {
public WorldItem(Item item) : base(0x1A) public WorldItem(Item item) : base(0x1A)
@ -909,80 +302,6 @@ namespace Server.Network
} }
} }
public sealed class UnkD3 : Packet
{
public UnkD3(Mobile beholder, Mobile beheld) : base(0xD3)
{
EnsureCapacity(256);
// int
// short
// short
// short
// byte
// byte
// short
// byte
// byte
// short
// short
// short
// while ( int != 0 )
// {
// short
// byte
// short
// }
Stream.Write(beheld.Serial);
Stream.Write((short)beheld.Body);
Stream.Write((short)beheld.X);
Stream.Write((short)beheld.Y);
Stream.Write((sbyte)beheld.Z);
Stream.Write((byte)beheld.Direction);
Stream.Write((ushort)beheld.Hue);
Stream.Write((byte)beheld.GetPacketFlags());
Stream.Write((byte)Notoriety.Compute(beholder, beheld));
Stream.Write((short)0);
Stream.Write((short)0);
Stream.Write((short)0);
Stream.Write(0);
}
}
public sealed class GQRequest : Packet
{
public GQRequest() : base(0xC3)
{
EnsureCapacity(256);
Stream.Write(1);
Stream.Write(2); // ID
Stream.Write(3); // Customer ? (this)
Stream.Write(4); // Customer this (?)
Stream.Write(0);
Stream.Write((short)0);
Stream.Write((short)6);
Stream.Write((byte)'r');
Stream.Write((byte)'e');
Stream.Write((byte)'g');
Stream.Write((byte)'i');
Stream.Write((byte)'o');
Stream.Write((byte)'n');
Stream.Write(7); // Call time in seconds
Stream.Write((short)2); // Map (0=fel,1=tram,2=ilsh)
Stream.Write(8); // X
Stream.Write(9); // Y
Stream.Write(10); // Z
Stream.Write(11); // Volume
Stream.Write(12); // Rank
Stream.Write(-1);
Stream.Write(1); // type
}
}
/// <summary> /// <summary>
/// Causes the client to walk in a given direction. It does not send a movement request. /// Causes the client to walk in a given direction. It does not send a movement request.
/// </summary> /// </summary>
@ -996,18 +315,6 @@ namespace Server.Network
} }
} }
/// <summary>
/// Displays a message "There are currently [count] available calls in the global queue.".
/// </summary>
public sealed class GQCount : Packet
{
public GQCount(int unk, int count) : base(0xCB, 7)
{
Stream.Write((short)unk);
Stream.Write(count);
}
}
/// <summary> /// <summary>
/// Asks the client for it's version /// Asks the client for it's version
/// </summary> /// </summary>
@ -1019,19 +326,6 @@ namespace Server.Network
} }
} }
/// <summary>
/// Asks the client for it's "assist version". (Perhaps for UOAssist?)
/// </summary>
public sealed class AssistVersionReq : Packet
{
public AssistVersionReq(int unk) : base(0xBE)
{
EnsureCapacity(7);
Stream.Write(unk);
}
}
public enum EffectType public enum EffectType
{ {
Moving = 0x00, Moving = 0x00,
@ -3444,70 +2738,6 @@ namespace Server.Network
} }
} }
[Flags]
public enum ThirdPartyFeature : ulong
{
FilterWeather = 1,
FilterLight = 1 << 1,
SmartTarget = 1 << 2,
RangedTarget = 1 << 3,
AutoOpenDoors = 1 << 4,
DequipOnCast = 1 << 5,
AutoPotionEquip = 1 << 6,
ProtectHeals = 1 << 7,
LoopedMacros = 1 << 8,
UseOnceAgent = 1 << 9,
RestockAgent = 1 << 10,
SellAgent = 1 << 11,
BuyAgent = 1 << 12,
PotionHotkeys = 1 << 13,
RandomTargets = 1 << 14,
ClosestTargets = 1 << 15, // All closest target hotkeys
OverheadHealth = 1 << 16, // Health and Mana/Stam messages shown over player's heads
AutolootAgent = 1 << 17,
BoneCutterAgent = 1 << 18,
AdvancedMacros = 1 << 19,
AutoRemount = 1 << 20,
AutoBandage = 1 << 21,
EnemyTargetShare = 1 << 22,
FilterSeason = 1 << 23,
SpellTargetShare = 1 << 24,
All = ulong.MaxValue
}
public static class FeatureProtection
{
public static ThirdPartyFeature DisabledFeatures { get; private set; } = 0;
public static void Disable(ThirdPartyFeature feature)
{
SetDisabled(feature, true);
}
public static void Enable(ThirdPartyFeature feature)
{
SetDisabled(feature, false);
}
public static void SetDisabled(ThirdPartyFeature feature, bool value)
{
if (value)
DisabledFeatures |= feature;
else
DisabledFeatures &= ~feature;
}
}
public sealed class CharacterList : Packet public sealed class CharacterList : Packet
{ {
// private static MD5CryptoServiceProvider m_MD5Provider; // private static MD5CryptoServiceProvider m_MD5Provider;
@ -3568,35 +2798,6 @@ namespace Server.Network
Stream.Write((int)(flags | AdditionalFlags)); // Additional Flags Stream.Write((int)(flags | AdditionalFlags)); // Additional Flags
Stream.Write((short)-1); Stream.Write((short)-1);
/*ThirdPartyFeature disabled = FeatureProtection.DisabledFeatures;
if (disabled != 0)
{
if (m_MD5Provider == null)
m_MD5Provider = new MD5CryptoServiceProvider();
m_Stream.UnderlyingStream.Flush();
byte[] hashCode = m_MD5Provider.ComputeHash(m_Stream.UnderlyingStream.GetBuffer(), 0,
(int)m_Stream.UnderlyingStream.Length);
byte[] buffer = new byte[28];
for (int i = 0; i < count; ++i)
{
Utility.RandomBytes(buffer);
m_Stream.Seek(35 + i * 60, SeekOrigin.Begin);
m_Stream.Write(buffer, 0, buffer.Length);
}
m_Stream.Seek(35, SeekOrigin.Begin);
m_Stream.Write((int)((long)disabled >> 32));
m_Stream.Write((int)disabled);
m_Stream.Seek(95, SeekOrigin.Begin);
m_Stream.Write(hashCode, 0, hashCode.Length);
}*/
} }
public static CharacterListFlags AdditionalFlags { get; set; } public static CharacterListFlags AdditionalFlags { get; set; }

View file

@ -0,0 +1,59 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: AccountPackets.cs - Created: 2020/05/08 - Updated: 2020/05/08 *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using Server.Accounting;
namespace Server.Network
{
public sealed class ChangeCharacter : Packet
{
public ChangeCharacter(IAccount a) : base(0x81)
{
EnsureCapacity(305);
var count = 0;
for (var i = 0; i < a.Length; ++i)
if (a[i] != null)
++count;
Stream.Write((byte)count);
Stream.Write((byte)0);
for (var i = 0; i < a.Length; ++i)
if (a[i] != null)
{
var name = a[i].Name;
if (name == null)
name = "-null-";
else if ((name = name.Trim()).Length == 0)
name = "-empty-";
Stream.WriteAsciiFixed(name, 30);
Stream.Fill(30); // password
}
else
{
Stream.Fill(60);
}
}
}
}

View file

@ -0,0 +1,35 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: DisplayHuePicker.cs *
* Created: 2020/05/08 - Updated: 2020/05/08 *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using Server.HuePickers;
namespace Server.Network
{
public sealed class DisplayHuePicker : Packet
{
public DisplayHuePicker(HuePicker huePicker) : base(0x95, 9)
{
Stream.Write(huePicker.Serial);
Stream.Write((short)0);
Stream.Write((short)huePicker.ItemID);
}
}
}

View file

@ -0,0 +1,131 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: EquipmentPackets.cs - Created: 2020/05/07 - Updated: 2020/05/07 * *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System;
namespace Server.Network
{
public class EquipInfoAttribute
{
public EquipInfoAttribute(int number, int charges = -1)
{
Number = number;
Charges = charges;
}
public int Number { get; }
public int Charges { get; }
}
public class EquipmentInfo
{
public EquipmentInfo(int number, Mobile crafter, bool unidentified, EquipInfoAttribute[] attributes)
{
Number = number;
Crafter = crafter;
Unidentified = unidentified;
Attributes = attributes;
}
public int Number { get; }
public Mobile Crafter { get; }
public bool Unidentified { get; }
public EquipInfoAttribute[] Attributes { get; }
}
public sealed class DisplayEquipmentInfo : Packet
{
public DisplayEquipmentInfo(Item item, EquipmentInfo info) : base(0xBF)
{
var attrs = info.Attributes;
EnsureCapacity(17 + (info.Crafter?.Name?.Length ?? 0) +
(info.Unidentified ? 4 : 0) + attrs.Length * 6);
Stream.Write((short)0x10);
Stream.Write(item.Serial);
Stream.Write(info.Number);
if (info.Crafter != null)
{
var name = info.Crafter.Name;
Stream.Write(-3);
if (name == null)
{
Stream.Write((ushort)0);
}
else
{
var length = name.Length;
Stream.Write((ushort)length);
Stream.WriteAsciiFixed(name, length);
}
}
if (info.Unidentified) Stream.Write(-4);
for (var i = 0; i < attrs.Length; ++i)
{
Stream.Write(attrs[i].Number);
Stream.Write((short)attrs[i].Charges);
}
Stream.Write(-1);
}
}
public sealed class EquipUpdate : Packet
{
public EquipUpdate(Item item) : base(0x2E, 15)
{
Serial parentSerial;
var parent = item.Parent as Mobile;
var hue = item.Hue;
if (parent != null)
{
parentSerial = parent.Serial;
if (parent.SolidHueOverride >= 0)
hue = parent.SolidHueOverride;
}
else
{
Console.WriteLine("Warning: EquipUpdate on item with !(parent is Mobile)");
parentSerial = Serial.Zero;
}
Stream.Write(item.Serial);
Stream.Write((short)item.ItemID);
Stream.Write((byte)0);
Stream.Write((byte)item.Layer);
Stream.Write(parentSerial);
Stream.Write((short)hue);
}
}
}

View file

@ -2,7 +2,7 @@
* ModernUO * * ModernUO *
* Copyright (C) 2019-2020 - ModernUO Development Team * * Copyright (C) 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com * * Email: hi@modernuo.com *
* File: MapPatches.cs - Created: 2020/05/03 - Updated: 2020/05/03 * * File: MapPackets.cs - Created: 2020/05/03 - Updated: 2020/05/08 *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by * * it under the terms of the GNU General Public License as published by *
@ -44,4 +44,11 @@ namespace Server.Network
Stream.Write(Map.Malas.Tiles.Patch.LandBlocks); Stream.Write(Map.Malas.Tiles.Patch.LandBlocks);
} }
} }
public sealed class InvalidMapEnable : Packet
{
public InvalidMapEnable() : base(0xC6, 1)
{
}
}
} }

View file

@ -0,0 +1,228 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: MenuPackets.cs - Created: 2020/05/08 - Updated: 2020/05/08 *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using Server.ContextMenus;
using Server.Menus;
using Server.Menus.ItemLists;
using Server.Menus.Questions;
namespace Server.Network
{
public sealed class DisplayItemListMenu : Packet
{
public DisplayItemListMenu(ItemListMenu menu) : base(0x7C)
{
EnsureCapacity(256);
Stream.Write(((IMenu)menu).Serial);
Stream.Write((short)0);
var question = menu.Question;
if (question == null)
{
Stream.Write((byte)0);
}
else
{
var questionLength = question.Length;
Stream.Write((byte)questionLength);
Stream.WriteAsciiFixed(question, questionLength);
}
var entries = menu.Entries;
int entriesLength = (byte)entries.Length;
Stream.Write((byte)entriesLength);
for (var i = 0; i < entriesLength; ++i)
{
var e = entries[i];
Stream.Write((ushort)e.ItemID);
Stream.Write((short)e.Hue);
var name = e.Name;
if (name == null)
{
Stream.Write((byte)0);
}
else
{
var nameLength = name.Length;
Stream.Write((byte)nameLength);
Stream.WriteAsciiFixed(name, nameLength);
}
}
}
}
public sealed class DisplayQuestionMenu : Packet
{
public DisplayQuestionMenu(QuestionMenu menu) : base(0x7C)
{
EnsureCapacity(256);
Stream.Write(((IMenu)menu).Serial);
Stream.Write((short)0);
var question = menu.Question;
if (question == null)
{
Stream.Write((byte)0);
}
else
{
var questionLength = question.Length;
Stream.Write((byte)questionLength);
Stream.WriteAsciiFixed(question, questionLength);
}
var answers = menu.Answers;
int answersLength = (byte)answers.Length;
Stream.Write((byte)answersLength);
for (var i = 0; i < answersLength; ++i)
{
Stream.Write(0);
var answer = answers[i];
if (answer == null)
{
Stream.Write((byte)0);
}
else
{
var answerLength = answer.Length;
Stream.Write((byte)answerLength);
Stream.WriteAsciiFixed(answer, answerLength);
}
}
}
}
public sealed class DisplayContextMenu : Packet
{
public DisplayContextMenu(ContextMenu menu) : base(0xBF)
{
var entries = menu.Entries;
int length = (byte)entries.Length;
EnsureCapacity(12 + length * 8);
Stream.Write((short)0x14);
Stream.Write((short)0x02);
var target = menu.Target;
Stream.Write(target.Serial);
Stream.Write((byte)length);
Point3D p = target switch
{
Mobile _ => target.Location,
Item item => item.GetWorldLocation(),
_ => Point3D.Zero
};
for (var i = 0; i < length; ++i)
{
var e = entries[i];
Stream.Write(e.Number);
Stream.Write((short)i);
var range = e.Range;
if (range == -1)
range = 18;
var flags = e.Flags;
if (!(e.Enabled && menu.From.InRange(p, range)))
flags |= CMEFlags.Disabled;
Stream.Write((short)flags);
}
}
}
public sealed class DisplayContextMenuOld : Packet
{
public DisplayContextMenuOld(ContextMenu menu) : base(0xBF)
{
var entries = menu.Entries;
int length = (byte)entries.Length;
EnsureCapacity(12 + length * 8);
Stream.Write((short)0x14);
Stream.Write((short)0x01);
var target = menu.Target;
Stream.Write(target.Serial);
Stream.Write((byte)length);
Point3D p = target switch
{
Mobile _ => target.Location,
Item item => item.GetWorldLocation(),
_ => Point3D.Zero
};
for (var i = 0; i < length; ++i)
{
var e = entries[i];
Stream.Write((short)i);
Stream.Write((ushort)(e.Number - 3000000));
var range = e.Range;
if (range == -1)
range = 18;
var flags = e.Flags;
if (!(e.Enabled && menu.From.InRange(p, range)))
flags |= CMEFlags.Disabled;
var color = e.Color & 0xFFFF;
if (color != 0xFFFF)
flags |= CMEFlags.Colored;
Stream.Write((short)flags);
if ((flags & CMEFlags.Colored) != 0)
Stream.Write((short)color);
}
}
}
}

View file

@ -0,0 +1,45 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: MobilePackets.cs - Created: 2020/05/07 - Updated: 2020/05/07 *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
namespace Server.Network
{
public sealed class DeathAnimation : Packet
{
public DeathAnimation(Mobile killed, Item corpse) : base(0xAF, 13)
{
Stream.Write(killed.Serial);
Stream.Write(corpse?.Serial ?? Serial.Zero);
Stream.Write(0);
}
}
public sealed class BondedStatus : Packet
{
public BondedStatus(Serial serial, bool bonded) : base(0xBF)
{
EnsureCapacity(11);
Stream.Write((short)0x19);
Stream.Write((byte)0);
Stream.Write(serial);
Stream.Write((byte)(bonded ? 1 : 0));
}
}
}

View file

@ -0,0 +1,154 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: PlayerPackets.cs - Created: 2020/05/07 - Updated: 2020/05/07 *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
namespace Server.Network
{
public sealed class StatLockInfo : Packet
{
public StatLockInfo(Mobile m) : base(0xBF)
{
EnsureCapacity(12);
Stream.Write((short)0x19);
Stream.Write((byte)2);
Stream.Write(m.Serial);
Stream.Write((byte)0);
var lockBits = ((int)m.StrLock << 4) | ((int)m.DexLock << 2) | (int)m.IntLock;
Stream.Write((byte)lockBits);
}
}
public sealed class ChangeCombatant : Packet
{
public ChangeCombatant(Mobile combatant) : base(0xAA, 5)
{
Stream.Write(combatant?.Serial ?? Serial.Zero);
}
}
public sealed class ChangeUpdateRange : Packet
{
private static readonly ChangeUpdateRange[] m_Cache = new ChangeUpdateRange[0x100];
public ChangeUpdateRange(int range) : base(0xC8, 2)
{
Stream.Write((byte)range);
}
public static ChangeUpdateRange Instantiate(int range)
{
var idx = (byte)range;
var p = m_Cache[idx];
if (p == null)
{
m_Cache[idx] = p = new ChangeUpdateRange(range);
p.SetStatic();
}
return p;
}
}
public sealed class DeathStatus : Packet
{
public static readonly Packet Dead = SetStatic(new DeathStatus(true));
public static readonly Packet Alive = SetStatic(new DeathStatus(false));
public DeathStatus(bool dead) : base(0x2C, 2)
{
Stream.Write((byte)(dead ? 0 : 2));
}
public static Packet Instantiate(bool dead) => dead ? Dead : Alive;
}
public sealed class SpeedControl : Packet
{
public static readonly Packet WalkSpeed = SetStatic(new SpeedControl(2));
public static readonly Packet MountSpeed = SetStatic(new SpeedControl(1));
public static readonly Packet Disable = SetStatic(new SpeedControl(0));
public SpeedControl(int speedControl) : base(0xBF)
{
EnsureCapacity(3);
Stream.Write((short)0x26);
Stream.Write((byte)speedControl);
}
}
public sealed class ToggleSpecialAbility : Packet
{
public ToggleSpecialAbility(int abilityID, bool active) : base(0xBF)
{
EnsureCapacity(7);
Stream.Write((short)0x25);
Stream.Write((short)abilityID);
Stream.Write(active);
}
}
public sealed class GlobalLightLevel : Packet
{
private static readonly GlobalLightLevel[] m_Cache = new GlobalLightLevel[0x100];
public GlobalLightLevel(int level) : base(0x4F, 2)
{
Stream.Write((sbyte)level);
}
public static GlobalLightLevel Instantiate(int level)
{
var lvl = (byte)level;
var p = m_Cache[lvl];
if (p == null)
{
m_Cache[lvl] = p = new GlobalLightLevel(level);
p.SetStatic();
}
return p;
}
}
public sealed class PersonalLightLevel : Packet
{
public PersonalLightLevel(Mobile m, int level) : base(0x4E, 6)
{
Stream.Write(m.Serial);
Stream.Write((sbyte)level);
}
}
public sealed class PersonalLightLevelZero : Packet
{
public PersonalLightLevelZero(Mobile m) : base(0x4E, 6)
{
Stream.Write(m.Serial);
Stream.Write((sbyte)0);
}
}
}

View file

@ -0,0 +1,38 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: UnicodePrompt.cs - Created: 2020/05/08 - Updated: 2020/05/08 *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using Server.Prompts;
namespace Server.Network
{
public sealed class UnicodePrompt : Packet
{
public UnicodePrompt(Prompt prompt) : base(0xC2)
{
EnsureCapacity(21);
Stream.Write(prompt.Serial); // TODO: Does this value even matter?
Stream.Write(prompt.Serial);
Stream.Write(0);
Stream.Write(0);
Stream.Write((short)0);
}
}
}

View file

@ -109,9 +109,20 @@ namespace Server.Network
var desc = bis.Description ?? ""; var desc = bis.Description ?? "";
// TODO: Test if this is actually WriteAsciiFixed and the extra null doesn't matter.
Stream.Write((byte)(desc.Length + 1)); Stream.Write((byte)(desc.Length + 1));
Stream.WriteAsciiNull(desc); Stream.WriteAsciiNull(desc);
} }
} }
} }
public sealed class EndVendorBuy : Packet
{
public EndVendorBuy(Mobile vendor) : base(0x3B, 8)
{
Stream.Write((ushort)8); // length
Stream.Write(vendor.Serial);
Stream.Write((byte)0);
}
}
} }

View file

@ -0,0 +1,61 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: VendorSellPackets.cs *
* Created: 2020/05/07 - Updated: 2020/05/07 *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System.Collections.Generic;
namespace Server.Network
{
public sealed class VendorSellList : Packet
{
public VendorSellList(Mobile shopkeeper, List<SellItemState> sis) : base(0x9E)
{
EnsureCapacity(256);
Stream.Write(shopkeeper.Serial);
Stream.Write((ushort)sis.Count);
foreach (var state in sis)
{
Stream.Write(state.Item.Serial);
Stream.Write((ushort)state.Item.ItemID);
Stream.Write((ushort)state.Item.Hue);
Stream.Write((ushort)state.Item.Amount);
Stream.Write((ushort)state.Price);
var name = string.IsNullOrWhiteSpace(state.Item.Name) ? state.Name ?? "" : state.Item.Name.Trim();
Stream.Write((ushort)name.Length);
Stream.WriteAsciiFixed(name, (ushort)name.Length);
}
}
}
public sealed class EndVendorSell : Packet
{
public EndVendorSell(Mobile vendor) : base(0x3B, 8)
{
Stream.Write((ushort)8); // length
Stream.Write(vendor.Serial);
Stream.Write((byte)0);
}
}
}

View file

@ -17,8 +17,8 @@
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
<LangVersion>8.0</LangVersion> <LangVersion>8.0</LangVersion>
<PublishDir>$(SolutionDir)\Distribution</PublishDir> <PublishDir>$(SolutionDir)\Distribution</PublishDir>
<!-- <OutDir>$(SolutionDir)\Distribution</OutDir> <!-- <OutDir>$(SolutionDir)\Distribution</OutDir>-->
<OutputPath>$(SolutionDir)\Distribution</OutputPath> --> <!-- <OutputPath>$(SolutionDir)\Distribution</OutputPath>-->
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors /> <WarningsAsErrors />
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>

View file

@ -2,7 +2,6 @@ dotnet clean
:<<"::SHELLSCRIPT" :<<"::SHELLSCRIPT"
@ECHO OFF @ECHO OFF
GOTO :CMDSCRIPT GOTO :CMDSCRIPT
::SHELLSCRIPT ::SHELLSCRIPT
Tools/build-native-libraries.cmd Tools/build-native-libraries.cmd
@ -15,33 +14,34 @@ fi
if [[ $1 ]] if [[ $1 ]]
then then
o="-r $1-x64" r="-r $1-x64"
else else
if [[ $(uname) = "Darwin" ]] if [[ $(uname) = "Darwin" ]]
then then
o="-r osx-x64" r="-r osx-x64"
else else
o="-r linux-x64" r="-r linux-x64"
fi fi
fi fi
echo dotnet publish ${c} ${o} --self-contained=false dotnet publish Projects/Server/Server.csproj ${c} ${r} --self-contained=false -o Distribution
dotnet publish ${c} ${o} --self-contained=false dotnet publish Projects/Scripts/Scripts.csproj ${c} ${r} --self-contained=false -o Distribution/Assemblies
exit $? exit $?
:CMDSCRIPT :CMDSCRIPT
Tools\build-native-libraries.cmd CALL Tools\build-native-libraries.cmd
IF "%~2" == "" ( IF "%~2" == "" (
SET c = "-c Release" SET c =-c Release
) ELSE ( ) ELSE (
SET c = "-c %~2" SET c =-c %~2
) )
IF "%~1" != "" ( IF NOT "%~1" == "" (
SET o = "-r %~1-x64" SET r =-r %~1-x64
) ELSE ( ) ELSE (
SET o = "-r win-x64" SET r =-r win-x64
) )
dotnet publish %c% %o% --self-contained=false dotnet publish Projects\Server\Server.csproj %c% %r% --self-contained=false -o Distribution
dotnet publish Projects\Scripts\Scripts.csproj %c% %r% --self-contained=false -o Distribution\Assemblies