diff --git a/.gitignore b/.gitignore index 5320519..c675dcc 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,7 @@ cdk.out cdk.context.json # Configuration -**/*config.ts \ No newline at end of file +**/*config.ts + +# Exception for JS files under the discord-bot folder +!server-hosting/discord-bot/**/*.js \ No newline at end of file diff --git a/server-hosting/discord-bot/README.md b/server-hosting/discord-bot/README.md new file mode 100644 index 0000000..d79eae6 --- /dev/null +++ b/server-hosting/discord-bot/README.md @@ -0,0 +1,30 @@ +# How to setup a discord bot to start your satisfactory server remotely + +# Requirements + +You will need: + +* A discord account +* A discord server that you manage (meaning you can add apps and bots to it) +* A machine with internet access (or whatever access needed to start your satisfactory server remotely) where your bot will be running +* NodeJS 16.6+ installed on that machine + +# Stage 1 : Setup the discord app and the code + +* Copy the code contained in this folder on your machine and install it by running `npm install` +* Get yourself a discord application with a bot and add the bot to your Discord server. I suggest you follow the very good instructions here: https://discordjs.guide/preparations/setting-up-a-bot-application.html +* Copy the important information (Bot Token, App Client Id and GuildId) in the `config.json` file +* Create your custom code to start your Satisfactory server in the `commands/ficsit.js` file (You will need to modify this file so it calls Lambda or any other service you wish to use to start your bot) + +# Stage 2 : Deploy your code + +* From the machine where your bot will run, deploy your commands with `node deploy-commands.js` (This registers the commands with your bot application so they can be used). This need to be done everytime you add a new command +* From the machine where your bot will run, start your bot with `node index.js` (This will login the bot in your server and he will be available to respond to commands and NEED to be running for your bot to stay online) +* Test out your commands : `/ping`, `/user` and `/server` are example commands included to test that your bot work with the most basic of commands. +* The `/ficsit` command is to be used to start your Satisfactory server. + +# Optional : If you want to run your bot as a linux service +* Modify the `discord-bot.service` with your appropriate PATHS, USER and GROUP and copy it to `/etc/systemd/system/discord-bot.service` +* Add `#!/usr/bin/env node` as the very first line of the `index.js` file +* Make the `index.js` file executable by running `chmod +x index.js` +* Use `sudo systemctl daemon-reload` followed by `sudo systemctl enable discord-bot.service` followed by `sudo systemctl start discord-bot.service` to register/enable/start your discord bot service \ No newline at end of file diff --git a/server-hosting/discord-bot/commands/ficsit.js b/server-hosting/discord-bot/commands/ficsit.js new file mode 100644 index 0000000..bcc6d55 --- /dev/null +++ b/server-hosting/discord-bot/commands/ficsit.js @@ -0,0 +1,15 @@ +const { SlashCommandBuilder } = require('@discordjs/builders'); + + +module.exports = { + data: new SlashCommandBuilder() + .setName('ficsit') + .setDescription('Start the satisfactory server!'), + async execute(interaction) { + await interaction.reply("Sending message to start Satisfactory Server!"); + ///////// Your code to start the Satisfactory Server here //////// + }, +}; + + + diff --git a/server-hosting/discord-bot/commands/ping.js b/server-hosting/discord-bot/commands/ping.js new file mode 100644 index 0000000..72de7b4 --- /dev/null +++ b/server-hosting/discord-bot/commands/ping.js @@ -0,0 +1,10 @@ +const { SlashCommandBuilder } = require('@discordjs/builders'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('ping') + .setDescription('Replies with Pong!'), + async execute(interaction) { + await interaction.reply('Pong!'); + }, +}; diff --git a/server-hosting/discord-bot/commands/server.js b/server-hosting/discord-bot/commands/server.js new file mode 100644 index 0000000..82ba12a --- /dev/null +++ b/server-hosting/discord-bot/commands/server.js @@ -0,0 +1,8 @@ +const { SlashCommandBuilder } = require('@discordjs/builders'); + +module.exports = { + data: new SlashCommandBuilder().setName('server').setDescription('Replies with server info!'), + async execute(interaction) { + await interaction.reply(`Server name: ${interaction.guild.name}\nTotal members: ${interaction.guild.memberCount}`); + }, +}; diff --git a/server-hosting/discord-bot/commands/user.js b/server-hosting/discord-bot/commands/user.js new file mode 100644 index 0000000..53ca354 --- /dev/null +++ b/server-hosting/discord-bot/commands/user.js @@ -0,0 +1,8 @@ +const { SlashCommandBuilder } = require('@discordjs/builders'); + +module.exports = { + data: new SlashCommandBuilder().setName('user').setDescription('Replies with user info!'), + async execute(interaction) { + await interaction.reply(`Your tag: ${interaction.user.tag}\nYour id: ${interaction.user.id}`); + }, +}; diff --git a/server-hosting/discord-bot/config.json b/server-hosting/discord-bot/config.json new file mode 100644 index 0000000..e882041 --- /dev/null +++ b/server-hosting/discord-bot/config.json @@ -0,0 +1,5 @@ +{ + "token": "Your Bot Token", + "clientId" : "Your App Oauth2 Client Id", + "guildId" : "Your Server (Guild) Id" +} diff --git a/server-hosting/discord-bot/deploy-commands.js b/server-hosting/discord-bot/deploy-commands.js new file mode 100644 index 0000000..abbb8bb --- /dev/null +++ b/server-hosting/discord-bot/deploy-commands.js @@ -0,0 +1,19 @@ +const fs = require('fs'); +const { SlashCommandBuilder } = require('@discordjs/builders'); +const { REST } = require('@discordjs/rest'); +const { Routes } = require('discord-api-types/v9'); +const { clientId, guildId, token } = require('./config.json'); + +const commands = []; +const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js')); + +for (const file of commandFiles) { + const command = require(`./commands/${file}`); + commands.push(command.data.toJSON()); +} + +const rest = new REST({ version: '9' }).setToken(token); + +rest.put(Routes.applicationGuildCommands(clientId,guildId), { body: commands }) + .then(() => console.log('Successfully registered application commands.')) + .catch(console.error); diff --git a/server-hosting/discord-bot/discord-bot.service b/server-hosting/discord-bot/discord-bot.service new file mode 100644 index 0000000..04ff698 --- /dev/null +++ b/server-hosting/discord-bot/discord-bot.service @@ -0,0 +1,15 @@ +[Unit] +Description=Discord Bot + +[Service] +ExecStart=/path/to/folder/discord-bot/index.js +Restart=on-failure +StandardOutput=journal +User=YOUR_USER +Group=YOUR_GROUP +Environment=PATH=/usr/bin:/usr/local/bin +Environment=NODE_ENV=production +WorkingDirectory=/path/to/folder/discord-bot + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/server-hosting/discord-bot/events/interactionCreate.js b/server-hosting/discord-bot/events/interactionCreate.js new file mode 100644 index 0000000..217b8fc --- /dev/null +++ b/server-hosting/discord-bot/events/interactionCreate.js @@ -0,0 +1,6 @@ +module.exports = { + name: 'interactionCreate', + execute(interaction) { + console.log(`${interaction.user.tag} in #${interaction.channel.name} triggered an interaction.`); + }, +}; \ No newline at end of file diff --git a/server-hosting/discord-bot/events/ready.js b/server-hosting/discord-bot/events/ready.js new file mode 100644 index 0000000..ad67ee0 --- /dev/null +++ b/server-hosting/discord-bot/events/ready.js @@ -0,0 +1,7 @@ +module.exports = { + name: 'ready', + once: true, + execute(client) { + console.log(`Ready! Logged in as ${client.user.tag}`); + }, +}; \ No newline at end of file diff --git a/server-hosting/discord-bot/index.js b/server-hosting/discord-bot/index.js new file mode 100644 index 0000000..521b6e5 --- /dev/null +++ b/server-hosting/discord-bot/index.js @@ -0,0 +1,46 @@ +// Require the necessary discord.js classes +const fs = require('fs'); +const { Client, Collection, Intents } = require('discord.js'); +const { token } = require('./config.json'); + +// Create a new client instance +const client = new Client({ intents: [Intents.FLAGS.GUILDS] }); + +client.commands = new Collection(); + +const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js')); +const eventFiles = fs.readdirSync('./events').filter(file => file.endsWith('.js')); + +for (const file of commandFiles) { + const command = require(`./commands/${file}`); + // Set a new item in the Collection + // With the key as the command name and the value as the exported module + client.commands.set(command.data.name, command); +} + +for (const file of eventFiles) { + const event = require(`./events/${file}`); + if (event.once) { + client.once(event.name, (...args) => event.execute(...args)); + } else { + client.on(event.name, (...args) => event.execute(...args)); + } +} + +client.on('interactionCreate', async interaction => { + if (!interaction.isCommand()) return; + + const command = client.commands.get(interaction.commandName); + + if (!command) return; + + try { + await command.execute(interaction); + } catch (error) { + console.error(error); + await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true }); + } +}); + +// Login to Discord with your client's token +client.login(token);