Removed external pack methods.

These do need to be reimploded at some point probably, but this at least gets them out of common code.
This commit is contained in:
flash 2025-04-25 21:22:25 +00:00
parent 3fc94c425e
commit 9f283e48fe
Signed by: flash
GPG key ID: 2C9C2C574D47FE3E
13 changed files with 200 additions and 103 deletions

View file

@ -1,8 +1,4 @@
using System; namespace SharpChat {
using System.Linq;
using System.Text;
namespace SharpChat {
public class ChatChannel( public class ChatChannel(
string name, string name,
string password = "", string password = "",
@ -19,18 +15,6 @@ namespace SharpChat {
public bool HasPassword public bool HasPassword
=> !string.IsNullOrWhiteSpace(Password); => !string.IsNullOrWhiteSpace(Password);
public string Pack() {
StringBuilder sb = new();
sb.Append(Name);
sb.Append('\t');
sb.Append(string.IsNullOrEmpty(Password) ? '0' : '1');
sb.Append('\t');
sb.Append(IsTemporary ? '1' : '0');
return sb.ToString();
}
public bool NameEquals(string name) { public bool NameEquals(string name) {
return string.Equals(name, Name, StringComparison.InvariantCultureIgnoreCase); return string.Equals(name, Name, StringComparison.InvariantCultureIgnoreCase);
} }

View file

@ -187,7 +187,7 @@ namespace SharpChat {
if(!string.IsNullOrWhiteSpace(previousName)) if(!string.IsNullOrWhiteSpace(previousName))
SendToUserChannels(user, new CommandResponseS2CPacket(RandomSnowflake.Next(), LCR.NICKNAME_CHANGE, false, previousName, user.LegacyNameWithStatus)); SendToUserChannels(user, new CommandResponseS2CPacket(RandomSnowflake.Next(), LCR.NICKNAME_CHANGE, false, previousName, user.LegacyNameWithStatus));
SendToUserChannels(user, new UserUpdateS2CPacket(user)); SendToUserChannels(user, new UserUpdateS2CPacket(user.UserId, user.LegacyNameWithStatus, user.Colour, user.Rank, user.Permissions));
} }
} }
@ -209,17 +209,38 @@ namespace SharpChat {
public void HandleJoin(ChatUser user, ChatChannel chan, ChatConnection conn, int maxMsgLength) { public void HandleJoin(ChatUser user, ChatChannel chan, ChatConnection conn, int maxMsgLength) {
if(!IsInChannel(user, chan)) { if(!IsInChannel(user, chan)) {
long msgId = RandomSnowflake.Next(); long msgId = RandomSnowflake.Next();
SendTo(chan, new UserConnectS2CPacket(msgId, DateTimeOffset.Now, user)); SendTo(chan, new UserConnectS2CPacket(msgId, DateTimeOffset.Now, user.UserId, user.LegacyNameWithStatus, user.Colour, user.Rank, user.Permissions));
Events.AddEvent(msgId, "user:connect", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log); Events.AddEvent(msgId, "user:connect", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
} }
conn.Send(new AuthSuccessS2CPacket(user, chan, maxMsgLength)); conn.Send(new AuthSuccessS2CPacket(
conn.Send(new ContextUsersS2CPacket(GetChannelUsers(chan).Except([user]).OrderByDescending(u => u.Rank))); user.UserId,
user.LegacyNameWithStatus,
user.Colour,
user.Rank,
user.Permissions,
chan.Name,
maxMsgLength
));
conn.Send(new ContextUsersS2CPacket(
GetChannelUsers(chan).Except([user]).OrderByDescending(u => u.Rank)
.Select(u => new ContextUsersS2CPacket.Entry(
u.UserId,
u.LegacyNameWithStatus,
u.Colour,
u.Rank,
u.Permissions,
true
))
));
foreach(StoredEventInfo msg in Events.GetChannelEventLog(chan.Name)) foreach(StoredEventInfo msg in Events.GetChannelEventLog(chan.Name))
conn.Send(new ContextMessageS2CPacket(msg)); conn.Send(new ContextMessageS2CPacket(msg));
conn.Send(new ContextChannelsS2CPacket(Channels.Where(c => c.Rank <= user.Rank))); conn.Send(new ContextChannelsS2CPacket(
Channels.Where(c => c.Rank <= user.Rank)
.Select(c => new ContextChannelsS2CPacket.Entry(c.Name, c.HasPassword, c.IsTemporary))
));
Users.Add(user); Users.Add(user);
@ -280,11 +301,21 @@ namespace SharpChat {
Events.AddEvent(leaveId, "chan:leave", oldChan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log); Events.AddEvent(leaveId, "chan:leave", oldChan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
long joinId = RandomSnowflake.Next(); long joinId = RandomSnowflake.Next();
SendTo(chan, new UserChannelJoinS2CPacket(joinId, user)); SendTo(chan, new UserChannelJoinS2CPacket(joinId, user.UserId, user.LegacyNameWithStatus, user.Colour, user.Rank, user.Permissions));
Events.AddEvent(joinId, "chan:join", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log); Events.AddEvent(joinId, "chan:join", chan.Name, user.UserId, user.LegacyName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
SendTo(user, new ContextClearS2CPacket(ContextClearMode.MessagesUsers)); SendTo(user, new ContextClearS2CPacket(ContextClearMode.MessagesUsers));
SendTo(user, new ContextUsersS2CPacket(GetChannelUsers(chan).Except([user]).OrderByDescending(u => u.Rank))); SendTo(user, new ContextUsersS2CPacket(
GetChannelUsers(chan).Except([user]).OrderByDescending(u => u.Rank)
.Select(u => new ContextUsersS2CPacket.Entry(
u.UserId,
u.LegacyNameWithStatus,
u.Colour,
u.Rank,
u.Permissions,
true
))
));
foreach(StoredEventInfo msg in Events.GetChannelEventLog(chan.Name)) foreach(StoredEventInfo msg in Events.GetChannelEventLog(chan.Name))
SendTo(user, new ContextMessageS2CPacket(msg)); SendTo(user, new ContextMessageS2CPacket(msg));
@ -364,9 +395,8 @@ namespace SharpChat {
channel.Password = password; channel.Password = password;
// TODO: Users that no longer have access to the channel/gained access to the channel by the hierarchy change should receive delete and create packets respectively // TODO: Users that no longer have access to the channel/gained access to the channel by the hierarchy change should receive delete and create packets respectively
foreach(ChatUser user in Users.Where(u => u.Rank >= channel.Rank)) { foreach(ChatUser user in Users.Where(u => u.Rank >= channel.Rank))
SendTo(user, new ChannelUpdateS2CPacket(channel.Name, channel)); SendTo(user, new ChannelUpdateS2CPacket(channel.Name, channel.Name, channel.HasPassword, channel.IsTemporary));
}
} }
public void RemoveChannel(ChatChannel channel) { public void RemoveChannel(ChatChannel channel) {

View file

@ -53,30 +53,6 @@ namespace SharpChat {
return strict ? perms == perm : perms > 0; return strict ? perms == perm : perms > 0;
} }
public string Pack() {
StringBuilder sb = new();
sb.Append(UserId);
sb.Append('\t');
sb.Append(LegacyNameWithStatus);
sb.Append('\t');
sb.Append(Colour);
sb.Append('\t');
sb.Append(Rank);
sb.Append(' ');
sb.Append(Can(ChatUserPermissions.KickUser) ? '1' : '0');
sb.Append(' ');
sb.Append(Can(ChatUserPermissions.ViewLogs) ? '1' : '0');
sb.Append(' ');
sb.Append(Can(ChatUserPermissions.SetOwnNickname) ? '1' : '0');
sb.Append(' ');
sb.Append(Can(ChatUserPermissions.CreateChannel | ChatUserPermissions.SetChannelPermanent, true) ? '2' : (
Can(ChatUserPermissions.CreateChannel) ? '1' : '0'
));
return sb.ToString();
}
public bool NameEquals(string name) { public bool NameEquals(string name) {
return string.Equals(name, UserName, StringComparison.InvariantCultureIgnoreCase) return string.Equals(name, UserName, StringComparison.InvariantCultureIgnoreCase)
|| string.Equals(name, NickName, StringComparison.InvariantCultureIgnoreCase) || string.Equals(name, NickName, StringComparison.InvariantCultureIgnoreCase)

View file

@ -53,7 +53,7 @@ namespace SharpChat.Commands {
ctx.Chat.Channels.Add(createChan); ctx.Chat.Channels.Add(createChan);
foreach(ChatUser ccu in ctx.Chat.Users.Where(u => u.Rank >= ctx.Channel.Rank)) foreach(ChatUser ccu in ctx.Chat.Users.Where(u => u.Rank >= ctx.Channel.Rank))
ctx.Chat.SendTo(ccu, new ChannelCreateS2CPacket(ctx.Channel)); ctx.Chat.SendTo(ccu, new ChannelCreateS2CPacket(createChan.Name, createChan.HasPassword, createChan.IsTemporary));
ctx.Chat.SwitchChannel(ctx.User, createChan, createChan.Password); ctx.Chat.SwitchChannel(ctx.User, createChan, createChan.Password);
ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.CHANNEL_CREATED, false, createChan.Name)); ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.CHANNEL_CREATED, false, createChan.Name));

View file

@ -2,21 +2,35 @@
namespace SharpChat.S2CPackets { namespace SharpChat.S2CPackets {
public class AuthSuccessS2CPacket( public class AuthSuccessS2CPacket(
ChatUser user, long userId,
ChatChannel channel, string userName,
ChatColour userColour,
int userRank,
ChatUserPermissions userPerms,
string channelName,
int maxMsgLength int maxMsgLength
) : S2CPacket { ) : S2CPacket {
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
public ChatChannel Channel { get; private set; } = channel ?? throw new ArgumentNullException(nameof(channel));
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
sb.Append('1'); sb.Append("1\ty\t");
sb.Append("\ty\t"); sb.Append(userId);
sb.Append(User.Pack());
sb.Append('\t'); sb.Append('\t');
sb.Append(Channel.Name); sb.Append(userName);
sb.Append('\t');
sb.Append(userColour);
sb.Append('\t');
sb.Append(userRank);
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.KickUser) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.ViewLogs) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.SetOwnNickname) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.CreateChannel) ? (userPerms.HasFlag(ChatUserPermissions.SetChannelPermanent) ? '2' : '1') : '0');
sb.Append('\t');
sb.Append(channelName);
sb.Append('\t'); sb.Append('\t');
sb.Append(maxMsgLength); sb.Append(maxMsgLength);

View file

@ -1,17 +1,20 @@
using System.Text; using System.Text;
namespace SharpChat.S2CPackets { namespace SharpChat.S2CPackets {
public class ChannelCreateS2CPacket(ChatChannel channel) : S2CPacket { public class ChannelCreateS2CPacket(
public ChatChannel Channel { get; private set; } = channel ?? throw new ArgumentNullException(nameof(channel)); string name,
bool hasPassword,
bool isTemporary
) : S2CPacket {
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
sb.Append('4'); sb.Append("4\t0\t");
sb.Append(name);
sb.Append('\t'); sb.Append('\t');
sb.Append('0'); sb.Append(hasPassword ? '1' : '0');
sb.Append('\t'); sb.Append('\t');
sb.Append(Channel.Pack()); sb.Append(isTemporary ? '1' : '0');
return sb.ToString(); return sb.ToString();
} }

View file

@ -1,10 +1,12 @@
using System.Text; using System.Text;
namespace SharpChat.S2CPackets { namespace SharpChat.S2CPackets {
public class ChannelUpdateS2CPacket(string previousName, ChatChannel channel) : S2CPacket { public class ChannelUpdateS2CPacket(
public string PreviousName { get; private set; } = previousName ?? throw new ArgumentNullException(nameof(previousName)); string previousName,
public ChatChannel Channel { get; private set; } = channel ?? throw new ArgumentNullException(nameof(channel)); string newName,
bool hasPassword,
bool isTemporary
) : S2CPacket {
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
@ -12,9 +14,13 @@ namespace SharpChat.S2CPackets {
sb.Append('\t'); sb.Append('\t');
sb.Append('1'); sb.Append('1');
sb.Append('\t'); sb.Append('\t');
sb.Append(PreviousName); sb.Append(previousName);
sb.Append('\t'); sb.Append('\t');
sb.Append(Channel.Pack()); sb.Append(newName);
sb.Append('\t');
sb.Append(hasPassword ? '1' : '0');
sb.Append('\t');
sb.Append(isTemporary ? '1' : '0');
return sb.ToString(); return sb.ToString();
} }

View file

@ -1,8 +1,8 @@
using System.Text; using System.Text;
namespace SharpChat.S2CPackets { namespace SharpChat.S2CPackets {
public class ContextChannelsS2CPacket(IEnumerable<ChatChannel> channels) : S2CPacket { public class ContextChannelsS2CPacket(IEnumerable<ContextChannelsS2CPacket.Entry> entries) : S2CPacket {
public IEnumerable<ChatChannel> Channels { get; private set; } = channels?.Where(c => c != null) ?? throw new ArgumentNullException(nameof(channels)); public record Entry(string name, bool hasPassword, bool isTemporary);
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
@ -11,11 +11,15 @@ namespace SharpChat.S2CPackets {
sb.Append('\t'); sb.Append('\t');
sb.Append('2'); sb.Append('2');
sb.Append('\t'); sb.Append('\t');
sb.Append(Channels.Count()); sb.Append(entries.Count());
foreach(ChatChannel channel in Channels) { foreach(Entry entry in entries) {
sb.Append('\t'); sb.Append('\t');
sb.Append(channel.Pack()); sb.Append(entry.name);
sb.Append('\t');
sb.Append(entry.hasPassword ? '1' : '0');
sb.Append('\t');
sb.Append(entry.isTemporary ? '1' : '0');
} }
return sb.ToString(); return sb.ToString();

View file

@ -29,7 +29,21 @@ namespace SharpChat.S2CPackets
sb.Append(V1_CHATBOT); sb.Append(V1_CHATBOT);
sb.Append("0\fsay\f"); sb.Append("0\fsay\f");
} else { } else {
sb.Append(Event.Sender.Pack()); sb.Append(Event.Sender.UserId);
sb.Append('\t');
sb.Append(Event.Sender.LegacyNameWithStatus);
sb.Append('\t');
sb.Append(Event.Sender.Colour);
sb.Append('\t');
sb.Append(Event.Sender.Rank);
sb.Append(' ');
sb.Append(Event.Sender.Permissions.HasFlag(ChatUserPermissions.KickUser) ? '1' : '0');
sb.Append(' ');
sb.Append(Event.Sender.Permissions.HasFlag(ChatUserPermissions.ViewLogs) ? '1' : '0');
sb.Append(' ');
sb.Append(Event.Sender.Permissions.HasFlag(ChatUserPermissions.SetOwnNickname) ? '1' : '0');
sb.Append(' ');
sb.Append(Event.Sender.Permissions.HasFlag(ChatUserPermissions.CreateChannel) ? (Event.Sender.Permissions.HasFlag(ChatUserPermissions.SetChannelPermanent) ? '2' : '1') : '0');
sb.Append('\t'); sb.Append('\t');
} }

View file

@ -1,8 +1,8 @@
using System.Text; using System.Text;
namespace SharpChat.S2CPackets { namespace SharpChat.S2CPackets {
public class ContextUsersS2CPacket(IEnumerable<ChatUser> users) : S2CPacket { public class ContextUsersS2CPacket(IEnumerable<ContextUsersS2CPacket.Entry> entries) : S2CPacket {
public IEnumerable<ChatUser> Users { get; private set; } = users?.Where(u => u != null) ?? throw new ArgumentNullException(nameof(users)); public record Entry(long id, string name, ChatColour colour, int rank, ChatUserPermissions perms, bool visible);
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
@ -11,13 +11,27 @@ namespace SharpChat.S2CPackets {
sb.Append('\t'); sb.Append('\t');
sb.Append('0'); sb.Append('0');
sb.Append('\t'); sb.Append('\t');
sb.Append(Users.Count()); sb.Append(entries.Count());
foreach(ChatUser user in Users) { foreach(Entry entry in entries) {
sb.Append('\t'); sb.Append('\t');
sb.Append(user.Pack()); sb.Append(entry.id);
sb.Append('\t'); sb.Append('\t');
sb.Append('1'); // visibility flag sb.Append(entry.name);
sb.Append('\t');
sb.Append(entry.colour);
sb.Append('\t');
sb.Append(entry.rank);
sb.Append(' ');
sb.Append(entry.perms.HasFlag(ChatUserPermissions.KickUser) ? '1' : '0');
sb.Append(' ');
sb.Append(entry.perms.HasFlag(ChatUserPermissions.ViewLogs) ? '1' : '0');
sb.Append(' ');
sb.Append(entry.perms.HasFlag(ChatUserPermissions.SetOwnNickname) ? '1' : '0');
sb.Append(' ');
sb.Append(entry.perms.HasFlag(ChatUserPermissions.CreateChannel) ? (entry.perms.HasFlag(ChatUserPermissions.SetChannelPermanent) ? '2' : '1') : '0');
sb.Append('\t');
sb.Append(entry.visible ? '1' : '0');
} }
return sb.ToString(); return sb.ToString();

View file

@ -1,17 +1,33 @@
using System.Text; using System.Text;
namespace SharpChat.S2CPackets { namespace SharpChat.S2CPackets {
public class UserChannelJoinS2CPacket(long msgId, ChatUser user) : S2CPacket { public class UserChannelJoinS2CPacket(
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user)); long msgId,
long userId,
string userName,
ChatColour userColour,
int userRank,
ChatUserPermissions userPerms
) : S2CPacket {
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
sb.Append('5'); sb.Append("5\t0\t");
sb.Append(userId);
sb.Append('\t'); sb.Append('\t');
sb.Append('0'); sb.Append(userName);
sb.Append('\t'); sb.Append('\t');
sb.Append(User.Pack()); sb.Append(userColour);
sb.Append('\t');
sb.Append(userRank);
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.KickUser) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.ViewLogs) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.SetOwnNickname) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.CreateChannel) ? (userPerms.HasFlag(ChatUserPermissions.SetChannelPermanent) ? '2' : '1') : '0');
sb.Append('\t'); sb.Append('\t');
sb.Append(msgId); sb.Append(msgId);

View file

@ -1,17 +1,36 @@
using System.Text; using System.Text;
namespace SharpChat.S2CPackets { namespace SharpChat.S2CPackets {
public class UserConnectS2CPacket(long msgId, DateTimeOffset joined, ChatUser user) : S2CPacket { public class UserConnectS2CPacket(
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user)); long msgId,
DateTimeOffset joined,
long userId,
string userName,
ChatColour userColour,
int userRank,
ChatUserPermissions userPerms
) : S2CPacket {
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
sb.Append('1'); sb.Append("1\t");
sb.Append('\t');
sb.Append(joined.ToUnixTimeSeconds()); sb.Append(joined.ToUnixTimeSeconds());
sb.Append('\t'); sb.Append('\t');
sb.Append(User.Pack()); sb.Append(userId);
sb.Append('\t');
sb.Append(userName);
sb.Append('\t');
sb.Append(userColour);
sb.Append('\t');
sb.Append(userRank);
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.KickUser) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.ViewLogs) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.SetOwnNickname) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.CreateChannel) ? (userPerms.HasFlag(ChatUserPermissions.SetChannelPermanent) ? '2' : '1') : '0');
sb.Append('\t'); sb.Append('\t');
sb.Append(msgId); sb.Append(msgId);

View file

@ -1,15 +1,32 @@
using System.Text; using System.Text;
namespace SharpChat.S2CPackets { namespace SharpChat.S2CPackets {
public class UserUpdateS2CPacket(ChatUser user) : S2CPacket { public class UserUpdateS2CPacket(
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user)); long userId,
string userName,
ChatColour userColour,
int userRank,
ChatUserPermissions userPerms
) : S2CPacket {
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
sb.Append("10"); sb.Append("10\t");
sb.Append(userId);
sb.Append('\t'); sb.Append('\t');
sb.Append(User.Pack()); sb.Append(userName);
sb.Append('\t');
sb.Append(userColour);
sb.Append('\t');
sb.Append(userRank);
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.KickUser) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.ViewLogs) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.SetOwnNickname) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.CreateChannel) ? (userPerms.HasFlag(ChatUserPermissions.SetChannelPermanent) ? '2' : '1') : '0');
return sb.ToString(); return sb.ToString();
} }