Jump to content

Recommended Posts

  • Active Member

🔒  BAN_ACCOUNT

/ban_account <character_name>

What it does:

This command blocks the account associated with the specified character name, whether that character is online or offline. It also disconnects all characters currently online from that account.

 

✅ Important: You cannot ban yourself or your own secondary characters. If you try to do so, you will receive:
<Ban Account> You cannot ban yourself.

In-Game Message:
<Ban Account> character_name's account (ID: x) has been blocked.



Example:

/ban_account uyvawd

This will block the account that owns the character named uyvawd and will kick him. Any other characters logged in from that account will be disconnected (shown in Example 2).

0d3f3235b4293f73ffbc4e6364bd6a72.gif

Example 2:

We target the same name as above, but that character is offline now, and the user went online on another character from the same account.

910b739e07eb9a288f640b95f7911045.gif

 

 

🌐 BAN_IP

/ban_ip <character_name>

What it does:
This command blocks all accounts that have used the same IP address as the specified character. It also disconnects any currently online characters from those accounts.

 

⚠️ Protections in place:

  • You cannot ban yourself, even if one of your alternate characters shares the same IP, but the rest of the accounts will be blocked and kicked.

 

In-Game Messages:

<BAN IP> All accounts with IP xx.xx.xx.xx were banned.
<BAN IP> Account ID 10001 has been blocked.
<BAN IP> Account ID 10002 has been blocked.
<BAN IP> You attempted to ban yourself. Action was prevented.  
<-- Only if: You banned your own name OR You or one of your alternate characters share the banned ip address.
 


Example:

/ban_ip uyvawd

The command will:

  • Identify the IP of the character uyvawd.
  • Ban all accounts that have logged in using that IP.
  • Disconnect all online characters from those accounts, except your own if you share the IP.


3b3eb9fe2823e96480cf9cf32508398f.gif

 

 

CODE

 
In cmd.cpp

Spoiler

find:    struct command_info cmd_info[] =

add above:

#ifdef _ENABLE_IPBAN_
ACMD(do_ban_account);
ACMD(do_ban_ip);
#endif

 

find:     { "\n",        NULL,            0,            POS_DEAD,    GM_IMPLEMENTOR    }

add above:

#ifdef _ENABLE_IPBAN_
    { "ban_account",        do_ban_account,                0,            POS_DEAD,    GM_HIGH_WIZARD    },
    { "ban_ip",                do_ban_ip,                    0,            POS_DEAD,    GM_HIGH_WIZARD    },
#endif

 

 

In cmd_gm.cpp

Spoiler

add at the end

#ifdef _ENABLE_IPBAN_

// Function to ban an account by character name
void do_ban_account(LPCHARACTER ch, const char *argument, int cmd, int subcmd)
{
    char arg1[256];
    one_argument(argument, arg1, sizeof(arg1));

    if (!*arg1) {
        ch->ChatPacket(CHAT_TYPE_INFO, "Usage: /ban_account <name>");
        return;
    }

    // Try to find the descriptor by character name
    LPDESC d = DESC_MANAGER::instance().FindByCharacterName(arg1);

    DWORD account_id = 0;
    bool is_self_ban = false;

    // If the player is online, get the account ID directly
    if (d && d->GetCharacter()) {
        account_id = d->GetCharacter()->GetAID();
    } else {
        // If the player is offline, retrieve account ID from the database
        std::unique_ptr<SQLMsg> msg(DBManager::instance().DirectQuery(
            "SELECT account_id FROM player%s WHERE name = '%s'", get_table_postfix(), arg1));

        if (msg->Get()->uiNumRows) {
            const auto row = mysql_fetch_row(msg->Get()->pSQLResult);
            str_to_number(account_id, row[0]);
        } else {
            ch->ChatPacket(CHAT_TYPE_INFO, "<Ban Account> Error: could not retrieve player information for %s.", arg1);
            return;
        }
    }

    if (account_id == 0) {
        ch->ChatPacket(CHAT_TYPE_INFO, "<Ban Account> Error: could not find account for %s.", arg1);
        return;
    }

    // Prevent banning your own account
    if (account_id == ch->GetAID()) {
        is_self_ban = true;
        ch->ChatPacket(CHAT_TYPE_INFO, "<Ban Account> You cannot ban your own account.");
        return;
    }

    // Block the account in the database
    if (!is_self_ban) {
        DBManager::instance().DirectQuery(
            "UPDATE account.account SET status = 'BLOCK' WHERE id = %u", account_id);

        ch->ChatPacket(CHAT_TYPE_INFO, "<Ban Account> %s's account (ID: %u) has been blocked.", arg1, account_id);

        // Disconnect all online characters associated with the banned account
        const DESC_MANAGER::DESC_SET& all_descs = DESC_MANAGER::instance().GetClientSet();
        for (auto& desc : all_descs) {
            if (desc && desc->GetCharacter()) {
                if (desc->GetCharacter()->GetAID() == account_id) {
                    sys_log(0, "Disconnecting character: %s", desc->GetCharacter()->GetName());
                    DESC_MANAGER::instance().DestroyDesc(desc);
                }
            }
        }
    }
}

