-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathindex.js
208 lines (171 loc) · 6.75 KB
/
index.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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
const Discord = require("discord.js");
var fs = require("fs");
var chokidar = require("chokidar");
var { Rcon } = require("rcon-client");
var config = require("./config.json");
const bot = new Discord.Client({ intents: ['GUILD_MESSAGES', 'GUILDS'], allowedMentions: { users: [], roles: [] } });
bot.login(config.token);
var rcon;
var tries = 1;
function RconConnect() {
rcon = new Rcon({ host: config.RconIP, port: config.RconPort, password: config.RconPassword });
rcon.connect().catch(error => {
console.error(error);
// try again with a max of 10 tries in a cooldown of 5 seconds per try
if (tries <= 10) {
console.log(`Reconnect attempt ${tries}/10..`)
setTimeout(function () {
RconConnect();
tries++;
}, 5000)
}
});
// Connected, which means the connection is successful
rcon.on("connect", () => {
console.log(`Connected to the factorio server!`)
});
// Authenticated, which means the authentication is successful and the system is online
rcon.on("authenticated", () => {
console.log(`Authenticated!`)
clearLogFile();
if (config.startupMessage.enabled) {
if (config.cleanMessages == true) {
rcon.send('/silent-command game.print("[Chat System]: ' + config.startupMessage.message + '")');
} else {
rcon.send('[Chat System]: ' + config.startupMessage.message);
}
}
});
// In case any errors occour, log them to console and terminate the connection
rcon.on("error", (err) => {
console.error(`Error: ${err}`);
rcon.end();
});
// In case the connection was ended, terminated or whatever else happened. Log a message and reconnect
rcon.on("end", () => {
console.log(`Socket connection ended! Reconnecting..`)
RconConnect();
});
};
/*
* Bot start event
*/
bot.on("ready", () => {
//connect to rcon
RconConnect();
console.log('Connected to Discord! Logged in as: ' + bot.user.username + ' - (' + bot.user.id + ')');
bot.channels.cache.get(config.chatChannel).send("[Chat System]: Online!")
//watch the log file for updates
chokidar.watch(config.logFile, { ignored: /(^|[\/\\])\../ }).on('all', (event, path) => {
readLastLine(config.logFile);
});
});
/*
* Discord message event
*/
bot.on("messageCreate", async (message) => {
if (!message.content.length > 0) return;
if (message.author.bot) return;
if (message.channel.id === config.chatChannel) {
// send to the server
if (config.cleanMessages == true) {
rcon.send('/silent-command game.print("[color=#7289DA][Discord] ' + message.author.username + ': ' + message.content + '[/color]")');
} else {
rcon.send('[color=#7289DA][Discord] ' + message.author.username + ': ' + message.content + '[/color]');
}
// send to the channel showing someone sent a message to the server and delete their message from the channel
message.channel.send(":speech_balloon: | `" + message.author.username + "`: " + message.content);
message.delete();
} else if (message.channel.id === config.consoleChannel) {
// send command to the server
rcon.send('/' + message.content);
// send to the channel showing someone sent a command to the server
message.channel.send("COMMAND RAN | `" + message.author.username + "`: " + message.content);
} else if (message.content.startsWith(`${config.prefix}online`)) {
// Command with the prefix defined in config.js to show online players
const players = await getOnlinePlayers();
// Send the message to the Discord channel
message.channel.send(`There are currently ${players.length} player(s) online${players.length > 0 ? ` with the name(s):\n- \`${players.join("`\n- `")}\`` : "."}`)
}
});
// Get online players
async function getOnlinePlayers() {
// Run the command "/players online"
var res = await rconCommand("/p o");
// Turn result into an array, remove the first and last array element
res = res.split("\n").slice(1, -1);
// create a new array
var onlinePlayers = [];
res.forEach(player => {
// remove white spaces at the start and remove (online) from the end
player = player.trim().split(" (online)")[0];
// push result to a new array
onlinePlayers.push(player);
})
return onlinePlayers;
}
/*
* Chat function to parse the messages
*/
function parseMessage(msg) {
var index = msg.indexOf(']');
var indexName = msg.indexOf(': ');
var newMsg = "`" + msg.slice(index + 2, indexName) + "`" + msg.slice(indexName);
if (msg.length && index > 1) {
if (msg.slice(1, index).includes("LEAVE")) {
// Send leave message to the Discord channel
bot.channels.cache.get(config.chatChannel).send(":red_circle: | " + msg.slice(index + 2))
// Send leave message to the server
if (config.cleanMessages == true) rcon.send('/silent-command game.print("[color=red]' + msg.slice(index + 2) + '[/color]")');
else rcon.send('[color=red]' + msg.slice(index + 2) + '[/color]');
} else if (msg.slice(1, index).includes("JOIN")) {
// Send join message to the Discord channel
bot.channels.cache.get(config.chatChannel).send(":green_circle: | " + msg.slice(index + 2))
// Send join message to the server
if (config.cleanMessages == true) rcon.send('/silent-command game.print("[color=green]' + msg.slice(index + 2) + '[/color]")');
else rcon.send('[color=green]' + msg.slice(index + 2) + '[/color]');
} else if (msg.slice(1, index).includes("CHAT") && !msg.includes("<server>")) {
// Send incoming chat from the server to the Discord channel
bot.channels.cache.get(config.chatChannel).send(":speech_left: | " + newMsg)
} else if (!msg.includes("<server>") && config.consoleChannel !== false) {
// Send incoming message from the server, which has no category or user to the Discord console channel
bot.channels.cache.get(config.consoleChannel).send("? | " + msg.slice(index + 1))
}
}
}
/*
* Logging function
*/
function readLastLine(path) {
fs.readFile(path, 'utf-8', function (err, data) {
//get last line of file.
if (err) throw err;
var lines = data.trim().split('\n');
lastLine = lines.slice(-1)[0];
// I should really optimize or completely remove this line
if (config.logLines == true) console.log(lastLine);
if (path == config.logFile && lastLine.length > 0) {
// Parse name and message and send it
parseMessage(lastLine);
}
});
}
// Clear the logFile to prevent massive disk usage
function clearLogFile() {
fs.writeFile(config.logFile, "", function () {
console.log("Cleared previous chat log");
});
}
/* rconCommand function
* Returns an array of 2, first being the command response, second being the error (if there is one, otherwise it's empty)
*/
async function rconCommand(command) {
if (!command.startsWith("/")) command = `/${command}`;
try {
let resp = await rcon.send(command);
if (typeof resp == "string" && resp.length) return resp;
else throw new Error("No length");
} catch (error) {
throw Error(`RCON Error --- Details --- \nNAME: ${error.name} \nDESC: ${error.description}`);
}
}