private bool Remove_From_Channel( EPersistenceID player_id, EChannelID channel_id, ELeftChannelReason reason, EPersistenceID source_player_id )
        {
            CServerChatChannel channel = Get_Channel_By_Channel_ID( channel_id );
            if ( channel == null )
            {
                Send_Message_To_Player( new CLeaveChatChannelFailureMessage( ELeaveChatChannelFailureReason.Unknown_Channel ), player_id );
                return false;
            }

            if ( reason == ELeftChannelReason.Self_Request && channel.IsMembershipClientLocked )
            {
                Send_Message_To_Player( new CLeaveChatChannelFailureMessage( ELeaveChatChannelFailureReason.Not_Allowed ), player_id );
                return false;
            }

            if ( !channel.Leave_Channel( player_id ) )
            {
                Send_Message_To_Player( new CLeaveChatChannelFailureMessage( ELeaveChatChannelFailureReason.Not_A_Member ), player_id );
                return false;
            }

            if ( reason != ELeftChannelReason.Channel_Shutdown )
            {
                Send_Notification_To_Channel( channel_id, source_player_id, player_id, Compute_Notification_From_Leave_Reason( reason ), player_id );
            }

            if ( channel.Update_Moderator() && reason != ELeftChannelReason.Channel_Shutdown )
            {
                Send_Notification_To_Channel( channel.ID, channel.Moderator, EChatNotification.New_Moderator, EPersistenceID.Invalid );
            }

            Remove_Channel_From_Player( player_id, channel_id );
            Send_Message_To_Player( new CLeftChatChannelMessage( channel_id, reason, Get_Player_Name_By_Persistence_ID( source_player_id ) ), player_id );

            if ( channel.MemberCount == 0 && channel.ShouldDestroyWhenEmpty && !channel.IsBeingDestroyed )
            {
                Request_Destroy_Channel( channel.ID );
            }

            return true;
        }
 // Construction
 public CLeftChatChannelMessage( EChannelID channel_id, ELeftChannelReason reason, string source_name )
     : base()
 {
     ChannelID = channel_id;
     Reason = reason;
     SourceName = source_name;
 }
        private EChatNotification Compute_Notification_From_Leave_Reason( ELeftChannelReason reason )
        {
            switch ( reason )
            {
                case ELeftChannelReason.Channel_Shutdown:
                case ELeftChannelReason.Self_Request:
                case ELeftChannelReason.Player_Logoff:
                case ELeftChannelReason.Swapped_By_Server:
                    return EChatNotification.Player_Left_Channel;

                case ELeftChannelReason.Kicked_By_Mod:
                case ELeftChannelReason.Kicked_By_Server:
                    return EChatNotification.Player_Kicked_From_Channel;
            }

            return EChatNotification.None;
        }