diff --git a/src/MultiplayerMod.Test/Environment/Network/CommandTools.cs b/src/MultiplayerMod.Test/Environment/Network/CommandTools.cs index 73688f72..5590bb51 100644 --- a/src/MultiplayerMod.Test/Environment/Network/CommandTools.cs +++ b/src/MultiplayerMod.Test/Environment/Network/CommandTools.cs @@ -1,7 +1,7 @@ -using System.IO; +using System.IO; using System.Runtime.Serialization.Formatters.Binary; using MultiplayerMod.Multiplayer.Commands; -using MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +using MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; namespace MultiplayerMod.Test.Environment.Network; diff --git a/src/MultiplayerMod.Test/Environment/Network/TestMultiplayerClient.cs b/src/MultiplayerMod.Test/Environment/Network/TestMultiplayerClient.cs index 6859973a..29a4007c 100644 --- a/src/MultiplayerMod.Test/Environment/Network/TestMultiplayerClient.cs +++ b/src/MultiplayerMod.Test/Environment/Network/TestMultiplayerClient.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using MultiplayerMod.ModRuntime; using MultiplayerMod.Multiplayer.Commands; @@ -83,4 +83,8 @@ public void Receive(IMultiplayerCommand command) { } } + public void Tick() + { + } + } diff --git a/src/MultiplayerMod.Test/Environment/Network/TestMultiplayerServer.cs b/src/MultiplayerMod.Test/Environment/Network/TestMultiplayerServer.cs index b19512a4..5631dd8f 100644 --- a/src/MultiplayerMod.Test/Environment/Network/TestMultiplayerServer.cs +++ b/src/MultiplayerMod.Test/Environment/Network/TestMultiplayerServer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using MultiplayerMod.Core.Extensions; @@ -113,4 +113,8 @@ public void Receive(TestMultiplayerClient source, IMultiplayerCommand command, M } } + public void Tick() + { + } + } diff --git a/src/MultiplayerMod.Test/Game/Chores/AbstractChoreTest.cs b/src/MultiplayerMod.Test/Game/Chores/AbstractChoreTest.cs index d41e9026..c3fc9721 100644 --- a/src/MultiplayerMod.Test/Game/Chores/AbstractChoreTest.cs +++ b/src/MultiplayerMod.Test/Game/Chores/AbstractChoreTest.cs @@ -8,7 +8,7 @@ using MultiplayerMod.Multiplayer.Commands; using MultiplayerMod.Multiplayer.Objects.Extensions; using MultiplayerMod.Network; -using MultiplayerMod.Platform.Steam.Network.Messaging; +using MultiplayerMod.Platform.Common.Network.Messaging; using MultiplayerMod.Test.Environment.Patches; using MultiplayerMod.Test.GameRuntime; using MultiplayerMod.Test.GameRuntime.Patches; diff --git a/src/MultiplayerMod.Test/Multiplayer/Chores/ChoreTest.cs b/src/MultiplayerMod.Test/Multiplayer/Chores/ChoreTest.cs index 980370f0..1fe3bc54 100644 --- a/src/MultiplayerMod.Test/Multiplayer/Chores/ChoreTest.cs +++ b/src/MultiplayerMod.Test/Multiplayer/Chores/ChoreTest.cs @@ -17,7 +17,7 @@ using MultiplayerMod.Multiplayer.StateMachines; using MultiplayerMod.Multiplayer.StateMachines.Configuration; using MultiplayerMod.Network; -using MultiplayerMod.Platform.Steam.Network.Messaging; +using MultiplayerMod.Platform.Common.Network.Messaging; using MultiplayerMod.Test.Environment; using MultiplayerMod.Test.Environment.Network; using MultiplayerMod.Test.Environment.Patches; diff --git a/src/MultiplayerMod.Test/MultiplayerMod.Test.csproj b/src/MultiplayerMod.Test/MultiplayerMod.Test.csproj index 8e5b3f33..47744711 100644 --- a/src/MultiplayerMod.Test/MultiplayerMod.Test.csproj +++ b/src/MultiplayerMod.Test/MultiplayerMod.Test.csproj @@ -12,31 +12,32 @@ true - + - - - + + + + - - - + + + - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/src/MultiplayerMod.Test/Network/CommandTests.cs b/src/MultiplayerMod.Test/Network/CommandTests.cs index 4bf168bc..2751b83f 100644 --- a/src/MultiplayerMod.Test/Network/CommandTests.cs +++ b/src/MultiplayerMod.Test/Network/CommandTests.cs @@ -1,10 +1,10 @@ -using System; +using System; using System.Linq; using System.Runtime.InteropServices; using MultiplayerMod.Multiplayer.Commands; using MultiplayerMod.Network; -using MultiplayerMod.Platform.Steam.Network; -using MultiplayerMod.Platform.Steam.Network.Messaging; +using MultiplayerMod.Platform.Common; +using MultiplayerMod.Platform.Common.Network.Messaging; using NUnit.Framework; namespace MultiplayerMod.Test.Network; diff --git a/src/MultiplayerMod/Core/Patch/PatchTargetResolver.cs b/src/MultiplayerMod/Core/Patch/PatchTargetResolver.cs index 262c8c8a..479b9096 100644 --- a/src/MultiplayerMod/Core/Patch/PatchTargetResolver.cs +++ b/src/MultiplayerMod/Core/Patch/PatchTargetResolver.cs @@ -1,10 +1,10 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.Serialization; using MultiplayerMod.Core.Logging; -using MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +using MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; using UnityEngine; namespace MultiplayerMod.Core.Patch; diff --git a/src/MultiplayerMod/Directory.Build.targets b/src/MultiplayerMod/Directory.Build.targets index 62b6f631..1466c3ce 100644 --- a/src/MultiplayerMod/Directory.Build.targets +++ b/src/MultiplayerMod/Directory.Build.targets @@ -43,6 +43,10 @@ + + + + @@ -62,10 +66,11 @@ + diff --git a/src/MultiplayerMod/Multiplayer/Commands/ArgumentUtils.cs b/src/MultiplayerMod/Multiplayer/Commands/ArgumentUtils.cs index 34702606..c2c2dd75 100644 --- a/src/MultiplayerMod/Multiplayer/Commands/ArgumentUtils.cs +++ b/src/MultiplayerMod/Multiplayer/Commands/ArgumentUtils.cs @@ -4,7 +4,7 @@ using System.Reflection; using MultiplayerMod.Multiplayer.Objects.Extensions; using MultiplayerMod.Multiplayer.Objects.Reference; -using MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +using MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; using UnityEngine; namespace MultiplayerMod.Multiplayer.Commands; diff --git a/src/MultiplayerMod/MultiplayerMod.csproj b/src/MultiplayerMod/MultiplayerMod.csproj index 62a67370..63d3e177 100644 --- a/src/MultiplayerMod/MultiplayerMod.csproj +++ b/src/MultiplayerMod/MultiplayerMod.csproj @@ -65,5 +65,6 @@ + diff --git a/src/MultiplayerMod/Network/IMultiplayerClient.cs b/src/MultiplayerMod/Network/IMultiplayerClient.cs index 96a77542..230c63cf 100644 --- a/src/MultiplayerMod/Network/IMultiplayerClient.cs +++ b/src/MultiplayerMod/Network/IMultiplayerClient.cs @@ -1,4 +1,4 @@ -using System; +using System; using MultiplayerMod.Multiplayer.Commands; namespace MultiplayerMod.Network; @@ -11,6 +11,7 @@ public interface IMultiplayerClient { void Disconnect(); void Send(IMultiplayerCommand command, MultiplayerCommandOptions options = MultiplayerCommandOptions.None); + void Tick(); event Action StateChanged; event Action CommandReceived; diff --git a/src/MultiplayerMod/Network/IMultiplayerServer.cs b/src/MultiplayerMod/Network/IMultiplayerServer.cs index d06cf2e2..3238922c 100644 --- a/src/MultiplayerMod/Network/IMultiplayerServer.cs +++ b/src/MultiplayerMod/Network/IMultiplayerServer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using MultiplayerMod.Multiplayer.Commands; @@ -14,6 +14,7 @@ public interface IMultiplayerServer { void Send(IMultiplayerClientId clientId, IMultiplayerCommand command); void Send(IMultiplayerCommand command, MultiplayerCommandOptions options = MultiplayerCommandOptions.None); + void Tick(); event Action StateChanged; event Action ClientConnected; diff --git a/src/MultiplayerMod/Platform/Common/Configuration.cs b/src/MultiplayerMod/Platform/Common/Configuration.cs new file mode 100644 index 00000000..f47dcaba --- /dev/null +++ b/src/MultiplayerMod/Platform/Common/Configuration.cs @@ -0,0 +1,18 @@ +using MultiplayerMod.Platform.Common.Network.Messaging; +using MultiplayerMod.Platform.Lan.Network; +using System; + +namespace MultiplayerMod.Platform.Common; + +public static class Configuration +{ + public const int MaxMessageSize = 524288; // 512 KiB + public static readonly int MaxFragmentDataSize = GetFragmentDataSize(); + + private static int GetFragmentDataSize() { + using var serialized = NetworkSerializer.Serialize(new NetworkMessageFragment(0, Array.Empty())); + return MaxMessageSize - (int) serialized.Size; + } + + public static bool useSteam { get { return !LanConfiguration.instance.isConfigured; } } +} diff --git a/src/MultiplayerMod/Platform/Common/Network/Components/ClientComponent.cs b/src/MultiplayerMod/Platform/Common/Network/Components/ClientComponent.cs new file mode 100644 index 00000000..7a8757ac --- /dev/null +++ b/src/MultiplayerMod/Platform/Common/Network/Components/ClientComponent.cs @@ -0,0 +1,17 @@ +using MultiplayerMod.Core.Dependency; +using MultiplayerMod.Core.Unity; +using MultiplayerMod.Platform.Common.Network; + +// ReSharper disable FieldCanBeMadeReadOnly.Local + +namespace MultiplayerMod.Platform.Common.Network.Components; + +public class ClientComponent : MultiplayerMonoBehaviour +{ + + [InjectDependency] + private SharedClient client = null!; + + private void Update() => client.Tick(); + +} diff --git a/src/MultiplayerMod/Platform/Common/Network/Components/ServerComponent.cs b/src/MultiplayerMod/Platform/Common/Network/Components/ServerComponent.cs new file mode 100644 index 00000000..8645e8a0 --- /dev/null +++ b/src/MultiplayerMod/Platform/Common/Network/Components/ServerComponent.cs @@ -0,0 +1,17 @@ +using MultiplayerMod.Core.Dependency; +using MultiplayerMod.Core.Unity; +using MultiplayerMod.Platform.Common.Network; + +// ReSharper disable FieldCanBeMadeReadOnly.Local + +namespace MultiplayerMod.Platform.Common.Network.Components; + +public class ServerComponent : MultiplayerMonoBehaviour +{ + + [InjectDependency] + private SharedServer server = null!; + + private void Update() => server.Tick(); + +} diff --git a/src/MultiplayerMod/Platform/Common/Network/Messaging/INetworkMessage.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/INetworkMessage.cs new file mode 100644 index 00000000..853cf31d --- /dev/null +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/INetworkMessage.cs @@ -0,0 +1,3 @@ +namespace MultiplayerMod.Platform.Common.Network.Messaging; + +public interface INetworkMessage { } diff --git a/src/MultiplayerMod/Platform/Common/Network/Messaging/INetworkMessageHandle.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/INetworkMessageHandle.cs new file mode 100644 index 00000000..17506d02 --- /dev/null +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/INetworkMessageHandle.cs @@ -0,0 +1,9 @@ +using System; + +namespace MultiplayerMod.Platform.Common.Network.Messaging; + +public interface INetworkMessageHandle : IDisposable +{ + public IntPtr Pointer { get; } + public uint Size { get; } +} diff --git a/src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkMessage.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkMessage.cs new file mode 100644 index 00000000..a0e0a810 --- /dev/null +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkMessage.cs @@ -0,0 +1,39 @@ +using System; +using System.IO; +using System.Runtime.Serialization.Formatters.Binary; +using MultiplayerMod.Multiplayer.Commands; +using MultiplayerMod.Network; +using MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; + +namespace MultiplayerMod.Platform.Common.Network.Messaging; + +[Serializable] +public class NetworkMessage : INetworkMessage +{ + private static BinaryFormatter formatter = new BinaryFormatter() { SurrogateSelector = SerializationSurrogates.Selector }; + + public IMultiplayerCommand Command { get; } + public MultiplayerCommandOptions Options { get; } + + public NetworkMessage(IMultiplayerCommand command, MultiplayerCommandOptions options) + { + Command = command; + Options = options; + } + + public byte[] toBytes() { + using (var memoryStream = new MemoryStream()) { + formatter.Serialize(memoryStream, this); + byte[] data = new byte[memoryStream.Length]; + Array.Copy(memoryStream.GetBuffer(), 0, data, 0, data.Length); + return data; + } + } + + public static NetworkMessage from(byte[] rawData) { + using (var memoryStream = new MemoryStream(rawData)) { + var message = (NetworkMessage) formatter.Deserialize(memoryStream); + return message; + } + } +} diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkMessageFactory.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkMessageFactory.cs similarity index 75% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkMessageFactory.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkMessageFactory.cs index c7711dc7..e6933357 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkMessageFactory.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkMessageFactory.cs @@ -1,16 +1,19 @@ -using System; +using System; using System.Collections.Generic; using MultiplayerMod.Multiplayer.Commands; using MultiplayerMod.Network; -using static MultiplayerMod.Platform.Steam.Network.Configuration; +using static MultiplayerMod.Platform.Common.Configuration; -namespace MultiplayerMod.Platform.Steam.Network.Messaging; +namespace MultiplayerMod.Platform.Common.Network.Messaging; -public class NetworkMessageFactory { +public class NetworkMessageFactory +{ - public IEnumerable Create(IMultiplayerCommand command, MultiplayerCommandOptions options) { + public IEnumerable Create(IMultiplayerCommand command, MultiplayerCommandOptions options) + { using var message = NetworkSerializer.Serialize(new NetworkMessage(command, options)); - if (message.Size <= MaxMessageSize) { + if (message.Size <= MaxMessageSize) + { yield return message; yield break; } @@ -20,7 +23,8 @@ public IEnumerable Create(IMultiplayerCommand command, Mu var serializedHeader = NetworkSerializer.Serialize(header); yield return serializedHeader; - for (var i = 0; i < fragmentsCount; i++) { + for (var i = 0; i < fragmentsCount; i++) + { var offset = i * MaxFragmentDataSize; var bufferSize = Math.Min(Math.Max((int) message.Size - offset, 0), MaxFragmentDataSize); var data = new byte[bufferSize]; diff --git a/src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkMessageFragment.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkMessageFragment.cs new file mode 100644 index 00000000..455ca138 --- /dev/null +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkMessageFragment.cs @@ -0,0 +1,18 @@ +using System; + +namespace MultiplayerMod.Platform.Common.Network.Messaging; + +[Serializable] +public class NetworkMessageFragment : INetworkMessage +{ + + public int MessageId { get; } + public byte[] Data { get; } + + public NetworkMessageFragment(int messageId, byte[] data) + { + MessageId = messageId; + Data = data; + } + +} diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkMessageFragmentsHeader.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkMessageFragmentsHeader.cs similarity index 60% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkMessageFragmentsHeader.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkMessageFragmentsHeader.cs index ebc7df89..e61f3298 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkMessageFragmentsHeader.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkMessageFragmentsHeader.cs @@ -1,17 +1,19 @@ using System; using System.Threading; -namespace MultiplayerMod.Platform.Steam.Network.Messaging; +namespace MultiplayerMod.Platform.Common.Network.Messaging; [Serializable] -public class NetworkMessageFragmentsHeader : INetworkMessage { +public class NetworkMessageFragmentsHeader : INetworkMessage +{ public int MessageId { get; } public int FragmentsCount { get; } private static int uniqueMessageId; - public NetworkMessageFragmentsHeader(int fragmentsCount) { + public NetworkMessageFragmentsHeader(int fragmentsCount) + { MessageId = Interlocked.Increment(ref uniqueMessageId); FragmentsCount = fragmentsCount; } diff --git a/src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkMessageHandle.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkMessageHandle.cs new file mode 100644 index 00000000..999f1e59 --- /dev/null +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkMessageHandle.cs @@ -0,0 +1,22 @@ +using System; + +namespace MultiplayerMod.Platform.Common.Network.Messaging; + +public class NetworkMessageHandle : INetworkMessageHandle +{ + + public IntPtr Pointer { get; } + public uint Size { get; } + + public NetworkMessageHandle(IntPtr pointer, uint size) + { + Pointer = pointer; + Size = size; + } + + public void Dispose() + { + // No disposal required + } + +} diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkMessageProcessor.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkMessageProcessor.cs similarity index 82% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkMessageProcessor.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkMessageProcessor.cs index 5e67b286..3c0d1124 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkMessageProcessor.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkMessageProcessor.cs @@ -1,33 +1,38 @@ -using System; +using System; using System.Collections.Concurrent; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using MultiplayerMod.Core.Logging; -using static MultiplayerMod.Platform.Steam.Network.Configuration; +using static MultiplayerMod.Platform.Common.Configuration; -namespace MultiplayerMod.Platform.Steam.Network.Messaging; +namespace MultiplayerMod.Platform.Common.Network.Messaging; -public class NetworkMessageProcessor { +public class NetworkMessageProcessor +{ private readonly ConcurrentDictionary> fragments = new(); private readonly Core.Logging.Logger log = LoggerFactory.GetLogger(); public NetworkMessage? Process(uint clientId, INetworkMessageHandle handle) => - NetworkSerializer.Deserialize(handle) switch { + NetworkSerializer.Deserialize(handle) switch + { NetworkMessage message => message, NetworkMessageFragmentsHeader header => ProcessFragmentsHeader(clientId, header), NetworkMessageFragment fragment => ProcessMessageFragment(clientId, fragment), _ => null }; - private NetworkMessage? ProcessFragmentsHeader(uint clientId, NetworkMessageFragmentsHeader header) { + private NetworkMessage? ProcessFragmentsHeader(uint clientId, NetworkMessageFragmentsHeader header) + { fragments.TryGetValue(clientId, out var index); - if (index == null) { + if (index == null) + { index = new ConcurrentDictionary(); fragments[clientId] = index; } var buffer = new FragmentsBuffer(header.FragmentsCount); - buffer.Timeout += () => { + buffer.Timeout += () => + { log.Warning($"Fragments buffer timed out (message id: {header.MessageId})"); index.TryRemove(header.MessageId, out _); }; @@ -35,16 +40,19 @@ public class NetworkMessageProcessor { return null; } - private NetworkMessage? ProcessMessageFragment(uint clientId, NetworkMessageFragment fragment) { + private NetworkMessage? ProcessMessageFragment(uint clientId, NetworkMessageFragment fragment) + { string ExceptionMessage() => $"Message (id: {fragment.MessageId}) fragment received, but no fragments buffer found"; - if (!fragments.TryGetValue(clientId, out var index)) { + if (!fragments.TryGetValue(clientId, out var index)) + { log.Warning(ExceptionMessage()); return null; } - if (!index.TryGetValue(fragment.MessageId, out var buffer)) { + if (!index.TryGetValue(fragment.MessageId, out var buffer)) + { log.Warning(ExceptionMessage()); return null; } @@ -56,7 +64,8 @@ string ExceptionMessage() => return message; } - private class FragmentsBuffer { + private class FragmentsBuffer + { private const int watchdogIntervalMs = 5000; private int index; @@ -65,18 +74,21 @@ private class FragmentsBuffer { public event System.Action? Timeout; - private readonly System.Timers.Timer watchdog = new(watchdogIntervalMs) { + private readonly System.Timers.Timer watchdog = new(watchdogIntervalMs) + { Enabled = true, AutoReset = false }; - public FragmentsBuffer(int count) { + public FragmentsBuffer(int count) + { this.count = count; buffer = new byte[count * MaxFragmentDataSize]; watchdog.Elapsed += (_, _) => Timeout?.Invoke(); } - public NetworkMessage? Append(NetworkMessageFragment fragment) { + public NetworkMessage? Append(NetworkMessageFragment fragment) + { if (index >= count) throw new NetworkPlatformException("Invalid fragmentation: more fragments than expected."); diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkSerializer.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkSerializer.cs similarity index 71% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkSerializer.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkSerializer.cs index bb2ef0fa..ed6dfdfa 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkSerializer.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/NetworkSerializer.cs @@ -1,12 +1,14 @@ -using System.IO; +using System.IO; using System.Runtime.Serialization.Formatters.Binary; -using MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +using MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -namespace MultiplayerMod.Platform.Steam.Network.Messaging; +namespace MultiplayerMod.Platform.Common.Network.Messaging; -public static class NetworkSerializer { +public static class NetworkSerializer +{ - public static SerializedNetworkMessage Serialize(INetworkMessage message) { + public static SerializedNetworkMessage Serialize(INetworkMessage message) + { return new SerializedNetworkMessage(message); } diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/SerializedNetworkMessage.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/SerializedNetworkMessage.cs similarity index 70% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/SerializedNetworkMessage.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/SerializedNetworkMessage.cs index 9c80b66c..2abce90a 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/SerializedNetworkMessage.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/SerializedNetworkMessage.cs @@ -1,12 +1,13 @@ -using System; +using System; using System.IO; using System.Runtime.InteropServices; using System.Runtime.Serialization.Formatters.Binary; -using MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +using MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -namespace MultiplayerMod.Platform.Steam.Network.Messaging; +namespace MultiplayerMod.Platform.Common.Network.Messaging; -public class SerializedNetworkMessage : INetworkMessageHandle { +public class SerializedNetworkMessage : INetworkMessageHandle +{ public IntPtr Pointer { get; } public uint Size { get; } @@ -14,7 +15,8 @@ public class SerializedNetworkMessage : INetworkMessageHandle { private readonly MemoryStream memory; private GCHandle handle; - public SerializedNetworkMessage(INetworkMessage message) { + public SerializedNetworkMessage(INetworkMessage message) + { memory = new MemoryStream(); var formatter = new BinaryFormatter { SurrogateSelector = SerializationSurrogates.Selector }; formatter.Serialize(memory, message); @@ -23,7 +25,8 @@ public SerializedNetworkMessage(INetworkMessage message) { Size = (uint) memory.Length; } - public void Dispose() { + public void Dispose() + { handle.Free(); memory.Close(); } diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/AssignmentGroupSurrogate.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/AssignmentGroupSurrogate.cs similarity index 81% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/AssignmentGroupSurrogate.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/AssignmentGroupSurrogate.cs index 6c5ceba9..f8f5317d 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/AssignmentGroupSurrogate.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/AssignmentGroupSurrogate.cs @@ -1,13 +1,15 @@ using System; using System.Runtime.Serialization; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -public class AssignmentGroupSurrogate : ISerializationSurrogate, ISurrogateType { +public class AssignmentGroupSurrogate : ISerializationSurrogate, ISurrogateType +{ public Type Type => typeof(AssignmentGroup); - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { var group = (AssignmentGroup) obj; info.AddValue("id", group.id); } @@ -17,7 +19,8 @@ public void GetObjectData(object obj, SerializationInfo info, StreamingContext c SerializationInfo info, StreamingContext context, ISurrogateSelector selector - ) { + ) + { var id = info.GetString("id"); return global::Game.Instance.assignmentManager.assignment_groups[id]; } diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/CarePackageInstanceDataSurrogate.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/CarePackageInstanceDataSurrogate.cs similarity index 89% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/CarePackageInstanceDataSurrogate.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/CarePackageInstanceDataSurrogate.cs index f545b1cb..9c8ffffb 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/CarePackageInstanceDataSurrogate.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/CarePackageInstanceDataSurrogate.cs @@ -1,13 +1,15 @@ using System; using System.Runtime.Serialization; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -public class CarePackageInstanceDataSurrogate : ISerializationSurrogate, ISurrogateType { +public class CarePackageInstanceDataSurrogate : ISerializationSurrogate, ISurrogateType +{ public Type Type => typeof(CarePackageContainer.CarePackageInstanceData); - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { var packageInstanceData = (CarePackageContainer.CarePackageInstanceData) obj; info.AddValue("facadeID", packageInstanceData.facadeID); info.AddValue("info.id", packageInstanceData.info.id); @@ -20,7 +22,8 @@ public object SetObjectData( SerializationInfo info, StreamingContext context, ISurrogateSelector selector - ) { + ) + { var packageInstanceData = (CarePackageContainer.CarePackageInstanceData) obj; packageInstanceData.info = new CarePackageInfo( info.GetString("info.id"), diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/ChoreTypeSurrogate.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/ChoreTypeSurrogate.cs similarity index 81% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/ChoreTypeSurrogate.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/ChoreTypeSurrogate.cs index befce71d..c8c26eca 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/ChoreTypeSurrogate.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/ChoreTypeSurrogate.cs @@ -1,13 +1,15 @@ using System; using System.Runtime.Serialization; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -public class ChoreTypeSurrogate : ISerializationSurrogate, ISurrogateType { +public class ChoreTypeSurrogate : ISerializationSurrogate, ISurrogateType +{ public Type Type => typeof(ChoreType); - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { var choreType = (ChoreType) obj; info.AddValue("id", choreType.Id); } @@ -17,7 +19,8 @@ public object SetObjectData( SerializationInfo info, StreamingContext context, ISurrogateSelector selector - ) { + ) + { var id = info.GetString("id"); return Db.Get().ChoreTypes.Get(id); } diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/ComplexRecipeSurrogate.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/ComplexRecipeSurrogate.cs similarity index 83% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/ComplexRecipeSurrogate.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/ComplexRecipeSurrogate.cs index 77f73768..f6654d67 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/ComplexRecipeSurrogate.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/ComplexRecipeSurrogate.cs @@ -2,13 +2,15 @@ using System.Linq; using System.Runtime.Serialization; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -public class ComplexRecipeSurrogate : ISerializationSurrogate, ISurrogateType { +public class ComplexRecipeSurrogate : ISerializationSurrogate, ISurrogateType +{ public Type Type => typeof(ComplexRecipe); - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { var recipe = (ComplexRecipe) obj; info.AddValue("id", recipe.id); } @@ -18,7 +20,8 @@ public object SetObjectData( SerializationInfo info, StreamingContext context, ISurrogateSelector selector - ) { + ) + { var id = info.GetString("id"); var recipe = ComplexRecipeManager.Get().recipes.Single(recipe => recipe.id == id); return recipe; diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/DeathSurrogate.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/DeathSurrogate.cs similarity index 81% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/DeathSurrogate.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/DeathSurrogate.cs index 0866e67e..9ac7df70 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/DeathSurrogate.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/DeathSurrogate.cs @@ -1,13 +1,15 @@ using System; using System.Runtime.Serialization; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -public class DeathSurrogate : ISerializationSurrogate, ISurrogateType { +public class DeathSurrogate : ISerializationSurrogate, ISurrogateType +{ public Type Type => typeof(Death); - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { var death = (Death) obj; info.AddValue("id", death.Id); } @@ -17,7 +19,8 @@ public object SetObjectData( SerializationInfo info, StreamingContext context, ISurrogateSelector selector - ) { + ) + { var id = info.GetString("id"); return Db.Get().Deaths.Get(id); } diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/EmoteSurrogate.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/EmoteSurrogate.cs similarity index 81% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/EmoteSurrogate.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/EmoteSurrogate.cs index 91353bf3..57ed2f6b 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/EmoteSurrogate.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/EmoteSurrogate.cs @@ -2,13 +2,15 @@ using System.Runtime.Serialization; using Klei.AI; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -public class EmoteSurrogate : ISerializationSurrogate, ISurrogateType { +public class EmoteSurrogate : ISerializationSurrogate, ISurrogateType +{ public Type Type => typeof(Emote); - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { var emote = (Emote) obj; info.AddValue("id", emote.Id); } @@ -18,7 +20,8 @@ public object SetObjectData( SerializationInfo info, StreamingContext context, ISurrogateSelector selector - ) { + ) + { var id = info.GetString("id"); return Db.Get().Emotes.Minion.Get(id); } diff --git a/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/ISurrogateType.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/ISurrogateType.cs new file mode 100644 index 00000000..8bfacdb4 --- /dev/null +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/ISurrogateType.cs @@ -0,0 +1,7 @@ +using System; + +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; + +public interface ISurrogateType { + public Type Type { get; } +} diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/KAnimFileSurrogate.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/KAnimFileSurrogate.cs similarity index 81% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/KAnimFileSurrogate.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/KAnimFileSurrogate.cs index 5be3bcf6..d48a8686 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/KAnimFileSurrogate.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/KAnimFileSurrogate.cs @@ -1,13 +1,15 @@ using System; using System.Runtime.Serialization; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -public class KAnimFileSurrogate : ISerializationSurrogate, ISurrogateType { +public class KAnimFileSurrogate : ISerializationSurrogate, ISurrogateType +{ public Type Type => typeof(KAnimFile); - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { var anim = (KAnimFile) obj; info.AddValue("name", anim.name); } @@ -17,7 +19,8 @@ public object SetObjectData( SerializationInfo info, StreamingContext context, ISurrogateSelector selector - ) { + ) + { var name = info.GetString("name"); return Assets.GetAnim(name); } diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/MinionStartingStatsSurrogate.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/MinionStartingStatsSurrogate.cs similarity index 93% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/MinionStartingStatsSurrogate.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/MinionStartingStatsSurrogate.cs index f040a03d..8717cd8b 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/MinionStartingStatsSurrogate.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/MinionStartingStatsSurrogate.cs @@ -3,13 +3,15 @@ using System.Linq; using System.Runtime.Serialization; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -public class MinionStartingStatsSurrogate : ISerializationSurrogate, ISurrogateType { +public class MinionStartingStatsSurrogate : ISerializationSurrogate, ISurrogateType +{ public Type Type => typeof(MinionStartingStats); - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { var stats = (MinionStartingStats) obj; info.AddValue("Name", stats.Name); info.AddValue("NameStringKey", stats.NameStringKey); @@ -32,7 +34,8 @@ public object SetObjectData( SerializationInfo info, StreamingContext context, ISurrogateSelector selector - ) { + ) + { var stats = (MinionStartingStats) obj; stats.Name = info.GetString("Name"); stats.NameStringKey = info.GetString("NameStringKey"); @@ -63,9 +66,11 @@ ISurrogateSelector selector private static Dictionary ToDictionary( IReadOnlyList keys, IReadOnlyList values - ) { + ) + { var result = new Dictionary(); - for (var i = 0; i < keys.Count; i++) { + for (var i = 0; i < keys.Count; i++) + { result[keys[i]] = values[i]; } return result; diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/PathNodeSurrogate.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/PathNodeSurrogate.cs similarity index 77% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/PathNodeSurrogate.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/PathNodeSurrogate.cs index 9ee24ca9..99793410 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/PathNodeSurrogate.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/PathNodeSurrogate.cs @@ -1,19 +1,22 @@ using System; using System.Runtime.Serialization; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -public class PathNodeSurrogate : ISerializationSurrogate, ISurrogateType { +public class PathNodeSurrogate : ISerializationSurrogate, ISurrogateType +{ public Type Type => typeof(BaseUtilityBuildTool.PathNode); - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { var node = (BaseUtilityBuildTool.PathNode) obj; info.AddValue("cell", node.cell); info.AddValue("valid", node.valid); } - public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) { + public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) + { var node = (BaseUtilityBuildTool.PathNode) obj; node.cell = info.GetInt32("cell"); node.valid = info.GetBoolean("valid"); diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/PrioritySettingSurrogate.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/PrioritySettingSurrogate.cs similarity index 78% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/PrioritySettingSurrogate.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/PrioritySettingSurrogate.cs index d5fdffb4..d7dbe2fd 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/PrioritySettingSurrogate.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/PrioritySettingSurrogate.cs @@ -1,19 +1,22 @@ using System; using System.Runtime.Serialization; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -public class PrioritySettingSurrogate : ISerializationSurrogate, ISurrogateType { +public class PrioritySettingSurrogate : ISerializationSurrogate, ISurrogateType +{ public Type Type => typeof(PrioritySetting); - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { var priority = (PrioritySetting) obj; info.AddValue("class", priority.priority_class); info.AddValue("value", priority.priority_value); } - public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) { + public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) + { var priority = (PrioritySetting) obj; priority.priority_class = (PriorityScreen.PriorityClass) info.GetInt32("class"); priority.priority_value = info.GetInt32("value"); diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/RoomSurrogate.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/RoomSurrogate.cs similarity index 87% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/RoomSurrogate.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/RoomSurrogate.cs index a4b0e79c..72f74e3c 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/RoomSurrogate.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/RoomSurrogate.cs @@ -3,13 +3,15 @@ using System.Linq; using System.Runtime.Serialization; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -public class RoomSurrogate : ISerializationSurrogate, ISurrogateType { +public class RoomSurrogate : ISerializationSurrogate, ISurrogateType +{ public Type Type => typeof(Room); - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { var room = obj as Room; var allIds = new List(room!.primary_buildings); allIds.AddRange(room.buildings); @@ -24,7 +26,8 @@ public void GetObjectData(object obj, SerializationInfo info, StreamingContext c SerializationInfo info, StreamingContext context, ISurrogateSelector selector - ) { + ) + { var cell = info.GetInt32("cell"); return global::Game.Instance.roomProber.GetCavityForCell(cell)?.room; } diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/ScheduleBlockTypeSurrogate.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/ScheduleBlockTypeSurrogate.cs similarity index 81% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/ScheduleBlockTypeSurrogate.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/ScheduleBlockTypeSurrogate.cs index a38ba1da..14e15656 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/ScheduleBlockTypeSurrogate.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/ScheduleBlockTypeSurrogate.cs @@ -1,13 +1,15 @@ using System; using System.Runtime.Serialization; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -public class ScheduleBlockTypeSurrogate : ISerializationSurrogate, ISurrogateType { +public class ScheduleBlockTypeSurrogate : ISerializationSurrogate, ISurrogateType +{ public Type Type => typeof(ScheduleBlockType); - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { var scheduleBlockType = (ScheduleBlockType) obj; info.AddValue("id", scheduleBlockType.Id); } @@ -17,7 +19,8 @@ public void GetObjectData(object obj, SerializationInfo info, StreamingContext c SerializationInfo info, StreamingContext context, ISurrogateSelector selector - ) { + ) + { var id = info.GetString("id"); return Db.Get().ScheduleBlockTypes.Get(id); } diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/SerializationSurrogates.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/SerializationSurrogates.cs similarity index 82% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/SerializationSurrogates.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/SerializationSurrogates.cs index 3161d66f..e5377a5e 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/SerializationSurrogates.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/SerializationSurrogates.cs @@ -1,13 +1,15 @@ -using System; +using System; using System.Runtime.Serialization; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -public static class SerializationSurrogates { +public static class SerializationSurrogates +{ public static readonly SurrogateSelector Selector = new(); - static SerializationSurrogates() { + static SerializationSurrogates() + { Selector.Add(new Vector2SerializationSurrogate()); Selector.Add(new Vector2fSerializationSurrogate()); Selector.Add(new Vector3SerializationSurrogate()); @@ -29,11 +31,13 @@ static SerializationSurrogates() { } private static void Add(this SurrogateSelector selector, T surrogate) - where T : ISerializationSurrogate, ISurrogateType { + where T : ISerializationSurrogate, ISurrogateType + { selector.AddSurrogate(surrogate.Type, new StreamingContext(StreamingContextStates.All), surrogate); } - public static bool HasSurrogate(Type type) { + public static bool HasSurrogate(Type type) + { return Selector.GetSurrogate(type, new StreamingContext(StreamingContextStates.All), out var _) != null; } diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/SpaceDestinationSurrogate.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/SpaceDestinationSurrogate.cs similarity index 81% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/SpaceDestinationSurrogate.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/SpaceDestinationSurrogate.cs index d0d8f849..9bb1d178 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/SpaceDestinationSurrogate.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/SpaceDestinationSurrogate.cs @@ -1,13 +1,15 @@ using System; using System.Runtime.Serialization; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -public class SpaceDestinationSurrogate : ISerializationSurrogate, ISurrogateType { +public class SpaceDestinationSurrogate : ISerializationSurrogate, ISurrogateType +{ public Type Type => typeof(SpaceDestination); - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { var destination = (SpaceDestination) obj; info.AddValue("id", destination.id); } @@ -17,7 +19,8 @@ public object SetObjectData( SerializationInfo info, StreamingContext context, ISurrogateSelector selector - ) { + ) + { var id = info.GetString("id"); return SpacecraftManager.instance.GetDestination(int.Parse(id)); } diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/SpiceGrinderSurrogate.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/SpiceGrinderSurrogate.cs similarity index 82% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/SpiceGrinderSurrogate.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/SpiceGrinderSurrogate.cs index 711307cd..d41c26e7 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/SpiceGrinderSurrogate.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/SpiceGrinderSurrogate.cs @@ -1,13 +1,15 @@ using System; using System.Runtime.Serialization; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -public class SpiceGrinderSurrogate : ISerializationSurrogate, ISurrogateType { +public class SpiceGrinderSurrogate : ISerializationSurrogate, ISurrogateType +{ public Type Type => typeof(SpiceGrinder.Option); - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { var option = (SpiceGrinder.Option) obj; info.AddValue("id", option.Id); } @@ -17,7 +19,8 @@ public object SetObjectData( SerializationInfo info, StreamingContext context, ISurrogateSelector selector - ) { + ) + { var tag = (Tag) info.GetValue("id", typeof(Tag)); return SpiceGrinder.SettingOptions[tag]; } diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/TagSurrogate.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/TagSurrogate.cs similarity index 75% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/TagSurrogate.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/TagSurrogate.cs index 1487bc29..104ff7c0 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/TagSurrogate.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/TagSurrogate.cs @@ -1,18 +1,21 @@ using System; using System.Runtime.Serialization; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -public class TagSurrogate : ISerializationSurrogate, ISurrogateType { +public class TagSurrogate : ISerializationSurrogate, ISurrogateType +{ public Type Type => typeof(Tag); - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { var tag = (Tag) obj; info.AddValue("hash", tag.hash); } - public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) { + public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) + { var tag = (Tag) obj; tag.hash = info.GetInt32("hash"); tag.name = TagManager.GetProperName(tag, stripLink: true); diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/Vector2SerializationSurrogate.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/Vector2SerializationSurrogate.cs similarity index 82% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/Vector2SerializationSurrogate.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/Vector2SerializationSurrogate.cs index 9b097264..4e51fdf6 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/Vector2SerializationSurrogate.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/Vector2SerializationSurrogate.cs @@ -2,13 +2,15 @@ using System.Runtime.Serialization; using UnityEngine; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -public class Vector2SerializationSurrogate : ISerializationSurrogate, ISurrogateType { +public class Vector2SerializationSurrogate : ISerializationSurrogate, ISurrogateType +{ public Type Type => typeof(Vector2); - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { var vector = (Vector2) obj; info.AddValue("x", vector.x); info.AddValue("y", vector.y); @@ -19,7 +21,8 @@ public object SetObjectData( SerializationInfo info, StreamingContext context, ISurrogateSelector selector - ) { + ) + { var vector = (Vector2) obj; vector.x = info.GetSingle("x"); vector.y = info.GetSingle("y"); diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/Vector2fSerializationSurrogate.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/Vector2fSerializationSurrogate.cs similarity index 83% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/Vector2fSerializationSurrogate.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/Vector2fSerializationSurrogate.cs index 5a2e4fcf..b576d9fb 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/Vector2fSerializationSurrogate.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/Vector2fSerializationSurrogate.cs @@ -1,14 +1,16 @@ using System; using System.Runtime.Serialization; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; // ReSharper disable once InconsistentNaming -public class Vector2fSerializationSurrogate : ISerializationSurrogate, ISurrogateType { +public class Vector2fSerializationSurrogate : ISerializationSurrogate, ISurrogateType +{ public Type Type => typeof(Vector2f); - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { var vector = (Vector2f) obj; info.AddValue("x", vector.x); info.AddValue("y", vector.y); @@ -19,7 +21,8 @@ public object SetObjectData( SerializationInfo info, StreamingContext context, ISurrogateSelector selector - ) { + ) + { var vector = (Vector2f) obj; vector.x = info.GetSingle("x"); vector.y = info.GetSingle("y"); diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/Vector3SerializationSurrogate.cs b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/Vector3SerializationSurrogate.cs similarity index 84% rename from src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/Vector3SerializationSurrogate.cs rename to src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/Vector3SerializationSurrogate.cs index 5ee6e60e..b678f0f7 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/Vector3SerializationSurrogate.cs +++ b/src/MultiplayerMod/Platform/Common/Network/Messaging/Surrogates/Vector3SerializationSurrogate.cs @@ -2,13 +2,15 @@ using System.Runtime.Serialization; using UnityEngine; -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; +namespace MultiplayerMod.Platform.Common.Network.Messaging.Surrogates; -public class Vector3SerializationSurrogate : ISerializationSurrogate, ISurrogateType { +public class Vector3SerializationSurrogate : ISerializationSurrogate, ISurrogateType +{ public Type Type => typeof(Vector3); - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { var vector = (Vector3) obj; info.AddValue("x", vector.x); info.AddValue("y", vector.y); @@ -20,7 +22,8 @@ public object SetObjectData( SerializationInfo info, StreamingContext context, ISurrogateSelector selector - ) { + ) + { var vector = (Vector3) obj; vector.x = info.GetSingle("x"); vector.y = info.GetSingle("y"); diff --git a/src/MultiplayerMod/Platform/Steam/Network/NetworkPlatformException.cs b/src/MultiplayerMod/Platform/Common/Network/NetworkPlatformException.cs similarity index 57% rename from src/MultiplayerMod/Platform/Steam/Network/NetworkPlatformException.cs rename to src/MultiplayerMod/Platform/Common/Network/NetworkPlatformException.cs index 57cb3cfb..73fe5143 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/NetworkPlatformException.cs +++ b/src/MultiplayerMod/Platform/Common/Network/NetworkPlatformException.cs @@ -1,8 +1,9 @@ -using System; +using System; -namespace MultiplayerMod.Platform.Steam.Network; +namespace MultiplayerMod.Platform.Common.Network; -public class NetworkPlatformException : PlatformException { +public class NetworkPlatformException : PlatformException +{ public NetworkPlatformException(string message) : base(message) { } public NetworkPlatformException(string message, Exception cause) : base(message, cause) { } } diff --git a/src/MultiplayerMod/Platform/Common/Network/SharedClient.cs b/src/MultiplayerMod/Platform/Common/Network/SharedClient.cs new file mode 100644 index 00000000..4694e417 --- /dev/null +++ b/src/MultiplayerMod/Platform/Common/Network/SharedClient.cs @@ -0,0 +1,41 @@ +using System; +using JetBrains.Annotations; +using MultiplayerMod.Core.Dependency; +using MultiplayerMod.Multiplayer.Commands; +using MultiplayerMod.Network; +using MultiplayerMod.Platform.Steam.Network; +using MultiplayerMod.Platform.Lan.Network; + +namespace MultiplayerMod.Platform.Common.Network; + +[Dependency, UsedImplicitly] +public class SharedClient : IMultiplayerClient +{ + public MultiplayerClientState State { get { return client.State; } } + + public event Action? StateChanged { add { client.StateChanged += value; } remove { client.StateChanged -= value; } } + public event Action? CommandReceived { add { client.CommandReceived += value; } remove { client.CommandReceived -= value; } } + public IMultiplayerClientId Id { get { return client.Id; } } + + public void Connect(IMultiplayerEndpoint endpoint) { client.Connect(endpoint); } + public void Disconnect() { client.Disconnect(); } + public void Send(IMultiplayerCommand command, MultiplayerCommandOptions options = MultiplayerCommandOptions.None) { client.Send(command, options); } + public void Tick() { client.Tick(); } + + private IMultiplayerClient? cachedClient = null; + private IMultiplayerClient client + { + get + { + if (cachedClient != null) { return cachedClient; } + + if (Configuration.useSteam) { + cachedClient = new SteamClient(); + } else { + cachedClient = new LanClient(); + } + return cachedClient; + } + } + +} diff --git a/src/MultiplayerMod/Platform/Common/Network/SharedServer.cs b/src/MultiplayerMod/Platform/Common/Network/SharedServer.cs new file mode 100644 index 00000000..e78a0ae8 --- /dev/null +++ b/src/MultiplayerMod/Platform/Common/Network/SharedServer.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using MultiplayerMod.Core.Dependency; +using MultiplayerMod.Multiplayer.Commands; +using MultiplayerMod.Network; +using MultiplayerMod.Platform.Steam.Network; +using MultiplayerMod.Platform.Lan.Network; + +namespace MultiplayerMod.Platform.Common.Network; + +[Dependency, UsedImplicitly] +public class SharedServer : IMultiplayerServer +{ + public MultiplayerServerState State { get { return server.State; } } + + public IMultiplayerEndpoint Endpoint { get { return server.Endpoint; } } + + public List Clients { get { return server.Clients; } } + + public event Action StateChanged { add { server.StateChanged += value; } remove { server.StateChanged -= value; } } + public event Action ClientConnected { add { server.ClientConnected += value; } remove { server.ClientConnected -= value; } } + public event Action ClientDisconnected { add { server.ClientDisconnected += value; } remove { server.ClientDisconnected -= value; } } + public event Action CommandReceived { add { server.CommandReceived += value; } remove { server.CommandReceived -= value; } } + + public void Send(IMultiplayerClientId clientId, IMultiplayerCommand command) { server.Send(clientId, command); } + + public void Send(IMultiplayerCommand command, MultiplayerCommandOptions options = MultiplayerCommandOptions.None) { server.Send(command, options); } + + public void Tick() { server.Tick(); } + + public void Start() { server.Start(); } + + public void Stop() { server.Stop(); } + + private IMultiplayerServer? cachedServer = null; + private IMultiplayerServer server + { + get + { + if (cachedServer != null) { return cachedServer; } + + if (Configuration.useSteam) { + cachedServer = new SteamServer(); + } else { + cachedServer = new LanServer(); + } + return cachedServer; + } + } + +} diff --git a/src/MultiplayerMod/Platform/Common/SharedMultiplayerOperations.cs b/src/MultiplayerMod/Platform/Common/SharedMultiplayerOperations.cs new file mode 100644 index 00000000..c24e5d37 --- /dev/null +++ b/src/MultiplayerMod/Platform/Common/SharedMultiplayerOperations.cs @@ -0,0 +1,28 @@ +using JetBrains.Annotations; +using MultiplayerMod.Core.Dependency; +using MultiplayerMod.Multiplayer; +using MultiplayerMod.Platform.Lan; +using MultiplayerMod.Platform.Steam; + +namespace MultiplayerMod.Platform.Common; + +[Dependency, UsedImplicitly] +public class SharedMultiplayerOperations : IMultiplayerOperations { + + public void Join() => instance.Join(); + + private IMultiplayerOperations? cachedInstance = null; + private IMultiplayerOperations instance { + get { + if (cachedInstance != null) { return cachedInstance; } + + if (Configuration.useSteam) { + cachedInstance = new SteamMultiplayerOperations(); + } else { + cachedInstance = new LanMultiplayerOperations(); + } + return cachedInstance; + } + } + +} diff --git a/src/MultiplayerMod/Platform/Common/SharedPlayerProfileProvider.cs b/src/MultiplayerMod/Platform/Common/SharedPlayerProfileProvider.cs new file mode 100644 index 00000000..2b43a4a5 --- /dev/null +++ b/src/MultiplayerMod/Platform/Common/SharedPlayerProfileProvider.cs @@ -0,0 +1,28 @@ +using JetBrains.Annotations; +using MultiplayerMod.Core.Dependency; +using MultiplayerMod.Multiplayer.Players; +using MultiplayerMod.Platform.Lan; +using MultiplayerMod.Platform.Steam; + +namespace MultiplayerMod.Platform.Common; + +[Dependency, UsedImplicitly] +public class SharedPlayerProfileProvider : IPlayerProfileProvider { + + public PlayerProfile GetPlayerProfile() => instance.GetPlayerProfile(); + + private IPlayerProfileProvider? cachedInstance = null; + private IPlayerProfileProvider instance { + get { + if (cachedInstance != null) { return cachedInstance; } + + if (Configuration.useSteam) { + cachedInstance = new SteamPlayerProfileProvider(); + } else { + cachedInstance = new LanPlayerProfileProvider(); + } + return cachedInstance; + } + } + +} diff --git a/src/MultiplayerMod/Platform/Lan/LanJoinRequestComponent.cs b/src/MultiplayerMod/Platform/Lan/LanJoinRequestComponent.cs new file mode 100644 index 00000000..4f767904 --- /dev/null +++ b/src/MultiplayerMod/Platform/Lan/LanJoinRequestComponent.cs @@ -0,0 +1,19 @@ +using MultiplayerMod.Core.Dependency; +using MultiplayerMod.Core.Events; +using MultiplayerMod.Core.Unity; + +// ReSharper disable FieldCanBeMadeReadOnly.Local + +namespace MultiplayerMod.Platform.Lan; + +public class LanJoinRequestComponent : MultiplayerMonoBehaviour { + public static LanJoinRequestComponent? instance; + + [InjectDependency] + public EventDispatcher eventDispatcher = null!; + + LanJoinRequestComponent() { + instance = this; + } + +} diff --git a/src/MultiplayerMod/Platform/Lan/LanMultiplayerOperations.cs b/src/MultiplayerMod/Platform/Lan/LanMultiplayerOperations.cs new file mode 100644 index 00000000..8cd7f98b --- /dev/null +++ b/src/MultiplayerMod/Platform/Lan/LanMultiplayerOperations.cs @@ -0,0 +1,12 @@ +using MultiplayerMod.Multiplayer; +using MultiplayerMod.Multiplayer.Players.Events; +using MultiplayerMod.Platform.Lan.Network; +using MultiplayerMod.Platform.Steam.Network; + +namespace MultiplayerMod.Platform.Lan; + +internal class LanMultiplayerOperations : IMultiplayerOperations { + public void Join() { + LanJoinRequestComponent.instance?.eventDispatcher.Dispatch(new MultiplayerJoinRequestedEvent(new LanServerEndpoint(), LanConfiguration.instance.displayName)); + } +} diff --git a/src/MultiplayerMod/Platform/Lan/LanPlatformConfigurer.cs b/src/MultiplayerMod/Platform/Lan/LanPlatformConfigurer.cs new file mode 100644 index 00000000..c4d1c208 --- /dev/null +++ b/src/MultiplayerMod/Platform/Lan/LanPlatformConfigurer.cs @@ -0,0 +1,16 @@ +using JetBrains.Annotations; +using MultiplayerMod.Core.Dependency; +using MultiplayerMod.Core.Unity; +using MultiplayerMod.ModRuntime.Loader; + +namespace MultiplayerMod.Platform.Lan; + +[UsedImplicitly] +[ModComponentOrder(ModComponentOrder.Platform)] +public class LanPlatformConfigurer : IModComponentConfigurer { + + public void Configure(DependencyContainerBuilder builder) { + builder.ContainerCreated += _ => UnityObject.CreateStaticWithComponent(); + } + +} diff --git a/src/MultiplayerMod/Platform/Lan/LanPlayerProfileProvider.cs b/src/MultiplayerMod/Platform/Lan/LanPlayerProfileProvider.cs new file mode 100644 index 00000000..c5a245ae --- /dev/null +++ b/src/MultiplayerMod/Platform/Lan/LanPlayerProfileProvider.cs @@ -0,0 +1,17 @@ +using MultiplayerMod.Multiplayer.Players; +using MultiplayerMod.Platform.Lan.Network; +using System; + +namespace MultiplayerMod.Platform.Lan +{ + internal class LanPlayerProfileProvider : IPlayerProfileProvider { + + private readonly Lazy profile = new( + () => new PlayerProfile( + LanConfiguration.instance.playerName + ) + ); + + public PlayerProfile GetPlayerProfile() => profile.Value; + } +} diff --git a/src/MultiplayerMod/Platform/Lan/Network/ClientMessage.cs b/src/MultiplayerMod/Platform/Lan/Network/ClientMessage.cs new file mode 100644 index 00000000..e43b347a --- /dev/null +++ b/src/MultiplayerMod/Platform/Lan/Network/ClientMessage.cs @@ -0,0 +1,14 @@ +using MultiplayerMod.Network; +using MultiplayerMod.Platform.Common.Network.Messaging; + +namespace MultiplayerMod.Platform.Lan.Network; + +internal class ClientMessage { + internal readonly IMultiplayerClientId clientId; + internal readonly NetworkMessage message; + + public ClientMessage(IMultiplayerClientId clientId, NetworkMessage message) { + this.clientId = clientId; + this.message = message; + } +} diff --git a/src/MultiplayerMod/Platform/Lan/Network/LanClient.cs b/src/MultiplayerMod/Platform/Lan/Network/LanClient.cs new file mode 100644 index 00000000..637c7834 --- /dev/null +++ b/src/MultiplayerMod/Platform/Lan/Network/LanClient.cs @@ -0,0 +1,133 @@ +using MultiplayerMod.Core.Logging; +using MultiplayerMod.Core.Scheduling; +using MultiplayerMod.Core.Unity; +using MultiplayerMod.ModRuntime.StaticCompatibility; +using MultiplayerMod.Multiplayer.Commands; +using MultiplayerMod.Multiplayer.Commands.Player; +using MultiplayerMod.Multiplayer.UI.Overlays; +using MultiplayerMod.Network; +using MultiplayerMod.Platform.Common.Network.Components; +using MultiplayerMod.Platform.Common.Network.Messaging; +using System; +using System.Collections.Concurrent; +using System.Threading.Tasks; +using UnityEngine; +using WebSocketSharp; + +namespace MultiplayerMod.Platform.Lan.Network; + +internal class LanClient : IMultiplayerClient { + public static LanClient? instance = null; + + public IMultiplayerClientId Id => lanMultiplayerClientId; + public MultiplayerClientState State { get; private set; } = MultiplayerClientState.Disconnected; + + public event Action? StateChanged; + public event Action? CommandReceived; + + internal readonly LanMultiplayerClientId lanMultiplayerClientId = new LanMultiplayerClientId(); + private WebSocket? network; + + private GameObject? gameObject = null!; + + private readonly Core.Logging.Logger log = LoggerFactory.GetLogger(); + private ConcurrentQueue commandQueue = new(); + + public LanClient() { + //log.Level = Core.Logging.LogLevel.Debug; + instance = this; + } + + public void Connect(IMultiplayerEndpoint endpoint) { + LanConfiguration.reload(); + log.Info("Client connecting to server " + LanConfiguration.instance.hostUrl); + commandQueue = new(); + network = new WebSocket(LanConfiguration.instance.hostUrl+"/oni"); + network.OnOpen += OnOpen; + network.OnMessage += OnMessage; + network.OnClose += OnClose; + network.OnError += OnError; + SetState(MultiplayerClientState.Connecting); + network.ConnectAsync(); + gameObject = UnityObject.CreateStaticWithComponent(); + } + + public void Disconnect() { + if (network == null) { return; } + log.Info("Client disconnected from server"); + var oldnetwork = network; + network = null; + oldnetwork.CloseAsync(); + if (gameObject != null) { + UnityObject.Destroy(gameObject); + gameObject = null!; + } + } + + public void Send(IMultiplayerCommand command, MultiplayerCommandOptions options = MultiplayerCommandOptions.None) { + if (network == null) { return; } + try { + var data = new NetworkMessage(command, options).toBytes(); + + if (command.GetType() != typeof(UpdatePlayerCursorPosition)) { + log.Debug("Client sending command " + command.GetType() + ". Client " + Id + ". Len " + data.Length); + } + network.Send(data); + } catch (Exception e) { + log.Debug("Client failed to send command " + command.GetType() + ". " + e.Message); + } + } + + public void Tick() { + while (commandQueue.TryDequeue(out var action)) { + action(); + } + } + + private void SetState(MultiplayerClientState status) { + State = status; + StateChanged?.Invoke(status); + } + + private void OnOpen(object sender, EventArgs e) { + log.Debug("Client connected to server"); + commandQueue.Enqueue(() => { + SetState(MultiplayerClientState.Connected); + }); + } + + private void OnClose(object sender, CloseEventArgs e) { + log.Debug("Client disconnected from server"); + commandQueue.Enqueue(() => { + if (State == MultiplayerClientState.Connecting) { + log.Warning("Multiplayer connection to server could not be established."); + MultiplayerStatusOverlay.Text = "Failed to connect to server"; + Task _ = this.closeOverlay(); + } + SetState(MultiplayerClientState.Disconnected); + Disconnect(); + }); + } + + private async Task closeOverlay() { + await Task.Delay(2000); + Dependencies.Get().Run(MultiplayerStatusOverlay.Close); + } + + private void OnMessage(object sender, MessageEventArgs e) { + var message = NetworkMessage.from(e.RawData); + log.Debug("Client received command " + message.Command.GetType() + ". Client " + Id + ". Len " + e.RawData.Length); + commandQueue.Enqueue(() => { + if (State != MultiplayerClientState.Connected) { return; } + CommandReceived?.Invoke(message.Command); + }); + } + + private void OnError(object sender, ErrorEventArgs e) { + log.Warning("Client error " + e.Message); + commandQueue.Enqueue(() => { + SetState(MultiplayerClientState.Error); + }); + } + +} diff --git a/src/MultiplayerMod/Platform/Lan/Network/LanConfiguration.cs b/src/MultiplayerMod/Platform/Lan/Network/LanConfiguration.cs new file mode 100644 index 00000000..a930344c --- /dev/null +++ b/src/MultiplayerMod/Platform/Lan/Network/LanConfiguration.cs @@ -0,0 +1,87 @@ +using MultiplayerMod.Core.Logging; +using System; +using System.IO; +using System.Reflection; +using System.Text; + +namespace MultiplayerMod.Platform.Lan.Network; + +public class LanConfiguration +{ + public static LanConfiguration instance = new LanConfiguration(); + public static void reload() { + var newConfig = new LanConfiguration(); + if (newConfig.isConfigured != instance.isConfigured) { + instance.log.Warning("Unable to enable/disable lan configuration while running, please restart Oxygen Not Included."); + return; + } + instance = newConfig; + } + + public bool isConfigured { get { return configured; } } + public string serverIp { get { return hostip; } } + public ushort serverPort { get { return hostport; } } + + public string hostUrl { get { + return "ws://" + serverIp + ":" + serverPort; + } + } + + public string displayName { get { return serverIp + " (" + serverPort + ")"; } } + public string playerName { get { return name; } } + + + private string hostfilename = "lanconfig.txt"; + private bool configured = false; + private string name = "LanPlayer"; + private string hostip = "127.0.0.1"; + private ushort hostport = 7171; + private readonly Core.Logging.Logger log = LoggerFactory.GetLogger(); + + private LanConfiguration() { + //log.Level = LogLevel.Debug; + configured = readConfiguration(); + } + + private bool readConfiguration() { + string moddir = Path.GetDirectoryName(Assembly.GetAssembly(typeof(LanConfiguration)).Location); + string fulldir = Path.Combine(moddir, hostfilename); + if (!File.Exists(fulldir)) { + return false; + } + + try { + using (FileStream fileStream = File.Open(fulldir, FileMode.Open, FileAccess.Read, FileShare.None)) { + using (var streamReader = new StreamReader(fileStream, Encoding.UTF8, true, 1024)) { + bool foundHost = false; + string line; + while ((line = streamReader.ReadLine()) != null) { + if (line.IndexOf("#") > -1) { line = line.Substring(0, line.IndexOf("#")); } + int splitat = line.IndexOf('='); + if (splitat == -1) { continue; } + + string key = line.Substring(0, splitat).Trim().ToLowerInvariant(); + string value = line.Substring(splitat + 1).Trim(); + switch (key) { + case "hostip": + hostip = value; + foundHost = true; + continue; + case "hostport": + hostport = ushort.Parse(value); + continue; + case "playername": + name = value; + continue; + } + } + return foundHost; + } + } + } catch (Exception e) { + log.Warning("Unable to read lan configuration from " + fulldir + ": "+e.Message); + } + return false; + } + +} diff --git a/src/MultiplayerMod/Platform/Lan/Network/LanConnection.cs b/src/MultiplayerMod/Platform/Lan/Network/LanConnection.cs new file mode 100644 index 00000000..514e813f --- /dev/null +++ b/src/MultiplayerMod/Platform/Lan/Network/LanConnection.cs @@ -0,0 +1,15 @@ +using System; + +namespace MultiplayerMod.Platform.Lan.Network; + +internal class LanConnection : IEquatable { + internal readonly LanMultiplayerClientId id; + + internal LanConnection(LanMultiplayerClientId id) { + this.id = id; + } + + public bool Equals(LanConnection other) { + return other.id == id; + } +} diff --git a/src/MultiplayerMod/Platform/Lan/Network/LanMultiplayerClientId.cs b/src/MultiplayerMod/Platform/Lan/Network/LanMultiplayerClientId.cs new file mode 100644 index 00000000..d058ee0c --- /dev/null +++ b/src/MultiplayerMod/Platform/Lan/Network/LanMultiplayerClientId.cs @@ -0,0 +1,23 @@ +using MultiplayerMod.Network; +using System; + +namespace MultiplayerMod.Platform.Lan.Network; + +[Serializable] +public record LanMultiplayerClientId : IMultiplayerClientId { + public readonly string Id; + + public LanMultiplayerClientId() : this(Guid.NewGuid().ToString()) { } + + public LanMultiplayerClientId(string id) { + Id = id; + } + + public bool Equals(IMultiplayerClientId other) { + return other is LanMultiplayerClientId player && player.Equals(this); + } + + public override string ToString() { + return Id; + } +} diff --git a/src/MultiplayerMod/Platform/Lan/Network/LanServer.cs b/src/MultiplayerMod/Platform/Lan/Network/LanServer.cs new file mode 100644 index 00000000..b604e6d4 --- /dev/null +++ b/src/MultiplayerMod/Platform/Lan/Network/LanServer.cs @@ -0,0 +1,200 @@ +using MultiplayerMod.Core.Logging; +using MultiplayerMod.Core.Unity; +using MultiplayerMod.Multiplayer.Commands; +using MultiplayerMod.Network; +using MultiplayerMod.Platform.Common.Network.Components; +using System; +using System.Collections.Generic; +using UnityEngine; +using MultiplayerMod.Platform.Common.Network; +using MultiplayerMod.ModRuntime.StaticCompatibility; +using MultiplayerMod.Multiplayer.Commands.Registry; +using WebSocketSharp; +using WebSocketSharp.Server; +using System.Linq; +using MultiplayerMod.Platform.Common.Network.Messaging; +using MultiplayerMod.Core.Extensions; +using MultiplayerMod.Core.Collections; +using System.Collections.Concurrent; +using MultiplayerMod.Multiplayer.Commands.Player; +namespace MultiplayerMod.Platform.Lan.Network; +public record ServerEndpoint : IMultiplayerEndpoint ; + +internal class LanServer : IMultiplayerServer { + public static LanServer? instance = null; + + public MultiplayerServerState State { private set; get; } = MultiplayerServerState.Stopped; + public IMultiplayerEndpoint Endpoint => new ServerEndpoint(); + + public List Clients => new(clientIdToLanClient.Select(it => it.Key)); + + public event Action? StateChanged; + public event Action? ClientConnected; + public event Action? ClientDisconnected; + public event Action? CommandReceived; + + private readonly Dictionary lanClientIdToClientId = new(); + private readonly Dictionary clientIdToLanClient = new(); + + private readonly Core.Logging.Logger log = LoggerFactory.GetLogger(); + private GameObject? gameObject; + + private readonly MultiplayerCommandRegistry commands; + + private WebSocketServer? network; + private ConcurrentQueue commandQueue = new(); + + public LanServer() : this(Dependencies.Get()) { } + + public LanServer(MultiplayerCommandRegistry commands) { + //log.Level = Core.Logging.LogLevel.Debug; + instance = this; + this.commands = commands; + } + + public void Start() { + LanConfiguration.reload(); + log.Info("Server preparing to listen on "+ LanConfiguration.instance.hostUrl); + commandQueue = new(); + SetState(MultiplayerServerState.Preparing); + network = new WebSocketServer(LanConfiguration.instance.serverPort); + network.AddWebSocketService("/oni"); + SetState(MultiplayerServerState.Starting); + network.Start(); + gameObject = UnityObject.CreateStaticWithComponent(); + SetState(MultiplayerServerState.Started); + } + + public void Stop() { + if (network == null) { return; } + + if (State <= MultiplayerServerState.Stopped) + throw new NetworkPlatformException("Server isn't started"); + + log.Info("Server preparing to stop"); + if (gameObject != null) { + UnityObject.Destroy(gameObject); + } + network.Stop(); + network = null; + SetState(MultiplayerServerState.Stopped); + } + + public void Send(IMultiplayerClientId clientId, IMultiplayerCommand command) { + var connections = new SingletonCollection(clientIdToLanClient[(LanMultiplayerClientId)clientId]); + SendCommand(command, MultiplayerCommandOptions.None, connections); + } + + public void Send(IMultiplayerCommand command, MultiplayerCommandOptions options = MultiplayerCommandOptions.None) { + IEnumerable> recipients = clientIdToLanClient; + if (options.HasFlag(MultiplayerCommandOptions.SkipHost) && LanClient.instance != null) { + recipients = recipients.Where(entry => !entry.Key.Equals(LanClient.instance.Id)); + } + + SendCommand(command, options, recipients.Select(it => it.Value)); + } + + public void Tick() { + while (commandQueue.TryDequeue(out var action)) { + action(); + } + } + + private void SetState(MultiplayerServerState state) { + State = state; + StateChanged?.Invoke(state); + } + + private void SendCommand(IMultiplayerCommand command, MultiplayerCommandOptions options, IEnumerable connections) { + var message = new NetworkMessage(command, options); + SendMessage(message, connections); + } + + private void SendMessage(NetworkMessage message, IEnumerable connections) { + if (connections.Count() == 0) { return; } + var clientId = lanClientIdToClientId[connections.First().ID]; + try { + var data = message.toBytes(); + + log.Debug("Server sending command " + message.Command.GetType() + " to " + connections.Count() + " clients (including " + clientId + "). Len " + data.Length); + connections.ForEach(client => { client.SendData(data); }); + } catch (Exception e) { + log.Warning("Server failed to send command " + message.Command.GetType() + " to " + connections.Count() + " clients (including " + clientId + "). " + e.Message); + } + } + + internal void AddClient(LanServerClient lanServerClient) { + LanMultiplayerClientId clientId; + if (lanClientIdToClientId.Count() == 0 && LanClient.instance != null) { + clientId = LanClient.instance.lanMultiplayerClientId; + } else { + clientId = new LanMultiplayerClientId(lanServerClient.ID); + } + lanClientIdToClientId.Add(lanServerClient.ID, clientId); + clientIdToLanClient.Add(clientId, lanServerClient); + commandQueue.Enqueue(() => { + log.Info("Server client connected - ID: " + clientId + ", IP: " + lanServerClient.Context.UserEndPoint.Address); + ClientConnected?.Invoke(clientId); + }); + } + + internal void RemoveClient(LanServerClient lanServerClient) { + var clientId = lanClientIdToClientId[lanServerClient.ID]; + lanClientIdToClientId.Remove(lanServerClient.ID); + clientIdToLanClient.Remove(clientId); + commandQueue.Enqueue(() => { + log.Info("Server client disconnected - ID: " + clientId); + ClientDisconnected?.Invoke(clientId); + }); + } + + internal void MessageReceived(LanServerClient lanServerClient, MessageEventArgs e) { + var clientId = lanClientIdToClientId[lanServerClient.ID]; + var message = NetworkMessage.from(e.RawData); + + if (message.Command.GetType() != typeof(UpdatePlayerCursorPosition)) { + log.Debug("Server received command " + message.Command.GetType() + " from client " + clientId.Id + ". Len " + e.RawData.Length); + } + + var configuration = commands.GetCommandConfiguration(message.Command.GetType()); + commandQueue.Enqueue(() => { + if (State != MultiplayerServerState.Starting + && State != MultiplayerServerState.Started) { + return; + } + + if (configuration.ExecuteOnServer) { + CommandReceived?.Invoke(clientId, message.Command); + } else { + var connections = clientIdToLanClient.Where(it => !it.Key.Equals(clientId)).Select(it => it.Value); + SendMessage(message, connections); + } + }); + } + +} + +internal class LanServerClient : WebSocketBehavior { + private readonly Core.Logging.Logger log = LoggerFactory.GetLogger(); + + protected override void OnOpen() { + LanServer.instance?.AddClient(this); + } + + protected override void OnClose(CloseEventArgs e) { + LanServer.instance?.RemoveClient(this); + } + + protected override void OnMessage(MessageEventArgs e) { + LanServer.instance?.MessageReceived(this, e); + } + + protected override void OnError(ErrorEventArgs e) { + log.Warning("Server client error " + e.Message); + } + + internal void SendData(byte[] data) { + Send(data); + } +} + diff --git a/src/MultiplayerMod/Platform/Lan/Network/LanServerEndpoint.cs b/src/MultiplayerMod/Platform/Lan/Network/LanServerEndpoint.cs new file mode 100644 index 00000000..73634c5f --- /dev/null +++ b/src/MultiplayerMod/Platform/Lan/Network/LanServerEndpoint.cs @@ -0,0 +1,5 @@ +using MultiplayerMod.Network; + +namespace MultiplayerMod.Platform.Steam.Network; + +public record LanServerEndpoint() : IMultiplayerEndpoint; diff --git a/src/MultiplayerMod/Platform/Steam/Network/Components/SteamClientComponent.cs b/src/MultiplayerMod/Platform/Steam/Network/Components/SteamClientComponent.cs deleted file mode 100644 index 16ac645c..00000000 --- a/src/MultiplayerMod/Platform/Steam/Network/Components/SteamClientComponent.cs +++ /dev/null @@ -1,15 +0,0 @@ -using MultiplayerMod.Core.Dependency; -using MultiplayerMod.Core.Unity; - -// ReSharper disable FieldCanBeMadeReadOnly.Local - -namespace MultiplayerMod.Platform.Steam.Network.Components; - -public class SteamClientComponent : MultiplayerMonoBehaviour { - - [InjectDependency] - private SteamClient client = null!; - - private void Update() => client.Tick(); - -} diff --git a/src/MultiplayerMod/Platform/Steam/Network/Components/SteamServerComponent.cs b/src/MultiplayerMod/Platform/Steam/Network/Components/SteamServerComponent.cs deleted file mode 100644 index f63c6715..00000000 --- a/src/MultiplayerMod/Platform/Steam/Network/Components/SteamServerComponent.cs +++ /dev/null @@ -1,15 +0,0 @@ -using MultiplayerMod.Core.Dependency; -using MultiplayerMod.Core.Unity; - -// ReSharper disable FieldCanBeMadeReadOnly.Local - -namespace MultiplayerMod.Platform.Steam.Network.Components; - -public class SteamServerComponent : MultiplayerMonoBehaviour { - - [InjectDependency] - private SteamServer server = null!; - - private void Update() => server.Tick(); - -} diff --git a/src/MultiplayerMod/Platform/Steam/Network/Configuration.cs b/src/MultiplayerMod/Platform/Steam/Network/Configuration.cs index 13915866..17e58319 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Configuration.cs +++ b/src/MultiplayerMod/Platform/Steam/Network/Configuration.cs @@ -1,5 +1,3 @@ -using System; -using MultiplayerMod.Platform.Steam.Network.Messaging; using Steamworks; namespace MultiplayerMod.Platform.Steam.Network; @@ -14,12 +12,4 @@ public static class Configuration { m_val = new SteamNetworkingConfigValue_t.OptionValue { m_int32 = size } }; - public const int MaxMessageSize = 524288; // 512 KiB - public static readonly int MaxFragmentDataSize = GetFragmentDataSize(); - - private static int GetFragmentDataSize() { - using var serialized = NetworkSerializer.Serialize(new NetworkMessageFragment(0, Array.Empty())); - return MaxMessageSize - (int) serialized.Size; - } - } diff --git a/src/MultiplayerMod/Platform/Steam/Network/Extensions.cs b/src/MultiplayerMod/Platform/Steam/Network/Extensions.cs index 47c1376f..311e4029 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/Extensions.cs +++ b/src/MultiplayerMod/Platform/Steam/Network/Extensions.cs @@ -1,4 +1,4 @@ -using MultiplayerMod.Platform.Steam.Network.Messaging; +using MultiplayerMod.Platform.Common.Network.Messaging; using Steamworks; namespace MultiplayerMod.Platform.Steam.Network; diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/INetworkMessage.cs b/src/MultiplayerMod/Platform/Steam/Network/Messaging/INetworkMessage.cs deleted file mode 100644 index 756a033a..00000000 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/INetworkMessage.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace MultiplayerMod.Platform.Steam.Network.Messaging; - -public interface INetworkMessage { } diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/INetworkMessageHandle.cs b/src/MultiplayerMod/Platform/Steam/Network/Messaging/INetworkMessageHandle.cs deleted file mode 100644 index 27fe4aa9..00000000 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/INetworkMessageHandle.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; - -namespace MultiplayerMod.Platform.Steam.Network.Messaging; - -public interface INetworkMessageHandle : IDisposable { - public IntPtr Pointer { get; } - public uint Size { get; } -} diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkMessage.cs b/src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkMessage.cs deleted file mode 100644 index 5bbcb68b..00000000 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkMessage.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using MultiplayerMod.Multiplayer.Commands; -using MultiplayerMod.Network; - -namespace MultiplayerMod.Platform.Steam.Network.Messaging; - -[Serializable] -public class NetworkMessage : INetworkMessage { - - public IMultiplayerCommand Command { get; } - public MultiplayerCommandOptions Options { get; } - - public NetworkMessage(IMultiplayerCommand command, MultiplayerCommandOptions options) { - Command = command; - Options = options; - } - -} diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkMessageFragment.cs b/src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkMessageFragment.cs deleted file mode 100644 index a136012c..00000000 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkMessageFragment.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace MultiplayerMod.Platform.Steam.Network.Messaging; - -[Serializable] -public class NetworkMessageFragment : INetworkMessage { - - public int MessageId { get; } - public byte[] Data { get; } - - public NetworkMessageFragment(int messageId, byte[] data) { - MessageId = messageId; - Data = data; - } - -} diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkMessageHandle.cs b/src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkMessageHandle.cs deleted file mode 100644 index 09a9dbfb..00000000 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/NetworkMessageHandle.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; - -namespace MultiplayerMod.Platform.Steam.Network.Messaging; - -public class NetworkMessageHandle : INetworkMessageHandle { - - public IntPtr Pointer { get; } - public uint Size { get; } - - public NetworkMessageHandle(IntPtr pointer, uint size) { - Pointer = pointer; - Size = size; - } - - public void Dispose() { - // No disposal required - } - -} diff --git a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/ISurrogateType.cs b/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/ISurrogateType.cs deleted file mode 100644 index 7a438d47..00000000 --- a/src/MultiplayerMod/Platform/Steam/Network/Messaging/Surrogates/ISurrogateType.cs +++ /dev/null @@ -1,7 +0,0 @@ -using System; - -namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates; - -public interface ISurrogateType { - public Type Type { get; } -} diff --git a/src/MultiplayerMod/Platform/Steam/Network/SteamClient.cs b/src/MultiplayerMod/Platform/Steam/Network/SteamClient.cs index ca9b324e..33048856 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/SteamClient.cs +++ b/src/MultiplayerMod/Platform/Steam/Network/SteamClient.cs @@ -1,22 +1,21 @@ -using System; +using System; using System.Runtime.InteropServices; -using JetBrains.Annotations; -using MultiplayerMod.Core.Dependency; using MultiplayerMod.Core.Extensions; using MultiplayerMod.Core.Logging; using MultiplayerMod.Core.Unity; +using MultiplayerMod.ModRuntime.StaticCompatibility; using MultiplayerMod.Multiplayer.Commands; using MultiplayerMod.Network; -using MultiplayerMod.Platform.Steam.Network.Components; -using MultiplayerMod.Platform.Steam.Network.Messaging; +using MultiplayerMod.Platform.Common.Network.Messaging; +using MultiplayerMod.Platform.Common.Network.Components; using Steamworks; using UnityEngine; using static Steamworks.Constants; using static Steamworks.ESteamNetConnectionEnd; +using MultiplayerMod.Platform.Common.Network; namespace MultiplayerMod.Platform.Steam.Network; -[Dependency, UsedImplicitly] public class SteamClient : IMultiplayerClient { public IMultiplayerClientId Id => playerContainer.Value; @@ -38,6 +37,8 @@ public class SteamClient : IMultiplayerClient { private GameObject gameObject = null!; + public SteamClient() : this(Dependencies.Get()) { } + public SteamClient(SteamLobby lobby) { this.lobby = lobby; } @@ -87,6 +88,8 @@ public void Send(IMultiplayerCommand command, MultiplayerCommandOptions options if (State != MultiplayerClientState.Connected) throw new NetworkPlatformException("Client not connected"); + log.Debug("Client sending command " + command.GetType() + ". Client " + Id + "."); + messageFactory.Create(command, options).ForEach( handle => { var result = SteamNetworkingSockets.SendMessageToConnection( @@ -124,7 +127,7 @@ private void OnLobbyJoin() { SetRichPresence(); - gameObject = UnityObject.CreateStaticWithComponent(); + gameObject = UnityObject.CreateStaticWithComponent(); SetState(MultiplayerClientState.Connected); } diff --git a/src/MultiplayerMod/Platform/Steam/Network/SteamLobby.cs b/src/MultiplayerMod/Platform/Steam/Network/SteamLobby.cs index dd46a61b..b7a685f9 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/SteamLobby.cs +++ b/src/MultiplayerMod/Platform/Steam/Network/SteamLobby.cs @@ -1,9 +1,9 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; using MultiplayerMod.Core.Dependency; using MultiplayerMod.Core.Logging; using Steamworks; -namespace MultiplayerMod.Platform.Steam.Network; +namespace MultiplayerMod.Platform.Common.Network; [Dependency, UsedImplicitly] public class SteamLobby { diff --git a/src/MultiplayerMod/Platform/Steam/Network/SteamServer.cs b/src/MultiplayerMod/Platform/Steam/Network/SteamServer.cs index d07874b1..4cc3360f 100644 --- a/src/MultiplayerMod/Platform/Steam/Network/SteamServer.cs +++ b/src/MultiplayerMod/Platform/Steam/Network/SteamServer.cs @@ -1,21 +1,21 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -using JetBrains.Annotations; using MultiplayerMod.Core.Collections; -using MultiplayerMod.Core.Dependency; using MultiplayerMod.Core.Extensions; using MultiplayerMod.Core.Logging; using MultiplayerMod.Core.Scheduling; using MultiplayerMod.Core.Unity; +using MultiplayerMod.ModRuntime.StaticCompatibility; using MultiplayerMod.Multiplayer.Commands; using MultiplayerMod.Multiplayer.Commands.Registry; using MultiplayerMod.Network; -using MultiplayerMod.Platform.Steam.Network.Components; -using MultiplayerMod.Platform.Steam.Network.Messaging; +using MultiplayerMod.Platform.Common.Network; +using MultiplayerMod.Platform.Common.Network.Components; +using MultiplayerMod.Platform.Common.Network.Messaging; using Steamworks; using UnityEngine; using static Steamworks.Constants; @@ -25,7 +25,6 @@ namespace MultiplayerMod.Platform.Steam.Network; -[Dependency, UsedImplicitly] public class SteamServer : IMultiplayerServer { public MultiplayerServerState State { private set; get; } = MultiplayerServerState.Stopped; @@ -69,6 +68,8 @@ public IMultiplayerEndpoint Endpoint { private GameObject? gameObject; + public SteamServer() : this(Dependencies.Get(), Dependencies.Get(), Dependencies.Get()) { } + public SteamServer(SteamLobby lobby, UnityTaskScheduler scheduler, MultiplayerCommandRegistry commands) { this.lobby = lobby; this.scheduler = scheduler; @@ -88,7 +89,7 @@ public void Start() { SetState(MultiplayerServerState.Error); throw; } - gameObject = UnityObject.CreateStaticWithComponent(); + gameObject = UnityObject.CreateStaticWithComponent(); } public void Stop() { @@ -132,7 +133,7 @@ private void SetState(MultiplayerServerState state) { } private void Initialize() { - steamServersConnectedCallback = Callback + steamServersConnectedCallback = Callback .CreateGameServer(_ => ConnectedToSteamCallback()); lobbyCompletionSource = new TaskCompletionSource(); diff --git a/src/MultiplayerMod/Platform/Steam/SteamMultiplayerOperations.cs b/src/MultiplayerMod/Platform/Steam/SteamMultiplayerOperations.cs index ff86a0fa..396fb439 100644 --- a/src/MultiplayerMod/Platform/Steam/SteamMultiplayerOperations.cs +++ b/src/MultiplayerMod/Platform/Steam/SteamMultiplayerOperations.cs @@ -1,11 +1,8 @@ -using JetBrains.Annotations; -using MultiplayerMod.Core.Dependency; using MultiplayerMod.Multiplayer; using Steamworks; namespace MultiplayerMod.Platform.Steam; -[Dependency, UsedImplicitly] public class SteamMultiplayerOperations : IMultiplayerOperations { public void Join() => SteamFriends.ActivateGameOverlay("friends"); diff --git a/src/MultiplayerMod/Platform/Steam/SteamPlayerProfileProvider.cs b/src/MultiplayerMod/Platform/Steam/SteamPlayerProfileProvider.cs index 6f48b775..feb76d65 100644 --- a/src/MultiplayerMod/Platform/Steam/SteamPlayerProfileProvider.cs +++ b/src/MultiplayerMod/Platform/Steam/SteamPlayerProfileProvider.cs @@ -1,12 +1,9 @@ -using System; -using JetBrains.Annotations; -using MultiplayerMod.Core.Dependency; +using System; using MultiplayerMod.Multiplayer.Players; using Steamworks; namespace MultiplayerMod.Platform.Steam; -[Dependency, UsedImplicitly] public class SteamPlayerProfileProvider : IPlayerProfileProvider { private readonly Lazy profile = new( diff --git a/src/MultiplayerMod/lanconfig.example.txt b/src/MultiplayerMod/lanconfig.example.txt new file mode 100644 index 00000000..09ceaf92 --- /dev/null +++ b/src/MultiplayerMod/lanconfig.example.txt @@ -0,0 +1,5 @@ +# To use a lan connection instead of the steam lobby, rename this file to lanconfig.txt and enter the ip of the host machine. +# You may also wish to enter a name you'd like to use. +playername=LanPlayer +hostip=192.168.1.1 +hostport=7171