From 02a921906cc29604121b859acca5d415bab3fb6f Mon Sep 17 00:00:00 2001 From: GalaxyLittlepaws Date: Sat, 25 Oct 2025 04:49:23 -0400 Subject: [PATCH 1/6] Adds the Region Restart Evasion feature, better handles Discord command registration, adds info about evasion status/location to stats --- DscEvents/clientReady.js | 9 + DscEvents/guildCreate.js | 14 +- DscSlash/stats.js | 14 ++ DscSlash/teleport.js | 6 + README.md | 2 +- config.js.example | 19 +- index.js | 22 ++- modules/RegionRestartHandler.js | 319 ++++++++++++++++++++++++++++++++ 8 files changed, 391 insertions(+), 14 deletions(-) create mode 100644 modules/RegionRestartHandler.js diff --git a/DscEvents/clientReady.js b/DscEvents/clientReady.js index c194210..e759437 100644 --- a/DscEvents/clientReady.js +++ b/DscEvents/clientReady.js @@ -3,6 +3,15 @@ module.exports = async client => { // Log that the bot is online. logger.log(`${client.user.tag}, ready to serve ${client.guilds.cache.map(g => g.memberCount).reduce((a, b) => a + b)} users in ${client.guilds.cache.size} servers.`, "ready"); + // Register slash commands globally so they work in DMs + try { + const globalCommands = client.container.slashcmds.map(cmd => cmd.data); + await client.application?.commands.set(globalCommands); + logger.log(`Registered ${globalCommands.length} global slash commands`, "ready"); + } catch (error) { + logger.log(`Failed to register global commands: ${error.message}`, "error"); + } + /// this sets the activity, so the bot is being silly. client.user.setActivity(`with the Metaverse`, { type: "PLAYING" }); }; diff --git a/DscEvents/guildCreate.js b/DscEvents/guildCreate.js index 411eb03..f9248db 100644 --- a/DscEvents/guildCreate.js +++ b/DscEvents/guildCreate.js @@ -3,14 +3,8 @@ const logger = require("../modules/Logger.js"); module.exports = (client, guild) => { logger.log(`[GUILD JOIN] ${guild.id} added the bot. Owner: ${guild.ownerId}`); - // We'll partition the slash commands based on the guildOnly boolean. - // Separating them into the correct objects defined in the array below. - const [globalCmds, guildCmds] = client.container.slashcmds.partition(c => !c.conf.guildOnly); - - // We'll use set but please keep in mind that `set` is overkill for a singular command. - // Set the guild commands like - client.guilds.cache.get(guild.id)?.commands.set(guildCmds.map(c => c.commandData)); - - // Then set the global commands like -client.application?.commands.set(globalCmds.map(c => c.commandData)).catch(e => console.log(e)); + + // Global commands are already registered in clientReady event + // No need to register them again here since they work in DMs and all guilds now + logger.log(`Global slash commands are available in guild ${guild.id}`, "log"); }; diff --git a/DscSlash/stats.js b/DscSlash/stats.js index 2533ce5..3a5291f 100644 --- a/DscSlash/stats.js +++ b/DscSlash/stats.js @@ -17,6 +17,18 @@ module.exports = { async execute(interaction) { const duration = durationFormatter.format(interaction.client.uptime); + + // Get region restart handler status + const regionRestartHandler = interaction.client.container.regionRestartHandler; + let currentLocation = 'Unknown'; + let evacuationStatus = 'Unknown'; + + if (regionRestartHandler) { + const status = regionRestartHandler.getStatus(); + currentLocation = status.currentRegion || 'Unknown'; + evacuationStatus = status.isEvacuating ? '🚨 Evacuating Region Restarts' : '✅ Normal'; + } + const statsEmbed = new EmbedBuilder() .setColor('#0099ff') .setTitle('STATISTICS') @@ -29,6 +41,8 @@ module.exports = { { name: 'Discord.js', value: `v${version}`, inline: true }, { name: 'Node.js', value: process.version, inline: true }, { name: 'Bot Version', value: `v${dversion}`, inline: true }, + { name: 'Current Region', value: currentLocation, inline: true }, + { name: 'Restarts Evacuation Status', value: evacuationStatus, inline: true }, ) .setTimestamp(); diff --git a/DscSlash/teleport.js b/DscSlash/teleport.js index e5e2324..3c70489 100644 --- a/DscSlash/teleport.js +++ b/DscSlash/teleport.js @@ -46,6 +46,12 @@ module.exports = { const position = new Vector3(loc.x, loc.y, loc.z); const lookAt = position; await interaction.client.container.SLbot.clientCommands.teleport.teleportTo(loc.region, position, lookAt); + + const regionRestartHandler = interaction.client.container.regionRestartHandler; + if (regionRestartHandler) { + regionRestartHandler.currentRegion = loc.region; + } + await interaction.followUp(`Teleport successful to ${loc.region} (${loc.x}, ${loc.y}, ${loc.z})`); } catch (err) { await interaction.followUp(`Teleport failed: ${err.message}`); diff --git a/README.md b/README.md index 7520f37..e022072 100644 --- a/README.md +++ b/README.md @@ -179,7 +179,7 @@ A Discord and Second Life bot capable of relaying messages between inworld Secon ## Roadmap -- [ ] Add Region Restart Evasion with Fallback Regions in the Config File +- [x] Add Region Restart Evasion with Fallback Regions in the Config File * On Region Restart notice, teleport to a fallback region, as well as on login, if can't login to the main region, teleport to a fallback region, don't want your bots sticking around somewhere you don't want it - [ ] Add Reload Capability of SL and Discord Commands/Event files. diff --git a/config.js.example b/config.js.example index 5d0bd9f..12fcf2f 100644 --- a/config.js.example +++ b/config.js.example @@ -7,11 +7,26 @@ const config = { // Bot Support, level 8 by default. Array of user ID strings 'support': [], - // To be implemented, fallback regions if the .env main region can't be reached. + // Fallback regions configuration for region restart scenarios + // Format: ['region-name', 'uri:RegionName&x&y&z'] fallbackRegions: new Map([ - ['regioname', 'uri'], + ['sandbox', 'uri:Sandbox%20Island&128&128&25'], + ['help', 'uri:Help%20Island%20Public&128&128&25'], + ['welcome', 'uri:Welcome%20Center&128&128&25'] ]), + // Region restart evasion settings + regionRestartSettings: { + // Enable automatic teleportation on region restart alerts + enabled: true, + // Time to wait between teleport attempts (seconds or minutes) + teleportRetryDelay: "30s", + // Time to wait before trying to return to startup location (seconds or minutes) + returnToStartupDelay: "5m", + // Maximum number of teleport attempts per location + maxTeleportAttempts: 3 + }, + // //// This maps inworld group UUIDs to Discord Channels. relays: new Map([ ["e38d0caa-2b71-031a-3e1b-4abe1a22e8f3", "1411469523856396359"] // Red Robot Main Group (Client: dark.nebula) diff --git a/index.js b/index.js index 4083363..8d41d11 100644 --- a/index.js +++ b/index.js @@ -13,6 +13,7 @@ const { readdirSync } = require('fs'); const { intents, partials, permLevels } = require('./config.js'); const config = require('./config.js'); const logger = require('./modules/Logger.js'); +const RegionRestartHandler = require('./modules/RegionRestartHandler.js'); // This is your client. Some people call it `bot`, some people call it `self`, // some might call it `cootchie`. Either way, when you see `client.something`, // or `bot.something`, this is what we're referring to. Your client. @@ -46,8 +47,11 @@ client.container = { nmv, }; +// Initialize Region Restart Handler +const regionRestartHandler = new RegionRestartHandler(client); +client.container.regionRestartHandler = regionRestartHandler; + const GroupChatEventHandler = require('./SLevents/GroupChat.js'); -const ChatEventHandler = require('./SLevents/ChatEvent.js'); // We're doing real fancy node 8 async/await stuff here, and to do that // we need to wrap stuff in an anonymous function. It's annoying but it works. @@ -62,6 +66,22 @@ const init = async () => { return client.container.SLbot.connectToSim(); }).then(() => { logger.log('SL: Connected to Region', 'log'); + + // Set startup location for region restart handler + const startLocation = process.env.SL_START; + if (startLocation && startLocation !== 'last') { + // Parse URI format: uri:RegionName&x&y&z + const uriMatch = startLocation.match(/uri:([^&]+)&(\d+)&(\d+)&(\d+)/); + if (uriMatch) { + const region = decodeURIComponent(uriMatch[1]); + const x = parseInt(uriMatch[2], 10); + const y = parseInt(uriMatch[3], 10); + const z = parseInt(uriMatch[4], 10); + regionRestartHandler.setStartupLocation(region, x, y, z); + } + } else { + logger.log('SL: Startup location set to default, will update region restart handler when region info is available', 'log'); + } }).then(async () => { diff --git a/modules/RegionRestartHandler.js b/modules/RegionRestartHandler.js new file mode 100644 index 0000000..a590b12 --- /dev/null +++ b/modules/RegionRestartHandler.js @@ -0,0 +1,319 @@ +const logger = require('./Logger.js'); +const config = require('../config.js'); + +class RegionRestartHandler { + constructor(client) { + this.client = client; + this.SLbot = client.container.SLbot; + this.nmv = client.container.nmv; + + // State management + this.isEvacuating = false; + this.currentLocationIndex = 0; + this.teleportAttempts = 0; + this.startupLocation = null; + this.returnTimer = null; + this.currentRegion = null; + + // Get settings from config + this.settings = config.regionRestartSettings || {}; + this.enabled = this.settings.enabled || false; + this.teleportRetryDelay = this.parseTimeValue(this.settings.teleportRetryDelay, 5000); + this.returnToStartupDelay = this.parseTimeValue(this.settings.returnToStartupDelay, 300000); + this.maxTeleportAttempts = this.settings.maxTeleportAttempts || 3; + this.fallbackRegions = config.fallbackRegions || new Map(); + this.backupLocations = Array.from(this.fallbackRegions.values()); + + if (this.enabled) { + logger.log('Region Restart Handler initialized and enabled', 'log'); + } else { + logger.log('Region Restart Handler initialized but disabled', 'log'); + } + } + + /** + * Parse time value - accepts seconds with 's' or minutes with 'm' + * Examples: "5s", "30s", "2m", "10m" + */ + parseTimeValue(value, defaultValue) { + if (!value) return defaultValue; + + // If it's a string, parse it + if (typeof value === 'string') { + const str = value.toLowerCase().trim(); + + // Extract number and unit + const match = str.match(/^(\d+(?:\.\d+)?)(s|m)$/); + if (!match) return defaultValue; + + const num = parseFloat(match[1]); + const unit = match[2]; + + switch (unit) { + case 's': + return num * 1000; + case 'm': + return num * 60 * 1000; + default: + return defaultValue; + } + } + + return defaultValue; + } + + /** + * Set the startup location to return to later + */ + setStartupLocation(region, x = 128, y = 128, z = 25) { + this.startupLocation = { region, x, y, z }; + this.currentRegion = region; + logger.log(`Startup location set to: ${region} (${x}, ${y}, ${z})`, 'log'); + } + + /** + * Check if a message contains region restart alert + */ + isRegionRestartAlert(message) { + if (!message || typeof message !== 'string') return false; + + // Check for various restart alert patterns + const restartPatterns = [ + /Alert info message: RegionRestartSeconds/i + ]; + + return restartPatterns.some(pattern => pattern.test(message)); + } + + /** + * Handle region restart alert + */ + async handleRegionRestartAlert(message) { + if (!this.enabled) { + logger.log('Region restart detected but handler is disabled', 'warn'); + return; + } + + if (this.isEvacuating) { + logger.log('Already evacuating, ignoring additional restart alert', 'warn'); + return; + } + + if (this.backupLocations.length === 0) { + logger.log('Region restart detected but no backup locations configured', 'error'); + return; + } + + logger.log(`Region restart alert detected: ${message}`, 'warn'); + this.isEvacuating = true; + this.currentLocationIndex = 0; + this.teleportAttempts = 0; + + // Clear any existing return timer + if (this.returnTimer) { + clearTimeout(this.returnTimer); + this.returnTimer = null; + } + + await this.beginEvacuation(); + } + + /** + * Begin evacuation process + */ + async beginEvacuation() { + if (this.backupLocations.length === 0) { + logger.log('No backup locations configured, cannot evacuate', 'error'); + this.isEvacuating = false; + return; + } + + logger.log('Beginning evacuation process', 'warn'); + await this.tryTeleportToBackupLocation(); + } + + /** + * Parse URI format location string + * Format: "uri:RegionName&x&y&z" + */ + parseLocationURI(uriString) { + if (!uriString || !uriString.startsWith('uri:')) { + return null; + } + + const match = uriString.match(/uri:([^&]+)&(\d+)&(\d+)&(\d+)/); + if (!match) { + return null; + } + + return { + region: decodeURIComponent(match[1]), + x: parseInt(match[2], 10), + y: parseInt(match[3], 10), + z: parseInt(match[4], 10) + }; + } + + /** + * Try to teleport to the current backup location + */ + async tryTeleportToBackupLocation() { + if (this.currentLocationIndex >= this.backupLocations.length) { + logger.log('All backup locations exhausted, evacuation failed', 'error'); + this.isEvacuating = false; + return; + } + + const locationURI = this.backupLocations[this.currentLocationIndex]; + const location = this.parseLocationURI(locationURI); + + if (!location) { + logger.log(`Invalid location URI format: ${locationURI}`, 'error'); + this.currentLocationIndex++; + this.teleportAttempts = 0; + setTimeout(async () => { + await this.tryTeleportToBackupLocation(); + }, this.teleportRetryDelay); + return; + } + + this.teleportAttempts++; + + logger.log(`Attempting teleport ${this.teleportAttempts}/${this.maxTeleportAttempts} to backup location: ${location.region} (${location.x}, ${location.y}, ${location.z})`, 'log'); + + try { + const { Vector3 } = this.nmv; + const position = new Vector3(location.x, location.y, location.z); + const lookAt = position; + + await this.SLbot.clientCommands.teleport.teleportTo(location.region, position, lookAt); + + logger.log(`Successfully evacuated to: ${location.region}`, 'log'); + this.currentRegion = location.region; + this.onEvacuationSuccess(); + + } catch (error) { + logger.log(`Teleport failed: ${error.message}`, 'error'); + await this.handleTeleportFailure(); + } + } + + /** + * Handle successful evacuation + */ + onEvacuationSuccess() { + this.isEvacuating = false; + this.teleportAttempts = 0; + + // Schedule return to startup location + if (this.startupLocation && this.returnToStartupDelay > 0) { + logger.log(`Scheduling return to startup location in ${this.returnToStartupDelay / 1000} seconds`, 'log'); + + this.returnTimer = setTimeout(async () => { + await this.returnToStartupLocation(); + }, this.returnToStartupDelay); + } + } + + /** + * Handle teleport failure + */ + async handleTeleportFailure() { + if (this.teleportAttempts >= this.maxTeleportAttempts) { + // Move to next location + logger.log(`Max attempts reached for current location, trying next backup location`, 'warn'); + this.currentLocationIndex++; + this.teleportAttempts = 0; + + // Wait before trying next location + setTimeout(async () => { + await this.tryTeleportToBackupLocation(); + }, this.teleportRetryDelay); + } else { + // Retry current location + logger.log(`Retrying current location in ${this.teleportRetryDelay / 1000} seconds`, 'log'); + + setTimeout(async () => { + await this.tryTeleportToBackupLocation(); + }, this.teleportRetryDelay); + } + } + + /** + * Return to startup location + */ + async returnToStartupLocation() { + if (!this.startupLocation) { + logger.log('No startup location set, cannot return', 'warn'); + return; + } + + // Check if we're already at the startup location + if (this.currentRegion === this.startupLocation.region) { + logger.log('Already at startup location, no need to return', 'log'); + return; + } + + logger.log(`Attempting to return to startup location: ${this.startupLocation.region}`, 'log'); + + try { + const { Vector3 } = this.nmv; + const position = new Vector3(this.startupLocation.x, this.startupLocation.y, this.startupLocation.z); + const lookAt = position; + + await this.SLbot.clientCommands.teleport.teleportTo( + this.startupLocation.region, + position, + lookAt + ); + + logger.log(`Successfully returned to startup location: ${this.startupLocation.region}`, 'log'); + this.currentRegion = this.startupLocation.region; + + } catch (error) { + logger.log(`Failed to return to startup location: ${error.message}`, 'error'); + + // Schedule another attempt in a bit + logger.log('Scheduling retry to return to startup location in 60 seconds', 'log'); + this.returnTimer = setTimeout(async () => { + await this.returnToStartupLocation(); + }, 60000); + } + } + + /** + * Manually trigger evacuation (for testing or manual use) + */ + async manualEvacuation() { + logger.log('Manual evacuation triggered', 'warn'); + await this.handleRegionRestartAlert('Manual evacuation triggered'); + } + + /** + * Get current status + */ + getStatus() { + return { + enabled: this.enabled, + isEvacuating: this.isEvacuating, + currentRegion: this.currentRegion, + startupLocation: this.startupLocation, + currentLocationIndex: this.currentLocationIndex, + teleportAttempts: this.teleportAttempts, + backupLocationsCount: this.backupLocations.length + }; + } + + /** + * Cleanup method + */ + cleanup() { + if (this.returnTimer) { + clearTimeout(this.returnTimer); + this.returnTimer = null; + } + this.isEvacuating = false; + } +} + +module.exports = RegionRestartHandler; \ No newline at end of file From 33ed3f393ea913c6a60ce1f329dee597e8974ea3 Mon Sep 17 00:00:00 2001 From: Galaxy Littlepaws <34807062+GalaxyLittlepaws@users.noreply.github.com> Date: Sun, 26 Oct 2025 15:47:36 -0400 Subject: [PATCH 2/6] Update index.js to resolve error "missing ChatEventHandler" --- index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/index.js b/index.js index 8d41d11..de998d5 100644 --- a/index.js +++ b/index.js @@ -52,6 +52,7 @@ const regionRestartHandler = new RegionRestartHandler(client); client.container.regionRestartHandler = regionRestartHandler; const GroupChatEventHandler = require('./SLevents/GroupChat.js'); +const ChatEventHandler = require('./SLevents/ChatEvent.js'); // We're doing real fancy node 8 async/await stuff here, and to do that // we need to wrap stuff in an anonymous function. It's annoying but it works. From e0627d6327c0085b96dc1428f1c7ec318a65746e Mon Sep 17 00:00:00 2001 From: GalaxyLittlepaws Date: Sun, 26 Oct 2025 20:13:59 -0400 Subject: [PATCH 3/6] Fixes error from duplicate interaction handlers --- index.js | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/index.js b/index.js index de998d5..4d90aa5 100644 --- a/index.js +++ b/index.js @@ -134,27 +134,6 @@ const init = async () => { client.on(eventName, event.bind(null, client)); } - // --- NEW: Add the interaction handler and ready event --- - // This event handler is critical for all slash commands. - client.on(Events.InteractionCreate, async interaction => { - // If the interaction isn't a slash command, do nothing. - if (!interaction.isChatInputCommand()) return; - - const command = client.container.slashcmds.get(interaction.commandName); - if (!command) return; - - try { - await command.execute(interaction); - } catch (error) { - console.error(error); - if (interaction.replied || interaction.deferred) { - await interaction.followUp({ content: 'There was an error while executing this command!', ephemeral: true }); - } else { - await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true }); - } - } - }); - // This logs a message to the console once the bot has successfully logged in. client.once(Events.ClientReady, c => { console.log(`Ready! Logged in as ${c.user.tag}`); From e8b5826d94c3908c1383611a68a65ec7ed1c023d Mon Sep 17 00:00:00 2001 From: Vault108 <44564111+Vault108@users.noreply.github.com> Date: Tue, 28 Oct 2025 05:02:54 -0400 Subject: [PATCH 4/6] adds logging back to the restart evade --- index.js | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 4d90aa5..7f6b61c 100644 --- a/index.js +++ b/index.js @@ -17,6 +17,7 @@ const RegionRestartHandler = require('./modules/RegionRestartHandler.js'); // This is your client. Some people call it `bot`, some people call it `self`, // some might call it `cootchie`. Either way, when you see `client.something`, // or `bot.something`, this is what we're referring to. Your client. +const packageinfo = require("../package.json"); const client = new Client({ intents, partials }); @@ -134,9 +135,41 @@ const init = async () => { client.on(eventName, event.bind(null, client)); } + // --- NEW: Add the interaction handler and ready event --- + // This event handler is critical for all slash commands. + client.on(Events.InteractionCreate, async interaction => { + // If the interaction isn't a slash command, do nothing. + if (!interaction.isChatInputCommand()) return; + + const command = client.container.slashcmds.get(interaction.commandName); + if (!command) return; + + try { + await command.execute(interaction); + } catch (error) { + console.error(error); + if (interaction.replied || interaction.deferred) { + await interaction.followUp({ content: 'There was an error while executing this command!', ephemeral: true }); + } else { + await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true }); + } + } + }); + // This logs a message to the console once the bot has successfully logged in. client.once(Events.ClientReady, c => { + const packageinfo = require("./package.json"); + const dversion = packageinfo.version; + const name = packageinfo.name; console.log(`Ready! Logged in as ${c.user.tag}`); + logger.log(`package name: ${name}`); + logger.log(`package version: ${dversion}`); + const pkg = require('./package.json'); + Object.entries(pkg.dependencies || {}).forEach(([dep, ver]) => { + logger.log(`dependency: ${dep}@${ver}`); + }); + + }); // This adds an error listener @@ -144,7 +177,6 @@ const init = async () => { console.error('Discord.js Error:', err); }); - // Here we login the client. client.login(); @@ -152,4 +184,4 @@ const init = async () => { // End top-level async/await function. }; -init(); \ No newline at end of file +init(); From a44a604c5fb1e4483970b01f1210abded627f72c Mon Sep 17 00:00:00 2001 From: GalaxyLittlepaws Date: Wed, 29 Oct 2025 00:54:00 -0400 Subject: [PATCH 5/6] Bot checks for SL-readiness before trying to do commands --- DscEvents/messageCreate.js | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/DscEvents/messageCreate.js b/DscEvents/messageCreate.js index 245d29e..637d5ae 100644 --- a/DscEvents/messageCreate.js +++ b/DscEvents/messageCreate.js @@ -32,15 +32,25 @@ module.exports = async (client, message) => { // Oh boi it is. if (value === message.channel.id) { - // console.debug("Discord Channel ID: " + message.channel.id + " maps to SL Group UUID: " + key + " " + typeof key + typeof message.channel.id); - const groupID = new nmv.UUID(key); - // Start a group chat session - equivalent to opening a group chat but not sending a message - await container.SLbot.clientCommands.comms.startGroupChatSession(groupID, ''); - let guild = client.guilds.fetch(message.guild.id); - const member = await message.guild.members.fetch(message.author); - let nickname = member ? member.displayName : null; - // Send a group message - await container.SLbot.clientCommands.comms.sendGroupMessage(groupID, 'From Discord: ' + nickname + ': ' + message.content); + // Check if SL bot is connected and ready before trying to use it + if (!container.SLbot || !container.SLbot.clientCommands) { + logger.log('SL bot not ready yet, skipping message relay', 'warn'); + return; + } + + try { + // console.debug("Discord Channel ID: " + message.channel.id + " maps to SL Group UUID: " + key + " " + typeof key + typeof message.channel.id); + const groupID = new nmv.UUID(key); + // Start a group chat session - equivalent to opening a group chat but not sending a message + await container.SLbot.clientCommands.comms.startGroupChatSession(groupID, ''); + let guild = client.guilds.fetch(message.guild.id); + const member = await message.guild.members.fetch(message.author); + let nickname = member ? member.displayName : null; + // Send a group message + await container.SLbot.clientCommands.comms.sendGroupMessage(groupID, 'From Discord: ' + nickname + ': ' + message.content); + } catch (error) { + logger.log(`Failed to relay message to SL: ${error.message}`, 'error'); + } } }) From b565042d641454a8db8368971d82c4f086dc3b13 Mon Sep 17 00:00:00 2001 From: GalaxyLittlepaws Date: Wed, 29 Oct 2025 00:58:44 -0400 Subject: [PATCH 6/6] Fixes call to packageinfo location in index --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 7f6b61c..2b66e8d 100644 --- a/index.js +++ b/index.js @@ -17,7 +17,7 @@ const RegionRestartHandler = require('./modules/RegionRestartHandler.js'); // This is your client. Some people call it `bot`, some people call it `self`, // some might call it `cootchie`. Either way, when you see `client.something`, // or `bot.something`, this is what we're referring to. Your client. -const packageinfo = require("../package.json"); +const packageinfo = require("./package.json"); const client = new Client({ intents, partials });