Fix mod communication (probably)

This commit is contained in:
Brant Martin
2018-12-24 18:02:43 -05:00
parent 76637b130c
commit 66b7adf485
3 changed files with 95 additions and 94 deletions

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Torch.Mod.Messages
{
/// <summary>
/// shim to store incoming message data
/// </summary>
internal class IncomingMessage : MessageBase
{
public IncomingMessage()
{
}
public override void ProcessClient()
{
throw new Exception();
}
public override void ProcessServer()
{
throw new Exception();
}
}
}

View File

@@ -8,6 +8,7 @@ using System.Threading.Tasks;
using Sandbox.ModAPI;
using Torch.Mod.Messages;
using VRage;
using VRage.Collections;
using VRage.Game.ModAPI;
using VRage.Utils;
using Task = ParallelTasks.Task;
@@ -18,24 +19,20 @@ namespace Torch.Mod
{
public const ushort NET_ID = 4352;
private static bool _closing;
private static ConcurrentQueue<MessageBase> _outgoing;
private static ConcurrentQueue<byte[]> _incoming;
private static BlockingCollection<MessageBase> _processing;
private static MyConcurrentPool<IncomingMessage> _messagePool;
private static List<IMyPlayer> _playerCache;
private static FastResourceLock _lock;
private static Task _task;
public static void Register()
{
MyLog.Default.WriteLineAndConsole("TORCH MOD: Registering mod communication.");
_outgoing = new ConcurrentQueue<MessageBase>();
_incoming = new ConcurrentQueue<byte[]>();
_processing = new BlockingCollection<MessageBase>(new ConcurrentQueue<MessageBase>());
_playerCache = new List<IMyPlayer>();
_lock = new FastResourceLock();
_messagePool = new MyConcurrentPool<IncomingMessage>(8);
MyAPIGateway.Multiplayer.RegisterMessageHandler(NET_ID, MessageHandler);
//background thread to handle de/compression and processing
_task = MyAPIGateway.Parallel.StartBackground(DoProcessing);
MyAPIGateway.Parallel.StartBackground(DoProcessing);
MyLog.Default.WriteLineAndConsole("TORCH MOD: Mod communication registered successfully.");
}
@@ -43,15 +40,16 @@ namespace Torch.Mod
{
MyLog.Default.WriteLineAndConsole("TORCH MOD: Unregistering mod communication.");
MyAPIGateway.Multiplayer?.UnregisterMessageHandler(NET_ID, MessageHandler);
ReleaseLock();
_processing.CompleteAdding();
_closing = true;
//_task.Wait();
}
private static void MessageHandler(byte[] bytes)
{
_incoming.Enqueue(bytes);
ReleaseLock();
var m = _messagePool.Get();
m.CompressedData = bytes;
_processing.Add(m);
}
public static void DoProcessing()
@@ -60,75 +58,68 @@ namespace Torch.Mod
{
try
{
byte[] incoming;
while (_incoming.TryDequeue(out incoming))
var m = _processing.Take();
if (m is IncomingMessage)
{
MessageBase m;
MessageBase i;
try
{
var o = MyCompression.Decompress(incoming);
m = MyAPIGateway.Utilities.SerializeFromBinary<MessageBase>(o);
var o = MyCompression.Decompress(m.CompressedData);
m.CompressedData = null;
_messagePool.Return((IncomingMessage)m);
i = MyAPIGateway.Utilities.SerializeFromBinary<MessageBase>(o);
}
catch (Exception ex)
{
MyLog.Default.WriteLineAndConsole($"TORCH MOD: Failed to deserialize message! {ex}");
continue;
}
if (MyAPIGateway.Multiplayer.IsServer)
m.ProcessServer();
else
m.ProcessClient();
}
if (!_outgoing.IsEmpty)
if (MyAPIGateway.Multiplayer.IsServer)
i.ProcessServer();
else
i.ProcessClient();
}
else
{
List<MessageBase> tosend = new List<MessageBase>(_outgoing.Count);
MessageBase outMessage;
while (_outgoing.TryDequeue(out outMessage))
{
var b = MyAPIGateway.Utilities.SerializeToBinary(outMessage);
outMessage.CompressedData = MyCompression.Compress(b);
tosend.Add(outMessage);
}
var b = MyAPIGateway.Utilities.SerializeToBinary(m);
m.CompressedData = MyCompression.Compress(b);
MyAPIGateway.Utilities.InvokeOnGameThread(() =>
{
MyAPIGateway.Players.GetPlayers(_playerCache);
foreach (var outgoing in tosend)
{
switch (outgoing.TargetType)
{
case MessageTarget.Single:
MyAPIGateway.Multiplayer.SendMessageTo(NET_ID, outgoing.CompressedData, outgoing.Target);
break;
case MessageTarget.Server:
MyAPIGateway.Multiplayer.SendMessageToServer(NET_ID, outgoing.CompressedData);
break;
case MessageTarget.AllClients:
foreach (var p in _playerCache)
{
if (p.SteamUserId == MyAPIGateway.Multiplayer.MyId)
continue;
MyAPIGateway.Multiplayer.SendMessageTo(NET_ID, outgoing.CompressedData, p.SteamUserId);
}
break;
case MessageTarget.AllExcept:
foreach (var p in _playerCache)
{
if (p.SteamUserId == MyAPIGateway.Multiplayer.MyId || outgoing.Ignore.Contains(p.SteamUserId))
continue;
MyAPIGateway.Multiplayer.SendMessageTo(NET_ID, outgoing.CompressedData, p.SteamUserId);
}
break;
default:
throw new Exception();
}
}
_playerCache.Clear();
});
}
{
AcquireLock();
switch (m.TargetType)
{
case MessageTarget.Single:
MyAPIGateway.Multiplayer.SendMessageTo(NET_ID, m.CompressedData, m.Target);
break;
case MessageTarget.Server:
MyAPIGateway.Multiplayer.SendMessageToServer(NET_ID, m.CompressedData);
break;
case MessageTarget.AllClients:
MyAPIGateway.Players.GetPlayers(_playerCache);
foreach (var p in _playerCache)
{
if (p.SteamUserId == MyAPIGateway.Multiplayer.MyId)
continue;
MyAPIGateway.Multiplayer.SendMessageTo(NET_ID, m.CompressedData, p.SteamUserId);
}
break;
case MessageTarget.AllExcept:
MyAPIGateway.Players.GetPlayers(_playerCache);
foreach (var p in _playerCache)
{
if (p.SteamUserId == MyAPIGateway.Multiplayer.MyId || m.Ignore.Contains(p.SteamUserId))
continue;
MyAPIGateway.Multiplayer.SendMessageTo(NET_ID, m.CompressedData, p.SteamUserId);
}
break;
default:
throw new Exception();
}
_playerCache.Clear();
});
}
}
catch (Exception ex)
{
@@ -136,14 +127,15 @@ namespace Torch.Mod
}
}
MyLog.Default.WriteLineAndConsole("TORCH MOD: COMMUNICATION THREAD: EXIT SIGNAL RECIEVED!");
MyLog.Default.WriteLineAndConsole("TORCH MOD: COMMUNICATION THREAD: EXIT SIGNAL RECEIVED!");
//exit signal received. Clean everything and GTFO
_outgoing = null;
_incoming = null;
_processing.Dispose();
_processing = null;
_messagePool.Clean();
_messagePool = null;
_playerCache = null;
_lock = null;
}
public static void SendMessageTo(MessageBase message, ulong target)
{
if (!MyAPIGateway.Multiplayer.IsServer)
@@ -155,8 +147,7 @@ namespace Torch.Mod
message.Target = target;
message.TargetType = MessageTarget.Single;
MyLog.Default.WriteLineAndConsole($"Sending message of type {message.GetType().FullName}");
_outgoing.Enqueue(message);
ReleaseLock();
_processing.Add(message);
}
public static void SendMessageToClients(MessageBase message)
@@ -168,8 +159,7 @@ namespace Torch.Mod
return;
message.TargetType = MessageTarget.AllClients;
_outgoing.Enqueue(message);
ReleaseLock();
_processing.Add(message);
}
public static void SendMessageExcept(MessageBase message, params ulong[] ignoredUsers)
@@ -182,8 +172,7 @@ namespace Torch.Mod
message.TargetType = MessageTarget.AllExcept;
message.Ignore = ignoredUsers;
_outgoing.Enqueue(message);
ReleaseLock();
_processing.Add(message);
}
public static void SendMessageToServer(MessageBase message)
@@ -192,22 +181,7 @@ namespace Torch.Mod
return;
message.TargetType = MessageTarget.Server;
_outgoing.Enqueue(message);
ReleaseLock();
}
private static void ReleaseLock()
{
while(_lock?.TryAcquireExclusive() == false)
_lock?.ReleaseExclusive();
_lock?.ReleaseExclusive();
}
private static void AcquireLock()
{
ReleaseLock();
_lock?.AcquireExclusive();
_lock?.AcquireExclusive();
_processing.Add(message);
}
}
}

View File

@@ -9,6 +9,7 @@
<Import_RootNamespace>Torch.Mod</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)Messages\IncomingMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Messages\NotificationMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Messages\DialogMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Messages\MessageBase.cs" />