diff --git a/BoneSync/BoneSync.csproj b/BoneSync/BoneSync.csproj
index 298185c..0555f47 100644
--- a/BoneSync/BoneSync.csproj
+++ b/BoneSync/BoneSync.csproj
@@ -1,5 +1,7 @@
+
+
Debug
@@ -13,6 +15,8 @@
512
true
+
+
true
@@ -35,37 +39,85 @@
- ..\..\..\..\AppData\Roaming\r2modmanPlus-local\BONEWORKS\profiles\aaaa\MelonLoader\MelonLoader.dll
+ ..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\Stationeers\MelonLoader\MelonLoader.dll
+
+
+ ..\packages\Microsoft.TestPlatform.ObjectModel.17.12.0\lib\net462\Microsoft.TestPlatform.CoreUtilities.dll
+
+
+ ..\packages\Microsoft.TestPlatform.ObjectModel.17.12.0\lib\net462\Microsoft.TestPlatform.PlatformAbstractions.dll
+
+
+ ..\packages\Microsoft.TestPlatform.ObjectModel.17.12.0\lib\net462\Microsoft.VisualStudio.TestPlatform.ObjectModel.dll
+
+ ..\packages\System.Collections.Immutable.1.5.0\lib\netstandard2.0\System.Collections.Immutable.dll
+
+
+
+ ..\packages\System.Reflection.Metadata.1.6.0\lib\netstandard2.0\System.Reflection.Metadata.dll
+
+
+
+
+ ..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll
+
+
+ ..\packages\xunit.assert.2.9.3\lib\netstandard1.1\xunit.assert.dll
+
+
+ ..\packages\xunit.extensibility.core.2.9.3\lib\net452\xunit.core.dll
+
+
+ ..\packages\xunit.extensibility.execution.2.9.3\lib\net452\xunit.execution.desktop.dll
+
+
+
+
-
-
-
+
{0289f09e-d594-46a9-96a7-b0f31f5d97b0}
Facepunch.Steamworks.Win64
+
+
+
+
+
+
+
- COPY "$(TargetPath)" "C:\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\Mods"
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/BoneSync/MelonLoaderMod.cs b/BoneSync/MelonLoaderMod.cs
index 68dde4c..5365064 100644
--- a/BoneSync/MelonLoaderMod.cs
+++ b/BoneSync/MelonLoaderMod.cs
@@ -16,8 +16,8 @@ namespace BoneSync
public class BoneSync : MelonMod
{
- LobbyManager lobby;
- TransportBase transport;
+ public static LobbyManager lobby;
+ public static TransportBase transport;
public override void OnApplicationStart()
{
MelonLogger.Msg("OnApplicationStart");
diff --git a/BoneSync/Networking/LobbyManager/LobbyManager.cs b/BoneSync/Networking/LobbyManager/LobbyManager.cs
index da19ed3..a42d18a 100644
--- a/BoneSync/Networking/LobbyManager/LobbyManager.cs
+++ b/BoneSync/Networking/LobbyManager/LobbyManager.cs
@@ -9,7 +9,7 @@ using Facepunch.Steamworks.Data;
namespace BoneSync.Networking.LobbyManager
{
- internal abstract class LobbyManager
+ public abstract class LobbyManager
{
public abstract ulong GetLobbyId();
public abstract ulong GetHostId();
diff --git a/BoneSync/Networking/Messages/LobbyInfoMessage.cs b/BoneSync/Networking/Messages/LobbyInfoMessage.cs
new file mode 100644
index 0000000..ea6d841
--- /dev/null
+++ b/BoneSync/Networking/Messages/LobbyInfoMessage.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace BoneSync.Networking.Messages
+{
+ [PacketType(PacketType.LobbyInfo)]
+ public class LobbyInfoMessage : NetworkMessage
+ {
+ public string LobbyName;
+ public string HostName;
+ public int MaxPlayers;
+ public int CurrentPlayers;
+ public LobbyInfoMessage(string lobbyName, string hostName, int maxPlayers, int currentPlayers)
+ {
+ LobbyName = lobbyName;
+ HostName = hostName;
+ MaxPlayers = maxPlayers;
+ CurrentPlayers = currentPlayers;
+ byteEncoder.WriteString(LobbyName);
+ byteEncoder.WriteString(HostName);
+ byteEncoder.WriteInt(MaxPlayers);
+ byteEncoder.WriteInt(CurrentPlayers);
+ }
+
+ public LobbyInfoMessage(Packet packet)
+ {
+ byteEncoder = new ByteEncoder(packet.Data);
+
+ LobbyName = byteEncoder.ReadString();
+ HostName = byteEncoder.ReadString();
+ MaxPlayers = byteEncoder.ReadInt();
+ CurrentPlayers = byteEncoder.ReadInt();
+ }
+
+ public override void Execute()
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public class LobbyInfoMessageTests
+ {
+ [Fact]
+ public void TestLobbyInfoMessage()
+ {
+ NetworkMessage.RegisterPacketTypes();
+
+ LobbyInfoMessage message = new LobbyInfoMessage("TestLobby", "TestHost", 10, 5);
+ Packet packet = message.GetPacket(0,0,0);
+ Assert.Equal(PacketType.LobbyInfo, packet.Info.packetType);
+ LobbyInfoMessage newMessage = (LobbyInfoMessage)NetworkMessage.ParsePacket(packet);
+ Assert.Equal("TestLobby", newMessage.LobbyName);
+ Assert.Equal("TestHost", newMessage.HostName);
+ Assert.Equal(10, newMessage.MaxPlayers);
+ Assert.Equal(5, newMessage.CurrentPlayers);
+ }
+ }
+}
diff --git a/BoneSync/Networking/Messages/NetworkMessage.cs b/BoneSync/Networking/Messages/NetworkMessage.cs
new file mode 100644
index 0000000..cf085c4
--- /dev/null
+++ b/BoneSync/Networking/Messages/NetworkMessage.cs
@@ -0,0 +1,120 @@
+using BoneSync.Networking.Transport;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace BoneSync.Networking.Messages
+{
+ public class PacketTypeAttribute : Attribute
+ {
+ public PacketTypeAttribute(PacketType type)
+ {
+ packetType = type;
+ }
+
+ public PacketType packetType { get; }
+ }
+
+ public abstract class NetworkMessage
+ {
+ private static bool _packetTypesRegistered = false;
+
+ internal static Dictionary PacketTypeMap = new Dictionary();
+
+ internal PacketType _packetType;
+ internal ByteEncoder byteEncoder = new ByteEncoder();
+
+
+ public byte[] GetBytes() => byteEncoder.ToArray();
+
+ public PacketType GetPacketType()
+ {
+ if (_packetType == PacketType.Unknown)
+ {
+ Type type = GetType();
+ _packetType = PacketTypeMap.FirstOrDefault(x => x.Value == type).Key;
+ if (_packetType == PacketType.Unknown)
+ {
+ throw new Exception("Cannot find packetType for " + type.Name);
+ }
+ }
+ return _packetType;
+ }
+
+ public static void RegisterPacketTypes()
+ {
+ if (_packetTypesRegistered)
+ {
+ return;
+ }
+ _packetTypesRegistered = true;
+ Assembly assembly = Assembly.GetExecutingAssembly();
+ Type[] types = assembly.GetTypes();
+ foreach (Type type in types)
+ {
+
+ if (type.IsSubclassOf(typeof(NetworkMessage)))
+ {
+ PacketType? packetType = type.GetCustomAttributesData().Where(x => x.AttributeType == typeof(PacketTypeAttribute)).Select(x => (PacketType)x.ConstructorArguments[0].Value).FirstOrDefault();
+ PacketTypeMap.Add((PacketType)packetType, type);
+ }
+ }
+ }
+ public static NetworkMessage ParsePacket(Packet packet)
+ {
+ // find a class that can parse this packet using Reflection
+ // and return it
+ if (!PacketTypeMap.ContainsKey(packet.Info.packetType))
+ {
+ throw new Exception("No class found for packet type '" + packet.Info.packetType+"'");
+ }
+ Type type = PacketTypeMap[packet.Info.packetType];
+ // get the constructor that takes a Packet
+ ConstructorInfo constructor = type.GetConstructor(new Type[] { typeof(Packet) });
+ // create an instance of the class
+ if (constructor == null)
+ {
+ throw new Exception("No constructor found for type " + type.Name);
+ }
+ NetworkMessage networkMessage = (NetworkMessage)constructor.Invoke(new object[] { packet });
+ return networkMessage;
+ }
+
+
+
+ public Packet GetPacket(int id, ulong senderId, ulong receiverId)
+ {
+ PacketInfo packetInfo = new PacketInfo(id, senderId, receiverId, GetPacketType());
+ Packet packet = new Packet(packetInfo, GetBytes());
+ return packet;
+ }
+ public void Broadcast()
+ {
+ Send(0);
+ }
+ public void Send(ulong receiverId)
+ {
+ int PacketId = Packet.GenerateId();
+ ulong senderId = BoneSync.lobby.GetLocalId();
+ Packet packet = GetPacket(PacketId, senderId, receiverId);
+ BoneSync.transport.Send(packet);
+ }
+
+ public abstract void Execute();
+
+ }
+ public class NetworkMessageTests
+ {
+ [Fact]
+ public void TestRegisterPackets()
+ {
+ NetworkMessage.RegisterPacketTypes();
+ Assert.NotEmpty(NetworkMessage.PacketTypeMap);
+ }
+ }
+}
diff --git a/BoneSync/Networking/Packet.cs b/BoneSync/Networking/Packet.cs
index e61305e..4a55bd4 100644
--- a/BoneSync/Networking/Packet.cs
+++ b/BoneSync/Networking/Packet.cs
@@ -3,22 +3,19 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using Xunit;
namespace BoneSync.Networking
{
- public enum PacketType
- {
- LobbyInfo = 0,
- CharacterInfo = 1,
- }
- internal struct PacketInfo
+
+ public struct PacketInfo
{
public int id;
- public int senderId;
+ public ulong senderId;
public ulong receiverId;
public PacketType packetType;
- public PacketInfo(int id, int senderId, ulong receiverId, PacketType packetType)
+ public PacketInfo(int id, ulong senderId, ulong receiverId, PacketType packetType)
{
this.id = id;
this.senderId = senderId;
@@ -26,30 +23,29 @@ namespace BoneSync.Networking
this.packetType = packetType;
}
}
- internal class Packet
+ public class Packet
{
-
public PacketInfo Info
{
get => _packetInfo;
private set => _packetInfo = value;
}
- private PacketInfo _packetInfo;
- private byte[] dataBytes;
+ private PacketInfo _packetInfo;
+ private byte[] _dataBytes;
private PacketInfo packetInfo;
public Packet(PacketInfo packetInfo, byte[] data)
{
- this.packetInfo = packetInfo;
- this.dataBytes = data;
+ _packetInfo = packetInfo;
+ _dataBytes = data;
}
public static Packet FromBytes(byte[] bytes)
{
ByteEncoder byteEncoder = new ByteEncoder();
byteEncoder.WriteBytes(bytes);
- PacketInfo packetInfo = new PacketInfo(byteEncoder.ReadInt(), byteEncoder.ReadInt(), byteEncoder.ReadUlong(), (PacketType)byteEncoder.ReadInt());
+ PacketInfo packetInfo = new PacketInfo(byteEncoder.ReadInt(), byteEncoder.ReadUlong(), byteEncoder.ReadUlong(), (PacketType)byteEncoder.ReadInt());
return new Packet(packetInfo, byteEncoder.ToArray());
}
@@ -57,15 +53,41 @@ namespace BoneSync.Networking
{
ByteEncoder byteEncoder = new ByteEncoder();
byteEncoder.WriteInt(packetInfo.id);
- byteEncoder.WriteInt(packetInfo.senderId);
+ byteEncoder.WriteUlong(packetInfo.senderId);
byteEncoder.WriteUlong(packetInfo.receiverId);
byteEncoder.WriteInt((int)packetInfo.packetType);
- byteEncoder.WriteBytes(dataBytes);
+ byteEncoder.WriteBytes(_dataBytes);
return byteEncoder.ToArray();
}
- public byte[] Data => dataBytes;
+ public byte[] Data => _dataBytes;
+ public static int GenerateId()
+ {
+ return new Random().Next();
+ }
+ }
+ public class PacketTests
+ {
+ [Fact]
+ public void TestPacketParsing()
+ {
+ Random random = new Random();
+
+ byte[] randomDataBytes = new byte[1024];
+ random.NextBytes(randomDataBytes);
+ PacketInfo originalPacketInfo = new PacketInfo(1, 2, 3, PacketType.LobbyInfo);
+ Packet originalPacket = new Packet(originalPacketInfo, randomDataBytes);
+
+ byte[] bytes = originalPacket.ToBytes();
+
+ Packet parsedPacket = Packet.FromBytes(bytes);
+ Assert.Equal(originalPacket.Info, parsedPacket.Info);
+ Assert.Equal(originalPacket.Data, parsedPacket.Data);
+
+ Assert.Equal(randomDataBytes, parsedPacket.Data);
+ Assert.NotEqual(bytes, randomDataBytes);
+ }
}
}
diff --git a/BoneSync/Networking/PacketTypes.cs b/BoneSync/Networking/PacketTypes.cs
new file mode 100644
index 0000000..05e3cbc
--- /dev/null
+++ b/BoneSync/Networking/PacketTypes.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BoneSync.Networking
+{
+ public enum PacketType
+ {
+ Unknown = 0,
+ LobbyInfo = 1,
+ CharacterInfo = 2,
+ }
+}
diff --git a/BoneSync/Networking/Transport/TransportBase.cs b/BoneSync/Networking/Transport/TransportBase.cs
index f10c39f..891e1d4 100644
--- a/BoneSync/Networking/Transport/TransportBase.cs
+++ b/BoneSync/Networking/Transport/TransportBase.cs
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace BoneSync.Networking.Transport
{
- internal abstract class TransportBase
+ public abstract class TransportBase
{
public abstract void Send(Packet packet);
public abstract bool Tick();
diff --git a/BoneSync/packages.config b/BoneSync/packages.config
new file mode 100644
index 0000000..a400c1b
--- /dev/null
+++ b/BoneSync/packages.config
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file