summaryrefslogtreecommitdiff
path: root/src/2b2w/main.ts
blob: 9edbbfd58d84d0287f45c798c6688a01d04537dd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import mc from 'minecraft-protocol'; // to handle minecraft login session
const webserver = require('./webserver.js') // to serve the webserver
import opn from 'opn'; //to open a browser window
import secrets from './secrets.json'; // read the creds
import config from './config.json'; // read the config

webserver.createServer(config.ports.web); // create the webserver
webserver.password = config.password;
webserver.onstart(() => { // set up actions for the webserver
	startQueuing();
});
webserver.onstop(() => {
	stop();
});

if (config.openBrowserOnStart) {
    opn('http://localhost:' + config.ports.web); //open a browser window
}
// mc-protocol 1.8.3

// lets
let proxyClient; // a reference to the client that is the actual minecraft game
let client; // the client to connect to 2b2t
let server; // the minecraft server to pass packets

// function to disconnect from the server
export function stop() {
	webserver.isInQueue = false;
	webserver.queuePlace = "None";
	webserver.ETA = "None";
	client.end("disconnect"); // disconnect
	if (proxyClient) {
		proxyClient.end("Stopped the proxy."); // boot the player from the server
	}
	server.close(); // close the server
}

// function to start the whole thing
export function startQueuing() {
	var playerId;
	webserver.isInQueue = true;
	client = mc.createClient({ // connect to 2b2t
		host: "2b2t.org",
		port: 25565,
		username: secrets.username,
		password: secrets.password,
		version: config.MCversion
	});
	let finishedQueue = false;
	client.on("packet", (data, meta) => { // each time 2b2t sends a packet
		if (!finishedQueue && meta.name === "playerlist_header") { // if the packet contains the player list, we can use it to see our place in the queue
			let headermessage = JSON.parse(data.header);
			let positioninqueue = headermessage.text.split("\n")[5].substring(25);
			let ETA = headermessage.text.split("\n")[6].substring(27);
			webserver.queuePlace = positioninqueue; // update info on the web page
			webserver.ETA = ETA;
			server.motd = `Place in queue: ${positioninqueue}`; // set the MOTD because why not
		}
		if(meta.name=="login"){
			playerId=data.entityId;
		}
		if (finishedQueue === false && meta.name === "chat") { // we can know if we're about to finish the queue by reading the chat message
			// we need to know if we finished the queue otherwise we crash when we're done, because the queue info is no longer in packets the server sends us.
			let chatMessage = JSON.parse(data.message);
			if (chatMessage.text && chatMessage.text === "Connecting to the server...") {
                if (webserver.restartQueue && proxyClient == null) { //if we have no client connected and we should restart
                    stop();
                    setTimeout(startQueuing, 100); // reconnect after 100 ms
                } else {
                    finishedQueue = true;
                    webserver.queuePlace = "FINISHED";
                    webserver.ETA = "NOW";  
                }
			}
		}

		if (proxyClient) { // if we are connected to the proxy, forward the packet we recieved to our game.
			filterPacketAndSend(data, meta, proxyClient);
		}
	});

	// set up actions in case we get disconnected.
	client.on('end', () => {
		if (proxyClient) {
            proxyClient.end("Connection reset by 2b2t server.\nReconnecting...");
            proxyClient = null;
		}
		stop();
		// setTimeout(startQueuing, 100); // reconnect after 100 ms
	});
	
	client.on('error', (err) => {
		if (proxyClient) {
            proxyClient.end(`Connection error by 2b2t server.\n Error message: ${err}\nReconnecting...`);
            proxyClient = null;
		}
		console.log('err', err);
		stop();
		// setTimeout(startQueuing, 100); // reconnect after 100 ms
	});

	server = mc.createServer({ // create a server for us to connect to
		'online-mode': true, // false
		encryption: true,
		host: '0.0.0.0',
		port: config.ports.minecraft,
		version: config.MCversion,
		'max-players': maxPlayers = 1
	});

	server.on('login', (newProxyClient) => { // handle login
		if (newProxyClient.username !== client.username) {
			stop();
		}
		newProxyClient.write('login', {
			entityId: playerId,
			levelType: 'default',
			gameMode: 0,
			dimension: 0,
			difficulty: 2,
			maxPlayers: server.maxPlayers,
			reducedDebugInfo: false
		});
		newProxyClient.write('position', {
			x: 0,
			y: 1.62,
			z: 0,
			yaw: 0,
			pitch: 0,
			flags: 0x00
		});

		newProxyClient.on('packet', (data, meta) => { // redirect everything we do to 2b2t
			filterPacketAndSend(data, meta, proxyClient);
		});

		proxyClient = newProxyClient;
	});
}

//function to filter out some packets that would make us disconnect otherwise.
//this is where you could filter out packets with sign data to prevent chunk bans.
export function filterPacketAndSend(data, meta, dest) {
	if (meta.name !="keep_alive" && meta.name !="update_time") { //keep alive packets are handled by the client we created, so if we were to forward them, the minecraft client would respond too and the server would kick us for responding twice.
		dest.write(meta.name, data);
	}
}