mirror of
https://github.com/Sanae6/SmoOnlineServer.git
synced 2024-11-21 18:55:17 +00:00
Packet cleanup and refactoring
This commit is contained in:
parent
3b13e1f86d
commit
c778d15644
10 changed files with 84 additions and 89 deletions
|
@ -12,14 +12,15 @@ CancellationTokenSource cts = new CancellationTokenSource();
|
||||||
Task listenTask = server.Listen(cts.Token);
|
Task listenTask = server.Listen(cts.Token);
|
||||||
Logger consoleLogger = new Logger("Console");
|
Logger consoleLogger = new Logger("Console");
|
||||||
|
|
||||||
server.ClientJoined += async (c, _) => {
|
server.ClientJoined += (c, _) => {
|
||||||
c.Metadata["shineSync"] = new ConcurrentBag<int>();
|
c.Metadata["shineSync"] = new ConcurrentBag<int>();
|
||||||
c.Metadata["loadedSave"] = false;
|
c.Metadata["loadedSave"] = false;
|
||||||
c.Metadata["scenario"] = 0;
|
c.Metadata["scenario"] = 0;
|
||||||
|
c.Metadata["2d"] = false;
|
||||||
c.PacketTransformer += (sender, packet) => {
|
c.PacketTransformer += (sender, packet) => {
|
||||||
if (Settings.Instance.Scenario.MergeEnabled && packet is PlayerPacket playerPacket) {
|
if (Settings.Instance.Scenario.MergeEnabled && packet is GamePacket gamePacket) {
|
||||||
playerPacket.ScenarioNum = (int) c.Metadata["scenario"];
|
gamePacket.ScenarioNum = (byte) c.Metadata["scenario"];
|
||||||
return playerPacket;
|
return gamePacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
return packet;
|
return packet;
|
||||||
|
@ -58,8 +59,9 @@ float MarioSize(bool is2d) {
|
||||||
|
|
||||||
server.PacketHandler = (c, p) => {
|
server.PacketHandler = (c, p) => {
|
||||||
{
|
{
|
||||||
if (p is PlayerPacket playerPacket) {
|
if (p is GamePacket gamePacket) {
|
||||||
c.Metadata["scenario"] = playerPacket.ScenarioNum;
|
c.Metadata["scenario"] = gamePacket.ScenarioNum;
|
||||||
|
c.Metadata["2d"] = gamePacket.Is2d;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (p) {
|
switch (p) {
|
||||||
|
@ -80,7 +82,7 @@ server.PacketHandler = (c, p) => {
|
||||||
case PlayerPacket playerPacket when Settings.Instance.Flip.Enabled
|
case PlayerPacket playerPacket when Settings.Instance.Flip.Enabled
|
||||||
&& Settings.Instance.Flip.Pov is FlipOptions.Both or FlipOptions.Others
|
&& Settings.Instance.Flip.Pov is FlipOptions.Both or FlipOptions.Others
|
||||||
&& Settings.Instance.Flip.Players.Contains(c.Id): {
|
&& Settings.Instance.Flip.Players.Contains(c.Id): {
|
||||||
playerPacket.Position += Vector3.UnitY * MarioSize(playerPacket.Is2d);
|
playerPacket.Position += Vector3.UnitY * MarioSize((bool) c.Metadata["2d"]);
|
||||||
playerPacket.Rotation *= Quaternion.CreateFromRotationMatrix(Matrix4x4.CreateRotationX(MathF.PI)) * Quaternion.CreateFromRotationMatrix(Matrix4x4.CreateRotationY(MathF.PI));
|
playerPacket.Rotation *= Quaternion.CreateFromRotationMatrix(Matrix4x4.CreateRotationX(MathF.PI)) * Quaternion.CreateFromRotationMatrix(Matrix4x4.CreateRotationY(MathF.PI));
|
||||||
server.Broadcast(playerPacket, c);
|
server.Broadcast(playerPacket, c);
|
||||||
return false;
|
return false;
|
||||||
|
@ -90,7 +92,7 @@ server.PacketHandler = (c, p) => {
|
||||||
&& !Settings.Instance.Flip.Players.Contains(c.Id): {
|
&& !Settings.Instance.Flip.Players.Contains(c.Id): {
|
||||||
server.BroadcastReplace(playerPacket, c, (from, to, sp) => {
|
server.BroadcastReplace(playerPacket, c, (from, to, sp) => {
|
||||||
if (Settings.Instance.Flip.Players.Contains(to.Id)) {
|
if (Settings.Instance.Flip.Players.Contains(to.Id)) {
|
||||||
sp.Position += Vector3.UnitY * MarioSize(playerPacket.Is2d);
|
sp.Position += Vector3.UnitY * MarioSize((bool) c.Metadata["2d"]);
|
||||||
sp.Rotation *= Quaternion.CreateFromRotationMatrix(Matrix4x4.CreateRotationX(MathF.PI)) * Quaternion.CreateFromRotationMatrix(Matrix4x4.CreateRotationY(MathF.PI));
|
sp.Rotation *= Quaternion.CreateFromRotationMatrix(Matrix4x4.CreateRotationX(MathF.PI)) * Quaternion.CreateFromRotationMatrix(Matrix4x4.CreateRotationY(MathF.PI));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,12 +144,11 @@ public class Server {
|
||||||
memory = memoryPool.Rent(Constants.HeaderSize + header.PacketSize);
|
memory = memoryPool.Rent(Constants.HeaderSize + header.PacketSize);
|
||||||
memTemp.Memory.Span[..Constants.HeaderSize].CopyTo(memory.Memory.Span[..Constants.HeaderSize]);
|
memTemp.Memory.Span[..Constants.HeaderSize].CopyTo(memory.Memory.Span[..Constants.HeaderSize]);
|
||||||
memTemp.Dispose();
|
memTemp.Dispose();
|
||||||
Logger.Info("smth");
|
|
||||||
if (!await Read(memory.Memory, header.PacketSize, Constants.HeaderSize))
|
if (!await Read(memory.Memory, header.PacketSize, Constants.HeaderSize))
|
||||||
throw new Exception("Not enough bytes for packet data sent to server");
|
throw new Exception("Not enough bytes for packet data sent to server");
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Info($"Got your mom {header.Id} {header.Type} 0x{header.PacketSize:X} 0x{memory.Memory.Length:X} 0x{header.Size:X}");
|
// if (header.Type is not PacketType.Player and not PacketType.Cap and not PacketType.Capture)Logger.Info($"Got your mom {header.Id} {header.Type} 0x{header.PacketSize:X} 0x{memory.Memory.Length:X} 0x{header.Size:X}");
|
||||||
|
|
||||||
// connection initialization
|
// connection initialization
|
||||||
if (first) {
|
if (first) {
|
||||||
|
@ -162,11 +161,11 @@ public class Server {
|
||||||
client.Name = connect.ClientName;
|
client.Name = connect.ClientName;
|
||||||
bool firstConn = false;
|
bool firstConn = false;
|
||||||
switch (connect.ConnectionType) {
|
switch (connect.ConnectionType) {
|
||||||
case ConnectionTypes.FirstConnection: {
|
case ConnectPacket.ConnectionTypes.FirstConnection: {
|
||||||
firstConn = true;
|
firstConn = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ConnectionTypes.Reconnecting: {
|
case ConnectPacket.ConnectionTypes.Reconnecting: {
|
||||||
client.Id = header.Id;
|
client.Id = header.Id;
|
||||||
if (FindExistingClient(header.Id) is { } newClient) {
|
if (FindExistingClient(header.Id) is { } newClient) {
|
||||||
if (newClient.Connected) throw new Exception($"Tried to join as already connected user {header.Id}");
|
if (newClient.Connected) throw new Exception($"Tried to join as already connected user {header.Id}");
|
||||||
|
@ -174,7 +173,7 @@ public class Server {
|
||||||
client = newClient;
|
client = newClient;
|
||||||
} else {
|
} else {
|
||||||
firstConn = true;
|
firstConn = true;
|
||||||
connect.ConnectionType = ConnectionTypes.FirstConnection;
|
connect.ConnectionType = ConnectPacket.ConnectionTypes.FirstConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -209,7 +208,7 @@ public class Server {
|
||||||
};
|
};
|
||||||
MemoryMarshal.Write(tempBuffer.Memory.Span, ref connectHeader);
|
MemoryMarshal.Write(tempBuffer.Memory.Span, ref connectHeader);
|
||||||
ConnectPacket connectPacket = new ConnectPacket {
|
ConnectPacket connectPacket = new ConnectPacket {
|
||||||
ConnectionType = ConnectionTypes.FirstConnection, // doesn't matter what it is
|
ConnectionType = ConnectPacket.ConnectionTypes.FirstConnection, // doesn't matter what it is
|
||||||
ClientName = other.Name
|
ClientName = other.Name
|
||||||
};
|
};
|
||||||
connectPacket.Serialize(tempBuffer.Memory.Span[Constants.HeaderSize..]);
|
connectPacket.Serialize(tempBuffer.Memory.Span[Constants.HeaderSize..]);
|
||||||
|
|
|
@ -9,19 +9,22 @@ public struct CapPacket : IPacket {
|
||||||
public const int NameSize = 0x30;
|
public const int NameSize = 0x30;
|
||||||
public Vector3 Position;
|
public Vector3 Position;
|
||||||
public Quaternion Rotation;
|
public Quaternion Rotation;
|
||||||
|
public bool CapOut;
|
||||||
public string CapAnim;
|
public string CapAnim;
|
||||||
|
|
||||||
public short Size => 0x4C;
|
public short Size => 0x50;
|
||||||
|
|
||||||
public void Serialize(Span<byte> data) {
|
public void Serialize(Span<byte> data) {
|
||||||
MemoryMarshal.Write(data, ref Position);
|
MemoryMarshal.Write(data, ref Position);
|
||||||
MemoryMarshal.Write(data[12..], ref Position);
|
MemoryMarshal.Write(data[12..], ref Rotation);
|
||||||
Encoding.UTF8.GetBytes(CapAnim).CopyTo(data[28..]);
|
MemoryMarshal.Write(data[28..], ref CapOut);
|
||||||
|
Encoding.UTF8.GetBytes(CapAnim).CopyTo(data[32..(32 + NameSize)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Deserialize(Span<byte> data) {
|
public void Deserialize(Span<byte> data) {
|
||||||
Position = MemoryMarshal.Read<Vector3>(data);
|
Position = MemoryMarshal.Read<Vector3>(data);
|
||||||
Rotation = MemoryMarshal.Read<Quaternion>(data[12..]);
|
Rotation = MemoryMarshal.Read<Quaternion>(data[12..]);
|
||||||
CapAnim = Encoding.UTF8.GetString(data[28..]).TrimEnd('\0');
|
CapOut = MemoryMarshal.Read<bool>(data[28..]);
|
||||||
|
CapAnim = Encoding.UTF8.GetString(data[32..(32 + NameSize)]).TrimEnd('\0');
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,17 +8,13 @@ public struct CapturePacket : IPacket {
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Constants.CostumeNameSize)]
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Constants.CostumeNameSize)]
|
||||||
public string ModelName;
|
public string ModelName;
|
||||||
|
|
||||||
public bool IsCaptured;
|
public short Size => Constants.CostumeNameSize;
|
||||||
|
|
||||||
public short Size => Constants.CostumeNameSize + 1;
|
|
||||||
public void Serialize(Span<byte> data) {
|
public void Serialize(Span<byte> data) {
|
||||||
Encoding.UTF8.GetBytes(ModelName).CopyTo(data[..Constants.CostumeNameSize]);
|
Encoding.UTF8.GetBytes(ModelName).CopyTo(data[..Constants.CostumeNameSize]);
|
||||||
MemoryMarshal.Write(data[Constants.CostumeNameSize..], ref IsCaptured);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Deserialize(Span<byte> data) {
|
public void Deserialize(Span<byte> data) {
|
||||||
ModelName = Encoding.UTF8.GetString(data[..Constants.CostumeNameSize]).TrimNullTerm();
|
ModelName = Encoding.UTF8.GetString(data[..Constants.CostumeNameSize]).TrimNullTerm();
|
||||||
IsCaptured = MemoryMarshal.Read<bool>(data[Constants.CostumeNameSize..]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -21,4 +21,9 @@ public struct ConnectPacket : IPacket {
|
||||||
ConnectionType = MemoryMarshal.Read<ConnectionTypes>(data);
|
ConnectionType = MemoryMarshal.Read<ConnectionTypes>(data);
|
||||||
ClientName = Encoding.UTF8.GetString(data[4..(4 + Constants.CostumeNameSize)]).TrimNullTerm();
|
ClientName = Encoding.UTF8.GetString(data[4..(4 + Constants.CostumeNameSize)]).TrimNullTerm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ConnectionTypes {
|
||||||
|
FirstConnection,
|
||||||
|
Reconnecting
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,6 +0,0 @@
|
||||||
namespace Shared.Packet.Packets;
|
|
||||||
|
|
||||||
public enum ConnectionTypes {
|
|
||||||
FirstConnection,
|
|
||||||
Reconnecting
|
|
||||||
}
|
|
25
Shared/Packet/Packets/GamePacket.cs
Normal file
25
Shared/Packet/Packets/GamePacket.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Shared.Packet.Packets;
|
||||||
|
|
||||||
|
[Packet(PacketType.Game)]
|
||||||
|
public struct GamePacket : IPacket {
|
||||||
|
private const int StageSize = 0x30;
|
||||||
|
public bool Is2d;
|
||||||
|
public byte ScenarioNum;
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = StageSize)]
|
||||||
|
public string Stage = "";
|
||||||
|
public short Size => 0x32;
|
||||||
|
public void Serialize(Span<byte> data) {
|
||||||
|
MemoryMarshal.Write(data[..0], ref Is2d);
|
||||||
|
MemoryMarshal.Write(data[1..1], ref ScenarioNum);
|
||||||
|
Encoding.UTF8.GetBytes(Stage).CopyTo(data[2..(2 + StageSize)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deserialize(Span<byte> data) {
|
||||||
|
Is2d = MemoryMarshal.Read<bool>(data);
|
||||||
|
ScenarioNum = MemoryMarshal.Read<byte>(data[1..]);
|
||||||
|
Stage = Encoding.UTF8.GetString(data[2..(2 + StageSize)]).TrimEnd('\0');
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,81 +6,43 @@ namespace Shared.Packet.Packets;
|
||||||
|
|
||||||
[Packet(PacketType.Player)]
|
[Packet(PacketType.Player)]
|
||||||
public struct PlayerPacket : IPacket {
|
public struct PlayerPacket : IPacket {
|
||||||
public const int NameSize = 0x20;
|
public const int ActSize = 0x20;
|
||||||
|
public const int SubActSize = 0x10;
|
||||||
|
|
||||||
public Vector3 Position = default;
|
public Vector3 Position;
|
||||||
public Quaternion Rotation = default;
|
public Quaternion Rotation;
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||||
public float[] AnimationBlendWeights = Array.Empty<float>();
|
public float[] AnimationBlendWeights = Array.Empty<float>();
|
||||||
|
|
||||||
public float AnimationRate = 0;
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = ActSize)]
|
||||||
public bool Is2d = false;
|
|
||||||
public bool ThrowingCap = false;
|
|
||||||
public bool IsIt = false;
|
|
||||||
public bool IsCaptured = false;
|
|
||||||
public int ScenarioNum = 0;
|
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x40)]
|
|
||||||
public string Stage = "";
|
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NameSize)]
|
|
||||||
public string Act = "";
|
public string Act = "";
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NameSize)]
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = SubActSize)]
|
||||||
public string SubAct = "";
|
public string SubAct = "";
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NameSize)]
|
public PlayerPacket() {
|
||||||
public string Hack = "";
|
Position = default;
|
||||||
|
Rotation = default;
|
||||||
|
}
|
||||||
|
|
||||||
public PlayerPacket() { }
|
public short Size => 0x64;
|
||||||
|
|
||||||
public short Size => 0xE0;
|
|
||||||
|
|
||||||
public void Serialize(Span<byte> data) {
|
public void Serialize(Span<byte> data) {
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
MemoryMarshal.Write(data, ref Position);
|
MemoryMarshal.Write(data[..(offset += Marshal.SizeOf<Vector3>())], ref Position);
|
||||||
offset += Marshal.SizeOf<Vector3>();
|
MemoryMarshal.Write(data[offset..(offset += Marshal.SizeOf<Quaternion>())], ref Rotation);
|
||||||
MemoryMarshal.Write(data[offset..], ref Rotation);
|
|
||||||
offset += Marshal.SizeOf<Quaternion>();
|
|
||||||
AnimationBlendWeights.CopyTo(MemoryMarshal.Cast<byte, float>(data[offset..(offset += 4 * 6)]));
|
AnimationBlendWeights.CopyTo(MemoryMarshal.Cast<byte, float>(data[offset..(offset += 4 * 6)]));
|
||||||
MemoryMarshal.Write(data[offset..], ref AnimationRate);
|
Encoding.UTF8.GetBytes(Act).CopyTo(data[offset..(offset += ActSize)]);
|
||||||
offset += 4;
|
Encoding.UTF8.GetBytes(SubAct).CopyTo(data[offset..(offset + SubActSize)]);
|
||||||
MemoryMarshal.Write(data[offset++..], ref Is2d);
|
|
||||||
MemoryMarshal.Write(data[offset++..], ref ThrowingCap);
|
|
||||||
MemoryMarshal.Write(data[offset++..], ref IsIt);
|
|
||||||
MemoryMarshal.Write(data[offset++..], ref IsCaptured);
|
|
||||||
MemoryMarshal.Write(data[offset..], ref ScenarioNum);
|
|
||||||
offset += 4;
|
|
||||||
Encoding.UTF8.GetBytes(Stage).CopyTo(data[offset..(offset + 0x40)]);
|
|
||||||
offset += 0x40;
|
|
||||||
Encoding.UTF8.GetBytes(Act).CopyTo(data[offset..(offset + NameSize)]);
|
|
||||||
offset += NameSize;
|
|
||||||
Encoding.UTF8.GetBytes(SubAct).CopyTo(data[offset..(offset + NameSize)]);
|
|
||||||
offset += NameSize;
|
|
||||||
Encoding.UTF8.GetBytes(Hack).CopyTo(data[offset..]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Deserialize(Span<byte> data) {
|
public void Deserialize(Span<byte> data) {
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
Position = MemoryMarshal.Read<Vector3>(data);
|
Position = MemoryMarshal.Read<Vector3>(data[..(offset += Marshal.SizeOf<Vector3>())]);
|
||||||
offset += Marshal.SizeOf<Vector3>();
|
Rotation = MemoryMarshal.Read<Quaternion>(data[offset..(offset += Marshal.SizeOf<Quaternion>())]);
|
||||||
Rotation = MemoryMarshal.Read<Quaternion>(data[offset..]);
|
|
||||||
offset += Marshal.SizeOf<Quaternion>();
|
|
||||||
AnimationBlendWeights = MemoryMarshal.Cast<byte, float>(data[offset..(offset += 4 * 6)]).ToArray();
|
AnimationBlendWeights = MemoryMarshal.Cast<byte, float>(data[offset..(offset += 4 * 6)]).ToArray();
|
||||||
AnimationRate = MemoryMarshal.Read<float>(data[offset..(offset += 4)]);
|
Act = Encoding.UTF8.GetString(data[offset..(offset += ActSize)]).TrimEnd('\0');
|
||||||
Is2d = MemoryMarshal.Read<bool>(data[offset++..]);
|
SubAct = Encoding.UTF8.GetString(data[offset..(offset + SubActSize)]).TrimEnd('\0');
|
||||||
ThrowingCap = MemoryMarshal.Read<bool>(data[offset++..]);
|
|
||||||
IsIt = MemoryMarshal.Read<bool>(data[offset++..]);
|
|
||||||
IsCaptured = MemoryMarshal.Read<bool>(data[offset++..]);
|
|
||||||
ScenarioNum = MemoryMarshal.Read<int>(data[offset..]);
|
|
||||||
offset += 4;
|
|
||||||
Stage = Encoding.UTF8.GetString(data[offset..(offset + 0x40)]).TrimEnd('\0');
|
|
||||||
offset += 0x40;
|
|
||||||
Act = Encoding.UTF8.GetString(data[offset..(offset + NameSize)]).TrimEnd('\0');
|
|
||||||
offset += NameSize;
|
|
||||||
SubAct = Encoding.UTF8.GetString(data[offset..(offset + NameSize)]).TrimEnd('\0');
|
|
||||||
offset += NameSize;
|
|
||||||
Hack = Encoding.UTF8.GetString(data[offset..(offset + NameSize)]).TrimEnd('\0');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,9 +4,12 @@ namespace Shared.Packet.Packets;
|
||||||
|
|
||||||
[Packet(PacketType.Tag)]
|
[Packet(PacketType.Tag)]
|
||||||
public struct TagPacket : IPacket {
|
public struct TagPacket : IPacket {
|
||||||
|
public TagUpdate UpdateType;
|
||||||
public bool IsIt;
|
public bool IsIt;
|
||||||
|
public byte Seconds;
|
||||||
|
public ushort Minutes;
|
||||||
|
|
||||||
public short Size => 1;
|
public short Size => 4;
|
||||||
|
|
||||||
public void Serialize(Span<byte> data) {
|
public void Serialize(Span<byte> data) {
|
||||||
MemoryMarshal.Write(data, ref IsIt);
|
MemoryMarshal.Write(data, ref IsIt);
|
||||||
|
@ -15,4 +18,10 @@ public struct TagPacket : IPacket {
|
||||||
public void Deserialize(Span<byte> data) {
|
public void Deserialize(Span<byte> data) {
|
||||||
IsIt = MemoryMarshal.Read<bool>(data);
|
IsIt = MemoryMarshal.Read<bool>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum TagUpdate : byte {
|
||||||
|
Time = 1,
|
||||||
|
State = 2
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -8,8 +8,8 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ObjectDumper.NET" Version="3.3.13"/>
|
<PackageReference Include="ObjectDumper.NET" Version="3.3.13" />
|
||||||
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0"/>
|
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
Loading…
Reference in a new issue