Overwrite

Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
Unstable Kitsune
2023-11-28 23:20:26 -05:00
parent 3cd54811de
commit b918192e4e
11608 changed files with 2644205 additions and 47 deletions

View File

@@ -0,0 +1,185 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
namespace Server.Engines.Chat
{
public class Channel
{
public static void Initialize()
{
EventSink.Disconnected += EventSink_Disconnected;
// TODO: Add a configuration framework to define static channels outside of code, for example as XML under the Data/ directory.
AddStaticChannel("Help");
AddStaticChannel("General");
AddStaticChannel("Trade");
AddStaticChannel("Looking For Group");
}
private static void EventSink_Disconnected(DisconnectedEventArgs e)
{
ChatUser.RemoveChatUser(e.Mobile);
}
public static void AddStaticChannel(string name)
{
AddChannel(name).AlwaysAvailable = true;
}
private string m_Name;
private bool m_AlwaysAvailable;
private List<ChatUser> m_Users;
public Channel(string name)
{
m_Name = name;
m_Users = new List<ChatUser>();
}
public string Name { get { return m_Name; } }
public IEnumerable<ChatUser> Users { get { return new ReadOnlyCollection<ChatUser>(m_Users); } }
public bool Contains(ChatUser user)
{
return m_Users.Contains(user);
}
public void AddUser(ChatUser user)
{
if (Contains(user))
{
user.SendMessage(46, m_Name); // You are already in the conference '%1'.
}
else
{
if (user.CurrentChannel != null)
user.CurrentChannel.RemoveUser(user); // Remove them from their current channel first
ChatSystem.SendCommandTo(user.Mobile, ChatCommand.JoinedChannel, m_Name);
SendCommand(ChatCommand.AddUserToChannel, user.GetColorCharacter() + user.Username);
m_Users.Add(user);
user.CurrentChannel = this;
SendUsersTo(user);
ChatLogging.LogJoin(Name, user.Username);
}
}
public void RemoveUser(ChatUser user)
{
if (Contains(user))
{
m_Users.Remove(user);
user.CurrentChannel = null;
SendCommand(ChatCommand.RemoveUserFromChannel, user, user.Username);
ChatSystem.SendCommandTo(user.Mobile, ChatCommand.LeaveChannel, string.Format("{{{0}}}", m_Name));
ChatSystem.SendCommandTo(user.Mobile, ChatCommand.LeftChannel, m_Name);
ChatLogging.LogLeave(Name, user.Username);
if (m_Users.Count == 0 && !m_AlwaysAvailable)
RemoveChannel(this);
}
}
public bool AlwaysAvailable { get { return m_AlwaysAvailable; } set { m_AlwaysAvailable = value; } }
public void SendMessage(int number, ChatUser from, string param1, string param2)
{
foreach (var user in m_Users)
{
if (user.CheckOnline())
user.SendMessage(number, from.Mobile, param1, param2);
}
}
public void SendCommand(ChatCommand command, string param1 = null, string param2 = null)
{
SendCommand(command, null, param1, param2);
}
public void SendCommand(ChatCommand command, ChatUser initiator, string param1 = null, string param2 = null)
{
foreach (var user in m_Users.ToArray())
{
if (user == initiator)
continue;
if (user.CheckOnline())
ChatSystem.SendCommandTo(user.Mobile, command, param1, param2);
}
}
public void SendUsersTo(ChatUser to)
{
foreach (var user in m_Users)
{
ChatSystem.SendCommandTo(to.Mobile, ChatCommand.AddUserToChannel, user.GetColorCharacter() + user.Username, String.Format("{{{0}}}", m_Name));
}
}
private static List<Channel> m_Channels = new List<Channel>();
public static List<Channel> Channels { get { return m_Channels; } }
public static void SendChannelsTo(ChatUser user)
{
foreach (var channel in m_Channels)
{
ChatSystem.SendCommandTo(user.Mobile, ChatCommand.AddChannel, channel.Name, "0");
}
}
public static Channel AddChannel(string name)
{
var channel = FindChannelByName(name);
if (channel == null)
{
channel = new Channel(name);
m_Channels.Add(channel);
}
ChatUser.GlobalSendCommand(ChatCommand.AddChannel, name, "0");
ChatLogging.LogCreateChannel(name);
return channel;
}
public static void RemoveChannel(string name)
{
RemoveChannel(FindChannelByName(name));
}
public static void RemoveChannel(Channel channel)
{
if (channel == null)
return;
if (m_Channels.Contains(channel) && channel.m_Users.Count == 0)
{
ChatUser.GlobalSendCommand(ChatCommand.RemoveChannel, channel.Name);
m_Channels.Remove(channel);
ChatLogging.LogRemoveChannel(channel.Name);
}
}
public static Channel FindChannelByName(string name)
{
return m_Channels.FirstOrDefault(channel => channel.Name == name);
}
public static Channel Default { get { return FindChannelByName(ChatSystem.DefaultChannel); } }
}
}

