diff --git a/README.md b/README.md index b45fcb5..a833d3e 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ iosはplay.js, androidはtermuxというアプリがおすすめです。
discordのbotが必要なので用意してください。 ### コピペしてみよう -上の方にサーバーのポート,discordbotのtoken,メッセージを送信するチャンネルのIDを入力してください。
+config.jsonにサーバーのポート,discordbotのtoken,メッセージを送信するチャンネルのIDを入力してください。
必要なモジュールも入れておいてください ### 動かす diff --git a/config.json b/config.json new file mode 100644 index 0000000..6235333 --- /dev/null +++ b/config.json @@ -0,0 +1,5 @@ +{ + "PORT": 19132, + "TOKEN": "", + "CHANNEL": "" +} diff --git a/index.js b/index.js index 1f87ac8..0b54694 100644 --- a/index.js +++ b/index.js @@ -5,87 +5,130 @@ const discord = require("discord.js"); const client = new discord.Client(); const ip = require("ip"); let connection = null; +const formation = new Map(); -//Websocketサーバーのポート番号 -const port = 8000; -//discordのBOTのトークン(流出注意) -const token = 'BOTのトークン'; -//メッセージを送信したいチャンネルのID -const channelId = 'チャンネルのID'; +// config.jsonから設定を読み込む +const { PORT, TOKEN, CHANNEL } = require('./config.json'); -//discordにログイン -client.login(token); +// discordにログイン +client.login(TOKEN); client.on('ready', () => { console.log(`${client.user.tag} でログインしています。`); - client.channels.cache.get(channelId).send('[log] 起動しました'); + sendD('[log] 起動しました'); }) // マイクラ側からの接続時に呼び出される関数 -const wss = new WebSocket.Server({ port: port }); +const wss = new WebSocket.Server({ port: PORT }); wss.on('connection', ws => { connection = ws; - console.log('[log] 接続を開始しました'); - client.channels.cache.get(channelId).send('[log] 接続を開始しました'); + sendCmd('getlocalplayername').then(data => { + console.log(getTime(), `[log] ${data.localplayername} : 接続を開始しました`); + sendD(`[log] ${data.localplayername} : 接続を開始しました`); + }); - // ユーザー発言時のイベントをsubscribe + // イベントを登録 ws.send(event('PlayerMessage')); ws.send(event('commandResponse')); - getPlayers(callback => { - let {players} = callback; - fs.writeFileSync('players.json', JSON.stringify(players, null, 2)); + // 接続時に現在のプレイヤーを取得しておく + getPlayers(data => { + fs.writeFileSync('players.json', JSON.stringify(data.players, null, 2)); }); - + + // 参加・退出通知 setInterval(player, 2000); // 各種イベント発生時に呼ばれる関数 ws.on('message', packet => { const res = JSON.parse(packet); + + if (res.header.messagePurpose == 'commandResponse') { + if (res.body.recipient == undefined) { + formation.set(res.header.requestId, res.body) + } + } + if (res.body.eventName == 'PlayerMessage') { if (res.body.properties.MessageType == 'chat' && res.body.properties.Sender != '外部') { let Message = res.body.properties.Message; let Sender = res.body.properties.Sender; + let chatMessage = `[${getTime()}] ${Sender.replace(/§./g, '')} : ${Message.replace(/§./g, '')}`; console.log(chatMessage); //minecraft->discord //@everyone,@hereが含まれていたら送信をブロック if (res.body.properties.Message.search(/(@everyone|@here)/) === -1) { - client.channels.cache.get(channelId).send(chatMessage); + sendD(chatMessage); } else { sendMsg(`§4禁止語句が含まれているため送信をブロックしました。`, Sender); } } } }); + + // 接続の切断時に呼び出される関数 + ws.on('close', () => { + console.log(getTime(), `[log] 接続が終了しました`); + sendD(`[log] 接続が終了しました`); + connection = null; + }); + }); -console.log(`Minecraft: /connect ${ip.address()}:${port}`); +console.log(`Minecraft: /connect ${ip.address()}:${PORT}`); -//discord->minecraft +// discord->minecraft client.on('message', message => { // メッセージが送信されたとき if (message.author.bot) return; - if (message.channel.id != channelId) return; - let logMessage = `[discord-${getTime()}] ${message.member.displayName} : ${message.content}`; - console.log(logMessage); - if (connection == null) return; - sendMsg(`§b${logMessage}`); + if (message.channel.id != CHANNEL) return; + + // command or message + if (message.content.startsWith('.')) { + let command = message.content.replace(/^./, ''); + + // .list でワールド内のプレイヤー一覧を表示 + if (command == 'list') { + getPlayers(data => { + let {current,max,players} = data; + sendD({ + embed: { + color: '#4287f5', + description: `現在の人数: ${current}/${max}\nプレイヤー:\n${players.sort().join(',')}`, + footer: { + text: `最終更新: ${getTime()}` + } + } + }); + }); + return; + } + + sendD('そのコマンドは存在しません'); + } else { + let logMessage = `[discord-${getTime()}] ${message.member.displayName} : ${message.content}`; + console.log(logMessage); + sendMsg(`§b${logMessage}`); + } + }); //時間取得用 -function getTime() { +function getTime(mode) { let date = new Date(); - let hour = date.getHours(); - let minute = date.getMinutes(); - let second = date.getSeconds(); - hour = ('0' + hour).slice(-2); - minute = ('0' + minute).slice(-2); - second = ('0' + second).slice(-2); - let time = hour + ':' + minute + ':' + second; - return time; + let month = date.getMonth()+1; + let day = date.getDate(); + let hour = ('0' + (date.getHours())).slice(-2); + let minute = ('0' + date.getMinutes()).slice(-2); + let second = ('0' + date.getSeconds()).slice(-2); + if (mode == 'date') { + return `${month}/${day} ${hour}:${minute}:${second}`; + } else { + return `${hour}:${minute}:${second}`; + } } //ユーザー発言時のイベント登録用JSON文字列を生成する関数 @@ -122,8 +165,9 @@ function command(x) { }); } -//レスポンス付きでコマンド実行 -function sendCmd(command, callback) { +//コマンド実行結果を返す +async function sendCmd(command) { + if (!connection) return; let json = { header: { requestId: uuidv4(), @@ -140,38 +184,64 @@ function sendCmd(command, callback) { } }; connection.send(JSON.stringify(json)); - if (callback == undefined) return; - connection.on('message', packet => { - let res = JSON.parse(packet); - if (res.header.requestId == json.header.requestId) { - callback(res.body); - } - }); + return await getResponse(json.header.requestId); } -//tellrawを送信 +function getResponse(id) { + return new Promise( (res, rej) =>{ + let interval = setInterval(() => { + if (!connection) { + clearInterval(interval); + return rej(); + } + let response = formation.get(id); + if (response != undefined) { + formation.delete(id); + clearInterval(interval); + res(response); + } + }, 400); + }); +} + +// tellrawメッセージを送信 function sendMsg(msg, target) { - if (target == undefined) target = '@a'; - let txt = `tellraw ${target} {"rawtext":[{"text":"${msg}"}]}`; + if (!connection) return; + target = (target === undefined) ? '@a' : `"${target}"`; + let rawtext = JSON.stringify({ + rawtext: [{ text: String(msg) }] + }); + let txt = `tellraw ${target} ${rawtext}`; connection.send(command(txt)); } -//ワールド内のプレイヤーを取得 +function sendD(msg, channel = CHANNEL) { + return client.channels.cache.get(channel).send(msg); +} + +// ワールド内のプレイヤーを取得 function getPlayers(fn) { - sendCmd('list', callback => { - let info = { - current: callback.statusCode < 0 ? 0 : callback.currentPlayerCount, - max: callback.statusCode < 0 ? 0 : callback.maxPlayerCount, - players: callback.statusCode < 0 ? [] : callback.players.split(', ') - } - fn(info); + if (!connection) { + fn({ + current: 0, + max: 0, + players: [] + }) + return; + } + sendCmd('list').then(data => { + fn({ + current: data.statusCode < 0 ? 0 : data.currentPlayerCount, + max: data.statusCode < 0 ? 0 : data.maxPlayerCount, + players: data.statusCode < 0 ? [] : data.players.split(', ') + }) }); } -//参加・退出通知 +// 参加・退出通知 function player() { - getPlayers(callback => { - let {current,max,players} = callback; + getPlayers(data => { + let {current,max,players} = data; let playersBefore = JSON.parse(fs.readFileSync('players.json')); fs.writeFileSync('players.json', JSON.stringify(players, null, 2)); @@ -179,7 +249,7 @@ function player() { let joined = players.filter(i => playersBefore.indexOf(i) == -1); let msg = `Joined: ${joined} || ${current}/${max}`; console.log(msg); - client.channels.cache.get(channelId).send({ + sendD({ embed: { color: '#48f542', description: `**${msg}**` @@ -190,7 +260,7 @@ function player() { let left = playersBefore.filter(i => players.indexOf(i) == -1); let msg = `Left: ${left} || ${current}/${max}`; console.log(msg); - client.channels.cache.get(channelId).send({ + sendD({ embed: { color: '#f54242', description: `**${msg}**` diff --git a/players.json b/players.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/players.json @@ -0,0 +1 @@ +[]