diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 3eeca27..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/README.md b/README.md index 12ad72f..e49c919 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,2 @@ -# Grow A Tree Analyzer -This bot works with Grow A Tree Bot by Limbo Labs. This project is not affiliated with Limbo Labs in any way. - -This bot allows easy comparison between a server's tree and other trees displayed on the leaderboard. - -## Usage -Add the bot to your server and make sure it has the proper permissions (`Send Messages` and `Send Messages in Threads` if applicable), then run `/setup` in the channel(s) that contain your server's tree and leaderboard messages. - -## Commands - -* `/setup` - Attempts automatic detection of your server's tree and leaderboard messages. -* `/setupinfo` - Displays your server's current configuration. -* `/reset` - Resets your server's configuration, run `/setup` again if needed. - - -## Database Structure - -### Table: guildinfo -``` -+-----------------+-------------+------+-----+---------+----------------+ -| Field | Type | Null | Key | Default | Extra | -+-----------------+-------------+------+-----+---------+----------------+ -| id | int(10) | NO | PRI | NULL | auto_increment | -| guild_id | varchar(50) | NO | | NULL | | -| tree_message_id | varchar(50) | NO | | NULL | | -| tree_channel_id | varchar(50) | NO | | NULL | | -| rank_message_id | varchar(50) | NO | | NULL | | -| rank_channel_id | varchar(50) | NO | | NULL | | -| tree_height | varchar(10) | NO | | NULL | | -+-----------------+-------------+------+-----+---------+----------------+ -``` -### Table: treeinfo -``` -+-----------+--------------+------+-----+---------+----------------+ -| Field | Type | Null | Key | Default | Extra | -+-----------+--------------+------+-----+---------+----------------+ -| id | int(10) | NO | PRI | NULL | auto_increment | -| treename | varchar(100) | NO | | NULL | | -| treerank | int(10) | NO | | NULL | | -| timestamp | varchar(50) | NO | | NULL | | -+-----------+--------------+------+-----+---------+----------------+ -``` - -## Changes to Implement - -* Move around some of the functions. -* Migrate storage to SQLite. \ No newline at end of file +# Discord Bot Template +This is a very basic Discord.js v14 bot template. This is meant to be an easy jumping-off point for quick bot creation without having to set up the basics every time. \ No newline at end of file diff --git a/data/config.json b/data/config.json index 479d43f..05eb669 100644 --- a/data/config.json +++ b/data/config.json @@ -1,9 +1,4 @@ { - "guildId": "868542949737246730", - "messageId": "", - "treeMessageId": "", - "treeHeight": 0, - "validCommands": [], - "rankMessageId": "", - "rankings": [] + "guildId": "", + "validCommands": [] } \ No newline at end of file diff --git a/data/guildInfo.json b/data/guildInfo.json deleted file mode 100644 index e26f355..0000000 --- a/data/guildInfo.json +++ /dev/null @@ -1 +0,0 @@ -{"269250657809072139":{"treeMessageId":"1042987280954032158","treeChannelId":"1042987243670872154","rankMessageId":"1065390277767987210","rankChannelId":"1042987923928256553","rankings":[{"rank":"111","name":"Taboo Tree","height":"3030.0"},{"rank":"112","name":"booster tree","height":"3029.0"},{"rank":"113","name":"Pod Birch","height":"3017.0"},{"rank":"114","name":"Wise Mystical Tree","height":"3013.0"},{"rank":"115","name":"Shimmer Doge DAO Tree","height":"2978.9"},{"rank":"116","name":"Simon","height":"2969.1"},{"rank":"117","name":"Cloud Tree","height":"2959.6"},{"rank":"118","name":"The Monke Tree","height":"2947.3"},{"rank":"119","name":"Woody","height":"2925.6"},{"rank":"120","name":"Azure Woodku","height":"2908.0"}],"treeHeight":"179.1"},"803049831839956992":{"treeMessageId":"1052343193980645376","treeChannelId":"1022324601864331335","rankMessageId":"1065121016604524544","rankChannelId":"1022324665374474341","rankings":[{"rank":"1 ","name":"WLR's Ultimate Sudowoodo","height":14203.5},{"rank":"2 ","name":"Our Bonfire Tree","height":13572.9},{"rank":"3 ","name":"The Gremlin Tree","height":12968},{"rank":"4 ","name":"World Tree","height":10600.6},{"rank":"5 ","name":"Emory's Baby","height":10163.9},{"rank":"6 ","name":"Charles the Tree","height":9920},{"rank":"7 ","name":"SMMO-Babel","height":9397},{"rank":"8 ","name":"Spaghetti","height":9341},{"rank":"9 ","name":"the fortnite tree","height":8883},{"rank":"10","name":"TreeVana","height":8002.6}],"treeHeight":261},"1006579138909458513":{"treeMessageId":"1065399196682821713","treeChannelId":"1065398553528250369","rankMessageId":"1065399316979662928","rankChannelId":"1065398553528250369","rankings":[{"rank":"1 ","name":"WLR's Ultimate Sudowoodo","height":"14232.9"},{"rank":"2 ","name":"Our Bonfire Tree","height":"13612.1"},{"rank":"3 ","name":"The Gremlin Tree","height":"12994.8"},{"rank":"4 ","name":"World Tree","height":"10623.0"},{"rank":"5 ","name":"Emory's Baby","height":"10187.8"},{"rank":"6 ","name":"Charles the Tree","height":"9951.0"},{"rank":"7 ","name":"SMMO-Babel","height":"9438.0"},{"rank":"8 ","name":"Spaghetti","height":"9365.0"},{"rank":"9 ","name":"the fortnite tree","height":"8895.0"},{"rank":"10","name":"TreeVana","height":"8019.2"}],"treeHeight":"7941.9"},"760701839427108874":{"treeMessageId":"1065405516400042114","treeChannelId":"1050272057839067178","rankMessageId":"1051889574365904907","rankChannelId":"1050272057839067178","rankings":[{"rank":"251","name":"Bom","height":"1621.0"},{"rank":"252","name":"Tree Of Happiness","height":"1621.0"},{"rank":"253","name":"Treehouse","height":"1604.0"},{"rank":"254","name":"Viktoria II","height":"1595.0"},{"rank":"255","name":"tree of virginity","height":"1588.0"},{"rank":"256","name":"nick's pride","height":"1588.0"},{"rank":"257","name":"Vitraya Ramunong","height":"1583.0"},{"rank":"258","name":"oven tree","height":"1538.7"},{"rank":"259","name":"Tr3e","height":"1527.1"},{"rank":"260","name":"Dicecraft","height":"1523.0"}],"treeHeight":"1527.1"},"868542949737246730":{"treeMessageId":"1065417587502092328","treeChannelId":"1065417555445043300","rankMessageId":"1065417630581801100","rankChannelId":"1065417587502092328","rankings":[{"rank":"1 ","name":"WLR's Ultimate Sudowoodo","height":"14233.4"},{"rank":"2 ","name":"Our Bonfire Tree","height":"13612.7"},{"rank":"3 ","name":"The Gremlin Tree","height":"12995.3"},{"rank":"4 ","name":"World Tree","height":"10623.8"},{"rank":"5 ","name":"Emory's Baby","height":"10188.1"},{"rank":"6 ","name":"Charles the Tree","height":"9951.0"},{"rank":"7 ","name":"SMMO-Babel","height":"9438.4"},{"rank":"8 ","name":"Spaghetti","height":"9365.5"},{"rank":"9 ","name":"the fortnite tree","height":"8895.0"},{"rank":"10","name":"TreeVana","height":"8020.0"}],"treeHeight":"1.0"}} \ No newline at end of file diff --git a/data/strings.json b/data/strings.json index fd8f889..6f3f0e9 100644 --- a/data/strings.json +++ b/data/strings.json @@ -1,22 +1,21 @@ { "help": { - "info": "This bot will analyze your tree (from the Grow A Tree Bot by Limbo Labs) and compare its growth to other trees displayed on the leaderboard.\n\nThis bot assumes that there is a single message and a single message that everyone uses. If everyone creates their own and , the reference messages will have to be updated every time, or old data will be displayed.", - "setup": "To begin analyzing your Tree, first you must set up the reference messages.\n\n1. Run in the channel(s) that contain your server's tree and leaderboard messages.\n2. Now simply run where you want your analysis to be visible.", - "permissions": "At a minimum, Grow A Tree Analyzer requires permissions to `Send Messages` and `Send Messages in Threads` if applicable. If Analyzer is given permission to `Manage Messages`, the bot will delete the `.settree` and `.setranks` messages to reduce spam." + "info": "", + "setup": "", + "permissions": "" }, "embeds": { - "footer": "Grow A Tree Analyzer is not affiliated with Grow A Tree or Limbo Labs", + "footer": "", "color": "0x55FF55" }, "emoji": { - "joint": "<:joint:862082955902976000>", "next": "⏭️", "previous": "⏮️", "confirm": "☑️", "cancel": "❌" }, "urls": { - "avatar": "https://cdn.discordapp.com/avatars/513184762073055252/12227aa23a06d5178853e59b72c7487b.webp?size=128" + "avatar": "" }, "temp": {} } \ No newline at end of file diff --git a/main.js b/main.js index f1ab4d0..dc55716 100644 --- a/main.js +++ b/main.js @@ -30,23 +30,20 @@ client.once('ready', () => { fn.collections.slashCommands(client); console.log('Ready!'); client.channels.fetch(statusChannelId).then(channel => { - channel.send(`${new Date().toISOString()} -- \nStartup Sequence Complete`); + channel.send(`${new Date().toISOString()} -- Ready`); }); }); // slash-commands client.on('interactionCreate', async interaction => { if (interaction.isCommand()) { - // if (isDev) { - // console.log(interaction); - // } const { commandName } = interaction; if (client.slashCommands.has(commandName)) { client.slashCommands.get(commandName).execute(interaction); } else { interaction.reply('Sorry, I don\'t have access to that command.'); - console.error('Slash command attempted to run but not found: ' + commandName); + console.error('Slash command attempted to run but not found: /' + commandName); } } diff --git a/modules/functions.js b/modules/functions.js index 8761aaa..f3edb7f 100644 --- a/modules/functions.js +++ b/modules/functions.js @@ -47,16 +47,6 @@ const functions = { ); return refreshActionRow; }, - comparisonEmbed(content, refreshActionRow) { - // Create the embed using the content passed to this function - const embed = new EmbedBuilder() - .setColor(strings.embeds.color) - .setTitle('Tree Growth Comparison') - .setDescription(content) - .setFooter({text: strings.embeds.footer}); - const messageContents = { embeds: [embed], components: [refreshActionRow] }; - return messageContents; - }, helpEmbed(content, private) { const embed = new EmbedBuilder() .setColor(strings.embeds.color) @@ -86,115 +76,6 @@ const functions = { return messageContents; } }, - rankings: { - parse(interaction) { - return new Promise ((resolve, reject) => { - if (guildInfo[interaction.guildId] == undefined) { - reject("The guild entry hasn't been created yet."); - return; - } - if (guildInfo[interaction.guildId].rankMessageId != undefined) { - interaction.guild.channels.fetch(guildInfo[interaction.guildId].rankChannelId).then(c => { - c.messages.fetch(guildInfo[interaction.guildId].rankMessageId).then(rankMessage => { - if ((rankMessage.embeds.length == 0) || (rankMessage.embeds[0].data.title != 'Tallest Trees' )) { - reject("This doesn't appear to be a valid ``/top trees`` message."); - return; - } - let lines = rankMessage.embeds[0].data.description.split('\n'); - let rankings = []; - for (let i = 0; i < 10; i++) { - let breakdown = lines[i].split(' - '); - if (breakdown[0].includes('🥇')) { - breakdown[0] = '``#1 ``' - } else if (breakdown[0].includes('🥈')) { - breakdown[0] = '``#2 ``' - } else if (breakdown[0].includes('🥉')) { - breakdown[0] = '``#3 ``' - } - - let trimmedRank = breakdown[0].slice(breakdown[0].indexOf('#') + 1, breakdown[0].lastIndexOf('``')); - - let trimmedName = breakdown[1].slice(breakdown[1].indexOf('``') + 2); - trimmedName = trimmedName.slice(0, trimmedName.indexOf('``')); - - let trimmedHeight = parseFloat(breakdown[2].slice(0, breakdown[2].indexOf('ft'))).toFixed(1); - - rankings.push({ - rank: trimmedRank, - name: trimmedName, - height: trimmedHeight - }); - } - - guildInfo[interaction.guildId].rankings = rankings; - fs.writeFileSync('../data/guildInfo.json', JSON.stringify(guildInfo)); - guildInfo = require('../data/guildInfo.json'); - resolve(rankings); - }); - }); - } else { - reject("The rankMessageId is undefined somehow"); - return; - } - }); - - }, - compare(interaction) { - if (guildInfo[interaction.guildId] == undefined) { - return `Please reset the reference messages! (${interaction.guildId})`; - } - let treeHeight = parseFloat(guildInfo[interaction.guildId].treeHeight).toFixed(1); - if ((guildInfo[interaction.guildId].rankings.length > 0) && (treeHeight > 0)) { - let replyString = 'Current Tree Height: ' + treeHeight + 'ft\n\n'; - guildInfo[interaction.guildId].rankings.forEach(e => { - let difference = parseFloat(e.height).toFixed(1) - treeHeight; - const absDifference = parseFloat(Math.abs(difference)).toFixed(1); - if (difference > 0) { - replyString += `${absDifference}ft shorter than rank #${e.rank}\n`; - } else if (difference < 0) { - replyString += `${absDifference}ft taller than rank #${e.rank}\n`; - } else if (difference == 0) { - replyString += `Same height as rank #${e.rank}\n`; - } - }); - return 'Here\'s how your tree compares: \n' + replyString; - } else { - console.error('Not configured correctly\n' + 'Guild ID: ' + interaction.guildId + '\nGuild Info: ' + JSON.stringify(guildInfo[interaction.guildId])); - return 'Not configured correctly'; - } - } - }, - tree: { - parse(interaction) { - let input; - return new Promise((resolve, reject) => { - if (guildInfo[interaction.guildId] == undefined) { - reject(`The guild entry hasn't been created yet. [${interaction.guildId || interaction.commandGuildId}]`); - return; - } - if (guildInfo[interaction.guildId].treeMessageId != "") { - interaction.guild.channels.fetch(guildInfo[interaction.guildId].treeChannelId).then(c => { - c.messages.fetch(guildInfo[interaction.guildId].treeMessageId).then(m => { - if ( (m.embeds.length == 0) || !(m.embeds[0].data.description.includes('Your tree is')) ) { - reject("This doesn't appear to be a valid ``/tree`` message."); - return; - } - input = m.embeds[0].data.description; - let lines = input.split('\n'); - guildInfo[interaction.guildId].treeHeight = parseFloat(lines[0].slice(lines[0].indexOf('is') + 3, lines[0].indexOf('ft'))).toFixed(1); - fs.writeFileSync('../data/guildInfo.json', JSON.stringify(guildInfo)); - guildInfo = require('../data/guildInfo.json'); - resolve("The reference tree message has been saved/updated."); - }); - }) - } else { - console.error('treeMessageId undefined'); - reject("There was an unknown error while setting the tree message."); - return; - } - }); - } - }, refresh(interaction) { functions.rankings.parse(interaction).then(r1 => { functions.tree.parse(interaction).then(r2 => { @@ -206,36 +87,6 @@ const functions = { }).catch(e => { interaction.reply(functions.builders.errorEmbed(e)); }); - }, - reset(guildId) { - delete guildInfo[guildId]; - fs.writeFileSync('../data/guildInfo.json', JSON.stringify(guildInfo)); - guildInfo = require('../data/guildInfo.json'); - return; - }, - getInfo(guildId) { - const guildInfo = guildInfo[guildId]; - if (guildInfo != undefined) { - let guildInfoString = ""; - if (guildInfo.treeMessageId != "") { - guildInfoString += `Tree Message ID: ${guildInfo.treeMessageId}\n`; - } - if (guildInfo.treeChannelId != "") { - guildInfoString += `Tree Channel ID: ${guildInfo.treeChannelId}\n`; - } - if (guildInfo.rankMessageId != "") { - guildInfoString += `Rank Message ID: ${guildInfo.rankMessageId}\n`; - } - if (guildInfo.rankChannelId != "") { - guildInfoString += `Rank Channel ID: ${guildInfo.rankChannelId}\n`; - } - if (guildInfo.treeHeight != "") { - guildInfoString += `Tree Height: ${guildInfo.treeHeight}\n`; - } - return `Here if your servers setup info:\n${guildInfoString}`; - } else { - return "Your guild hasn't been set up yet."; - } } }; diff --git a/package.json b/package.json deleted file mode 100644 index 03adfd0..0000000 --- a/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "treeanalyzer", - "version": "1.0.0", - "description": "Analyze Grow A Tree", - "main": "main.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/voidf1sh/treeanalyzer.git" - }, - "author": "Skylar Grant", - "license": "ISC", - "bugs": { - "url": "https://github.com/voidf1sh/treeanalyzer/issues" - }, - "homepage": "https://github.com/voidf1sh/treeanalyzer#readme", - "dependencies": { - "discord.js": "^14.7.1", - "dotenv": "^16.0.3" - } -} diff --git a/slash-commands/compare.js b/slash-commands/compare.js deleted file mode 100644 index cf0ba38..0000000 --- a/slash-commands/compare.js +++ /dev/null @@ -1,12 +0,0 @@ -const { SlashCommandBuilder } = require('discord.js'); -const fn = require('../modules/functions.js'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('compare') - .setDescription('See how your tree compares to other trees!'), - async execute(interaction) { - const embed = fn.builders.comparisonEmbed(fn.rankings.compare(interaction), fn.builders.refreshAction()); - interaction.reply(embed); - }, -}; \ No newline at end of file diff --git a/slash-commands/help.js b/slash-commands/help.js deleted file mode 100644 index 3ad4e16..0000000 --- a/slash-commands/help.js +++ /dev/null @@ -1,49 +0,0 @@ -const { SlashCommandBuilder, messageLink } = require('discord.js'); -const fn = require('../modules/functions.js'); -const strings = require('../data/strings.json'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('help') - .setDescription('Get help using the bot') - .addSubcommand(subcommand => - subcommand - .setName('info') - .setDescription('Learn about the bot') - .addStringOption(o => - o.setName('private') - .setDescription('Should the response be sent privately?') - .setRequired(true) - .addChoices( - { name: "True", value: "true" }, - { name: "False", value: "false" } - ))) - .addSubcommand(subcommand => - subcommand - .setName('setup') - .setDescription('Learn how to setup the bot') - .addStringOption(o => - o.setName('private') - .setDescription('Should the response be sent privately?') - .setRequired(true) - .addChoices( - { name: "True", value: "true" }, - { name: "False", value: "false" } - ))) - .addSubcommand(subcommand => - subcommand - .setName('permissions') - .setDescription('Learn about the bot\'s permissions') - .addStringOption(o => - o.setName('private') - .setDescription('Should the response be sent privately?') - .setRequired(true) - .addChoices( - { name: "True", value: "true" }, - { name: "False", value: "false" } - ))), - execute(interaction) { - const helpEmbed = fn.builders.helpEmbed(strings.help[interaction.options.getSubcommand()], interaction.options.getString('private')); - interaction.reply(helpEmbed); - }, -}; \ No newline at end of file diff --git a/slash-commands/reset.js b/slash-commands/reset.js deleted file mode 100644 index cecb3cd..0000000 --- a/slash-commands/reset.js +++ /dev/null @@ -1,12 +0,0 @@ -const { SlashCommandBuilder } = require('discord.js'); -const fn = require('../modules/functions.js'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('reset') - .setDescription('Reset all message assignments in your server'), - execute(interaction) { - fn.reset(interaction.guildId); - interaction.reply(fn.builders.embed("Assignments Reset")); - }, -}; \ No newline at end of file diff --git a/slash-commands/setup.js b/slash-commands/setup.js deleted file mode 100644 index 05e327d..0000000 --- a/slash-commands/setup.js +++ /dev/null @@ -1,47 +0,0 @@ -const { SlashCommandBuilder } = require('discord.js'); -const fn = require('../modules/functions.js'); -const guildInfo = require('../data/guildInfo.json'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('setup') - .setDescription('Attempt automatic configuration of the bot.'), - execute(interaction) { - if (guildInfo[interaction.guildId] == undefined) { - guildInfo[interaction.guildId] = { - "treeMessageId": "", - "treeChannelId": "", - "rankMessageId": "", - "rankChannelId": "", - "rankings": [], - "treeHeight": 0 - }; - } - interaction.channel.messages.fetch({ limit: 20 }).then(msgs => { - let treeFound = false; - let rankFound = false; - msgs.forEach(msg => { - if (msg.embeds.length > 0) { - if (msg.embeds[0].data.description.includes("Your tree is")) { - treeFound = true; - guildInfo[interaction.guildId].treeChannelId = msg.channelId; - guildInfo[interaction.guildId].treeMessageId = msg.id; - fn.tree.parse(msg); - } else if (msg.embeds[0].data.title == "Tallest Trees") { - rankFound = true; - guildInfo[interaction.guildId].rankChannelId = msg.channelId; - guildInfo[interaction.guildId].rankMessageId = msg.id; - fn.rankings.parse(msg); - } - } - }); - if (treeFound && !(rankFound)) { - interaction.reply(fn.builders.embed("A tree message was found, but a leaderboard message was not. Please run this command again in the channel containing the leaderboard if you haven't done so already. Run ``/setupinfo`` to see if the message is set.")); - } else if (!(treeFound) && rankFound) { - interaction.reply(fn.builders.embed("A leaderboard message was found, but a tree message was not. Please run this command again in the channel containing the tree if you haven't done so already. Run ``/setupinfo`` to see if the message is set.")); - } else if (treeFound && rankFound) { - interaction.reply(fn.builders.embed("Tree and leaderboard messages were both found, setup is complete. Run ``/setupinfo`` to verify.")); - } - }); - }, -}; \ No newline at end of file diff --git a/slash-commands/setupinfo.js b/slash-commands/setupinfo.js deleted file mode 100644 index b30871a..0000000 --- a/slash-commands/setupinfo.js +++ /dev/null @@ -1,12 +0,0 @@ -const { SlashCommandBuilder } = require('discord.js'); -const fn = require('../modules/functions.js'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('setupinfo') - .setDescription('View information about how the bot is set up in your server'), - execute(interaction) { - const embed = fn.builders.embed(fn.getInfo(interaction.guildId)); - interaction.reply(embed); - }, -}; \ No newline at end of file