View File

@@ -0,0 +1,21 @@
using System;
namespace Server.Engines.Chat
{
public delegate void OnChatAction(ChatUser from, Channel channel, string param);
public class ChatActionHandler
{
private bool m_RequireConference;
private OnChatAction m_Callback;
public bool RequireConference { get { return m_RequireConference; } }
public OnChatAction Callback { get { return m_Callback; } }
public ChatActionHandler(bool requireConference, OnChatAction callback)
{
m_RequireConference = requireConference;
m_Callback = callback;
}
}
}

View File

@@ -0,0 +1,109 @@
using System;
namespace Server.Engines.Chat
{
public class ChatActionHandlers
{
private static ChatActionHandler[] m_Handlers;
static ChatActionHandlers()
{
m_Handlers = new ChatActionHandler[0x100];
Register(0x43, true, LeaveChannel);
Register(0x61, true, ChannelMessage);
Register(0x62, false, JoinChannel);
Register(0x63, false, CreateChannel);
}
public static void Register(int actionId, bool requireConference, OnChatAction callback)
{
if (actionId >= 0 && actionId < m_Handlers.Length)
m_Handlers[actionId] = new ChatActionHandler(requireConference, callback);
}
public static ChatActionHandler GetHandler(int actionId)
{
if (actionId >= 0 && actionId < m_Handlers.Length)
return m_Handlers[actionId];
return null;
}
public static void ChannelMessage(ChatUser from, Channel channel, string param)
{
channel.SendMessage(57, from, from.GetColorCharacter() + from.Username, string.Format("{{{0}}} {1}", channel.Name, param)); // %1: %2
ChatLogging.LogMessage(channel.Name, from.Username, param);
}
public static void LeaveChannel(ChatUser from, Channel channel, string param)
{
channel.RemoveUser(from);
}
public static void JoinChannel(ChatUser from, Channel channel, string param)
{
string name;
string password = null;
int start = param.IndexOf('\"');
if (start >= 0)
{
int end = param.IndexOf('\"', ++start);
if (end >= 0)
{
name = param.Substring(start, end - start);
password = param.Substring(++end);
}
else
{
name = param.Substring(start);
}
}
else
{
int indexOf = param.IndexOf(' ');
if (indexOf >= 0)
{
name = param.Substring(0, indexOf++);
password = param.Substring(indexOf);
}
else
{
name = param;
}
}
CreateAndJoin(from, name);
}
public static void CreateChannel(ChatUser from, Channel channel, string param)
{
CreateAndJoin(from, param);
}
private static void CreateAndJoin(ChatUser from, string name)
{
var joined = Channel.FindChannelByName(name);
if (joined == null)
{
if (ChatSystem.AllowCreateChannels)
{
from.Mobile.SendMessage("You have created the channel {0}", name);
joined = Channel.AddChannel(name);
}
else
{
from.Mobile.SendMessage("Channel creation is not allowed right now. Switching to default channel...");
joined = Channel.Default;
}
}
joined.AddUser(from);
}
}
}

View File

@@ -0,0 +1,52 @@
using System;
namespace Server.Engines.Chat
{
public enum ChatCommand
{
/// <summary>
/// Add a channel to top list.
/// </summary>
AddChannel = 0x3E8,
/// <summary>
/// Remove channel from top list.
/// </summary>
RemoveChannel = 0x3E9,
/// <summary>
/// Closes the chat window.
/// </summary>
CloseChatWindow = 0x3EC,
/// <summary>
/// Opens the chat window.
/// </summary>
OpenChatWindow = 0x3ED,
/// <summary>
/// Add a user to current channel.
/// </summary>
AddUserToChannel = 0x3EE,
/// <summary>
/// Remove a user from current channel.
/// </summary>
RemoveUserFromChannel = 0x3EF,
/// <summary>
/// Send a message putting generic conference name at top when player leaves a channel.
/// </summary>
LeaveChannel = 0x3F0,
/// <summary>
/// Send a message putting Channel name at top and telling player he joined the channel.
/// </summary>
JoinedChannel = 0x3F1,
/// <summary>
/// Send a message putting Channel name at top and telling player he left the channel.
/// </summary>
LeftChannel = 0x3F4,
}
}

