PrismarineJS / PrismarineJS/node-minecraft-protocol

proxy example: anticheat flags for actions that wouldn't get you kicked on the first time, before recreating the target client.

Open
#1,358 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

possible bug
Dominant language
JavaScript
Stars
1.4k
Forks
290
Avg merge
4d 8h
Merged PRs (30d)
7

Description

[ ] The FAQ doesn't contain a resolution to my issue

Versions

  • minecraft-protocol: 1.51.0
  • node: v22.11.0

Detailed description of a problem

A clear and concise description of what the problem is.

Current code

const mc = require('minecraft-protocol');
const states = mc.states;
var Socks = require("socks5-client");
const { exec } = require('child_process');

function printHelpAndExit(exitCode) {
    console.log('usage: node proxy.js <target_srv> <version>');
    process.exit(exitCode);
}

if (process.argv.length < 4) {
    console.log('Too few arguments!');
    printHelpAndExit(1);
}

process.argv.forEach(function (val) {
    if (val === '-h') {
        printHelpAndExit(0);
    }
});

const args = process.argv.slice(2);
let host;
let port = 25565;
let version;

(function () {
    let i = 0;
    for (i = 0; i < args.length; i++) {
        const option = args[i];
        if (!/^-/.test(option)) break;
        i++;
    }
    if (!(i + 2 <= args.length && args.length <= i + 4)) printHelpAndExit(1);
    host = args[i++];
    version = args[i++];
})();

if (host.indexOf(':') !== -1) {
    port = host.substring(host.indexOf(':') + 1);
    host = host.substring(0, host.indexOf(':'));
}

const srv = mc.createServer({
    'online-mode': false,
    port: 25566,
    keepAlive: false,
    version
});

// Array to store the connected clients
let clients = [];
let targetClients = [];  // Track target clients

srv.on('login', function (client) {
    const addr = client.socket.remoteAddress;
    console.log('Incoming connection', '(' + addr + ')');

    // Add the new client to the clients array
    clients.push(client);

    let endedClient = false;
    let endedTargetClient = false;
    let targetClient;

    client.on('end', function () {
        endedClient = true;
        console.log('Connection closed by client', '(' + addr + ')');
        // Remove client from the array when they disconnect
        clients = clients.filter(c => c !== client);

        if (!endedTargetClient) {
            targetClient.end('End');
        }
    });

    client.on('error', function (err) {
        endedClient = false;
        console.log('Connection error by client', '(' + addr + ')');
        console.log(err.stack);
    });

    function generateRandomUsername() {
        const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        let username = '';
        const length = 12;

        for (let i = 0; i < length; i++) {
            const randomIndex = Math.floor(Math.random() * characters.length);
            username += characters[randomIndex];
        }

        return username;
    }

    // Function to set up the target client
    function setupTargetClient() {
        // Close all previously connected target clients
        targetClients.forEach((tc) => {
            tc.end('End');
        });

        // Create new target client
        targetClient = mc.createClient({
            host: host,
            port: port,
            username: generateRandomUsername(),
            keepAlive: false,
            version: '1.8.9'
        });

        // Store the new target client
        targetClients = [targetClient];

        // Forwarding packets between client and target server
        client.on('packet', function (data, meta) {
            if (targetClient.state === states.PLAY && meta.state === states.PLAY) {
                 // Check if the packet is not a kick packet
            if (meta.name === 'kick_disconnect') {
                // Do nothing to prevent the kick packet from being processed
                return;
            }
                targetClient.write(meta.name, data);
            }
        });

        targetClient.on('packet', function (data, meta) {

            if (meta.state === states.PLAY && client.state === states.PLAY) {
                 // Check if the packet is not a kick packet
                if (meta.name === 'kick_disconnect') {
                    // Do nothing to prevent the kick packet from being processed
                    return;
                }
                client.write(meta.name, data);
                if (meta.name === 'set_compression') {
                    client.compressionThreshold = data.threshold;
                }
            }
        });

        let hasRegistered = false;

        function delay(ms) {
            return new Promise(resolve => setTimeout(resolve, ms));
        }

        targetClient.on('chat', async (message) => {
            if (String(message).includes('register') || hasRegistered) {
                return;
            }

            await delay(2000);
            targetClient.chat('/register 123123 123123');
            hasRegistered = true;
        });

        targetClient.on('end', function () {
            endedTargetClient = true;
            console.log('Target client disconnected from server', '(' + addr + ')');
            
            // // Run the 'resetip.bat' command first
            // exec('resetip.bat', (error, stdout, stderr) => {
            //     if (error) {
            //         console.error(`exec error: ${error}`);
            //         return;
            //     }
            //     if (stderr) {
            //         console.error(`stderr: ${stderr}`);
            //         return;
            //     }
            //     console.log(`stdout: ${stdout}`);
            // });
            // -- deleted the ip resetter temporarily (in the video it isn't used)
            // delay(3350).then(() => {
                setupTargetClient(); // Reconnect to the target server
                console.log('Reconnected with new target client');
            // });
        });
    }

    // Call the function initially
    setupTargetClient();
});

Expected behavior

After reconnecting from a kick, everything should work normally, and I shouldn't be kicked, in the moment where I got kicked in the video.

Additional context

I am trying to make a code that would automatically reconnect when I get kicked from a server, also without kicking me from the localhost server, I am playing on.

What happens:
https://streamable.com/ufbfu5 (uploading here, since the file is too big).

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the behavior with the provided proxy code on minecraft-protocol 1.51.0 and Node v22.11.0, then trace the packet forwarding and target-client reconnection paths shown in the example. The issue does not name a library file or test; completion would require identifying the cause of the anticheat kick and demonstrating that reconnecting no longer triggers it.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, node.js
Domain
networking
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.