Files
Torch/Torch/Managers/ChatManager/ChatManagerServer.cs
2019-01-17 15:52:16 -08:00

221 lines
7.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using NLog;
using Sandbox.Engine.Multiplayer;
using Sandbox.Engine.Networking;
using Sandbox.Game.Gui;
using Sandbox.Game.Multiplayer;
using Sandbox.Game.World;
using Torch.API;
using Torch.API.Managers;
using Torch.Utils;
using VRage;
using VRage.Library.Collections;
using VRage.Network;
namespace Torch.Managers.ChatManager
{
public class ChatManagerServer : ChatManagerClient, IChatManagerServer
{
[Dependency(Optional = true)]
private INetworkManager _networkManager;
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
private static readonly Logger _chatLog = LogManager.GetLogger("Chat");
private readonly ChatIntercept _chatIntercept;
/// <inheritdoc />
public ChatManagerServer(ITorchBase torchInstance) : base(torchInstance)
{
_chatIntercept = new ChatIntercept(this);
}
/// <inheritdoc />
public event MessageProcessingDel MessageProcessing;
/// <inheritdoc />
public void SendMessageAsOther(ulong authorId, string message, ulong targetSteamId = 0)
{
if (targetSteamId == Sync.MyId)
{
RaiseMessageRecieved(new TorchChatMessage(authorId, message));
return;
}
if (MyMultiplayer.Static == null)
{
if ((targetSteamId == MyGameService.UserId || targetSteamId == 0) && HasHud)
MyHud.Chat?.ShowMessage(authorId == MyGameService.UserId ?
(MySession.Static.LocalHumanPlayer?.DisplayName ?? "Player") : $"user_{authorId}", message);
return;
}
if (MyMultiplayer.Static is MyDedicatedServerBase dedicated)
{
var msg = new ChatMsg() { Author = authorId, Text = message };
_dedicatedServerBaseSendChatMessage.Invoke(ref msg);
_dedicatedServerBaseOnChatMessage.Invoke(dedicated, new object[] { msg });
}
}
#pragma warning disable 649
private delegate void MultiplayerBaseSendChatMessageDel(ref ChatMsg arg);
[ReflectedStaticMethod(Name = "SendChatMessage", Type = typeof(MyMultiplayerBase))]
private static MultiplayerBaseSendChatMessageDel _dedicatedServerBaseSendChatMessage;
// [ReflectedMethod] doesn't play well with instance methods and refs.
[ReflectedMethodInfo(typeof(MyDedicatedServerBase), "OnChatMessage")]
private static MethodInfo _dedicatedServerBaseOnChatMessage;
#pragma warning restore 649
/// <inheritdoc />
public void SendMessageAsOther(string author, string message, string font, ulong targetSteamId = 0)
{
if (targetSteamId == Sync.MyId)
{
RaiseMessageRecieved(new TorchChatMessage(author, message, font));
return;
}
if (MyMultiplayer.Static == null)
{
if ((targetSteamId == MyGameService.UserId || targetSteamId == 0) && HasHud)
MyHud.Chat?.ShowMessage(author, message, font);
return;
}
var scripted = new ScriptedChatMsg()
{
Author = author,
Text = message,
Font = font,
Target = Sync.Players.TryGetIdentityId(targetSteamId)
};
_chatLog.Info($"{author} (to {GetMemberName(targetSteamId)}): {message}");
MyMultiplayerBase.SendScriptedChatMessage(ref scripted);
}
/// <inheritdoc/>
public override void Attach()
{
base.Attach();
if (_networkManager != null)
try
{
_networkManager.RegisterNetworkHandler(_chatIntercept);
_log.Debug("Initialized network intercept for chat messages");
return;
}
catch
{
// Discard exception and use second method
}
if (MyMultiplayer.Static != null)
{
MyMultiplayer.Static.ChatMessageReceived += MpStaticChatMessageReceived;
_log.Warn(
"Failed to initialize network intercept, we can't discard chat messages! Falling back to another method.");
}
else
{
_log.Debug("Using offline message processor");
}
}
/// <inheritdoc />
protected override bool OfflineMessageProcessor(TorchChatMessage msg)
{
if (MyMultiplayer.Static != null)
return false;
var consumed = false;
MessageProcessing?.Invoke(msg, ref consumed);
return consumed;
}
private void MpStaticChatMessageReceived(ulong steamUserId, string messageText, ChatChannel channel, long targetId, string customAuthorName)
{
var tmp = false;
RaiseMessageRecieved(new ChatMsg
{
Author = steamUserId,
Text = messageText
}, ref tmp);
}
/// <inheritdoc/>
public override void Detach()
{
if (MyMultiplayer.Static != null)
MyMultiplayer.Static.ChatMessageReceived -= MpStaticChatMessageReceived;
_networkManager?.UnregisterNetworkHandler(_chatIntercept);
base.Detach();
}
internal void RaiseMessageRecieved(ChatMsg message, ref bool consumed)
{
var torchMsg = new TorchChatMessage(GetMemberName(message.Author), message.Author, message.Text);
MessageProcessing?.Invoke(torchMsg, ref consumed);
if (!consumed)
_chatLog.Info($"{torchMsg.Author}: {torchMsg.Message}");
}
public static string GetMemberName(ulong steamId)
{
return MyMultiplayer.Static?.GetMemberName(steamId) ?? $"user_{steamId}";
}
internal class ChatIntercept : NetworkHandlerBase, INetworkHandler
{
private readonly ChatManagerServer _chatManager;
private bool? _unitTestResult;
public ChatIntercept(ChatManagerServer chatManager)
{
_chatManager = chatManager;
}
/// <inheritdoc/>
public override bool CanHandle(CallSite site)
{
if (site.MethodInfo.Name != "OnChatMessageRecieved")
return false;
if (_unitTestResult.HasValue)
return _unitTestResult.Value;
ParameterInfo[] parameters = site.MethodInfo.GetParameters();
if (parameters.Length != 1)
{
_unitTestResult = false;
return false;
}
if (parameters[0].ParameterType != typeof(ChatMsg))
_unitTestResult = false;
_unitTestResult = true;
return _unitTestResult.Value;
}
/// <inheritdoc/>
public override bool Handle(ulong remoteUserId, CallSite site, BitStream stream, object obj, MyPacket packet)
{
var msg = new ChatMsg();
Serialize(site.MethodInfo, stream, ref msg);
var consumed = false;
_chatManager.RaiseMessageRecieved(msg, ref consumed);
return consumed;
}
}
}
}