2023-07-23 21:31:13 +00:00
using SharpChat.Events ;
using SharpChat.EventStorage ;
2024-05-20 23:00:47 +00:00
using SharpChat.PacketsS2C ;
2022-08-30 15:00:58 +00:00
using System ;
using System.Collections.Generic ;
2023-02-10 06:07:59 +00:00
using System.Linq ;
2023-02-19 22:27:08 +00:00
using System.Threading ;
2022-08-30 15:00:58 +00:00
2024-05-09 21:31:19 +00:00
namespace SharpChat {
2023-02-10 06:07:59 +00:00
public class ChatContext {
2023-02-19 22:27:08 +00:00
public readonly SemaphoreSlim ContextAccess = new ( 1 , 1 ) ;
2022-08-30 15:00:58 +00:00
2024-05-19 21:02:17 +00:00
public ChannelsContext Channels { get ; } = new ( ) ;
2024-05-20 16:16:32 +00:00
public ConnectionsContext Connections { get ; } = new ( ) ;
2024-05-19 21:02:17 +00:00
public UsersContext Users { get ; } = new ( ) ;
2023-02-10 06:07:59 +00:00
public IEventStorage Events { get ; }
2024-05-19 21:02:17 +00:00
public ChannelsUsersContext ChannelsUsers { get ; } = new ( ) ;
2023-02-19 22:27:08 +00:00
public Dictionary < long , RateLimiter > UserRateLimiters { get ; } = new ( ) ;
2023-02-17 19:02:35 +00:00
2023-02-10 06:07:59 +00:00
public ChatContext ( IEventStorage evtStore ) {
2024-05-19 01:53:14 +00:00
Events = evtStore ;
2022-08-30 15:00:58 +00:00
}
2023-07-23 21:31:13 +00:00
public void DispatchEvent ( IChatEvent eventInfo ) {
if ( eventInfo is MessageCreateEvent mce ) {
if ( mce . IsBroadcast ) {
2024-05-20 23:00:47 +00:00
Send ( new MessageBroadcastS2CPacket ( mce . MessageText ) ) ;
2023-07-23 21:31:13 +00:00
} else if ( mce . IsPrivate ) {
// The channel name returned by GetDMChannelName should not be exposed to the user, instead @<Target User> should be displayed
// e.g. nook sees @Arysil and Arysil sees @nook
// this entire routine is garbage, channels should probably in the db
2024-05-10 19:18:55 +00:00
if ( mce . ChannelName ? . StartsWith ( "@" ) ! = true )
2023-07-23 21:31:13 +00:00
return ;
2024-05-19 01:53:14 +00:00
long [ ] targetIds = mce . ChannelName [ 1. . ] . Split ( '-' , 3 ) . Select ( u = > long . TryParse ( u , out long up ) ? up : - 1 ) . ToArray ( ) ;
if ( targetIds . Length ! = 2 )
2023-07-23 21:31:13 +00:00
return ;
2024-05-19 21:02:17 +00:00
UserInfo [ ] users = Users . GetMany ( targetIds ) ;
2024-05-19 02:17:51 +00:00
UserInfo ? target = users . FirstOrDefault ( u = > u . UserId ! = mce . SenderId ) ;
2023-07-23 21:31:13 +00:00
if ( target = = null )
return ;
2024-05-19 02:17:51 +00:00
foreach ( UserInfo user in users )
2024-05-20 23:00:47 +00:00
SendTo ( user , new MessageAddS2CPacket (
2023-07-23 21:31:13 +00:00
mce . MessageId ,
DateTimeOffset . Now ,
mce . SenderId ,
2024-05-19 21:02:17 +00:00
mce . SenderId = = user . UserId ? $"{SockChatUtility.GetUserName(target)} {mce.MessageText}" : mce . MessageText ,
2023-07-23 21:31:13 +00:00
mce . IsAction ,
true
) ) ;
} else {
2024-05-19 21:02:17 +00:00
ChannelInfo ? channel = Channels . Get ( mce . ChannelName , SockChatUtility . SanitiseChannelName ) ;
2024-05-10 19:18:55 +00:00
if ( channel ! = null )
2024-05-20 23:00:47 +00:00
SendTo ( channel , new MessageAddS2CPacket (
2024-05-10 19:18:55 +00:00
mce . MessageId ,
DateTimeOffset . Now ,
mce . SenderId ,
mce . MessageText ,
mce . IsAction ,
false
) ) ;
2023-07-23 21:31:13 +00:00
}
Events . AddEvent (
mce . MessageId , "msg:add" ,
mce . ChannelName ,
mce . SenderId , mce . SenderName , mce . SenderColour , mce . SenderRank , mce . SenderNickName , mce . SenderPerms ,
new { text = mce . MessageText } ,
( mce . IsBroadcast ? StoredEventFlags . Broadcast : 0 )
| ( mce . IsAction ? StoredEventFlags . Action : 0 )
| ( mce . IsPrivate ? StoredEventFlags . Private : 0 )
) ;
return ;
}
}
2022-08-30 15:00:58 +00:00
public void Update ( ) {
2024-05-20 16:16:32 +00:00
ConnectionInfo [ ] timedOut = Connections . GetTimedOut ( ) ;
foreach ( ConnectionInfo conn in timedOut ) {
Connections . Remove ( conn ) ;
conn . Close ( 1002 ) ;
2023-02-19 22:27:08 +00:00
2024-05-20 16:16:32 +00:00
Logger . Write ( $"<{conn.RemoteEndPoint}> Nuked timed out connection from user #{conn.UserId}." ) ;
}
2023-02-19 22:27:08 +00:00
2024-05-19 21:02:17 +00:00
foreach ( UserInfo user in Users . All )
2024-05-20 16:16:32 +00:00
if ( ! Connections . HasUser ( user ) ) {
2024-05-19 02:17:51 +00:00
HandleDisconnect ( user , UserDisconnectReason . TimeOut ) ;
2023-02-19 22:27:08 +00:00
Logger . Write ( $"Timed out {user} (no more connections)." ) ;
}
}
public void SafeUpdate ( ) {
ContextAccess . Wait ( ) ;
try {
Update ( ) ;
} finally {
ContextAccess . Release ( ) ;
2023-02-16 22:33:48 +00:00
}
2022-08-30 15:00:58 +00:00
}
2024-05-19 02:17:51 +00:00
public ChannelInfo [ ] GetUserChannels ( UserInfo user ) {
2024-05-19 21:02:17 +00:00
return Channels . GetMany ( ChannelsUsers . GetUserChannelNames ( user ) ) ;
2023-02-17 19:02:35 +00:00
}
2024-05-19 02:17:51 +00:00
public UserInfo [ ] GetChannelUsers ( ChannelInfo channel ) {
2024-05-19 21:02:17 +00:00
return Users . GetMany ( ChannelsUsers . GetChannelUserIds ( channel ) ) ;
2023-02-17 19:02:35 +00:00
}
2023-02-22 00:28:53 +00:00
public void UpdateUser (
2024-05-19 02:17:51 +00:00
UserInfo user ,
2024-05-10 19:18:55 +00:00
string? userName = null ,
string? nickName = null ,
2024-05-19 02:17:51 +00:00
Colour ? colour = null ,
UserStatus ? status = null ,
2024-05-10 19:18:55 +00:00
string? statusText = null ,
2023-02-22 00:28:53 +00:00
int? rank = null ,
2024-05-19 02:17:51 +00:00
UserPermissions ? perms = null ,
2023-11-07 14:49:12 +00:00
bool? isSuper = null ,
2023-02-22 00:28:53 +00:00
bool silent = false
) {
bool hasChanged = false ;
2024-05-10 19:18:55 +00:00
string? previousName = null ;
2023-02-22 00:28:53 +00:00
if ( userName ! = null & & ! user . UserName . Equals ( userName ) ) {
user . UserName = userName ;
hasChanged = true ;
}
if ( nickName ! = null & & ! user . NickName . Equals ( nickName ) ) {
if ( ! silent )
previousName = string . IsNullOrWhiteSpace ( user . NickName ) ? user . UserName : user . NickName ;
user . NickName = nickName ;
hasChanged = true ;
}
2024-05-19 01:53:14 +00:00
if ( colour . HasValue & & user . Colour . Equals ( colour . Value ) ) {
2023-02-22 00:28:53 +00:00
user . Colour = colour . Value ;
hasChanged = true ;
}
if ( status . HasValue & & user . Status ! = status . Value ) {
user . Status = status . Value ;
hasChanged = true ;
}
if ( statusText ! = null & & ! user . StatusText . Equals ( statusText ) ) {
user . StatusText = statusText ;
hasChanged = true ;
}
if ( rank ! = null & & user . Rank ! = rank ) {
user . Rank = ( int ) rank ;
hasChanged = true ;
}
if ( perms . HasValue & & user . Permissions ! = perms ) {
user . Permissions = perms . Value ;
hasChanged = true ;
}
2023-11-07 14:49:12 +00:00
if ( isSuper . HasValue ) {
user . IsSuper = isSuper . Value ;
hasChanged = true ;
}
2024-05-10 15:07:56 +00:00
if ( hasChanged ) {
if ( previousName ! = null )
2024-05-20 23:00:47 +00:00
SendToUserChannels ( user , new UserUpdateNotificationS2CPacket ( previousName , SockChatUtility . GetUserNameWithStatus ( user ) ) ) ;
2024-05-10 15:07:56 +00:00
2024-05-20 23:00:47 +00:00
SendToUserChannels ( user , new UserUpdateS2CPacket (
2024-05-10 18:29:48 +00:00
user . UserId ,
2024-05-19 21:02:17 +00:00
SockChatUtility . GetUserNameWithStatus ( user ) ,
2024-05-10 18:29:48 +00:00
user . Colour ,
user . Rank ,
user . Permissions
) ) ;
2024-05-10 15:07:56 +00:00
}
2023-02-22 00:28:53 +00:00
}
2024-05-19 02:17:51 +00:00
public void BanUser ( UserInfo user , TimeSpan duration , UserDisconnectReason reason = UserDisconnectReason . Kicked ) {
2024-05-09 21:31:19 +00:00
if ( duration > TimeSpan . Zero ) {
2023-07-23 21:45:10 +00:00
DateTimeOffset expires = duration > = TimeSpan . MaxValue ? DateTimeOffset . MaxValue : DateTimeOffset . Now + duration ;
2024-05-20 23:00:47 +00:00
SendTo ( user , new ForceDisconnectS2CPacket ( expires ) ) ;
2023-07-23 21:45:10 +00:00
} else
2024-05-20 23:00:47 +00:00
SendTo ( user , new ForceDisconnectS2CPacket ( ) ) ;
2023-02-16 22:33:48 +00:00
2024-05-20 16:16:32 +00:00
ConnectionInfo [ ] conns = Connections . GetUser ( user ) ;
foreach ( ConnectionInfo conn in conns ) {
Connections . Remove ( conn ) ;
conn . Close ( 1000 ) ;
Logger . Write ( $"<{conn.RemoteEndPoint}> Nuked connection from banned user #{conn.UserId}." ) ;
}
2022-08-30 15:00:58 +00:00
2023-02-17 19:02:35 +00:00
HandleDisconnect ( user , reason ) ;
2022-08-30 15:00:58 +00:00
}
2024-05-20 02:16:38 +00:00
public void HandleChannelEventLog ( string channelName , Action < SockChatS2CPacket > handler ) {
2024-05-14 22:56:56 +00:00
foreach ( StoredEventInfo msg in Events . GetChannelEventLog ( channelName ) )
handler ( msg . Type switch {
2024-05-20 23:00:47 +00:00
"msg:add" = > new MessageAddLogS2CPacket (
2024-05-20 01:35:33 +00:00
msg . Id ,
msg . Created ,
msg . Sender ? . UserId ? ? - 1 ,
msg . Sender = = null ? "ChatBot" : SockChatUtility . GetUserName ( msg . Sender ) ,
msg . Sender ? . Colour ? ? Colour . None ,
msg . Sender ? . Rank ? ? 0 ,
msg . Sender ? . Permissions ? ? 0 ,
msg . Data . RootElement . GetProperty ( "text" ) . GetString ( ) ? ? string . Empty ,
msg . Flags . HasFlag ( StoredEventFlags . Action ) ,
msg . Flags . HasFlag ( StoredEventFlags . Private ) ,
msg . Flags . HasFlag ( StoredEventFlags . Broadcast ) ,
false
) ,
2024-05-20 23:00:47 +00:00
"user:connect" = > new UserConnectLogS2CPacket (
2024-05-20 02:16:38 +00:00
msg . Id ,
2024-05-20 01:35:33 +00:00
msg . Created ,
msg . Sender = = null ? string . Empty : SockChatUtility . GetUserName ( msg . Sender )
) ,
2024-05-20 23:00:47 +00:00
"user:disconnect" = > new UserDisconnectLogS2CPacket (
2024-05-20 02:16:38 +00:00
msg . Id ,
2024-05-14 22:56:56 +00:00
msg . Created ,
2024-05-19 21:02:17 +00:00
msg . Sender = = null ? string . Empty : SockChatUtility . GetUserNameWithStatus ( msg . Sender ) ,
2024-05-19 02:17:51 +00:00
( UserDisconnectReason ) msg . Data . RootElement . GetProperty ( "reason" ) . GetByte ( )
2024-05-14 22:56:56 +00:00
) ,
2024-05-20 23:00:47 +00:00
"chan:join" = > new UserChannelJoinLogS2CPacket (
2024-05-20 02:16:38 +00:00
msg . Id ,
2024-05-20 01:35:33 +00:00
msg . Created ,
msg . Sender = = null ? string . Empty : SockChatUtility . GetUserName ( msg . Sender )
) ,
2024-05-20 23:00:47 +00:00
"chan:leave" = > new UserChannelLeaveLogS2CPacket (
2024-05-20 02:16:38 +00:00
msg . Id ,
2024-05-20 01:35:33 +00:00
msg . Created ,
msg . Sender = = null ? string . Empty : SockChatUtility . GetUserName ( msg . Sender )
) ,
_ = > throw new Exception ( $"Unsupported backlog type: {msg.Type}" ) ,
2024-05-14 22:56:56 +00:00
} ) ;
}
2024-05-19 02:17:51 +00:00
public void HandleJoin ( UserInfo user , ChannelInfo chan , ConnectionInfo conn , int maxMsgLength ) {
2024-05-19 21:02:17 +00:00
if ( ! ChannelsUsers . Has ( chan , user ) ) {
2024-05-20 23:00:47 +00:00
SendTo ( chan , new UserConnectS2CPacket (
2024-05-10 18:29:48 +00:00
user . UserId ,
2024-05-19 21:02:17 +00:00
SockChatUtility . GetUserNameWithStatus ( user ) ,
2024-05-10 18:29:48 +00:00
user . Colour ,
user . Rank ,
user . Permissions
) ) ;
2023-02-23 21:46:49 +00:00
Events . AddEvent ( "user:connect" , user , chan , flags : StoredEventFlags . Log ) ;
2023-02-19 22:27:08 +00:00
}
2022-08-30 15:00:58 +00:00
2024-05-20 23:00:47 +00:00
conn . Send ( new AuthSuccessS2CPacket (
2024-05-10 18:29:48 +00:00
user . UserId ,
2024-05-19 21:02:17 +00:00
SockChatUtility . GetUserNameWithStatus ( user ) ,
2024-05-10 18:29:48 +00:00
user . Colour ,
user . Rank ,
user . Permissions ,
chan . Name ,
maxMsgLength
) ) ;
2024-05-20 23:00:47 +00:00
conn . Send ( new UsersPopulateS2CPacket ( GetChannelUsers ( chan ) . Except ( new [ ] { user } ) . Select (
user = > new UsersPopulateS2CPacket . ListEntry (
2024-05-19 21:02:17 +00:00
user . UserId ,
SockChatUtility . GetUserNameWithStatus ( user ) ,
user . Colour ,
user . Rank ,
user . Permissions ,
true
)
2024-05-10 18:29:48 +00:00
) . OrderByDescending ( user = > user . Rank ) . ToArray ( ) ) ) ;
2022-08-30 15:00:58 +00:00
2024-05-14 22:56:56 +00:00
HandleChannelEventLog ( chan . Name , p = > conn . Send ( p ) ) ;
2022-08-30 15:00:58 +00:00
2024-05-20 23:00:47 +00:00
conn . Send ( new ChannelsPopulateS2CPacket ( Channels . GetMany ( isPublic : true , minRank : user . Rank ) . Select (
channel = > new ChannelsPopulateS2CPacket . ListEntry ( channel . Name , channel . HasPassword , channel . IsTemporary )
2024-05-10 18:29:48 +00:00
) . ToArray ( ) ) ) ;
2022-08-30 15:00:58 +00:00
2024-05-19 21:02:17 +00:00
if ( Users . Get ( userId : user . UserId ) = = null )
Users . Add ( user ) ;
2023-02-17 19:02:35 +00:00
2024-05-19 21:02:17 +00:00
ChannelsUsers . Join ( chan . Name , user . UserId ) ;
2022-08-30 15:00:58 +00:00
}
2024-05-19 02:17:51 +00:00
public void HandleDisconnect ( UserInfo user , UserDisconnectReason reason = UserDisconnectReason . Leave ) {
UpdateUser ( user , status : UserStatus . Offline ) ;
2024-05-19 01:53:14 +00:00
Users . Remove ( user . UserId ) ;
2022-08-30 15:00:58 +00:00
2024-05-19 02:17:51 +00:00
ChannelInfo [ ] channels = GetUserChannels ( user ) ;
2024-05-19 21:02:17 +00:00
ChannelsUsers . DeleteUser ( user ) ;
2022-08-30 15:00:58 +00:00
2024-05-19 02:17:51 +00:00
foreach ( ChannelInfo chan in channels ) {
2024-05-20 23:00:47 +00:00
SendTo ( chan , new UserDisconnectS2CPacket (
2024-05-19 21:02:17 +00:00
user . UserId ,
SockChatUtility . GetUserNameWithStatus ( user ) ,
reason
) ) ;
2023-02-23 21:46:49 +00:00
Events . AddEvent ( "user:disconnect" , user , chan , new { reason = ( int ) reason } , StoredEventFlags . Log ) ;
2023-02-17 19:02:35 +00:00
2023-02-22 00:28:53 +00:00
if ( chan . IsTemporary & & chan . IsOwner ( user ) )
2023-02-19 22:27:08 +00:00
RemoveChannel ( chan ) ;
2023-02-10 06:07:59 +00:00
}
2022-08-30 15:00:58 +00:00
}
2024-05-19 02:17:51 +00:00
public void SwitchChannel ( UserInfo user , ChannelInfo chan , string password ) {
2024-05-19 21:02:17 +00:00
if ( ChannelsUsers . IsUserLastChannel ( user , chan ) ) {
2023-02-16 22:33:48 +00:00
ForceChannel ( user ) ;
2022-08-30 15:00:58 +00:00
return ;
}
2024-05-19 02:17:51 +00:00
if ( ! user . Permissions . HasFlag ( UserPermissions . JoinAnyChannel ) & & chan . IsOwner ( user ) ) {
2023-02-07 15:01:56 +00:00
if ( chan . Rank > user . Rank ) {
2024-05-20 23:00:47 +00:00
SendTo ( user , new ChannelRankTooLowErrorS2CPacket ( chan . Name ) ) ;
2023-02-16 22:33:48 +00:00
ForceChannel ( user ) ;
2022-08-30 15:00:58 +00:00
return ;
}
2024-05-14 22:17:25 +00:00
if ( ! string . IsNullOrEmpty ( chan . Password ) & & chan . Password . Equals ( password ) ) {
2024-05-20 23:00:47 +00:00
SendTo ( user , new ChannelPasswordWrongErrorS2CPacket ( chan . Name ) ) ;
2023-02-16 22:33:48 +00:00
ForceChannel ( user ) ;
2022-08-30 15:00:58 +00:00
return ;
}
}
ForceChannelSwitch ( user , chan ) ;
}
2024-05-19 02:17:51 +00:00
public void ForceChannelSwitch ( UserInfo user , ChannelInfo chan ) {
2024-05-19 21:02:17 +00:00
ChannelInfo ? oldChan = Channels . Get ( ChannelsUsers . GetUserLastChannel ( user ) ) ;
2022-08-30 15:00:58 +00:00
2024-05-19 21:02:17 +00:00
if ( oldChan ! = null ) {
2024-05-20 23:00:47 +00:00
SendTo ( oldChan , new UserChannelLeaveS2CPacket ( user . UserId ) ) ;
2024-05-19 21:02:17 +00:00
Events . AddEvent ( "chan:leave" , user , oldChan , flags : StoredEventFlags . Log ) ;
}
2022-08-30 15:00:58 +00:00
2024-05-20 23:00:47 +00:00
SendTo ( chan , new UserChannelJoinS2CPacket (
2024-05-19 21:02:17 +00:00
user . UserId ,
SockChatUtility . GetUserNameWithStatus ( user ) ,
user . Colour ,
user . Rank ,
user . Permissions
) ) ;
if ( oldChan ! = null )
Events . AddEvent ( "chan:join" , user , oldChan , flags : StoredEventFlags . Log ) ;
2022-08-30 15:00:58 +00:00
2024-05-20 23:00:47 +00:00
SendTo ( user , new ContextClearS2CPacket ( ContextClearS2CPacket . ClearMode . MessagesUsers ) ) ;
SendTo ( user , new UsersPopulateS2CPacket ( GetChannelUsers ( chan ) . Except ( new [ ] { user } ) . Select (
user = > new UsersPopulateS2CPacket . ListEntry (
2024-05-19 21:02:17 +00:00
user . UserId ,
SockChatUtility . GetUserNameWithStatus ( user ) ,
user . Colour ,
user . Rank ,
user . Permissions ,
true
)
2024-05-10 18:29:48 +00:00
) . OrderByDescending ( u = > u . Rank ) . ToArray ( ) ) ) ;
2022-08-30 15:00:58 +00:00
2024-05-14 22:56:56 +00:00
HandleChannelEventLog ( chan . Name , p = > SendTo ( user , p ) ) ;
2023-02-19 22:27:08 +00:00
ForceChannel ( user , chan ) ;
2023-02-17 19:02:35 +00:00
2024-05-19 21:02:17 +00:00
if ( oldChan ! = null )
ChannelsUsers . Leave ( oldChan , user ) ;
ChannelsUsers . Join ( chan , user ) ;
2022-08-30 15:00:58 +00:00
2024-05-19 21:02:17 +00:00
if ( oldChan ! = null & & oldChan . IsTemporary & & oldChan . IsOwner ( user ) )
2023-02-19 22:27:08 +00:00
RemoveChannel ( oldChan ) ;
2022-08-30 15:00:58 +00:00
}
2024-05-20 02:16:38 +00:00
public void Send ( SockChatS2CPacket packet ) {
2024-05-20 16:24:14 +00:00
string data = packet . Pack ( ) ;
Connections . WithAuthed ( conn = > conn . Send ( data ) ) ;
2023-02-16 22:33:48 +00:00
}
2024-05-20 02:16:38 +00:00
public void SendTo ( UserInfo user , SockChatS2CPacket packet ) {
2024-05-20 16:24:14 +00:00
string data = packet . Pack ( ) ;
Connections . WithUser ( user , conn = > conn . Send ( data ) ) ;
2023-02-16 22:33:48 +00:00
}
2024-05-20 02:16:38 +00:00
public void SendTo ( ChannelInfo channel , SockChatS2CPacket packet ) {
2024-05-20 16:24:14 +00:00
SendTo ( channel , packet . Pack ( ) ) ;
}
public void SendTo ( ChannelInfo channel , string packet ) {
2024-05-19 21:02:17 +00:00
long [ ] userIds = ChannelsUsers . GetChannelUserIds ( channel ) ;
2024-05-20 16:16:32 +00:00
foreach ( long userId in userIds )
Connections . WithUser ( userId , conn = > conn . Send ( packet ) ) ;
2023-02-16 22:33:48 +00:00
}
2024-05-20 02:16:38 +00:00
public void SendToUserChannels ( UserInfo user , SockChatS2CPacket packet ) {
2024-05-19 21:02:17 +00:00
ChannelInfo [ ] chans = GetUserChannels ( user ) ;
2024-05-20 16:24:14 +00:00
string data = packet . Pack ( ) ;
2024-05-19 21:02:17 +00:00
foreach ( ChannelInfo chan in chans )
2024-05-20 16:24:14 +00:00
SendTo ( chan , data ) ;
2023-02-22 00:28:53 +00:00
}
2024-05-19 02:17:51 +00:00
public void ForceChannel ( UserInfo user , ChannelInfo ? chan = null ) {
2024-05-19 21:02:17 +00:00
chan ? ? = Channels . Get ( ChannelsUsers . GetUserLastChannel ( user ) ) ;
if ( chan ! = null )
2024-05-20 23:00:47 +00:00
SendTo ( user , new UserChannelForceJoinS2CPacket ( chan . Name ) ) ;
2023-02-10 06:07:59 +00:00
}
2022-08-30 15:00:58 +00:00
2024-05-10 19:18:55 +00:00
public void UpdateChannel (
2024-05-19 02:17:51 +00:00
ChannelInfo channel ,
2024-05-10 19:18:55 +00:00
bool? temporary = null ,
int? minRank = null ,
string? password = null
) {
2024-05-10 18:29:48 +00:00
string prevName = channel . Name ;
2023-02-10 06:07:59 +00:00
if ( temporary . HasValue )
channel . IsTemporary = temporary . Value ;
2024-05-10 18:29:48 +00:00
if ( minRank . HasValue )
channel . Rank = minRank . Value ;
2023-02-10 06:07:59 +00:00
if ( password ! = null )
channel . Password = password ;
2022-08-30 15:00:58 +00:00
2024-05-10 18:29:48 +00:00
// TODO: Users that no longer have access to the channel/gained access to the channel by the rank change should receive delete and create packets respectively
2024-05-19 21:02:17 +00:00
// the server currently doesn't keep track of what channels a user is already aware of so can't really simulate this yet.
foreach ( UserInfo user in Users . GetMany ( minRank : channel . Rank ) )
2024-05-20 23:00:47 +00:00
SendTo ( user , new ChannelUpdateS2CPacket ( prevName , channel . Name , channel . HasPassword , channel . IsTemporary ) ) ;
2023-02-06 20:14:50 +00:00
}
2022-08-30 15:00:58 +00:00
2024-05-19 02:17:51 +00:00
public void RemoveChannel ( ChannelInfo channel ) {
2024-05-19 21:02:17 +00:00
if ( channel = = null | | Channels . PublicCount > 1 )
2023-02-10 06:07:59 +00:00
return ;
2024-05-19 21:02:17 +00:00
ChannelInfo ? defaultChannel = Channels . MainChannel ;
2023-02-10 06:07:59 +00:00
if ( defaultChannel = = null )
2022-08-30 15:00:58 +00:00
return ;
2023-02-10 06:07:59 +00:00
// Remove channel from the listing
2024-05-19 21:02:17 +00:00
Channels . Remove ( channel ) ;
2023-02-10 06:07:59 +00:00
// Move all users back to the main channel
// TODO: Replace this with a kick. SCv2 supports being in 0 channels, SCv1 should force the user back to DefaultChannel.
2024-05-19 02:17:51 +00:00
foreach ( UserInfo user in GetChannelUsers ( channel ) )
2023-02-10 06:07:59 +00:00
SwitchChannel ( user , defaultChannel , string . Empty ) ;
// Broadcast deletion of channel
2024-05-19 21:02:17 +00:00
foreach ( UserInfo user in Users . GetMany ( minRank : channel . Rank ) )
2024-05-20 23:00:47 +00:00
SendTo ( user , new ChannelDeleteS2CPacket ( channel . Name ) ) ;
2022-08-30 15:00:58 +00:00
}
}
}