View File

@@ -0,0 +1,91 @@
using System;
using System.IO;
using Server.Network;
namespace Server.Engines.Chat
{
public class ChatSystem
{
public static readonly bool Enabled = Config.Get("Chat.Enabled", true);
public static readonly bool AllowCreateChannels = Config.Get("Chat.AllowCreateChannels", true);
public static readonly string DefaultChannel = "Help";
public static void Initialize()
{
PacketHandlers.Register(0xB5, 0x40, true, OpenChatWindowRequest);
PacketHandlers.Register(0xB3, 0, true, ChatAction);
}
public static void OpenChatWindowRequest(NetState state, PacketReader pvSrc)
{
var from = state.Mobile;
if (!Enabled)
{
from.SendMessage("The chat system has been disabled.");
return;
}
//pvSrc.Seek(2, SeekOrigin.Begin);
///*string chatName = */pvSrc.ReadUnicodeStringSafe((0x40 - 2) >> 1).Trim();
var chatName = from.Name;
SendCommandTo(from, ChatCommand.OpenChatWindow, chatName);
ChatUser.AddChatUser(from);
}
public static void ChatAction(NetState state, PacketReader pvSrc)
{
if (!Enabled)
return;
try
{
var from = state.Mobile;
var user = ChatUser.GetChatUser(from);
if (user == null)
return;
var lang = pvSrc.ReadStringSafe(4);
var actionId = pvSrc.ReadInt16();
var param = pvSrc.ReadUnicodeString();
var handler = ChatActionHandlers.GetHandler(actionId);
if (handler != null)
{
var channel = user.CurrentChannel;
if (handler.RequireConference && channel == null)
{
/* You must be in a conference to do this.
* To join a conference, select one from the Conference menu.
*/
user.SendMessage(31);
}
else
{
handler.Callback(user, channel, param);
}
}
else
{
Console.WriteLine("Client: {0}: Unknown chat action 0x{1:X}: {2}", state, actionId, param);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
public static void SendCommandTo(Mobile to, ChatCommand type, string param1 = null, string param2 = null)
{
if (to != null)
to.Send(new ChatMessagePacket(null, (int)type + 20, param1, param2));
}
}
}

View File

@@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Server.Engines.Chat
{
public class ChatUser
{
private Mobile m_Mobile;
private Channel m_Channel;
public ChatUser(Mobile m)
{
m_Mobile = m;
}
public Mobile Mobile { get { return m_Mobile; } }
public string Username { get { return String.Format("<{0}>{1}", m_Mobile.Serial.Value, m_Mobile.Name); } }
public Channel CurrentChannel { get { return m_Channel; } set { m_Channel = value; } }
public bool IsOnline { get { return (m_Mobile.NetState != null); } }
public const char NormalColorCharacter = '0';
public char GetColorCharacter()
{
return NormalColorCharacter;
}
public bool CheckOnline()
{
if (IsOnline)
return true;
RemoveChatUser(this);
return false;
}
public void SendMessage(int number, string param1 = null, string param2 = null)
{
SendMessage(number, m_Mobile, param1, param2);
}
public void SendMessage(int number, Mobile from, string param1, string param2)
{
if (m_Mobile.NetState != null)
m_Mobile.Send(new ChatMessagePacket(from, number, param1, param2));
}
private static List<ChatUser> m_Users = new List<ChatUser>();
private static Dictionary<Mobile, ChatUser> m_Table = new Dictionary<Mobile, ChatUser>();
public static ChatUser AddChatUser(Mobile from)
{
var user = GetChatUser(from);
if (user == null)
{
user = new ChatUser(from);
m_Users.Add(user);
m_Table[from] = user;
Channel.SendChannelsTo(user);
}
return user;
}
public static void RemoveChatUser(ChatUser user)
{
if (user == null)
return;
if (m_Users.Contains(user))
{
ChatSystem.SendCommandTo(user.Mobile, ChatCommand.CloseChatWindow);
if (user.m_Channel != null)
user.m_Channel.RemoveUser(user);
m_Users.Remove(user);
m_Table.Remove(user.m_Mobile);
}
}
public static void RemoveChatUser(Mobile from)
{
var user = GetChatUser(from);
RemoveChatUser(user);
}
public static ChatUser GetChatUser(Mobile from)
{
ChatUser c;
m_Table.TryGetValue(from, out c);
return c;
}
public static ChatUser GetChatUser(string username)
{
return m_Users.FirstOrDefault(user => user.Username == username);
}
public static void GlobalSendCommand(ChatCommand command, string param1 = null, string param2 = null)
{
GlobalSendCommand(command, null, param1, param2);
}
public static void GlobalSendCommand(ChatCommand command, ChatUser initiator, string param1 = null, string param2 = null)
{
foreach (var user in m_Users.ToArray())
{
if (user == initiator)
continue;
if (user.CheckOnline())
ChatSystem.SendCommandTo(user.m_Mobile, command, param1, param2);
}
}
}
}

View File

@@ -0,0 +1,121 @@
using System;
using System.IO;
using System.Collections.Generic;
namespace Server.Engines.Chat
{
public class ChatLogging
{
public static readonly bool Enabled = true;
private static StreamWriter m_Output;
private static Dictionary<string, StreamWriter> m_OutputPerChannel;
public static void Initialize()
{
if (!Directory.Exists("Logs"))
Directory.CreateDirectory("Logs");
var directory = Path.Combine("Logs", "Chat");
if (!Directory.Exists(directory))
Directory.CreateDirectory(directory);
m_OutputPerChannel = new Dictionary<string, StreamWriter>();
try
{
m_Output = new StreamWriter(Path.Combine(directory, string.Format("{0}.log", DateTime.UtcNow.ToLongDateString())), true);
m_Output.AutoFlush = true;
m_Output.WriteLine("##############################");
m_Output.WriteLine("Log started on {0}", DateTime.UtcNow);
m_Output.WriteLine();
}
catch
{
}
}
public static void WriteLine(string channel, string format, params object[] args)
{
WriteLine(channel, string.Format(format, args));
}
public static void WriteLine(string channel, string text)
{
if (!Enabled)
return;
try
{
m_Output.WriteLine("{0}: [{1}] {2}", DateTime.UtcNow, channel, text);
StreamWriter channelOutput;
if (m_OutputPerChannel.ContainsKey(channel))
channelOutput = m_OutputPerChannel[channel];
else
{
var path = "Logs";
AppendPath(ref path, "chat");
AppendPath(ref path, "channels");
path = Path.Combine(path, string.Format("{0}.log", channel));
channelOutput = new StreamWriter(path, true);
channelOutput.AutoFlush = true;
m_OutputPerChannel[channel] = channelOutput;
}
channelOutput.WriteLine("{0}: {1}", DateTime.UtcNow, text);
}
catch
{
}
}
public static void AppendPath(ref string path, string toAppend)
{
path = Path.Combine(path, toAppend);
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
}
public static void LogMessage(string channel, string username, string message)
{
WriteLine(channel, "{0} says: {1}", username, message);
}
public static void LogCreateChannel(string channel)
{
WriteLine(channel, "************** Channel was created.");
}
public static void LogRemoveChannel(string channel)
{
WriteLine(channel, "************** Channel was removed.");
}
public static void LogJoin(string channel, string username)
{
WriteLine(channel, "{0} joined the channel.", username);
}
public static void LogLeave(string channel, string username)
{
WriteLine(channel, "{0} left the channel.", username);
if ( m_OutputPerChannel.ContainsKey( channel ) )
m_OutputPerChannel[channel].Dispose();
}
public static void Log(string channel, string message)
{
WriteLine(channel, message);
}
}
}

View File

@@ -0,0 +1,31 @@
using System;
using Server.Network;
namespace Server.Engines.Chat
{
public sealed class ChatMessagePacket : Packet
{
public ChatMessagePacket(Mobile who, int number, string param1, string param2)
: base(0xB2)
{
if (param1 == null)
param1 = String.Empty;
if (param2 == null)
param2 = String.Empty;
EnsureCapacity(13 + ((param1.Length + param2.Length) * 2));
m_Stream.Write((ushort)(number - 20));
if (who != null)
m_Stream.WriteAsciiFixed(who.Language, 4);
else
m_Stream.Write((int)0);
m_Stream.WriteBigUniNull(param1);
m_Stream.WriteBigUniNull(param2);
}
}
}