private EChannelJoinError Request_Join_Channel( EPersistenceID player_id, EChannelID channel_id, EChannelGameProperties remove_mask )
        {
            Remove_Player_From_Channels( player_id, remove_mask );

            CServerChatChannel channel = Get_Channel_By_Channel_ID( channel_id );
            if ( channel == null )
            {
                return EChannelJoinError.ChannelDoesNotExist;
            }

            EChannelJoinError error = channel.Join_Channel( player_id );
            if ( error == EChannelJoinError.None )
            {
                channel.Update_Moderator();
                Add_Channel_To_Player( player_id, channel_id );

                CJoinChatChannelResultMessage result_msg = new CJoinChatChannelResultMessage();
                result_msg.ChannelID = channel_id;
                result_msg.ChannelName = channel.ExternalName;
                result_msg.AnnounceJoinLeave = channel.ShouldAnnounceJoinLeave;

                channel.Members.Apply( n => result_msg.Add_Member( n ) );
                channel.Gagged.Apply( n => result_msg.Add_Gagged( n ) );

                Send_Notification_To_Channel( channel_id, player_id, EChatNotification.Player_Joined_Channel, player_id );

                if ( channel.Update_Moderator() )
                {
                    Send_Notification_To_Channel( channel.ID, channel.Moderator, EChatNotification.New_Moderator, EPersistenceID.Invalid );
                }

                result_msg.Moderator = channel.Moderator;
                Send_Message_To_Player( result_msg, player_id );
            }

            return error;
        }
        private void Request_Create_Or_Join_Channel( EPersistenceID player_id, string channel_name, CJoinChatChannelResultMessage result_msg )
        {
            if ( Get_Player_By_Persistence_ID( player_id ) == null )
            {
                result_msg.CreateError = EChannelCreationError.UnknownPlayer;
                return;
            }

            if ( !CServerChatChannel.Is_Client_Channel_Name( channel_name ) )
            {
                result_msg.CreateError = EChannelCreationError.InvalidInternalName;
                return;
            }

            CServerChatChannel channel = Get_Channel_By_Internal_Name( channel_name );
            if ( channel == null )
            {
                CChatChannelConfig channel_config = new CChatChannelConfig( channel_name, channel_name, player_id, EChannelGameProperties.User );
                channel_config.DestroyWhenEmpty = true;
                channel_config.AllowsModeration = true;

                result_msg.CreateError = channel_config.Make_Valid();
                if ( result_msg.CreateError != EChannelCreationError.None )
                {
                    return;
                }

                EChannelID channel_id = Allocate_Channel_ID();
                channel = new CServerChatChannel( channel_id, channel_config );

                m_Channels.Add( channel_id, channel );
                m_ChannelInternalNames.Add( channel_config.InternalName.ToUpper(), channel_id );
            }

            if ( channel.IsServerChannel )
            {
                result_msg.JoinError = EChannelJoinError.NoPermission;
                return;
            }

            result_msg.JoinError = channel.Join_Channel( player_id );
            if ( result_msg.JoinError == EChannelJoinError.None )
            {
                channel.Update_Moderator();
                Add_Channel_To_Player( player_id, channel.ID );

                result_msg.ChannelID = channel.ID;
                result_msg.ChannelName = channel.ExternalName;
                result_msg.AnnounceJoinLeave = channel.ShouldAnnounceJoinLeave;
                channel.Members.Apply( id => result_msg.Add_Member( id ) );
                channel.Gagged.Apply( id => result_msg.Add_Gagged( id ) );

                Send_Notification_To_Channel( channel.ID, player_id, EChatNotification.Player_Joined_Channel, player_id );

                if ( channel.Update_Moderator() )
                {
                    Send_Notification_To_Channel( channel.ID, channel.Moderator, EChatNotification.New_Moderator, EPersistenceID.Invalid );
                }

                result_msg.Moderator = channel.Moderator;
            }
            else
            {
                Request_Destroy_Channel( channel.ID );
            }
        }
        private void On_Join_Chat_Channel_Result( CJoinChatChannelResultMessage message )
        {
            if ( message.ChannelID != EChannelID.Invalid )
            {
                Add_Client_Channel( message.ChannelID, message.ChannelName, message.AnnounceJoinLeave );

                CClientChatChannel channel = Get_Channel_By_Channel_ID( message.ChannelID );
                channel.Moderator = message.Moderator;

                message.Members.Apply( n => channel.Add_Player( n ) );
                message.Gagged.Apply( n => channel.Set_Gag_Status( n, true ) );
            }
            else
            {
                if ( message.CreateError != EChannelCreationError.None )
                {
                    Handle_Create_Channel_Error( message.CreateError );
                }
                else if ( message.JoinError != EChannelJoinError.None )
                {
                    Handle_Join_Channel_Error( message.JoinError );
                }
            }
        }
        private void Handle_Create_Or_Join_Chat_Channel_Client_Message( CCreateOrJoinChatChannelMessage message, EPersistenceID player_id )
        {
            CJoinChatChannelResultMessage result_msg = new CJoinChatChannelResultMessage();
            Instance.Request_Create_Or_Join_Channel( player_id, message.ChannelName, result_msg );
            Instance.Send_Message_To_Player( result_msg, player_id );

            CLog.Log( ELoggingChannel.Chat, ELogLevel.Medium, String.Format( "Player {0} creater/join user channel {1} with create error = {2}, join error = {3}.",
                                                                                                  Instance.Get_Player_Name_By_Persistence_ID( player_id ),
                                                                                                  message.ChannelName,
                                                                                                  result_msg.CreateError.ToString(),
                                                                                                  result_msg.JoinError.ToString() ) );
        }
		private static void Build_Chat_Message_Samples( List< CNetworkMessage > message_list )
		{
			message_list.Add( new CBroadcastToChatChannelMessage( EChannelID.Invalid, "This is a sample chat broadcast" ) );
			message_list.Add( new CPlayerChatMessage( EChannelID.Invalid, "PlayerName", "A sample player chat message" ) );
			message_list.Add( new CBroadcastFailureMessage( EChannelBroadcastError.UnknownChannel ) );
			message_list.Add( new CCreateOrJoinChatChannelMessage( "SampleChatChannel" ) );

			CJoinChatChannelResultMessage join_result = new CJoinChatChannelResultMessage();
			join_result.ChannelID = EChannelID.Invalid;
			join_result.ChannelName = "JoinedChannel";
			join_result.AnnounceJoinLeave = true;
			join_result.CreateError = EChannelCreationError.InvalidExternalName;
			join_result.JoinError = EChannelJoinError.ChannelDoesNotExist;
			join_result.Moderator = ( EPersistenceID ) 5;
			for ( int i = 0; i < 20; i++ )
			{
				join_result.Add_Member( (EPersistenceID) i );
			}
			for ( int i = 11; i < 14; i++ )
			{
				join_result.Add_Gagged( (EPersistenceID) i );
			}

			message_list.Add( join_result );
			message_list.Add( new CLeaveChatChannelMessage( EChannelID.Invalid ) );
			message_list.Add( new CLeaveChatChannelFailureMessage( ELeaveChatChannelFailureReason.Not_A_Member ) );
			message_list.Add( new CChatClientNotificationMessage( (EChannelID) 2, "SomeTargetPlayer", (EPersistenceID) 3, EChatNotification.Player_Kicked_From_Channel, "SomeSourcePlayer" ) );
			message_list.Add( new CLeftChatChannelMessage( (EChannelID) 3, ELeftChannelReason.Channel_Shutdown, "SomeLeavingPlayer" ) );
			message_list.Add( new CChatModOperationMessage( (EChannelID) 4, EChatModOperation.Ungag, "SomeUngaggedPlayer" ) );
			message_list.Add( new CChatModOperationErrorMessage( EChatModOperationError.No_Such_Player_In_Channel ) );
			message_list.Add( new CPlayerTellMessage( "SomePlayer", "A chat tell from one player to another" ) );
			message_list.Add( new CPlayerTellRequest( "SirTalkyTalk", "SirTalkyTalk's steamy tell to his secret lover." ) );
			message_list.Add( new CPlayerTellResponse( EMessageRequestID.Start ) );
		}