// Function to ban all accounts using the same IP address as a character
void do_ban_ip(LPCHARACTER ch, const char *argument, int cmd, int subcmd)
{
    char arg1[256];
    one_argument(argument, arg1, sizeof(arg1));

    if (!*arg1) {
        ch->ChatPacket(CHAT_TYPE_INFO, "Usage: /ban_ip <name>");
        return;
    }

    // Try to find the descriptor by character name
    LPDESC d = DESC_MANAGER::instance().FindByCharacterName(arg1);

    std::string ip;
    DWORD account_id = 0;

    // If player is online, get IP from descriptor
    if (d && d->GetCharacter()) {
        ip = d->GetHostName();
        account_id = d->GetCharacter()->GetAID();
    } else {
        // If offline, query database for IP and account ID
        std::unique_ptr<SQLMsg> msg(DBManager::instance().DirectQuery(
            "SELECT ip, account_id FROM player%s WHERE name = '%s'", get_table_postfix(), arg1));

        if (msg->Get()->uiNumRows) {
            const auto row = mysql_fetch_row(msg->Get()->pSQLResult);
            ip = row[0];
            str_to_number(account_id, row[1]);
        } else {
            ch->ChatPacket(CHAT_TYPE_INFO, "<Ban IP> Error: could not retrieve player information for %s.", arg1);
            return;
        }
    }

    if (ip.empty()) {
        ch->ChatPacket(CHAT_TYPE_INFO, "<Ban IP> Error: could not retrieve IP address.");
        return;
    }

    // Get all unique account IDs associated with this IP address
    std::unique_ptr<SQLMsg> msg_accounts(DBManager::instance().DirectQuery(
        "SELECT DISTINCT account_id FROM player%s WHERE ip = '%s'", get_table_postfix(), ip.c_str()));

    if (!msg_accounts->Get()->uiNumRows) {
        ch->ChatPacket(CHAT_TYPE_INFO, "<Ban IP> No accounts found for IP: %s.", ip.c_str());
        return;
    }

    ch->ChatPacket(CHAT_TYPE_INFO, "<Ban IP> All accounts with IP %s were banned.", ip.c_str());

    MYSQL_ROW row;
    bool is_self_ban = false;

    while ((row = mysql_fetch_row(msg_accounts->Get()->pSQLResult)) != nullptr) {
        DWORD account_id_to_block = 0;
        str_to_number(account_id_to_block, row[0]);

        if (account_id_to_block == ch->GetAID()) {
            is_self_ban = true;
            continue;
        }

        DBManager::instance().DirectQuery(
            "UPDATE account.account SET status = 'BLOCK' WHERE id = %u", account_id_to_block);

        ch->ChatPacket(CHAT_TYPE_INFO, "<Ban IP> Account ID %u has been blocked.", account_id_to_block);

        // Disconnect all online characters for each banned account
        const DESC_MANAGER::DESC_SET& all_descs = DESC_MANAGER::instance().GetClientSet();
        for (auto& desc : all_descs) {
            if (desc && desc->GetCharacter()) {
                if (desc->GetCharacter()->GetAID() == account_id_to_block) {
                    sys_log(0, "Disconnecting character: %s", desc->GetCharacter()->GetName());
                    DESC_MANAGER::instance().DestroyDesc(desc);
                }
            }
        }
    }

    // Notify the user if they attempted to ban themselves
    if (is_self_ban) {
        ch->ChatPacket(CHAT_TYPE_INFO, "<Ban IP> You attempted to ban yourself. Action was prevented.");
        return;
    }

    // Disconnect the user if their account was also banned
    if (d && d->GetCharacter() && d->GetCharacter()->GetAID() == account_id) {
        sys_log(0, "Disconnecting self (initiator of the ban): %s", d->GetCharacter()->GetName());
        DESC_MANAGER::instance().DestroyDesc(d);
    }
}

#endif

 

🧠 Notes for Developers & Staff

  • Characters do not need to be online for /ban_account or /ban_ip to work.
  • DESC_MANAGER::DestroyDesc(desc) is used to disconnect online characters.

 

🧪 What’s coming next (future improvements in the next few days so you should check this topic later as well):

  • ✅ Detection and prevention of banning GMs with higher or equal authority.
  • ✅ Case-insensitive character name input (UyVaWd, uyvawd, UYVAWD, etc.).
  • ✅ IP chain-tracking (ban all accounts across linked IPs used by that player).
  • ✅ Character disconnection from all cores (e.g., core99) and channels.
  • ✅ SQL query improvements for multi-server environments.

 

Edited by Anielle Noir
Subject name modification
  • Metin2 Dev 4
  • muscle 1
  • Love 1

Don't use any images from : imgur, turkmmop, freakgamers, inforge, hizliresim... Or your content will be deleted without notice...
Use : https://metin2.download/media/add/

Please use https://metin2.download/ when uploading files smaller than 100MB, otherwise the approval will take longer due to manual upload.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.