diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 5192343..552a13f 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -7,9 +7,7 @@ on: jobs: build: - runs-on: ubuntu-latest - steps: - uses: actions/checkout@v3 - name: Build the Docker image diff --git a/.github/workflows/first-time-setup.yml b/.github/workflows/first-time-setup.yml index 8ebc6b0..3ed0243 100644 --- a/.github/workflows/first-time-setup.yml +++ b/.github/workflows/first-time-setup.yml @@ -1,6 +1,11 @@ name: first-time-setup run-name: Initialize repo from template +# Todo: This workflow is not working as intended - other workflows +# like deploy.yml are still running before this one finishes. + +# This workflow is triggered when a user creates a new repo from the template. + on: # run when branch created (repo generated from template) create: diff --git a/package-lock.json b/package-lock.json index 128fd11..e5593f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,18 +18,18 @@ "express": "^4.18.2", "heatmap.js": "^2.0.5", "lokijs": "^1.5.12", - "puppeteer": "^21.3.4" + "puppeteer": "^21.3.8" }, "devDependencies": { "@semantic-release/changelog": "^6.0.3", "@semantic-release/commit-analyzer": "^11.0.0", "@semantic-release/git": "^10.0.1", - "@semantic-release/github": "^9.0.7", + "@semantic-release/github": "^9.2.1", "@semantic-release/npm": "^11.0.0", "@semantic-release/release-notes-generator": "^12.0.0", "commitizen": "^4.3.0", "cz-conventional-changelog": "^3.3.0", - "eslint": "^8.50.0", + "eslint": "^8.51.0", "eslint-plugin-sonarjs": "^0.21.0", "nodemon": "^3.0.1", "semantic-release": "^22.0.5" @@ -399,9 +399,9 @@ "dev": true }, "node_modules/@eslint/js": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.50.0.tgz", - "integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", + "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -768,14 +768,6 @@ "node": ">=12" } }, - "node_modules/@puppeteer/browsers/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, "node_modules/@sapphire/async-queue": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", @@ -878,9 +870,9 @@ } }, "node_modules/@semantic-release/github": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-9.0.7.tgz", - "integrity": "sha512-SU3ayJ4/0TeIVyfCMLmuKoa4KvLclarPCmwY/zippm7sK95SwgWoFd8aFfAJIPGCRYnP3rfHRdYzphsrrNI3Cg==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-9.2.1.tgz", + "integrity": "sha512-fEn9uOe6jwWR6ro2Wh6YNBCBuZ5lRi8Myz+1j3KDTSt8OuUGlpVM4lFac/0bDrql2NOKrIEAMGCfWb9WMIdzIg==", "dev": true, "dependencies": { "@octokit/core": "^5.0.0", @@ -2036,9 +2028,9 @@ } }, "node_modules/chromium-bidi": { - "version": "0.4.28", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.28.tgz", - "integrity": "sha512-2HZ74QlAApJrEwcGlU/sUu0s4VS+FI3CJ09Toc9aE9VemMyhHZXeaROQgJKNRaYMUTUx6qIv1cLBs3F+vfgjSw==", + "version": "0.4.31", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.31.tgz", + "integrity": "sha512-OtvEg2JMRQrHsmLx4FV3u1Hf9waYxB5PmL+yM0HkFpc9H2x3TMbUqS+GP2/fC4399hzOO+EQF8uVU43By9ILag==", "dependencies": { "mitt": "3.0.1", "urlpattern-polyfill": "9.0.0" @@ -2544,9 +2536,9 @@ } }, "node_modules/data-uri-to-buffer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-5.0.1.tgz", - "integrity": "sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.1.tgz", + "integrity": "sha512-MZd3VlchQkp8rdend6vrx7MmVDJzSNTBvghvKjirLkD+WTChA3KUf0jkE68Q4UyctNqI11zZO9/x2Yx+ub5Cvg==", "engines": { "node": ">= 14" } @@ -3020,15 +3012,15 @@ } }, "node_modules/eslint": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz", - "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", + "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.50.0", + "@eslint/js": "8.51.0", "@humanwhocodes/config-array": "^0.11.11", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -3692,12 +3684,12 @@ } }, "node_modules/get-uri": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.1.tgz", - "integrity": "sha512-7ZqONUVqaabogsYNWlYj0t3YZaL6dhuEueZXGF+/YVmf6dHmaFg8/6psJKqhx9QykIDKzpGcy2cn4oV4YC7V/Q==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.2.tgz", + "integrity": "sha512-5KLucCJobh8vBY1K07EFV4+cPZH3mrV9YeAruUseCQKHB58SGjjT2l9/eA9LD082IiuMjSlFJEcdJ27TXvbZNw==", "dependencies": { "basic-ftp": "^5.0.2", - "data-uri-to-buffer": "^5.0.1", + "data-uri-to-buffer": "^6.0.0", "debug": "^4.3.4", "fs-extra": "^8.1.0" }, @@ -9060,26 +9052,26 @@ } }, "node_modules/puppeteer": { - "version": "21.3.4", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-21.3.4.tgz", - "integrity": "sha512-kE67k1KR6hQs3g0Yf/i3GYOhTU8zC2dtcpHhtcSC9bGoVxRgqDo/hwVkDqlNKxJsJHuVX+qviWC7F0FdSjcFTA==", + "version": "21.3.8", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-21.3.8.tgz", + "integrity": "sha512-4OrInVIAtDgcznENUV4Du4gYSZhRmbCkckvOoPstXrUH4JsQ3atSegY+9f/tOKCDB2qh7sXaszDcFEn+RymY0g==", "hasInstallScript": true, "dependencies": { "@puppeteer/browsers": "1.7.1", "cosmiconfig": "8.3.6", - "puppeteer-core": "21.3.4" + "puppeteer-core": "21.3.8" }, "engines": { "node": ">=16.3.0" } }, "node_modules/puppeteer-core": { - "version": "21.3.4", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-21.3.4.tgz", - "integrity": "sha512-iaG7ScTXOm9hlsBTBGGtr5dAAsA8IiWTx8E0Ghr0b5Ntl42bdcPS8EXjcERKocDhua2YqdlnFGs/cBxHY+VNyA==", + "version": "21.3.8", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-21.3.8.tgz", + "integrity": "sha512-yv12E/+zZ7Lei5tJB4sUkSrsuqKibuYpYxLGbmtLUjjYIqGE5HKz9OUI2I/RFHEvF+pHi2bTbv5bWydeCGJ6Mw==", "dependencies": { "@puppeteer/browsers": "1.7.1", - "chromium-bidi": "0.4.28", + "chromium-bidi": "0.4.31", "cross-fetch": "4.0.0", "debug": "4.3.4", "devtools-protocol": "0.0.1179426", @@ -10938,11 +10930,10 @@ "node": ">=12" } }, - "node_modules/yargs/node_modules/yargs-parser": { + "node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, "engines": { "node": ">=12" } @@ -11260,9 +11251,9 @@ } }, "@eslint/js": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.50.0.tgz", - "integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", + "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", "dev": true }, "@humanwhocodes/config-array": { @@ -11555,11 +11546,6 @@ "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" } } }, @@ -11632,9 +11618,9 @@ } }, "@semantic-release/github": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-9.0.7.tgz", - "integrity": "sha512-SU3ayJ4/0TeIVyfCMLmuKoa4KvLclarPCmwY/zippm7sK95SwgWoFd8aFfAJIPGCRYnP3rfHRdYzphsrrNI3Cg==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-9.2.1.tgz", + "integrity": "sha512-fEn9uOe6jwWR6ro2Wh6YNBCBuZ5lRi8Myz+1j3KDTSt8OuUGlpVM4lFac/0bDrql2NOKrIEAMGCfWb9WMIdzIg==", "dev": true, "requires": { "@octokit/core": "^5.0.0", @@ -12453,9 +12439,9 @@ } }, "chromium-bidi": { - "version": "0.4.28", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.28.tgz", - "integrity": "sha512-2HZ74QlAApJrEwcGlU/sUu0s4VS+FI3CJ09Toc9aE9VemMyhHZXeaROQgJKNRaYMUTUx6qIv1cLBs3F+vfgjSw==", + "version": "0.4.31", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.31.tgz", + "integrity": "sha512-OtvEg2JMRQrHsmLx4FV3u1Hf9waYxB5PmL+yM0HkFpc9H2x3TMbUqS+GP2/fC4399hzOO+EQF8uVU43By9ILag==", "requires": { "mitt": "3.0.1", "urlpattern-polyfill": "9.0.0" @@ -12821,9 +12807,9 @@ } }, "data-uri-to-buffer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-5.0.1.tgz", - "integrity": "sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg==" + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.1.tgz", + "integrity": "sha512-MZd3VlchQkp8rdend6vrx7MmVDJzSNTBvghvKjirLkD+WTChA3KUf0jkE68Q4UyctNqI11zZO9/x2Yx+ub5Cvg==" }, "debug": { "version": "4.3.4", @@ -13151,15 +13137,15 @@ } }, "eslint": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz", - "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", + "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.50.0", + "@eslint/js": "8.51.0", "@humanwhocodes/config-array": "^0.11.11", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -13664,12 +13650,12 @@ "dev": true }, "get-uri": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.1.tgz", - "integrity": "sha512-7ZqONUVqaabogsYNWlYj0t3YZaL6dhuEueZXGF+/YVmf6dHmaFg8/6psJKqhx9QykIDKzpGcy2cn4oV4YC7V/Q==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.2.tgz", + "integrity": "sha512-5KLucCJobh8vBY1K07EFV4+cPZH3mrV9YeAruUseCQKHB58SGjjT2l9/eA9LD082IiuMjSlFJEcdJ27TXvbZNw==", "requires": { "basic-ftp": "^5.0.2", - "data-uri-to-buffer": "^5.0.1", + "data-uri-to-buffer": "^6.0.0", "debug": "^4.3.4", "fs-extra": "^8.1.0" }, @@ -17399,22 +17385,22 @@ "dev": true }, "puppeteer": { - "version": "21.3.4", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-21.3.4.tgz", - "integrity": "sha512-kE67k1KR6hQs3g0Yf/i3GYOhTU8zC2dtcpHhtcSC9bGoVxRgqDo/hwVkDqlNKxJsJHuVX+qviWC7F0FdSjcFTA==", + "version": "21.3.8", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-21.3.8.tgz", + "integrity": "sha512-4OrInVIAtDgcznENUV4Du4gYSZhRmbCkckvOoPstXrUH4JsQ3atSegY+9f/tOKCDB2qh7sXaszDcFEn+RymY0g==", "requires": { "@puppeteer/browsers": "1.7.1", "cosmiconfig": "8.3.6", - "puppeteer-core": "21.3.4" + "puppeteer-core": "21.3.8" } }, "puppeteer-core": { - "version": "21.3.4", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-21.3.4.tgz", - "integrity": "sha512-iaG7ScTXOm9hlsBTBGGtr5dAAsA8IiWTx8E0Ghr0b5Ntl42bdcPS8EXjcERKocDhua2YqdlnFGs/cBxHY+VNyA==", + "version": "21.3.8", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-21.3.8.tgz", + "integrity": "sha512-yv12E/+zZ7Lei5tJB4sUkSrsuqKibuYpYxLGbmtLUjjYIqGE5HKz9OUI2I/RFHEvF+pHi2bTbv5bWydeCGJ6Mw==", "requires": { "@puppeteer/browsers": "1.7.1", - "chromium-bidi": "0.4.28", + "chromium-bidi": "0.4.31", "cross-fetch": "4.0.0", "debug": "4.3.4", "devtools-protocol": "0.0.1179426", @@ -18735,16 +18721,13 @@ "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" - }, - "dependencies": { - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - } } }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" + }, "yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", diff --git a/package.json b/package.json index 1154c94..243ebb1 100644 --- a/package.json +++ b/package.json @@ -41,19 +41,19 @@ "dotenv": "^16.3.1", "express": "^4.18.2", "heatmap.js": "^2.0.5", - "puppeteer": "^21.3.4", + "puppeteer": "^21.3.8", "lokijs": "^1.5.12" }, "devDependencies": { "@semantic-release/changelog": "^6.0.3", "@semantic-release/commit-analyzer": "^11.0.0", "@semantic-release/git": "^10.0.1", - "@semantic-release/github": "^9.0.7", + "@semantic-release/github": "^9.2.1", "@semantic-release/npm": "^11.0.0", "@semantic-release/release-notes-generator": "^12.0.0", "commitizen": "^4.3.0", "cz-conventional-changelog": "^3.3.0", - "eslint": "^8.50.0", + "eslint": "^8.51.0", "eslint-plugin-sonarjs": "^0.21.0", "nodemon": "^3.0.1", "semantic-release": "^22.0.5" diff --git a/src/commands/admin/change-game-time.js b/src/commands/admin/change-game-time.js new file mode 100644 index 0000000..0d9a99e --- /dev/null +++ b/src/commands/admin/change-game-time.js @@ -0,0 +1,88 @@ +const { ApplicationCommandOptionType } = require('discord.js'); +const { ChatInputCommand } = require('../../classes/Commands'); +const { + requiredServerConfigCommandOption, + getServerConfigCommandOptionValue, + postGameLabsAction, + broadcastMessage +} = require('../../modules/cftClient'); + +module.exports = new ChatInputCommand({ + permLevel: 'Administrator', + global: true, + data: { + description: 'Change the current in-game time', + options: [ + requiredServerConfigCommandOption, + { + name: 'hour', + description: 'The hour to set the time to', + type: ApplicationCommandOptionType.Integer, + required: true, + min_value: 0, + max_value: 23 + }, + { + name: 'minute', + description: 'The minute to set the time to', + type: ApplicationCommandOptionType.Integer, + required: true, + min_value: 0, + max_value: 59 + }, + { + name: 'notify-players', + description: 'Send a global notification to the players, default true', + type: ApplicationCommandOptionType.Boolean, + required: false + } + ] + }, + + run: async (client, interaction) => { + // Destructuring + const { member, options } = interaction; + const { emojis } = client.container; + const hour = options.getInteger('hour'); + const minute = options.getInteger('minute'); + const notifyPlayers = options.getBoolean('notify-players') ?? true; + + // Deferring our reply + await interaction.deferReply(); + + // Resolve options + const serverCfg = getServerConfigCommandOptionValue(interaction); + + // Performing request + const res = await postGameLabsAction( + serverCfg.CFTOOLS_SERVER_API_ID, + 'CFCloud_WorldTime', + 'world', + null, + { + hour: { valueInt: hour }, + minute: { valueInt: minute } + } + ); + + if (res !== true) { + interaction.editReply({ content: `${ emojis.error } ${ member }, invalid response code - time might not have been updated` }); + return; + } + + const hourStr = hour.toString().padStart(2, '0'); + const minuteStr = minute.toString().padStart(2, '0'); + const timeStr = `${ hourStr }:${ minuteStr }`; + + // Notify player + if (notifyPlayers) { + await broadcastMessage( + serverCfg.CFTOOLS_SERVER_API_ID, + `The time has been changed to ${ timeStr } by an administrator (this might take a while to take effect)` + ); + } + + // User feedback on success + interaction.editReply({ content: `${ emojis.success } ${ member }, time has been changed to **\`${ timeStr }\`**!` }); + } +}); diff --git a/src/commands/admin/change-game-weather.js b/src/commands/admin/change-game-weather.js new file mode 100644 index 0000000..c520315 --- /dev/null +++ b/src/commands/admin/change-game-weather.js @@ -0,0 +1,111 @@ +const { ApplicationCommandOptionType } = require('discord.js'); +const { ChatInputCommand } = require('../../classes/Commands'); +const { + requiredServerConfigCommandOption, + getServerConfigCommandOptionValue, + postGameLabsAction, + broadcastMessage +} = require('../../modules/cftClient'); + +module.exports = new ChatInputCommand({ + permLevel: 'Administrator', + global: true, + data: { + description: 'Change the current in-game weather', + options: [ + requiredServerConfigCommandOption, + { + name: 'overcast', + description: 'The overcast value to set', + type: ApplicationCommandOptionType.Number, + required: true, + min_value: 0.0000, + max_value: 1.0000 + }, + { + name: 'fog', + description: 'The fog value to set', + type: ApplicationCommandOptionType.Number, + required: true, + min_value: 0.0000, + max_value: 1.0000 + }, + { + name: 'rain', + description: 'The rain value to set', + type: ApplicationCommandOptionType.Number, + required: true, + min_value: 0.0000, + max_value: 1.0000 + }, + { + name: 'wind', + description: 'The wind value to set, in km/h', + type: ApplicationCommandOptionType.Integer, + required: true, + min_value: 0, + max_value: 100 + }, + { + name: 'notify-players', + description: 'Send a global notification to the players, default true', + type: ApplicationCommandOptionType.Boolean, + required: false + } + ] + }, + + run: async (client, interaction) => { + // Destructuring + const { member, options } = interaction; + const { emojis } = client.container; + const overcast = options.getNumber('overcast'); + const fog = options.getNumber('fog'); + const rain = options.getNumber('rain'); + const wind = options.getInteger('wind'); + const notifyPlayers = options.getBoolean('notify-players') ?? true; + + // Deferring our reply + await interaction.deferReply(); + + // Resolve options + const serverCfg = getServerConfigCommandOptionValue(interaction); + + // Performing request + const res = await postGameLabsAction( + serverCfg.CFTOOLS_SERVER_API_ID, + 'CFCloud_WorldWeather', + 'world', + null, + { + overcast: { valueFloat: overcast }, + fog: { valueFloat: fog }, + rain: { valueFloat: rain }, + wind: { valueInt: wind } + } + ); + + if (res !== true) { + interaction.editReply({ content: `${ emojis.error } ${ member }, invalid response code - weather might not have been updated` }); + return; + } + + // Resolve weather string + const overcastStr = overcast.toFixed(2); + const fogStr = fog.toFixed(2); + const rainStr = rain.toFixed(2); + const windStr = wind.toString().padStart(3, '0'); + const weatherStr = `Overcast: ${ overcastStr }\nFog: ${ fogStr }\nRain: ${ rainStr }\nWind: ${ windStr }`; + + // Notify player + if (notifyPlayers) { + await broadcastMessage( + serverCfg.CFTOOLS_SERVER_API_ID, + 'The weather has been changed by an administrator (this might take a while to take effect)' + ); + } + + // User feedback on success + interaction.editReply({ content: `${ emojis.success } ${ member }, weather has been changed to:\n\n\`\`\`${ weatherStr }\`\`\`` }); + } +}); diff --git a/src/commands/admin/set-weather-stormy.js b/src/commands/admin/set-weather-stormy.js new file mode 100644 index 0000000..30a5b59 --- /dev/null +++ b/src/commands/admin/set-weather-stormy.js @@ -0,0 +1,79 @@ +const { ApplicationCommandOptionType } = require('discord.js'); +const { ChatInputCommand } = require('../../classes/Commands'); +const { + requiredServerConfigCommandOption, + getServerConfigCommandOptionValue, + postGameLabsAction, + broadcastMessage +} = require('../../modules/cftClient'); + +module.exports = new ChatInputCommand({ + permLevel: 'Administrator', + global: true, + data: { + description: 'Change the current in-game weather', + options: [ + requiredServerConfigCommandOption, + { + name: 'notify-players', + description: 'Send a global notification to the players, default true', + type: ApplicationCommandOptionType.Boolean, + required: false + } + ] + }, + + run: async (client, interaction) => { + // Destructuring + const { member, options } = interaction; + const { emojis } = client.container; + const notifyPlayers = options.getBoolean('notify-players') ?? true; + + // Deferring our reply + await interaction.deferReply(); + + // Resolve options + const serverCfg = getServerConfigCommandOptionValue(interaction); + + // Performing request + const overcast = 1.00; + const fog = .35; + const rain = .9; + const wind = .75; + const res = await postGameLabsAction( + serverCfg.CFTOOLS_SERVER_API_ID, + 'CFCloud_WorldWeather', + 'world', + null, + { + overcast: { valueFloat: overcast }, + fog: { valueFloat: fog }, + rain: { valueFloat: rain }, + wind: { valueInt: wind } + } + ); + + if (res !== true) { + interaction.editReply({ content: `${ emojis.error } ${ member }, invalid response code - weather might not have been updated to \`stormy\`` }); + return; + } + + // Resolve weather string + const overcastStr = overcast.toFixed(2); + const fogStr = fog.toFixed(2); + const rainStr = rain.toFixed(2); + const windStr = wind.toString().padStart(3, '0'); + const weatherStr = `Overcast: ${ overcastStr }\nFog: ${ fogStr }\nRain: ${ rainStr }\nWind: ${ windStr }`; + + // Notify player + if (notifyPlayers) { + await broadcastMessage( + serverCfg.CFTOOLS_SERVER_API_ID, + 'The weather has been changed to stormy by an administrator (this might take a while to take effect)' + ); + } + + // User feedback on success + interaction.editReply({ content: `${ emojis.success } ${ member }, weather has been changed to:\n\n\`\`\`${ weatherStr }\`\`\`` }); + } +}); diff --git a/src/commands/admin/set-weather-sunny.js b/src/commands/admin/set-weather-sunny.js new file mode 100644 index 0000000..f8cd0e8 --- /dev/null +++ b/src/commands/admin/set-weather-sunny.js @@ -0,0 +1,63 @@ +const { ApplicationCommandOptionType } = require('discord.js'); +const { ChatInputCommand } = require('../../classes/Commands'); +const { + requiredServerConfigCommandOption, + getServerConfigCommandOptionValue, + postGameLabsAction, + broadcastMessage +} = require('../../modules/cftClient'); + +module.exports = new ChatInputCommand({ + permLevel: 'Administrator', + global: true, + data: { + description: 'Change the current in-game weather to by clear & sunny', + options: [ + requiredServerConfigCommandOption, + { + name: 'notify-players', + description: 'Send a global notification to the players, default true', + type: ApplicationCommandOptionType.Boolean, + required: false + } + ] + }, + + run: async (client, interaction) => { + // Destructuring + const { member, options } = interaction; + const { emojis } = client.container; + const notifyPlayers = options.getBoolean('notify-players') ?? true; + + // Deferring our reply + await interaction.deferReply(); + + // Resolve options + const serverCfg = getServerConfigCommandOptionValue(interaction); + + // Performing request + const res = await postGameLabsAction( + serverCfg.CFTOOLS_SERVER_API_ID, + 'CFCloud_WorldWeatherSunny', + 'world', + null, + {} + ); + + if (res !== true) { + interaction.editReply({ content: `${ emojis.error } ${ member }, invalid response code - weather might not have been updated to clear/sunny` }); + return; + } + + // Notify player + if (notifyPlayers) { + await broadcastMessage( + serverCfg.CFTOOLS_SERVER_API_ID, + 'The weather has been changed to clear/sunny by an administrator (this might take a while to take effect)' + ); + } + + // User feedback on success + interaction.editReply({ content: `${ emojis.success } ${ member }, weather has been changed to **\`sunny/clear\`**` }); + } +}); diff --git a/src/commands/admin/spawn-item-on-coords.js b/src/commands/admin/spawn-item-on-coords.js new file mode 100644 index 0000000..5ba7fef --- /dev/null +++ b/src/commands/admin/spawn-item-on-coords.js @@ -0,0 +1,145 @@ +const { ApplicationCommandOptionType } = require('discord.js'); +const { ChatInputCommand } = require('../../classes/Commands'); +const { + requiredServerConfigCommandOption, + getServerConfigCommandOptionValue, + postGameLabsAction, + broadcastMessage +} = require('../../modules/cftClient'); + +module.exports = new ChatInputCommand({ + permLevel: 'Administrator', + global: true, + data: { + description: 'Spawn an item at provided coordinates', + options: [ + requiredServerConfigCommandOption, + { + name: 'item-class', + description: 'The class name of the item to give to the player', + type: ApplicationCommandOptionType.String, + required: true, + min_length: 1, + max_length: 256 + }, + { + name: 'x-coordinate', + description: 'The X level coordinate to teleport the player to', + type: ApplicationCommandOptionType.Number, + required: true, + min_value: 0.0000, + max_value: 100000.000 + }, + { + name: 'y-coordinate', + description: 'The Y level coordinate to teleport the player to', + type: ApplicationCommandOptionType.Number, + required: true, + min_value: 0.0000, + max_value: 100000.000 + }, + { + name: 'z-coordinate', + description: 'The Z level coordinate to teleport the player to', + type: ApplicationCommandOptionType.Number, + required: true, + min_value: 0.0000, + max_value: 100000.000 + }, + { + name: 'quantity', + description: 'The quantity for this item, default is 1', + type: ApplicationCommandOptionType.Number, + required: false, + min_value: 0.0000, + max_value: 1000 + }, + { + name: 'stacked', + description: 'Spawn items as a stack (only works if item supports to be stacked), default is false', + type: ApplicationCommandOptionType.Boolean, + required: false + }, + { + name: 'debug', + description: 'Use debug spawn method to automatically populate specific items', + type: ApplicationCommandOptionType.Boolean, + required: false + }, + { + name: 'notify-players', + description: 'Send a global notification to the players, default FALSE', + type: ApplicationCommandOptionType.Boolean, + required: false + } + ] + }, + + run: async (client, interaction) => { + // Destructuring + const { member, options } = interaction; + const { emojis } = client.container; + const itemClass = options.getString('item-class'); + const quantity = options.getNumber('quantity') ?? 1; + const stacked = options.getBoolean('stacked') ?? false; + const debug = options.getBoolean('debug') ?? false; + const x = options.getNumber('x-coordinate'); + const y = options.getNumber('y-coordinate'); + const z = options.getNumber('z-coordinate'); + const notifyPlayers = options.getBoolean('notify-players') ?? false; + + // Deferring our reply + await interaction.deferReply(); + + // Resolve options + const serverCfg = getServerConfigCommandOptionValue(interaction); + + // Performing request + const res = await postGameLabsAction( + serverCfg.CFTOOLS_SERVER_API_ID, + 'CFCloud_SpawnItemWorld', + 'world', + null, + { + vector: { + dataType: 'vector', + valueVectorX: x, + valueVectorY: y, + valueVectorZ: z + }, + item: { + dataType: 'string', + valueString: itemClass + }, + quantity: { + dataType: 'int', + valueInt: quantity + }, + stacked: { + dataType: 'boolean', + valueBool: stacked + }, + debug: { + dataType: 'boolean', + valueBool: debug + } + } + ); + + if (res !== true) { + interaction.editReply({ content: `${ emojis.error } ${ member }, invalid response code - item might not have been spawned at provided coordinates` }); + return; + } + + // Notify player + if (notifyPlayers) { + await broadcastMessage( + serverCfg.CFTOOLS_SERVER_API_ID, + `${ itemClass } has spawned at ${ x }, ${ y }, ${ z }!` + ); + } + + // User feedback on success + interaction.editReply({ content: `${ emojis.success } ${ member }, ${ itemClass } has been spawned at ${ x }, ${ y }, ${ z }` }); + } +}); diff --git a/src/commands/admin/spawn-item.js b/src/commands/admin/spawn-item-on-player.js similarity index 100% rename from src/commands/admin/spawn-item.js rename to src/commands/admin/spawn-item-on-player.js diff --git a/src/commands/admin/wipe-world-ai.js b/src/commands/admin/wipe-world-ai.js new file mode 100644 index 0000000..76c1b0a --- /dev/null +++ b/src/commands/admin/wipe-world-ai.js @@ -0,0 +1,63 @@ +const { ApplicationCommandOptionType } = require('discord.js'); +const { ChatInputCommand } = require('../../classes/Commands'); +const { + requiredServerConfigCommandOption, + getServerConfigCommandOptionValue, + postGameLabsAction, + broadcastMessage +} = require('../../modules/cftClient'); + +module.exports = new ChatInputCommand({ + permLevel: 'Administrator', + global: true, + data: { + description: 'Wipe/clear all AI from the world', + options: [ + requiredServerConfigCommandOption, + { + name: 'notify-players', + description: 'Send a global notification to the players, default true', + type: ApplicationCommandOptionType.Boolean, + required: false + } + ] + }, + + run: async (client, interaction) => { + // Destructuring + const { member, options } = interaction; + const { emojis } = client.container; + const notifyPlayers = options.getBoolean('notify-players') ?? true; + + // Deferring our reply + await interaction.deferReply(); + + // Resolve options + const serverCfg = getServerConfigCommandOptionValue(interaction); + + // Performing request + const res = await postGameLabsAction( + serverCfg.CFTOOLS_SERVER_API_ID, + 'CFCloud_WorldWipeAI', + 'world', + null, + {} + ); + + if (res !== true) { + interaction.editReply({ content: `${ emojis.error } ${ member }, invalid response code - AI might not have been wiped` }); + return; + } + + // Notify player + if (notifyPlayers) { + await broadcastMessage( + serverCfg.CFTOOLS_SERVER_API_ID, + 'All AI has been wiped/cleared by an administrator (this might take a while to take effect)' + ); + } + + // User feedback on success + interaction.editReply({ content: `${ emojis.success } ${ member }, all world AI has been wiped/cleared` }); + } +}); diff --git a/src/commands/admin/wipe-world-vehicles.js b/src/commands/admin/wipe-world-vehicles.js new file mode 100644 index 0000000..45fd307 --- /dev/null +++ b/src/commands/admin/wipe-world-vehicles.js @@ -0,0 +1,63 @@ +const { ApplicationCommandOptionType } = require('discord.js'); +const { ChatInputCommand } = require('../../classes/Commands'); +const { + requiredServerConfigCommandOption, + getServerConfigCommandOptionValue, + postGameLabsAction, + broadcastMessage +} = require('../../modules/cftClient'); + +module.exports = new ChatInputCommand({ + permLevel: 'Administrator', + global: true, + data: { + description: 'Wipe/clear all vehicles from the world', + options: [ + requiredServerConfigCommandOption, + { + name: 'notify-players', + description: 'Send a global notification to the players, default true', + type: ApplicationCommandOptionType.Boolean, + required: false + } + ] + }, + + run: async (client, interaction) => { + // Destructuring + const { member, options } = interaction; + const { emojis } = client.container; + const notifyPlayers = options.getBoolean('notify-players') ?? true; + + // Deferring our reply + await interaction.deferReply(); + + // Resolve options + const serverCfg = getServerConfigCommandOptionValue(interaction); + + // Performing request + const res = await postGameLabsAction( + serverCfg.CFTOOLS_SERVER_API_ID, + 'CFCloud_WorldWipeVehicles', + 'world', + null, + {} + ); + + if (res !== true) { + interaction.editReply({ content: `${ emojis.error } ${ member }, invalid response code - vehicles might not have been wiped` }); + return; + } + + // Notify player + if (notifyPlayers) { + await broadcastMessage( + serverCfg.CFTOOLS_SERVER_API_ID, + 'All vehicles has been wiped/cleared by an administrator (this might take a while to take effect)' + ); + } + + // User feedback on success + interaction.editReply({ content: `${ emojis.success } ${ member }, all world vehicles have been wiped/cleared` }); + } +}); diff --git a/src/commands/moderator/explode-player.js b/src/commands/moderator/explode-player.js new file mode 100644 index 0000000..d92a025 --- /dev/null +++ b/src/commands/moderator/explode-player.js @@ -0,0 +1,69 @@ +const { ApplicationCommandOptionType } = require('discord.js'); +const { ChatInputCommand } = require('../../classes/Commands'); +const { + requiredServerConfigCommandOption, + requiredPlayerSessionOption, + getServerConfigCommandOptionValue, + getPlayerSessionOptionValue, + messageSurvivor, + postGameLabsAction +} = require('../../modules/cftClient'); + +module.exports = new ChatInputCommand({ + permLevel: 'Administrator', + global: true, + data: { + description: 'Explode a player that is currently online', + options: [ + requiredServerConfigCommandOption, + requiredPlayerSessionOption, + { + name: 'notify-player', + description: 'Send a DM to the player as a notification, default true', + type: ApplicationCommandOptionType.Boolean, + required: false + } + ] + }, + + run: async (client, interaction) => { + // Destructuring + const { member, options } = interaction; + const { emojis } = client.container; + const notifyPlayer = options.getBoolean('notify-player') ?? true; + + // Deferring our reply + await interaction.deferReply(); + + // Resolve options + const serverCfg = getServerConfigCommandOptionValue(interaction); + const session = await getPlayerSessionOptionValue(interaction); + + // Check session, might have logged out + if (!session) { + interaction.editReply(`${ emojis.error } ${ member }, can't resolve provided player/session, player most likely logged out - this command has been cancelled`); + return; + } + + // Performing request + const res = await postGameLabsAction( + serverCfg.CFTOOLS_SERVER_API_ID, + 'CFCloud_ExplodePlayer', + 'player', + session.steamId.id + ); + + if (res !== true) { + interaction.editReply({ content: `${ emojis.error } ${ member }, invalid response code - **\`${ session.playerName }\`** might not have been killed by explosion` }); + return; + } + + // Notify player + if (notifyPlayer) { + await messageSurvivor(serverCfg.CFTOOLS_SERVER_API_ID, session.id, 'You have been killed by an explosion, as executed by an administrator'); + } + + // User feedback on success + interaction.editReply({ content: `${ emojis.success } ${ member }, **\`${ session.playerName }\`** has been killed by an explosion!` }); + } +}); diff --git a/src/commands/moderator/heal.js b/src/commands/moderator/heal-player.js similarity index 69% rename from src/commands/moderator/heal.js rename to src/commands/moderator/heal-player.js index 6401ff2..2dd0546 100644 --- a/src/commands/moderator/heal.js +++ b/src/commands/moderator/heal-player.js @@ -4,22 +4,35 @@ const { requiredPlayerSessionOption, requiredServerConfigCommandOption, getPlayerSessionOptionValue, - cftClient + cftClient, + messageSurvivor } = require('../../modules/cftClient'); const { ChatInputCommand } = require('../../classes/Commands'); const { ServerApiId } = require('cftools-sdk'); +const { ApplicationCommandOptionType } = require('discord.js'); module.exports = new ChatInputCommand({ global: true, permLevel: 'Moderator', data: { description: 'Heal a player that is currently online', - options: [ requiredServerConfigCommandOption, requiredPlayerSessionOption ] + options: [ + requiredServerConfigCommandOption, + requiredPlayerSessionOption, + { + name: 'notify-player', + description: 'Send a DM to the player as a notification, default true', + type: ApplicationCommandOptionType.Boolean, + required: false + } + + ] }, run: async (client, interaction) => { // Destructuring and assignments const { member } = interaction; const { emojis } = client.container; + const notifyPlayer = interaction.options.getBoolean('notify-player') ?? true; const serverCfg = getServerConfigCommandOptionValue(interaction); // Deferring our reply @@ -44,6 +57,11 @@ module.exports = new ChatInputCommand({ return; } + // Notify player + if (notifyPlayer) { + await messageSurvivor(serverCfg.CFTOOLS_SERVER_API_ID, session.id, 'You have been healed by an administrator'); + } + // Ok, feedback interaction.editReply({ content: `${ emojis.success } ${ member }, **\`${ session.playerName }\`** has been healed` }); } diff --git a/src/commands/moderator/kick.js b/src/commands/moderator/kick-player.js similarity index 100% rename from src/commands/moderator/kick.js rename to src/commands/moderator/kick-player.js diff --git a/src/commands/moderator/kill-player.js b/src/commands/moderator/kill-player.js new file mode 100644 index 0000000..2a38c27 --- /dev/null +++ b/src/commands/moderator/kill-player.js @@ -0,0 +1,69 @@ +const { ApplicationCommandOptionType } = require('discord.js'); +const { ChatInputCommand } = require('../../classes/Commands'); +const { + requiredServerConfigCommandOption, + requiredPlayerSessionOption, + getServerConfigCommandOptionValue, + getPlayerSessionOptionValue, + messageSurvivor, + postGameLabsAction +} = require('../../modules/cftClient'); + +module.exports = new ChatInputCommand({ + permLevel: 'Administrator', + global: true, + data: { + description: 'Kill a player that is currently online', + options: [ + requiredServerConfigCommandOption, + requiredPlayerSessionOption, + { + name: 'notify-player', + description: 'Send a DM to the player as a notification, default true', + type: ApplicationCommandOptionType.Boolean, + required: false + } + ] + }, + + run: async (client, interaction) => { + // Destructuring + const { member, options } = interaction; + const { emojis } = client.container; + const notifyPlayer = options.getBoolean('notify-player') ?? true; + + // Deferring our reply + await interaction.deferReply(); + + // Resolve options + const serverCfg = getServerConfigCommandOptionValue(interaction); + const session = await getPlayerSessionOptionValue(interaction); + + // Check session, might have logged out + if (!session) { + interaction.editReply(`${ emojis.error } ${ member }, can't resolve provided player/session, player most likely logged out - this command has been cancelled`); + return; + } + + // Performing request + const res = await postGameLabsAction( + serverCfg.CFTOOLS_SERVER_API_ID, + 'CFCloud_KillPlayer', + 'player', + session.steamId.id + ); + + if (res !== true) { + interaction.editReply({ content: `${ emojis.error } ${ member }, invalid response code - **\`${ session.playerName }\`** might not have been killed` }); + return; + } + + // Notify player + if (notifyPlayer) { + await messageSurvivor(serverCfg.CFTOOLS_SERVER_API_ID, session.id, 'You have been killed by an administrator'); + } + + // User feedback on success + interaction.editReply({ content: `${ emojis.success } ${ member }, **\`${ session.playerName }\`** has been killed!` }); + } +}); diff --git a/src/commands/moderator/strip-player.js b/src/commands/moderator/strip-player.js new file mode 100644 index 0000000..250bc9f --- /dev/null +++ b/src/commands/moderator/strip-player.js @@ -0,0 +1,69 @@ +const { ApplicationCommandOptionType } = require('discord.js'); +const { ChatInputCommand } = require('../../classes/Commands'); +const { + requiredServerConfigCommandOption, + requiredPlayerSessionOption, + getServerConfigCommandOptionValue, + getPlayerSessionOptionValue, + messageSurvivor, + postGameLabsAction +} = require('../../modules/cftClient'); + +module.exports = new ChatInputCommand({ + permLevel: 'Administrator', + global: true, + data: { + description: 'Strip a player that is currently online, removing everything from their inventory', + options: [ + requiredServerConfigCommandOption, + requiredPlayerSessionOption, + { + name: 'notify-player', + description: 'Send a DM to the player as a notification, default true', + type: ApplicationCommandOptionType.Boolean, + required: false + } + ] + }, + + run: async (client, interaction) => { + // Destructuring + const { member, options } = interaction; + const { emojis } = client.container; + const notifyPlayer = options.getBoolean('notify-player') ?? true; + + // Deferring our reply + await interaction.deferReply(); + + // Resolve options + const serverCfg = getServerConfigCommandOptionValue(interaction); + const session = await getPlayerSessionOptionValue(interaction); + + // Check session, might have logged out + if (!session) { + interaction.editReply(`${ emojis.error } ${ member }, can't resolve provided player/session, player most likely logged out - this command has been cancelled`); + return; + } + + // Performing request + const res = await postGameLabsAction( + serverCfg.CFTOOLS_SERVER_API_ID, + 'CFCloud_StripPlayer', + 'player', + session.steamId.id + ); + + if (res !== true) { + interaction.editReply({ content: `${ emojis.error } ${ member }, invalid response code - **\`${ session.playerName }\`** might not have been killed by stripped` }); + return; + } + + // Notify player + if (notifyPlayer) { + await messageSurvivor(serverCfg.CFTOOLS_SERVER_API_ID, session.id, 'You have been stripped of all your possessions by an administrator'); + } + + // User feedback on success + interaction.editReply({ content: `${ emojis.success } ${ member }, **\`${ session.playerName }\`** has been stripped of all their possessions!` }); + } +}); diff --git a/src/commands/admin/teleport-all-to-location.js b/src/commands/teleport/teleport-all-to-location.js similarity index 100% rename from src/commands/admin/teleport-all-to-location.js rename to src/commands/teleport/teleport-all-to-location.js diff --git a/src/commands/admin/teleport-all-to-player.js b/src/commands/teleport/teleport-all-to-player.js similarity index 100% rename from src/commands/admin/teleport-all-to-player.js rename to src/commands/teleport/teleport-all-to-player.js diff --git a/src/commands/admin/teleport-multiple-to-location.js b/src/commands/teleport/teleport-multiple-to-location.js similarity index 100% rename from src/commands/admin/teleport-multiple-to-location.js rename to src/commands/teleport/teleport-multiple-to-location.js diff --git a/src/commands/admin/teleport-multiple-to-player.js b/src/commands/teleport/teleport-multiple-to-player.js similarity index 100% rename from src/commands/admin/teleport-multiple-to-player.js rename to src/commands/teleport/teleport-multiple-to-player.js diff --git a/src/commands/admin/teleport-to-coords.js b/src/commands/teleport/teleport-to-coords.js similarity index 100% rename from src/commands/admin/teleport-to-coords.js rename to src/commands/teleport/teleport-to-coords.js diff --git a/src/commands/admin/teleport-to-location.js b/src/commands/teleport/teleport-to-location.js similarity index 100% rename from src/commands/admin/teleport-to-location.js rename to src/commands/teleport/teleport-to-location.js diff --git a/src/commands/admin/teleport-to-player.js b/src/commands/teleport/teleport-to-player.js similarity index 100% rename from src/commands/admin/teleport-to-player.js rename to src/commands/teleport/teleport-to-player.js diff --git a/src/modules/cftClient.js b/src/modules/cftClient.js index 1854d01..f925cfe 100644 --- a/src/modules/cftClient.js +++ b/src/modules/cftClient.js @@ -293,6 +293,38 @@ const kickPlayer = async ( } }; +const postGameLabsAction = async ( + CFTOOLS_SERVER_API_ID, + actionCode, + actionContext, + referenceKey, + parameters = {} +) => { + try { + const body = { + actionCode, + actionContext, + parameters + }; + if (referenceKey) body.referenceKey = referenceKey; + const data = await fetch( + `${ CFTOOLS_API_URL }/server/${ CFTOOLS_SERVER_API_ID }/GameLabs/action`, + { + method: 'POST', + headers: { Authorization: `Bearer ${ await getAPIToken() }` }, + body: JSON.stringify(body) + } + ); + return data?.status === 204; + } + catch (err) { + logger.syserr('Error encounter while POSTing GameLabs action'); + logger.printErr(err); + return null; + } +}; + + // Position data isn't currently included in cftools-sdk =( // JK, FlorianSW added it =) // const gsmCache = new Map(); @@ -353,5 +385,6 @@ module.exports = { getAPIToken, messageSurvivor, broadcastMessage, - kickPlayer + kickPlayer, + postGameLabsAction };