209 lines
9.6 KiB
JavaScript
Executable File
209 lines
9.6 KiB
JavaScript
Executable File
"use strict";
|
|
|
|
const Discord = require("discord.js");
|
|
const WebSocket = require("ws");
|
|
|
|
const config = require("./config");
|
|
|
|
var discordBot = new Discord.Client({disableEveryone:true});
|
|
discordBot.login(config.discord_token);
|
|
var banlist;
|
|
|
|
var bridges = {}; // owop websockets to discord channels
|
|
discordBot.once("ready", function(){
|
|
for (let owopWorld in config.bridges) {
|
|
let {discordChannels, password} = config.bridges[owopWorld];
|
|
var b = createOWOPbridge(owopWorld, discordChannels, password);
|
|
if (b) bridges[b.owopSocket] = b.discordChannels;
|
|
}
|
|
banlist = require("./banlist")(discordBot);
|
|
});
|
|
|
|
|
|
function createOWOPbridge(owopWorld, configDiscordChannels, password) {
|
|
var discordChannels = configDiscordChannels.map(configDiscordChannel => {
|
|
var c = discordBot.channels.get(configDiscordChannel.id);
|
|
if (!c) return console.error(`Could not find discord channel ${configDiscordChannel.id} to bridge to owop world "${owopWorld}"`);
|
|
// attach webhook to channel object for webhook inter-discord-channel broadcast method
|
|
if (configDiscordChannel.webhook) c.webhook = new Discord.WebhookClient(configDiscordChannel.webhook.id, configDiscordChannel.webhook.token, {disableEveryone: true});
|
|
return c;
|
|
}).filter(x => x);
|
|
if (!configDiscordChannels.length) return console.error("Could not find any of the discord channels:", configDiscordChannels.map(x => x.id));
|
|
var botId = 0, owopSocket;
|
|
(function connect() {
|
|
owopSocket = new WebSocket("wss://ourworldofpixels.com", {
|
|
origin: "https://ourworldofpixels.com/"
|
|
});
|
|
owopSocket.on("open", function () {
|
|
console.log("owop", owopWorld, "open");
|
|
});
|
|
owopSocket.on("message", function (data) {
|
|
if (typeof data == "string") {
|
|
// owop to discord
|
|
console.log(`[${owopWorld}]`, data);
|
|
if (data.startsWith(botId) || data.startsWith(`[${botId}]`)) return; // ignore self if regular user
|
|
if (data.startsWith("[D]")) return; // ignore self if special discord user
|
|
if (data.startsWith("DEV")) return;
|
|
if (data.startsWith("Nickname")) return; // ignore nickname change messages
|
|
if (data.startsWith("User: ")) return;
|
|
if (data.startsWith("<")) return; // ignore HTML greeting
|
|
if (data == "Server: You are now a moderator. Do /help for a list of commands.") return; // ignore that
|
|
if (data.startsWith("[Server]")) return; // ignore [Server] messages
|
|
if (data.startsWith("->")) return; // ignore direct messages because spam
|
|
if (data == "Welcome to /flags<br>https://discord.io/owopflagworld") return;
|
|
let msg = data;
|
|
msg = msg.replace(/<@/g, "<\\@"); // escape mentions
|
|
msg = msg.replace(/(\*|_|\||~|`|\\)/g, '\\$1'); // escape formatting chars
|
|
//if (msg.startsWith("(A)")) msg = msg.replace("(A)", "**(A)**");
|
|
//if (msg.startsWith("(M)")) msg = msg.replace("(M)", "**(M)**");
|
|
//{ let x = msg.split(':'); x[0] = `**${x[0]}**`; msg = x.join(':'); } // bold prefix to distinguish from newline fakes
|
|
if (msg.includes(':')) msg = '**' + msg.replace(':', ':**'); // simpler version of above, to include the colon in bold
|
|
if (owopWorld == "main") msg = require('./antiswear')(msg);
|
|
for (let discordChannel of discordChannels) {
|
|
if (discordChannel.guild.id != "350296414720491530" && data == "You are banned. Appeal on the OWOP discord server, (https://discord.io/owop)") return;
|
|
let lastMessage = discordChannel.messages.last();
|
|
if (lastMessage && lastMessage.originalMsg && lastMessage.originalMsg == msg && lastMessage.author.id == discordBot.user.id) {
|
|
// if this owop message is same as source of last message and last message was sent by this bot
|
|
// edit last message with incremented number of repetitions
|
|
let postfix = ` [x${++lastMessage.repetitions}]`;
|
|
lastMessage.edit(msg.substr(0, 2000-postfix.length) + postfix).catch(error => console.error(`Could not edit message ${lastMessage.id}`, error.message));
|
|
lastMessage.realmsg = msg; // attach actual message to Message object because now the message content has been edited
|
|
} else {
|
|
// send new message
|
|
discordChannel.send(msg, { split: { char: '' } }).then(message => {
|
|
message.originalMsg = msg; // attach original owop message to Message object so we can edit for repetitions
|
|
message.repetitions = 1; // keep track of number of repetitions
|
|
}).catch(error => console.error(`Failed to send OWOP message to discordChannel ${[discordChannel.id, '#'+discordChannel.name, discordChannel.guild.name]}:`, error.message));
|
|
}
|
|
}
|
|
} else {
|
|
switch (data.readUInt8(0)) {
|
|
case 0: // Get id
|
|
botId = data.readUInt32LE(1);
|
|
console.log("owop", owopWorld, "ready");
|
|
if (password) owopSocket.send("/pass " + password + String.fromCharCode(10));
|
|
sendMove();
|
|
break;
|
|
case 5: // Captcha
|
|
switch (data.readUInt8(1)) {
|
|
case 0:
|
|
owopSocket.send("CaptchALETMEINPLZ" + config.captcha_password);
|
|
break;
|
|
case 3:
|
|
joinWorld(owopWorld);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
owopSocket.on("close", function () {
|
|
console.log("owop", owopWorld, "close");
|
|
setTimeout(()=>{
|
|
connect();
|
|
}, 5000);
|
|
});
|
|
owopSocket.on("error", function (error) {
|
|
console.error("owop", owopWorld, "error:", error);
|
|
});
|
|
})();
|
|
|
|
function sendMove() {
|
|
if (owopSocket.readyState == WebSocket.OPEN) owopSocket.send(new Buffer([127, 255, 255, 255, 127, 255, 255, 255, 0, 0, 0, 0]));
|
|
}
|
|
setInterval(sendMove, 600000);
|
|
function joinWorld(name) {
|
|
var nstr = stoi(name, 24/*OldProtocol.maxWorldNameLength*/);
|
|
//_global.eventSys.emit(_conf.EVENTS.net.world.joining, name);
|
|
var array = new ArrayBuffer(nstr[0].length + 2);
|
|
var dv = new DataView(array);
|
|
for (var i = nstr[0].length; i--;) {
|
|
dv.setUint8(i, nstr[0][i]);
|
|
}
|
|
dv.setUint16(nstr[0].length, 25565/*OldProtocol.misc.worldVerification*/, true);
|
|
if (owopSocket.readyState == WebSocket.OPEN) owopSocket.send(array);
|
|
return nstr[1];
|
|
}
|
|
function stoi(string, max) {
|
|
var ints = [];
|
|
var fstring = "";
|
|
string = string.toLowerCase();
|
|
for (var i = 0; i < string.length && i < max; i++) {
|
|
var charCode = string.charCodeAt(i);
|
|
if (charCode < 123 && charCode > 96 || charCode < 58 && charCode > 47 || charCode == 95 || charCode == 46) {
|
|
fstring += String.fromCharCode(charCode);
|
|
ints.push(charCode);
|
|
}
|
|
}
|
|
return [ints, fstring];
|
|
}
|
|
|
|
discordBot.on("message", function (message) {
|
|
if (!configDiscordChannels.map(x => x.id).includes(message.channel.id)) return; // only listen to the bridged channels
|
|
if (message.author.id == discordBot.user.id) return; // ignore self of course
|
|
if (discordChannels.filter(x => x.webhook).map(x => x.webhook.id).includes(message.author.id)) return; // ignore any of our webhooks
|
|
|
|
if (banlist().includes(message.author.id)) return message.react("🚫"); // block users banned from owop discord //TODO only main world
|
|
|
|
// broadcast message to other discord channels bridged to the same owop world
|
|
discordChannels.forEach(discordChannel => {
|
|
if (discordChannel.id == message.channel.id) return;
|
|
if (discordChannel.webhook) {
|
|
// send using webhook if available, to save visual space
|
|
let username = message.member && message.member.displayName || message.author.username;
|
|
if (message.guild) username += ' @ ' + message.guild.name;
|
|
if (username.length > 32) username = username.substring(0, 31) + '…';
|
|
discordChannel.webhook.send(message.cleanContent, {
|
|
username,
|
|
avatarURL: message.author.avatarURL,
|
|
embeds: message.embeds,
|
|
files: message.attachments.map(x => new Discord.Attachment(x.url, x.filename))
|
|
}).catch(error => {
|
|
console.error(`Failed to send Discord broadcast via webhook to discordChannel ${[discordChannel.id, '#'+discordChannel.name, discordChannel.guild.name]}:`, error.message);
|
|
// fallback to embed if webhook fails
|
|
regularBroadcast();
|
|
});
|
|
} else regularBroadcast();
|
|
// send as embed
|
|
function regularBroadcast() {
|
|
discordChannel.send(
|
|
new Discord.RichEmbed()
|
|
.setAuthor(message.member && message.member.displayName || message.author.username, message.author.avatarURL)
|
|
.setColor(message.member && message.member.displayColor)
|
|
.setDescription(message.content)
|
|
.setFooter(`from ${message.guild.name}`, message.guild.iconURL)
|
|
.setImage(message.attachments.first() && message.attachments.first().width && message.attachments.first().url)
|
|
).catch(error => console.error(`Failed to send Discord broadcast embed to discordChannel ${[discordChannel.id, '#'+discordChannel.name, discordChannel.guild.name]}:`, error.message));
|
|
}
|
|
});
|
|
|
|
// discord to owop
|
|
if (owopSocket.readyState != WebSocket.OPEN) return;
|
|
let authorname = (message.member && message.member.displayName) || message.author.username;
|
|
let nickname, prefix = "";
|
|
if (password) {
|
|
if (owopWorld == "main") {
|
|
nickname = authorname;
|
|
} else {
|
|
nickname = `[D] ${authorname}`;
|
|
}
|
|
if (owopWorld != "main") if (nickname.length > 16) nickname = nickname.substr(0,15) + '…';
|
|
} else {
|
|
prefix = `[D] ${authorname}: `;
|
|
}
|
|
if (nickname) owopSocket.send("/nick " + nickname + String.fromCharCode(10));
|
|
let msg = prefix + message.cleanContent;
|
|
if (msg.startsWith('/')) msg = ' ' + msg;
|
|
if (message.attachments.size > 0) msg += ' ' + message.attachments.map(a => a.url).join(' ');
|
|
if (msg.length > 128) msg = msg.substr(0,127) + '…';
|
|
owopSocket.send(msg + String.fromCharCode(10));
|
|
});
|
|
|
|
console.log("bridged owop world", owopWorld, "to discord channels", discordChannels.map(d => [d.id, d.name, d.guild.name]));
|
|
return {owopSocket, discordChannels}
|
|
}
|
|
|
|
|
|
if (config.enable_commands) require("./commands")(discordBot);
|
|
if (config.reddit) require("./pixelart2reddit&facebook")(discordBot);
|