mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
270 lines
10 KiB
C#
270 lines
10 KiB
C#
using Lidgren.Network;
|
|
using SS14.Server.Interfaces;
|
|
using SS14.Server.Interfaces.Chat;
|
|
using SS14.Server.Interfaces.GOC;
|
|
using SS14.Server.Interfaces.Network;
|
|
using SS14.Server.Interfaces.Player;
|
|
using SS14.Shared;
|
|
using SS14.Shared.GO;
|
|
using SS14.Shared.IoC;
|
|
using SS14.Shared.Log;
|
|
using SS14.Shared.Utility;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Xml.Serialization;
|
|
|
|
namespace SS14.Server.Chat
|
|
{
|
|
[IoCTarget]
|
|
public class ChatManager : IChatManager
|
|
{
|
|
private ISS14Server _serverMain;
|
|
|
|
private Dictionary<string, Emote> _emotes = new Dictionary<string, Emote>();
|
|
private Dictionary<string, IChatCommand> _commands = new Dictionary<string, IChatCommand>();
|
|
private string _emotePath = @"emotes.xml";
|
|
|
|
public IDictionary<string, IChatCommand> Commands => _commands;
|
|
|
|
#region IChatManager Members
|
|
|
|
public void Initialize(ISS14Server server)
|
|
{
|
|
_serverMain = server;
|
|
LoadEmotes();
|
|
LoadCommands();
|
|
}
|
|
|
|
public void HandleNetMessage(NetIncomingMessage message)
|
|
{
|
|
var channel = (ChatChannel)message.ReadByte();
|
|
string text = message.ReadString();
|
|
|
|
IClient client = _serverMain.GetClient(message.SenderConnection);
|
|
string playerName = client.PlayerName;
|
|
|
|
LogManager.Log("CHAT:: Channel: " + channel.ToString() + " :: Player: " + playerName + " :: Message: " + text, Shared.ServerEnums.LogLevel.Debug);
|
|
|
|
var entityId = IoCManager.Resolve<IPlayerManager>().GetSessionByConnection(message.SenderConnection).AttachedEntityUid;
|
|
|
|
bool hasChannelIdentifier = false;
|
|
if (channel != ChatChannel.Lobby)
|
|
channel = DetectChannel(text, out hasChannelIdentifier);
|
|
if (hasChannelIdentifier)
|
|
text = text.Substring(1);
|
|
text = text.Trim(); // Remove whitespace
|
|
|
|
if (text[0] == '/')
|
|
ProcessCommand(text, playerName, channel, entityId, client);
|
|
else if (text[0] == '*')
|
|
ProcessEmote(text, playerName, channel, entityId, message.SenderConnection);
|
|
else
|
|
SendChatMessage(channel, text, playerName, entityId);
|
|
}
|
|
|
|
public void SendChatMessage(ChatChannel channel, string text, string name, int? entityId)
|
|
{
|
|
NetOutgoingMessage message = MakeNetChatMessage(channel, text, name, entityId);
|
|
|
|
switch (channel)
|
|
{
|
|
case ChatChannel.Server:
|
|
case ChatChannel.OOC:
|
|
case ChatChannel.Radio:
|
|
case ChatChannel.Player:
|
|
case ChatChannel.Default:
|
|
IoCManager.Resolve<ISS14NetServer>().SendToAll(message);
|
|
break;
|
|
|
|
case ChatChannel.Damage:
|
|
case ChatChannel.Ingame:
|
|
case ChatChannel.Visual:
|
|
case ChatChannel.Emote:
|
|
SendToPlayersInRange(message, entityId);
|
|
break;
|
|
|
|
case ChatChannel.Lobby:
|
|
SendToLobby(message);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void SendPrivateMessage(IClient client, ChatChannel channel, string text, string name, int? entityId)
|
|
{
|
|
NetOutgoingMessage message = MakeNetChatMessage(channel, text, name, entityId);
|
|
IoCManager.Resolve<ISS14NetServer>().SendMessage(message, client.NetConnection);
|
|
}
|
|
|
|
private NetOutgoingMessage MakeNetChatMessage(ChatChannel channel, string text, string name, int? entityId)
|
|
{
|
|
string fullmsg = text;
|
|
if (!string.IsNullOrEmpty(name) && channel == ChatChannel.Emote)
|
|
fullmsg = text; //Emote already has name in it probably...
|
|
else if (channel == ChatChannel.Ingame || channel == ChatChannel.OOC || channel == ChatChannel.Radio ||
|
|
channel == ChatChannel.Lobby)
|
|
fullmsg = name + ": " + text;
|
|
|
|
NetOutgoingMessage message = IoCManager.Resolve<ISS14NetServer>().CreateMessage();
|
|
|
|
message.Write((byte)NetMessage.ChatMessage);
|
|
message.Write((byte)channel);
|
|
message.Write(fullmsg);
|
|
if (entityId == null)
|
|
message.Write(-1);
|
|
else
|
|
message.Write((int)entityId);
|
|
|
|
return message;
|
|
}
|
|
|
|
#endregion IChatManager Members
|
|
|
|
private ChatChannel DetectChannel(string message, out bool hasChannelIdentifier)
|
|
{
|
|
hasChannelIdentifier = false;
|
|
var channel = ChatChannel.Ingame;
|
|
switch (message[0])
|
|
{
|
|
case '[':
|
|
channel = ChatChannel.OOC;
|
|
hasChannelIdentifier = true;
|
|
break;
|
|
|
|
case ':':
|
|
channel = ChatChannel.Radio;
|
|
hasChannelIdentifier = true;
|
|
break;
|
|
|
|
case '@':
|
|
channel = ChatChannel.Emote;
|
|
hasChannelIdentifier = true;
|
|
break;
|
|
}
|
|
return channel;
|
|
}
|
|
|
|
private void LoadEmotes()
|
|
{
|
|
if (File.Exists(_emotePath))
|
|
{
|
|
using (var emoteFileStream = new FileStream(_emotePath, FileMode.Open, FileAccess.Read))
|
|
{
|
|
XmlSerializer serializer = new XmlSerializer(typeof(List<Emote>));
|
|
|
|
var emotes = (List<Emote>)serializer.Deserialize(emoteFileStream);
|
|
emoteFileStream.Close();
|
|
foreach (var emote in emotes)
|
|
{
|
|
_emotes.Add(emote.Command, emote);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
using (var emoteFileStream = new FileStream(_emotePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
|
|
{
|
|
var emote = new Emote();
|
|
emote.Command = "default";
|
|
emote.OtherText = "{0} does something!";
|
|
emote.SelfText = "You do something!";
|
|
_emotes.Add("default", emote);
|
|
XmlSerializer serializer = new XmlSerializer(typeof(List<Emote>));
|
|
serializer.Serialize(emoteFileStream, _emotes.Values.ToList());
|
|
emoteFileStream.Close();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Load all command types.
|
|
private void LoadCommands()
|
|
{
|
|
foreach (Type t in IoCManager.ResolveEnumerable<IChatCommand>())
|
|
{
|
|
IChatCommand instance = (IChatCommand)Activator.CreateInstance(t, null);
|
|
if (_commands.ContainsKey(instance.Command))
|
|
{
|
|
LogManager.Log(string.Format("Command has duplicate name: {0}", instance.Command), Shared.ServerEnums.LogLevel.Error);
|
|
continue;
|
|
}
|
|
_commands[instance.Command] = instance;
|
|
}
|
|
}
|
|
|
|
private void SendToPlayersInRange(NetOutgoingMessage message, int? entityId)
|
|
{
|
|
int withinRange = 512;
|
|
if (entityId == null)
|
|
return;
|
|
List<NetConnection> recipients =
|
|
IoCManager.Resolve<IPlayerManager>().GetPlayersInRange(
|
|
_serverMain.EntityManager.GetEntity((int)entityId).GetComponent<ITransformComponent>(
|
|
ComponentFamily.Transform).Position, withinRange).Select(p => p.ConnectedClient).ToList();
|
|
IoCManager.Resolve<ISS14NetServer>().SendToMany(message, recipients);
|
|
}
|
|
|
|
private void SendToLobby(NetOutgoingMessage message)
|
|
{
|
|
List<NetConnection> recipients =
|
|
IoCManager.Resolve<IPlayerManager>().GetPlayersInLobby().Select(p => p.ConnectedClient).ToList();
|
|
IoCManager.Resolve<ISS14NetServer>().SendToMany(message, recipients);
|
|
}
|
|
|
|
private void ProcessEmote(string text, string name, ChatChannel channel, int? entityId, NetConnection client)
|
|
{
|
|
if (entityId == null)
|
|
return; //No emotes from non-entities!
|
|
|
|
var args = new List<string>();
|
|
|
|
CommandParsing.ParseArguments(text, args);
|
|
if (_emotes.ContainsKey(args[0]))
|
|
{
|
|
var userText = String.Format(_emotes[args[0]].SelfText, name);//todo user-only channel
|
|
var otherText = String.Format(_emotes[args[0]].OtherText, name, "his"); //todo pronouns, gender
|
|
SendChatMessage(ChatChannel.Emote, otherText, name, entityId);
|
|
}
|
|
else
|
|
{
|
|
//todo Bitch at the user
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Processes commands (chat messages starting with /)
|
|
/// </summary>
|
|
/// <param name="text">Text content.</param>
|
|
/// <param name="name">Player name that sent the chat text.</param>
|
|
/// <param name="channel">Channel message was recieved on.</param>
|
|
/// <param name="client">Client that sent the command.</param>
|
|
private void ProcessCommand(string text, string name, ChatChannel channel, int? entityId, IClient client)
|
|
{
|
|
List<string> args = new List<string>();
|
|
|
|
CommandParsing.ParseArguments(text.Substring(1), args); // Parse, but cut out the first character (/).
|
|
|
|
if (args.Count <= 0)
|
|
return;
|
|
|
|
string command = args[0];
|
|
if (!_commands.ContainsKey(command))
|
|
{
|
|
string message = string.Format("Command '{0}' not found.", command);
|
|
SendPrivateMessage(client, ChatChannel.Default, message, "Server", null);
|
|
return;
|
|
}
|
|
|
|
_commands[command].Execute(this, client, args.ToArray());
|
|
}
|
|
}
|
|
|
|
public struct Emote
|
|
{
|
|
public string Command;
|
|
public string SelfText;
|
|
public string OtherText;
|
|
}
|
|
}
|