forked from llbit/minechat
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathminechat.js
executable file
·185 lines (156 loc) · 4.74 KB
/
minechat.js
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#!/usr/bin/env node
var readline = require('readline');
var mineflayer = require('mineflayer');
var ansicolors = require('ansicolors');
var colorizers = {
black: ansicolors.brightBlack,
dark_blue: ansicolors.blue,
dark_green: ansicolors.green,
dark_aqua: ansicolors.cyan,
dark_red: ansicolors.red,
dark_purple: ansicolors.magenta,
gold: ansicolors.yellow,
gray: ansicolors.brightBlack,
dark_gray: ansicolors.brightBlack,
blue: ansicolors.brightBlue,
green: ansicolors.brightGreen,
aqua: ansicolors.brightCyan,
red: ansicolors.brightRed,
light_purple: ansicolors.brightMagenta,
yellow: ansicolors.brightYellow,
white: ansicolors.brightWhite,
reset: ansicolors.white,
};
function print_help() {
console.log("usage: [PASSWORD=<password>] node minechat.js <hostname>[:port] <user>");
}
if (process.argv.length < 4) {
console.log("Too few arguments!");
print_help();
process.exit(1);
}
process.argv.forEach(function(val, index, array) {
if (val == "-h") {
print_help();
process.exit(0);
}
});
var options = {
username: process.argv[3],
password: process.env.PASSWORD,
};
var host = process.argv[2];
if (host.indexOf(':') != -1) {
options.host = host.substring(0, host.indexOf(':'));
options.port = host.substring(host.indexOf(':')+1);
} else {
options.host = host;
}
console.log("connecting to " + host);
console.log("user: " + options.username);
if (options.password) {
console.log("using provided password");
} else {
console.log("no password provided");
}
var bot = mineflayer.createBot(options);
function tabCompleter(linePartial, done) {
bot._client.write('tab_complete', {
text: linePartial,
assumeCommand: false,
});
// Minecraft's suggestions only include the last space-separated word
const completed = linePartial.replace(/.* /, '');
bot._client.once('tab_complete', function(tabResponse) {
done(null, [tabResponse.matches, completed]);
});
}
bot.once('game', function () {
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: process.stdout.isTTY,
completer: tabCompleter
});
rl.on('line', function(line) {
bot.chat(line);
rl.prompt();
});
rl.on('close', function() {
rl.output.write('\nClosing connection...\n');
bot.quit();
});
bot.on('message', function(message) {
readlineOutput(rl, renderMessage(message) + '\n');
});
rl.prompt();
});
function onServerEnd(reason) {
process.stdout.write('\nConnection closed.\n');
if (reason) {
process.stdout.write(reason + '\n');
}
process.exit(0);
}
bot.on('kicked', function(reason) {
onServerEnd(renderMessage(JSON.parse(reason)));
});
bot.on('error', function(err) {
onServerEnd(String(err));
});
// `end` is emitted before `kicked`! We wait a bit, in case a kick is coming right
// after that. If one doesn't, we'll exit anyway.
bot.on('end', function(reason) {
setTimeout(onServerEnd.bind(null, reason), 100);
});
// This function erases the current readline "entry area" from the screen,
// so that it can be overwritten with output. Works even if the current
// "line" spans several terminal rows.
//
// The cursor is left in the leftmost screen column, in the row where the
// prompt previously stood.
//
// This is all done using some code copied from `readline.js`, and accessing
// an undocumented `prevRows` property. In other words, expect breakage if
// `readline.js` changes significantly.
function readlineErase(rl) {
var prevRows = rl.prevRows || 0;
if (prevRows > 0) {
readline.moveCursor(rl.output, 0, -prevRows);
}
// convince readline that it won't need to go upwards before prompting
rl.prevRows = 0;
// move to leftmost column
readline.cursorTo(rl.output, 0);
// clear bottom of screen
readline.clearScreenDown(rl.output);
}
// Outputs one or more rows of text (should end in a newline) to
// readline's output. The readline prompt and current entry are saved
// and restored so that new rows appear to be inserted above the prompt.
function readlineOutput(rl, text) {
readlineErase(rl);
rl.output.write(text);
rl.prompt(/*preserveCursor*/true);
}
// Turns a Minecraft JSON chat message into an ANSI-colored string
function renderMessage(message) {
if (typeof message === 'string') {
return message;
}
if (message.translate) {
console.log(JSON.stringify(message));
// punt to mineflayer's rendering for localizable messages
return message.toAnsi();
}
var colorizer = colorizers[message.color] || function(t) { return t };
var extras = message.extra ? message.extra.map(renderMessage).join('') : '';
var text = message.text + extras;
if (message.clickEvent && message.clickEvent.action === 'open_url'
// work around Spigot's overeager hyperlink insertion
&& message.clickEvent.value !== 'http://' + text
) {
text = '[' + text + '](' + message.clickEvent.value + ')';
}
return colorizer(text);
}