diff --git a/API/functions/getLatestProfile.js b/API/functions/getLatestProfile.js index e9b0bcc6..c540b360 100644 --- a/API/functions/getLatestProfile.js +++ b/API/functions/getLatestProfile.js @@ -18,7 +18,12 @@ async function getLatestProfile(uuid) { axios.get( `https://api.hypixel.net/skyblock/profiles?key=${config.api.hypixelAPIkey}&uuid=${uuid}` ), - ]); + ]).catch( + (error) => { + // eslint-disable-next-line no-throw-literal + throw error?.response?.data?.cause ?? "Request to Hypixel API failed. Please try again!"; + } + ) playerRes = playerRes?.data ?? {}; profileRes = profileRes?.data ?? {}; @@ -68,7 +73,6 @@ async function getLatestProfile(uuid) { }; } catch (error) { - throw error; } } diff --git a/config.example.json b/config.example.json index 634aadca..88f4ff2d 100644 --- a/config.example.json +++ b/config.example.json @@ -4,7 +4,8 @@ "guildID": "HYPIXEL_GUILD_ID", "guildExp": 0, "messageRepeatBypass": true, - "messageRepeatBypassLength": 24 + "messageRepeatBypassLength": 24, + "messageFormat": " »" }, "discord": { "token": "TOKEN", diff --git a/data/skyblockNotifer.json b/data/skyblockNotifer.json index 67ce3ae1..1922ceee 100644 --- a/data/skyblockNotifer.json +++ b/data/skyblockNotifer.json @@ -94,7 +94,10 @@ "Minecraft Server and Public API Unavailable | Monitoring - A fix has been implemented and we are slowly re-opening the server to players. | Feb 6, 18:58 EST", "Minecraft Server and Public API Unavailable | Investigating - We are currently investigating a major issue with our backend systems causing the Minecraft Server and Public API to be unavailable. | Feb 6, 17:41 EST", "SkyBlock Profiles API | Resolved - We have made some backend changes with the aim to improve the recent issues of increased response times on the SkyBlock profiles API and it is now operating normally. We will be monitoring the results over the coming days and will made additional changes if needed. | Feb 4, 17:49 EST", - "SkyBlock Profiles API | Investigating - We are investigating issues with the SkyBlock Profiles endpoints on the Hypixel Public API. During this time the endpoint may be disabled while we attempt to investigate and work on a solution. | Feb 4, 14:32 EST" + "SkyBlock Profiles API | Investigating - We are investigating issues with the SkyBlock Profiles endpoints on the Hypixel Public API. During this time the endpoint may be disabled while we attempt to investigate and work on a solution. | Feb 4, 14:32 EST", + "SkyBlock Update 0.18 | Completed - The scheduled maintenance has been completed. | Feb 14, 12:18 EST", + "SkyBlock Update 0.18 | In progress - SkyBlock is currently undergoing maintenance for the release of 0.18. | Feb 14, 09:56 EST", + "SkyBlock Update 0.18 | Scheduled - SkyBlock will be undergoing maintenance for the release of 0.18. | Feb 14, 09:51 EST" ], "skyblockUpdates": [ "[December 13] SkyBlock Patch Notes | https://hypixel.net/threads/december-13-skyblock-patch-notes.5199900/ | Tue, 10 Jan 2023 23:14:20 +0000", @@ -120,6 +123,11 @@ "[February 3] Autopet Changes | https://hypixel.net/threads/february-3-autopet-changes.5262861/ | Wed, 08 Feb 2023 05:11:13 +0000", "[February 6] SkyBlock Patch Notes | https://hypixel.net/threads/february-6-skyblock-patch-notes.5266045/ | Wed, 08 Feb 2023 05:10:43 +0000", "[February 2] Patch 0.17.3 Bug Fixes | https://hypixel.net/threads/february-2-patch-0-17-3-bug-fixes.5261361/ | Wed, 08 Feb 2023 04:59:09 +0000", - "[January 10th] Some Bug Fixes | https://hypixel.net/threads/january-10th-some-bug-fixes.5233523/ | Sun, 29 Jan 2023 11:32:32 +0000" + "[January 10th] Some Bug Fixes | https://hypixel.net/threads/january-10th-some-bug-fixes.5233523/ | Sun, 29 Jan 2023 11:32:32 +0000", + "[February 16] Final Dungeon Journals | https://hypixel.net/threads/february-16-final-dungeon-journals.5276354/ | Mon, 20 Feb 2023 14:27:42 +0000", + "[February 3] Autopet Changes | https://hypixel.net/threads/february-3-autopet-changes.5262861/ | Wed, 15 Feb 2023 13:47:12 +0000", + "[February 2] Patch 0.17.3 Bug Fixes | https://hypixel.net/threads/february-2-patch-0-17-3-bug-fixes.5261361/ | Tue, 14 Feb 2023 22:27:01 +0000", + "[February 6] SkyBlock Patch Notes | https://hypixel.net/threads/february-6-skyblock-patch-notes.5266045/ | Sun, 12 Feb 2023 07:12:37 +0000", + "[February 16] Final Dungeon Journals | https://hypixel.net/threads/february-16-final-dungeon-journals.5276354/ | Tue, 21 Feb 2023 01:47:54 +0000" ] } diff --git a/hypixel-discord-chat-bridge.zip b/hypixel-discord-chat-bridge.zip new file mode 100644 index 00000000..a60977dc Binary files /dev/null and b/hypixel-discord-chat-bridge.zip differ diff --git a/messages.json b/messages.json index 1cee76f2..cf8b891c 100644 --- a/messages.json +++ b/messages.json @@ -27,5 +27,6 @@ "blacklistMessage": " has been successfully blacklisted.", "blacklistRemoveMessage": " has been successfully removed from the blacklist.", "alreadyBlacklistedMessage": "Player is already blacklisted.", - "cannotMuteMoreThanOneMonthMessage": "You cannot mute someone for more than one month" + "cannotMuteMoreThanOneMonthMessage": "You cannot mute someone for more than one month", + "guildLevelUpMessage": "The guild has reached level" } diff --git a/package.json b/package.json index 8eba06bd..62dd540a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hypixel-discord-chat-bridge", - "version": "2.7", + "version": "3.1.12", "description": "A Hypixel guild chat and Discord chat bridge", "main": "index.js", "scripts": { @@ -31,11 +31,12 @@ "homepage": "https://github.com/DuckySoLucky/hypixel-discord-chat-bridge#readme", "dependencies": { "@discordjs/rest": "^1.5.0", - "axios": "^1.2.1", + "axios": "0.27.2", "bad-words": "^3.0.4", "canvas": "2.10.1", "chalk": "^4.1.0", "discord-api-types": "^0.37.33", + "discord-emoji-converter": "^1.2.8", "discord.js": "^14.7.1", "express": "^4.18.1", "hypixel-api-reborn": "^10.0.0", @@ -57,8 +58,6 @@ "globals": { "bot": true, "client": true, - "minecraftCommandList": true, - "uptime": true, "bridgeChat": true } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c6514168..c698435b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,50 +1,52 @@ lockfileVersion: 5.4 specifiers: - '@discordjs/rest': ^1.3.0 - axios: ^1.2.1 + '@discordjs/rest': ^1.5.0 + axios: 0.27.2 bad-words: ^3.0.4 canvas: 2.10.1 chalk: ^4.1.0 - discord-api-types: ^0.37.25 + discord-api-types: ^0.37.33 + discord-emoji-converter: ^1.2.8 discord.js: ^14.7.1 - eslint: ^8.32.0 + eslint: ^8.34.0 eslint-plugin-import: ^2.27.5 express: ^4.18.1 hypixel-api-reborn: ^10.0.0 imgur: ^2.2.0 lilyweight: ^2.7.0 - mineflayer: ^4.5.1 + mineflayer: ^4.8.1 moment: ^2.29.4 nodemon: ^2.0.19 - prettier: 2.8.3 + prettier: 2.8.4 prismarine-nbt: ^2.2.1 skyhelper-networth: 1.11.0 util: ^0.12.5 dependencies: '@discordjs/rest': 1.5.0 - axios: 1.2.2 + axios: 0.27.2 bad-words: 3.0.4 canvas: 2.10.1 chalk: 4.1.2 - discord-api-types: 0.37.25 + discord-api-types: 0.37.35 + discord-emoji-converter: 1.2.8 discord.js: 14.7.1 express: 4.18.2 hypixel-api-reborn: 10.0.0 imgur: 2.2.0 lilyweight: 2.7.0 - mineflayer: 4.6.0 + mineflayer: 4.8.1 moment: 2.29.4 prismarine-nbt: 2.2.1 skyhelper-networth: 1.11.0 util: 0.12.5 devDependencies: - eslint: 8.32.0 - eslint-plugin-import: 2.27.5_eslint@8.32.0 + eslint: 8.34.0 + eslint-plugin-import: 2.27.5_eslint@8.34.0 nodemon: 2.0.20 - prettier: 2.8.3 + prettier: 2.8.4 packages: @@ -68,7 +70,7 @@ packages: dependencies: '@discordjs/util': 0.1.0 '@sapphire/shapeshift': 3.8.1 - discord-api-types: 0.37.25 + discord-api-types: 0.37.35 fast-deep-equal: 3.1.3 ts-mixer: 6.0.2 tslib: 2.4.1 @@ -87,7 +89,7 @@ packages: '@discordjs/util': 0.1.0 '@sapphire/async-queue': 1.5.0 '@sapphire/snowflake': 3.4.0 - discord-api-types: 0.37.25 + discord-api-types: 0.37.35 file-type: 18.0.0 tslib: 2.4.1 undici: 5.14.0 @@ -389,16 +391,6 @@ packages: - debug dev: false - /axios/1.2.2: - resolution: {integrity: sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==} - dependencies: - follow-redirects: 1.15.2_debug@4.3.4 - form-data: 4.0.0 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - dev: false - /bad-words/3.0.4: resolution: {integrity: sha512-v/Q9uRPH4+yzDVLL4vR1+S9KoFgOEUl5s4axd6NIAq8SV2mradgi4E8lma/Y0cw1ltVdvyegCQQKffCPRCp8fg==} engines: {node: '>=8.0.0'} @@ -688,8 +680,12 @@ packages: resolution: {integrity: sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==} dev: false - /discord-api-types/0.37.25: - resolution: {integrity: sha512-aCwA2sWnL1zPQgTELkkMzQneuWyCXXUjZCUKswesiE6RDCfOfxAPXOHg6ZTlBA5layPSikGCBBRjyh8S3Wzd+A==} + /discord-api-types/0.37.35: + resolution: {integrity: sha512-iyKZ/82k7FX3lcmHiAvvWu5TmyfVo78RtghBV/YsehK6CID83k5SI03DKKopBcln+TiEIYw5MGgq7SJXSpNzMg==} + dev: false + + /discord-emoji-converter/1.2.8: + resolution: {integrity: sha512-95UIHZugZ5nvfZb/hX4+UK9a0run8ZleU1u3xOMFxZjusfigpmrQlxbSHJemzeB5ebCJ7gJVt9Pmmhi8+zKMHw==} dev: false /discord.js/14.7.1: @@ -702,7 +698,7 @@ packages: '@discordjs/util': 0.1.0 '@sapphire/snowflake': 3.4.0 '@types/ws': 8.5.4 - discord-api-types: 0.37.25 + discord-api-types: 0.37.35 fast-deep-equal: 3.1.3 lodash.snakecase: 4.1.1 tslib: 2.4.1 @@ -836,7 +832,7 @@ packages: - supports-color dev: true - /eslint-module-utils/2.7.4_tdm2zecdp3gdwhfxnfmevnwugq: + /eslint-module-utils/2.7.4_eyqnu5kib2hfrvsonwfdq4ojse: resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} engines: {node: '>=4'} peerDependencies: @@ -858,13 +854,13 @@ packages: optional: true dependencies: debug: 3.2.7 - eslint: 8.32.0 + eslint: 8.34.0 eslint-import-resolver-node: 0.3.7 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-import/2.27.5_eslint@8.32.0: + /eslint-plugin-import/2.27.5_eslint@8.34.0: resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} engines: {node: '>=4'} peerDependencies: @@ -879,9 +875,9 @@ packages: array.prototype.flatmap: 1.3.1 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.32.0 + eslint: 8.34.0 eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.7.4_tdm2zecdp3gdwhfxnfmevnwugq + eslint-module-utils: 2.7.4_eyqnu5kib2hfrvsonwfdq4ojse has: 1.0.3 is-core-module: 2.11.0 is-glob: 4.0.3 @@ -904,13 +900,13 @@ packages: estraverse: 5.3.0 dev: true - /eslint-utils/3.0.0_eslint@8.32.0: + /eslint-utils/3.0.0_eslint@8.34.0: resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} peerDependencies: eslint: '>=5' dependencies: - eslint: 8.32.0 + eslint: 8.34.0 eslint-visitor-keys: 2.1.0 dev: true @@ -924,8 +920,8 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint/8.32.0: - resolution: {integrity: sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==} + /eslint/8.34.0: + resolution: {integrity: sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: @@ -940,7 +936,7 @@ packages: doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.1.1 - eslint-utils: 3.0.0_eslint@8.32.0 + eslint-utils: 3.0.0_eslint@8.34.0 eslint-visitor-keys: 3.3.0 espree: 9.4.1 esquery: 1.4.0 @@ -1757,16 +1753,16 @@ packages: engines: {node: '>=8'} dev: false - /minecraft-data/3.20.0: - resolution: {integrity: sha512-xBQZwY0FoVq7jirFTD8mexNatSddP72CpDYweISHKE3J0co+CgfjtvQ94ykdQW+QPTMgrIIlATxVGIlk0Xjm8w==} + /minecraft-data/3.28.0: + resolution: {integrity: sha512-+JK15SNgZgnP3xcjoywMyO5TyXENkCajQCLu5yQ75J53ExK+SQ+ObBdPB3jfPTt73eqfGa0yZfx9e0Bjq/psSw==} dev: false /minecraft-folder-path/1.2.0: resolution: {integrity: sha512-qaUSbKWoOsH9brn0JQuBhxNAzTDMwrOXorwuRxdJKKKDYvZhtml+6GVCUrY5HRiEsieBEjCUnhVpDuQiKsiFaw==} dev: false - /minecraft-protocol/1.36.2: - resolution: {integrity: sha512-Z7wNk1FTe0bnlmHxJEbpVnIpWLOsAfjoKDFR6DbUHVuL+rNuG9gR/Z3la3a20o4ZrlnToV6vbJkkPhvtn1rSYg==} + /minecraft-protocol/1.41.0: + resolution: {integrity: sha512-lkpkrJCbT8XIqppac+KvH23AajjwfTJSbn1rwb6dEx3dT4GbA1sSvCy/hltBzRF3bifJq3/0U5F/CnQD69F3Jg==} engines: {node: '>=14'} dependencies: '@types/readable-stream': 2.3.15 @@ -1776,12 +1772,13 @@ packages: endian-toggle: 0.0.0 lodash.get: 4.4.2 lodash.merge: 4.6.2 - minecraft-data: 3.20.0 + minecraft-data: 3.28.0 minecraft-folder-path: 1.2.0 node-fetch: 2.6.7 node-rsa: 0.4.2 - prismarine-auth: 2.1.1 + prismarine-auth: 2.2.0 prismarine-nbt: 2.2.1 + prismarine-realms: 1.3.0 protodef: 1.15.0 readable-stream: 4.2.0 uuid-1345: 1.0.2 @@ -1791,13 +1788,13 @@ packages: - supports-color dev: false - /mineflayer/4.6.0: - resolution: {integrity: sha512-/07dw9Qquu7CYMDqKW+gUVZo1XYtkfUbQ7XtmIVNF3/rMGgvcs6UYt/kLWvYpom6GVL8Bie4ZhdNUJNLaZaAQw==} + /mineflayer/4.8.1: + resolution: {integrity: sha512-xqt5gdBvYHO1UV2slBm1QFFI2dHyfoMAxwSgxIGOuobIrZ05pY56XV6GW+NWQK0gqS4+MA5n0VakXPWZ5trzBQ==} engines: {node: '>=14'} dependencies: - minecraft-data: 3.20.0 - minecraft-protocol: 1.36.2 - prismarine-biome: 1.3.0_bsuncksy3nsk4hpjnvjzbnhgiy + minecraft-data: 3.28.0 + minecraft-protocol: 1.41.0 + prismarine-biome: 1.3.0_3lbbl4xxcsrzeyofiuu7t7lpdu prismarine-block: 1.16.3 prismarine-chat: 1.7.2 prismarine-chunk: 1.32.0 @@ -2089,14 +2086,14 @@ packages: engines: {node: '>= 0.8.0'} dev: true - /prettier/2.8.3: - resolution: {integrity: sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==} + /prettier/2.8.4: + resolution: {integrity: sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==} engines: {node: '>=10.13.0'} hasBin: true dev: true - /prismarine-auth/2.1.1: - resolution: {integrity: sha512-KPWA2ZL4Tewl2gDKL2WT9yUSRKfE7MNgQ++RY+mSDUo+dJpRsqKnR7VZIhyRn8ai/iA8v/SFc/MmJiZ2TsZGmQ==} + /prismarine-auth/2.2.0: + resolution: {integrity: sha512-3XfR3bqrd7nrTVyEqMwuYRr+/Vy+hkfBplubSDuoRAcRCs90lDx7R4EG3fjMSoKY53RLTXjeFnsB6m1krhL/2A==} dependencies: '@azure/msal-node': 1.14.5 '@xboxreplay/xboxlive-auth': 3.3.3_debug@4.3.4 @@ -2110,21 +2107,21 @@ packages: - supports-color dev: false - /prismarine-biome/1.3.0_bsuncksy3nsk4hpjnvjzbnhgiy: + /prismarine-biome/1.3.0_3lbbl4xxcsrzeyofiuu7t7lpdu: resolution: {integrity: sha512-GY6nZxq93mTErT7jD7jt8YS1aPrOakbJHh39seYsJFXvueIOdHAmW16kYQVrTVMW5MlWLQVxV/EquRwOgr4MnQ==} peerDependencies: minecraft-data: ^3.0.0 prismarine-registry: ^1.1.0 dependencies: - minecraft-data: 3.20.0 + minecraft-data: 3.28.0 prismarine-registry: 1.6.0 dev: false /prismarine-block/1.16.3: resolution: {integrity: sha512-E9OazjIqnEgcXM6me6EIeQFMcNRWZzsaftWtetRSIKVoW+4UKWleb6lTNKh9kq7wNxciKavcYBmKL3sF7HfSaA==} dependencies: - minecraft-data: 3.20.0 - prismarine-biome: 1.3.0_bsuncksy3nsk4hpjnvjzbnhgiy + minecraft-data: 3.28.0 + prismarine-biome: 1.3.0_3lbbl4xxcsrzeyofiuu7t7lpdu prismarine-chat: 1.7.2 prismarine-item: 1.12.1 prismarine-nbt: 2.2.1 @@ -2145,8 +2142,8 @@ packages: resolution: {integrity: sha512-2Abh7M93BPbqRZEclmjIHC2RcETWN2/0zYsbPc5SgWXqe7u34kQaB2lv3YUS1xZ3vg9kdtR8mzElk8i84eX7PA==} engines: {node: '>=14'} dependencies: - minecraft-data: 3.20.0 - prismarine-biome: 1.3.0_bsuncksy3nsk4hpjnvjzbnhgiy + minecraft-data: 3.28.0 + prismarine-biome: 1.3.0_3lbbl4xxcsrzeyofiuu7t7lpdu prismarine-block: 1.16.3 prismarine-registry: 1.6.0 smart-buffer: 4.2.0 @@ -2158,7 +2155,7 @@ packages: /prismarine-entity/2.2.0: resolution: {integrity: sha512-boqJbMpGHG2ddFUUo9aKkKPUHQbFMWkUCw8SRdZ+jrZxABsstL9619I8ujwPYoOMJjMyfYWgdEPNyHGiUqqukA==} dependencies: - minecraft-data: 3.20.0 + minecraft-data: 3.28.0 prismarine-chat: 1.7.2 prismarine-item: 1.12.1 prismarine-registry: 1.6.0 @@ -2187,11 +2184,21 @@ packages: /prismarine-physics/1.5.2: resolution: {integrity: sha512-Ak1yM/Fv9qxIt8Lgp/pHYS0v5P1bkZLq27Cb35Z/0YMCEUk0zXGfJOg0R666EQJOnAA1ABNZlRjglL9ZBMnWqg==} dependencies: - minecraft-data: 3.20.0 + minecraft-data: 3.28.0 prismarine-nbt: 2.2.1 vec3: 0.1.7 dev: false + /prismarine-realms/1.3.0: + resolution: {integrity: sha512-heAzbP2bI/dGjoHUWAe3pncg3jHwNLjN0nkZb98jbpJxgsogx/8Cqejd1Oc+EVnqnVwNyiyITfCoH3ECqYeikw==} + dependencies: + debug: 4.3.4 + node-fetch: 2.6.7 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /prismarine-recipe/1.3.1_prismarine-registry@1.6.0: resolution: {integrity: sha512-xfa9E9ACoaDi+YzNQ+nk8kWSIqt5vSZOOCHIT+dTXscf/dng2HaJ/59uwe1D/jvOkAd2OvM6RRJM6fFe0q/LDA==} peerDependencies: @@ -2203,7 +2210,7 @@ packages: /prismarine-registry/1.6.0: resolution: {integrity: sha512-oduDRuwa5rXT8CkPeMSlBsuBzxZF9oRsDpFK0oBStpIoNwSuTqqGGGgLlyL20OS2O9pmqYpOMlmG80CW4uuKJw==} dependencies: - minecraft-data: 3.20.0 + minecraft-data: 3.28.0 prismarine-nbt: 2.2.1 dev: false @@ -2252,10 +2259,6 @@ packages: ipaddr.js: 1.9.1 dev: false - /proxy-from-env/1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - dev: false - /pstree.remy/1.1.8: resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} dev: true diff --git a/src/discord/DiscordManager.js b/src/discord/DiscordManager.js index 3cff74b6..efb26bd6 100644 --- a/src/discord/DiscordManager.js +++ b/src/discord/DiscordManager.js @@ -1,5 +1,10 @@ /*eslint-disable */ -const { Client, Collection, AttachmentBuilder, GatewayIntentBits } = require("discord.js"); +const { + Client, + Collection, + AttachmentBuilder, + GatewayIntentBits, +} = require("discord.js"); const CommunicationBridge = require("../contracts/CommunicationBridge.js"); const messageToImage = require("../contracts/messageToImage.js"); const MessageHandler = require("./handlers/MessageHandler.js"); @@ -36,9 +41,13 @@ class DiscordManager extends CommunicationBridge { this.client = client; this.client.on("ready", () => this.stateHandler.onReady()); - this.client.on("messageCreate", (message) => this.messageHandler.onMessage(message)); + this.client.on("messageCreate", (message) => + this.messageHandler.onMessage(message) + ); - this.client.login(config.discord.token).catch((error) => {Logger.errorMessage(error)}); + this.client.login(config.discord.token).catch((error) => { + Logger.errorMessage(error); + }); client.commands = new Collection(); const commandFiles = fs @@ -58,14 +67,16 @@ class DiscordManager extends CommunicationBridge { for (const file of eventFiles) { const filePath = path.join(eventsPath, file); const event = require(filePath); - event.once ? client.once(event.name, (...args) => event.execute(...args)) : client.on(event.name, (...args) => event.execute(...args)); + event.once + ? client.once(event.name, (...args) => event.execute(...args)) + : client.on(event.name, (...args) => event.execute(...args)); } global.guild = await client.guilds.fetch(config.discord.serverID); process.on("SIGINT", () => { this.stateHandler.onClose().then(() => { - client.destroy() + client.destroy(); kill(process.pid); }); }); @@ -95,31 +106,48 @@ class DiscordManager extends CommunicationBridge { async getWebhook(discord, type) { channel = await this.getChannel(type); const webhooks = await channel.fetchWebhooks(); - if (webhooks.first()) { - return webhooks.first(); - } else { - const response = await channel.createWebhook( - discord.client.user.username, - { avatar: discord.client.user.avatarURL() } - ); - return response; + + if (webhooks.size === 0) { + channel.createWebhook({ + name: "Hypixel Chat Bridge", + avatar: "https://i.imgur.com/AfFp7pu.png", + }); + + await this.getWebhook(discord, type); } + + return webhooks.first(); } - async onBroadcast({ fullMessage, username, message, guildRank, chat }) { - if (message == "debug_temp_message_ignore" && config.discord.messageMode != "minecraft") return; - if (chat != "debugChannel") { + async onBroadcast({ + fullMessage, + username, + message, + guildRank, + chat, + color = 1752220, + }) { + let mode = config.discord.messageMode.toLowerCase(); + if (message === undefined) { + if (config.console.debug === false) { + return; + } + + mode = "minecraft"; + } + + if (username !== undefined) { Logger.broadcastMessage(`${username} [${guildRank}]: ${message}`, `Discord`); } - channel = await this.getChannel(chat); - switch (config.discord.messageMode.toLowerCase()) { + channel = await this.getChannel(chat || "Guild"); + switch (mode) { case "bot": channel.send({ embeds: [ { description: message, - color: 3447003, + color: this.hexToDec(color), timestamp: new Date(), footer: { text: guildRank, @@ -162,7 +190,7 @@ class DiscordManager extends CommunicationBridge { } break; - + default: throw new Error( "Invalid message mode: must be bot, webhook or minecraft" @@ -253,6 +281,10 @@ class DiscordManager extends CommunicationBridge { throw new Error("Invalid message mode: must be bot or webhook"); } } + + hexToDec(hex) { + return parseInt(hex.replace("#", ""), 16); + } } module.exports = DiscordManager; diff --git a/src/discord/commands/helpCommand.js b/src/discord/commands/helpCommand.js index 20181ea5..0e40df84 100644 --- a/src/discord/commands/helpCommand.js +++ b/src/discord/commands/helpCommand.js @@ -16,46 +16,50 @@ module.exports = { ], execute: async (interaction, client) => { - const commandName = interaction.options.getString("command"); - if (!commandName) { - let discordCommands = "", - minecraftCommands = ""; - const discordCommandFiles = fs - .readdirSync("src/discord/commands") - .filter((file) => file.endsWith(".js")); - for (const file of discordCommandFiles) { - const command = require(`./${file}`); - let discordOptions = ""; - if (!command.options) { + const commandName = interaction.options.getString("command") || undefined; + const commands = interaction.client.commands; + + if (commandName === undefined) { + let discordCommands = ""; + commands.map((command) => { + if (command.options !== undefined) { + discordCommands += `- \`${command.name}`; + command.options.map((option) => { + if (option.required === true) { + discordCommands += ` (${option.name})`; + } else { + discordCommands += ` [${option.name}]`; + } + }); + discordCommands += `\`\n`; + } else { discordCommands += `- \`${command.name}\`\n`; - continue; } - for (let i = 0; i < command.options.length; i++) { - for (let j = 0; j < command.options.length; j++) { - discordOptions += ` [${command.options[j].name}]`; - } - discordCommands += `- \`${command.name}${discordOptions}\`\n`; - break; - } - } - for (let i = 0; i < minecraftCommandList.length; i++) { - if (minecraftCommandList[i].options?.length < 1) { - minecraftCommands += `- \`${minecraftCommandList[i].name}${ - minecraftCommandList[i].options != "" - ? ` [${minecraftCommandList[i].options}]\`\n` - : `\`\n` - }`; - } else { - let options = ""; - for (let j = 0; j < minecraftCommandList[i].options.length; j++) { - options += ` [${minecraftCommandList[i].options[j]}]`; - } - minecraftCommands += `- \`${minecraftCommandList[i].name}${options}\`\n`; + }); + let minecraftCommands = ""; + const minecraftCommandFiles = fs + .readdirSync("./src/minecraft/commands") + .filter((file) => file.endsWith(".js")); + for (const file of minecraftCommandFiles) { + const command = new (require(`../../minecraft/commands/${file}`))(); + + minecraftCommands += `- \`${command.name}`; + + if (command.options !== undefined) { + command.options.map((option) => { + if (option.required === true) { + minecraftCommands += ` (${option.name})`; + } else { + minecraftCommands += ` [${option.name}]`; + } + }); + minecraftCommands += `\`\n`; } } + const helpMenu = new EmbedBuilder() .setColor(0x0099ff) - .setTitle("Hypixel Bridge Bot Commands") + .setTitle("Hypixel Discord Chat Bridge Commands") .setDescription("() = required argument, [] = optional argument") .addFields( { @@ -63,132 +67,59 @@ module.exports = { value: `${minecraftCommands}`, inline: true, }, - { name: "**Discord**: ", value: `${discordCommands}`, inline: true } + { + name: "**Discord**: ", + value: `${discordCommands}`, + inline: true, + } ) .setFooter({ text: "by DuckySoLucky#5181 | /help [command] for more information", iconURL: "https://imgur.com/tgwQJTX.png", }); + await interaction.followUp({ embeds: [helpMenu] }); } else { - let options = "", - found = false; - // Discord Commands - const discordCommandFiles = fs - .readdirSync("src/discord/commands") - .filter((file) => file.endsWith(".js")); - for (const file of discordCommandFiles) { - const command = require(`./${file}`); - if (command.name === commandName) { - const description = command.description; - found = true; - if (!command.options) { - const commandData = new EmbedBuilder() - .setColor(0x0099ff) - .setTitle(`**${config.minecraft.prefix}${command.name}**`) - .setDescription(description + "\n") - .setFooter({ - text: "by DuckySoLucky#5181 | () = required, [] = optional", - iconURL: "https://imgur.com/tgwQJTX.png", - }); - await interaction.followUp({ embeds: [commandData] }); - break; - } - for (let i = 0; i < command.options.length; i++) { - for (let j = 0; j < command.options.length; j++) { - options += `${ - command.options[j].name != "" - ? `\`[${command.options[j].name}]\`:` - : `` - }${ - command.options[j].description != "" - ? ` ${command.options[j].description}\n` - : `` - }`; - } + const minecraftCommand = fs.readdirSync("./src/minecraft/commands").filter((file) => file.endsWith(".js")).map((file) => new (require(`../../minecraft/commands/${file}`))()).find((command) => command.name === commandName || command.aliases.includes(commandName)) + const command = commands.find((command) => command.name === commandName) || minecraftCommand + const type = commands.find((command) => command.name === commandName) ? "discord" : "minecraft" - const commandData = new EmbedBuilder() - .setColor(0x0099ff) - .setTitle(`**${config.minecraft.prefix}${command.name}**`) - .setDescription(description + "\n") - .addFields({ - name: "**Options** ", - value: `${options}`, - inline: true, - }) - .setFooter({ - text: "by DuckySoLucky#5181 | () = required, [] = optional", - iconURL: "https://imgur.com/tgwQJTX.png", - }); - await interaction.followUp({ embeds: [commandData] }); - break; - } - } + if (command === undefined) { + const errorEmbed = new EmbedBuilder() + .setColor("#ff0000") + .setTitle("Error") + .setDescription(`Command \`${commandName}\` was not found`) + .setFooter({ + text: "by DuckySoLucky#5181 | /help [command] for more information", + iconURL: "https://imgur.com/tgwQJTX.png", + }); + + return await interaction.followUp({ embeds: [errorEmbed] }); } - if (found) return; - // Minecraft Commands - for (let i = 0; i < minecraftCommandList.length; i++) { - if (minecraftCommandList[i].name === commandName) { - const description = minecraftCommandList[i].description; - found = true; - if ( - minecraftCommandList[i].options.length == 0 || - minecraftCommandList[i].options == [] - ) { - const commandData = new EmbedBuilder() - .setColor(0x0099ff) - .setTitle( - `**${config.minecraft.prefix}${minecraftCommandList[i].name}**` - ) - .setDescription(description + "\n") - .setFooter({ - text: "by DuckySoLucky#5181 | () = required, [] = optional", - iconURL: "https://imgur.com/tgwQJTX.png", - }); - await interaction.followUp({ embeds: [commandData] }); - break; + + let description = ""; + description += `${command.description}\n\n`; + if (command.options !== undefined) { + description += `**Options**\n`; + command.options.map((option) => { + if (option.required === true) { + description += `\`(${option.name})\`: ${option.description}\n`; } else { - for (let j = 0; j < minecraftCommandList[i].options.length; j++) { - options += `${ - minecraftCommandList[i].options[j] != "" - ? `\`[${minecraftCommandList[i].options[j]}]\`:` - : `` - }${ - minecraftCommandList[i].optionsDescription[j] != "" - ? ` ${minecraftCommandList[i].optionsDescription[j]}\n` - : `` - }`; - } + description += `\`[${option.name}]\`: ${option.description}\n`; } - const commandData = new EmbedBuilder() - .setColor(0x0099ff) - .setTitle( - `**${config.minecraft.prefix}${minecraftCommandList[i].name}**` - ) - .setDescription(minecraftCommandList[i].description + "\n") - .addFields({ - name: "**Options** ", - value: `${options}`, - inline: true, - }) - .setFooter({ - text: "by DuckySoLucky#5181 | () = required, [] = optional", - iconURL: "https://imgur.com/tgwQJTX.png", - }); - await interaction.followUp({ embeds: [commandData] }); - break; - } + }); } - if (found) return; - const errorEmbed = new EmbedBuilder() - .setColor("#ff0000") - .setTitle("Error") - .setDescription(`Command \`${commandName}\` was not found`) + + const embed = new EmbedBuilder() + .setColor(0x0099ff) + .setTitle(`**${type === "discord" ? "/" : config.minecraft.prefix}${command.name}**`) + .setDescription(description + "\n") .setFooter({ - text: "by DuckySoLucky#5181", + text: "by DuckySoLucky#5181 | () = required, [] = optional", iconURL: "https://imgur.com/tgwQJTX.png", }); - await interaction.followUp({ embeds: [errorEmbed] }); + + await interaction.followUp({ embeds: [embed] }); } }, }; diff --git a/src/discord/commands/infoCommand.js b/src/discord/commands/infoCommand.js index aaf3cccc..ddd2f8c9 100644 --- a/src/discord/commands/infoCommand.js +++ b/src/discord/commands/infoCommand.js @@ -10,41 +10,9 @@ module.exports = { description: "Shows information about the bot.", execute: async (interaction, client) => { - let discordCommands = "", - minecraftCommands = ""; - const discordCommandFiles = fs - .readdirSync("src/discord/commands") - .filter((file) => file.endsWith(".js")); - for (const file of discordCommandFiles) { - const command = require(`./${file}`); - let discordOptions = ""; - if (!command.options) { - discordCommands += `- \`${command.name}\`\n`; - continue; - } - for (let i = 0; i < command.options.length; i++) { - for (let j = 0; j < command.options.length; j++) { - discordOptions += ` [${command.options[j].name}]`; - } - discordCommands += `- \`${command.name}${discordOptions}\`\n`; - break; - } - } - for (let i = 0; i < minecraftCommandList.length; i++) { - if (minecraftCommandList[i].options.length < 1) { - minecraftCommands += `- \`${minecraftCommandList[i].name}${ - minecraftCommandList[i].options != "" - ? ` [${minecraftCommandList[i].options}]\`\n` - : `\`\n` - }`; - } else { - let options = ""; - for (let j = 0; j < minecraftCommandList[i].options.length; j++) { - options += ` [${minecraftCommandList[i].options[j]}]`; - } - minecraftCommands += `- \`${minecraftCommandList[i].name}${options}\`\n`; - } - } + const commands = interaction.client.commands; + + const { discordCommands, minecraftCommands } = getCommands(commands); const infoEmbed = new EmbedBuilder() .setColor(0x0099ff) @@ -63,12 +31,15 @@ module.exports = { { name: "\u200B", value: "\u200B" }, { name: "**Minecraft Information**:", - value: `Bot: \`${bot.username}\`\nPrefix: \`${ + value: `Bot Username: \`${bot.username}\`\nPrefix: \`${ config.minecraft.prefix - }\`\nUptime: Online since \nVersion: \`${version}\``, + }\`\nSkyBlock Events: \`${ + config.event.enabled ? "enabled" : "disabled" + }\`\nAuto Accept: \`${ + config.guildRequirement.autoAccept ? "enabled" : "disabled" + }\`\nGuild Experience Requirement: \`${config.minecraft.guildExp.toLocaleString()}\`\nUptime: Online since \nVersion: \`${require("../../../package.json").version}\`\n`, inline: true, }, { @@ -90,9 +61,9 @@ module.exports = { ? `<#${config.console.debugChannel}>` : "None" }\nCommand Role: <@&${config.discord.commandRole}>\nMessage Mode: \`${ - config.discord.messageMode + config.discord.messageMode ? "enabled" : "disabled" }\`\nFilter: \`${config.discord.filterMessages}\`\nJoin Messages: \`${ - config.discord.joinMessage + config.discord.joinMessage ? "enabled" : "disabled" }\``, inline: true, } @@ -104,3 +75,45 @@ module.exports = { await interaction.followUp({ embeds: [infoEmbed] }); }, }; + +function getCommands(commands) { + let discordCommands = ""; + commands.map((command) => { + if (command.options !== undefined) { + discordCommands += `- \`${command.name}`; + command.options.map((option) => { + if (option.required === true) { + discordCommands += ` (${option.name})`; + } else { + discordCommands += ` [${option.name}]`; + } + }); + discordCommands += `\`\n`; + } else { + discordCommands += `- \`${command.name}\`\n`; + } + }); + + let minecraftCommands = ""; + const minecraftCommandFiles = fs + .readdirSync("./src/minecraft/commands") + .filter((file) => file.endsWith(".js")); + for (const file of minecraftCommandFiles) { + const command = new (require(`../../minecraft/commands/${file}`))(); + + minecraftCommands += `- \`${command.name}`; + + if (command.options !== undefined) { + command.options.map((option) => { + if (option.required === true) { + minecraftCommands += ` (${option.name})`; + } else { + minecraftCommands += ` [${option.name}]`; + } + }); + minecraftCommands += `\`\n`; + } + } + + return { discordCommands, minecraftCommands }; +} diff --git a/src/discord/commands/onlineCommand.js b/src/discord/commands/onlineCommand.js index 6d6c28c2..92881019 100644 --- a/src/discord/commands/onlineCommand.js +++ b/src/discord/commands/onlineCommand.js @@ -1,12 +1,105 @@ +const { EmbedBuilder } = require("discord.js"); +const { replaceAllRanks } = require("../../contracts/helperFunctions"); + module.exports = { name: "online", description: "List of online members.", execute: async (interaction, client) => { - bot.chat(`/g online`); - await interaction.followUp({ - content: "Command has been executed successfully.", - ephemeral: true, + const cachedMessages = []; + const promise = new Promise((resolve, reject) => { + const listener = (message) => { + cachedMessages.push(message.toString()); + + if (message.toString().startsWith("Offline Members")) { + bot.removeListener("message", listener); + resolve(cachedMessages); + } + }; + + bot.on("message", listener); + bot.chat("/g online"); + + setTimeout(() => { + bot.removeListener("message", listener); + reject("Command timed out. Please try again."); + }, 5000); }); + + try { + const messages = await promise; + messages.map((message) => message.trim()); + let onlineMembers = messages.find((message) => + message.startsWith("Online Members: ") + ); + onlineMembers = + onlineMembers.split(": ")[0] + + ": " + + `\`${onlineMembers.split(": ")[1]}\``; + + let offlineMembers = messages.find((message) => + message.startsWith("Offline Members: ") + ); + offlineMembers = + offlineMembers.split(": ")[0] + + ": " + + `\`${offlineMembers.split(": ")[1]}\``; + + let totalMembers = messages.find((message) => + message.startsWith("Total Members: ") + ); + totalMembers = + totalMembers.split(": ")[0] + + ": " + + `\`${totalMembers.split(": ")[1]}\``; + + const onlineMembersList = messages + + let description = `**ONLINE**\n${onlineMembers}\n${offlineMembers}\n${totalMembers}\n\n`; + let online = []; + for (const [index, item] of Object.entries(onlineMembersList)) { + if (item.includes("-- ")) { + const nextLine = onlineMembersList[parseInt(index) + 1]; + if (nextLine) { + if (nextLine.includes("●")) { + online = online.concat( + nextLine.split("●").map((item) => item.trim()) + ); + } + } + } + } + + online = online.filter((item) => item); + + description += online + .map((item) => { + return `\`${item}\``; + }) + .join(", "); + + const embed = new EmbedBuilder() + .setColor("#2ECC71") + .setTitle("Online Members") + .setDescription(description) + .setFooter({ + text: "by DuckySoLucky#5181 | /help [command] for more information", + iconURL: "https://imgur.com/tgwQJTX.png", + }); + + return await interaction.followUp({ embeds: [embed] }); + } catch (error) { + console.log(error); + const errorEmbed = new EmbedBuilder() + .setColor("#E74C3C") + .setTitle("Error") + .setDescription(`\`\`\`${error}\`\`\``) + .setFooter({ + text: "by DuckySoLucky#5181 | /help [command] for more information", + iconURL: "https://imgur.com/tgwQJTX.png", + }); + + return await interaction.followUp({ embeds: [errorEmbed] }); + } }, }; diff --git a/src/discord/handlers/MessageHandler.js b/src/discord/handlers/MessageHandler.js index 4661d4dd..117dc9a0 100644 --- a/src/discord/handlers/MessageHandler.js +++ b/src/discord/handlers/MessageHandler.js @@ -1,6 +1,7 @@ +const { demojify } = require("discord-emoji-converter"); const config = require("../../../config.json"); -const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); -const { generateID } = require("../../contracts/helperFunctions.js"); +const { ImgurClient } = require("imgur"); +const imgurClient = new ImgurClient({ clientId: config.api.imgurAPIkey }); class MessageHandler { constructor(discord, command) { @@ -9,69 +10,123 @@ class MessageHandler { } async onMessage(message) { - if (message.author.id === client.user.id || !this.shouldBroadcastMessage(message)) { + if ( + message.author.id === client.user.id || + !this.shouldBroadcastMessage(message) + ) { return; } - if (message.content.includes("<@")) { - message.content = message.content.replace(/<@!?(\d+)>/g, (match, id) => { - const user = client.users.cache.get(id); - if (user) { - return `@${user.username}`; - } - - return match; - }); - } - const content = this.stripDiscordContent(message.content).trim(); if (content.length === 0) return; - const messageData = { member: message.member.user, channel: message.channel.id, username: message.member.displayName, message: content, - replyingTo: await this.fetchReply(message) + replyingTo: await this.fetchReply(message), }; this.discord.broadcastMessage(messageData); + if (message.attachments.values().length === 0) return; + + messageData.message = ""; for (const attachment of message.attachments.values()) { - await delay(1000) - messageData.message = `${attachment.url} - ${generateID(config.minecraft.messageRepeatBypassLength)}`; - this.discord.broadcastMessage(messageData); + const imgurLink = await imgurClient.upload({ + image: attachment.url, + type: "url", + }); + messageData.message += `${imgurLink.data.link} `; } + + if (messageData.message.length === 0) return; + + this.discord.broadcastMessage(messageData); } - + async fetchReply(message) { try { if (message.reference === undefined) return null; - - const reference = await message.channel.messages.fetch(message.reference.messageId); - - return reference.author.username; + const reference = await message.channel.messages.fetch( + message.reference.messageId + ); + + const mentionedUserName = message?.mentions?.repliedUser?.username + if (config.discord.messageMode === "bot") { + const embedAuthorName = reference?.embeds?.[0]?.author?.name; + + return embedAuthorName ?? mentionedUserName; + } + + if (config.discord.messageMode === "minecraft") { + const attachmentName = reference?.attachments?.values()?.next() + ?.value?.name; + + return attachmentName + ? attachmentName.split(".")[0] + : mentionedUserName; + } + + if (config.discord.messageMode === "webhook") { + return reference.author.username ?? mentionedUserName + } } catch (error) { return null; } } stripDiscordContent(message) { - return message + message = message .split("\n") .map((part) => { part = part.trim(); - return part.length === 0 ? "" : part.replace(/@(everyone|here)/gi, "").trim() + " "; + return part.length === 0 + ? "" + : part.replace(/@(everyone|here)/gi, "").trim() + " "; }) .join(""); + + const hasMentions = /<@|<#|<:| with @DuckySoLucky + const userMentionPattern = /<@(\d+)>/g; + const replaceUserMention = (match, mentionedUserId) => { + const mentionedUser = message.guild.members.cache.get(mentionedUserId); + + return `@${mentionedUser.displayName}`; + }; + message = message.replace(userMentionPattern, replaceUserMention); + + // Replace <#1072863636596465726> with #💬・guild-chat + const channelMentionPattern = /<#(\d+)>/g; + const replaceChannelMention = (match, mentionedChannelId) => { + const mentionedChannel = + message.guild.channels.cache.get(mentionedChannelId); + + return `#${mentionedChannel.name}`; + }; + message = message.replace(channelMentionPattern, replaceChannelMention); + + // Replace <:KEKW:628249422253391902> with :KEKW: || Replace with :KEKW: + const emojiMentionPattern = //g; + message = message.replace(emojiMentionPattern, ":$1:"); + } + + return demojify(message); } shouldBroadcastMessage(message) { const isValid = !message.author.bot && message.content.length > 0; + const validChannelIds = [ + config.discord.officerChannel, + config.discord.guildChatChannel, + config.console.debugChannel, + ]; - return (isValid && (message.channel.id == config.discord.officerChannel || message.channel.id == config.discord.guildChatChannel || message.channel.id == config.console.debugChannel)); + return isValid && validChannelIds.includes(message.channel.id); } } diff --git a/src/discord/handlers/StateHandler.js b/src/discord/handlers/StateHandler.js index da6ad56a..8933beb5 100644 --- a/src/discord/handlers/StateHandler.js +++ b/src/discord/handlers/StateHandler.js @@ -18,7 +18,6 @@ class StateHandler { }); const channel = await getChannel("Guild"); global.bridgeChat = config.discord.guildChatChannel; - global.uptime = new Date().getTime(); channel.send({ embeds: [ diff --git a/src/minecraft/CommandHandler.js b/src/minecraft/CommandHandler.js index 94d9a311..88eefef7 100644 --- a/src/minecraft/CommandHandler.js +++ b/src/minecraft/CommandHandler.js @@ -13,10 +13,8 @@ class CommandHandler { this.commands = new Collection(); const commandFiles = fs.readdirSync("./src/minecraft/commands").filter((file) => file.endsWith(".js")); - global.minecraftCommandList = []; for (const file of commandFiles) { const command = new (require(`./commands/${file}`))(minecraft); - minecraftCommandList.push(command); this.commands.set(command.name, command); } diff --git a/src/minecraft/MinecraftManager.js b/src/minecraft/MinecraftManager.js index a13538f9..166d433c 100644 --- a/src/minecraft/MinecraftManager.js +++ b/src/minecraft/MinecraftManager.js @@ -54,22 +54,24 @@ class MinecraftManager extends CommunicationBridge { return this.bot.chat(message); } + const symbol = config.minecraft.messageFormat; + if (channel === config.discord.guildChatChannel) { return config.discord.filterMessages ? this.bot.chat( filter.clean( `/gc ${ replyingTo - ? `${username} replying to ${replyingTo} »` - : `${username} »` + ? `${username} replying to ${replyingTo}${symbol}` + : `${username}${symbol}` } ${message}` ) ) : this.bot.chat( `/gc ${ replyingTo - ? `${username} replying to ${replyingTo} »` - : `${username} »` + ? `${username} replying to ${replyingTo}${symbol}` + : `${username}${symbol}` } ${message}` ); } @@ -80,16 +82,16 @@ class MinecraftManager extends CommunicationBridge { filter.clean( `/oc ${ replyingTo - ? `${username} replying to ${replyingTo} »` - : `${username} »` + ? `${username} replying to ${replyingTo}${symbol}` + : `${username}${symbol}` } ${message}` ) ) : this.bot.chat( `/oc ${ replyingTo - ? `${username} replying to ${replyingTo} »` - : `${username} »` + ? `${username} replying to ${replyingTo}${symbol}` + : `${username}${symbol}` } ${message}` ); } diff --git a/src/minecraft/commands/8ballCommand.js b/src/minecraft/commands/8ballCommand.js index e5778182..aa1fb8d9 100644 --- a/src/minecraft/commands/8ballCommand.js +++ b/src/minecraft/commands/8ballCommand.js @@ -8,17 +8,20 @@ class EightBallCommand extends minecraftCommand { this.name = "8ball"; this.aliases = ["8b"]; this.description = "Ask an 8ball a question."; - this.options = ["question"]; - this.optionsDescription = ["Any kind of question"]; + this.options = [ + { + name: "question", + description: "The question you want to ask the 8ball", + required: true, + }, + ]; } - async onCommand(username, message) { try { - const { data } = await axios.get(`https://www.eightballapi.com/api`) + const { data } = await axios.get(`https://www.eightballapi.com/api`); this.send(`/gc ${data.reading}`); - } catch (error) { this.send(`/gc Error: ${error?.response?.data?.error}`); } diff --git a/src/minecraft/commands/BedwarsStatsCommand.js b/src/minecraft/commands/BedwarsStatsCommand.js index 9169a77d..3d0c2ef9 100644 --- a/src/minecraft/commands/BedwarsStatsCommand.js +++ b/src/minecraft/commands/BedwarsStatsCommand.js @@ -10,8 +10,13 @@ class BedwarsCommand extends minecraftCommand { this.name = "bedwars"; this.aliases = ["bw", "bws"]; this.description = "BedWars stats of specified user."; - this.options = ["name"]; - this.optionsDescription = ["Minecraft Username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } async onCommand(username, message) { diff --git a/src/minecraft/commands/CatacombsCommand.js b/src/minecraft/commands/CatacombsCommand.js index 24274267..908eaf3a 100644 --- a/src/minecraft/commands/CatacombsCommand.js +++ b/src/minecraft/commands/CatacombsCommand.js @@ -1,6 +1,9 @@ const minecraftCommand = require("../../contracts/minecraftCommand.js"); const getDungeons = require("../../../API/stats/dungeons.js"); -const { numberWithCommas, formatUsername } = require("../../contracts/helperFunctions.js"); +const { + numberWithCommas, + formatUsername, +} = require("../../contracts/helperFunctions.js"); const { getLatestProfile, } = require("../../../API/functions/getLatestProfile.js"); @@ -12,8 +15,13 @@ class CatacombsCommand extends minecraftCommand { this.name = "catacombs"; this.aliases = ["cata", "dungeons"]; this.description = "Skyblock Dungeons Stats of specified user."; - this.options = ["name"]; - this.optionsDescription = ["Minecraft Username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } async onCommand(username, message) { @@ -28,36 +36,40 @@ class CatacombsCommand extends minecraftCommand { if (dungeons == null) { // eslint-disable-next-line no-throw-literal - throw `${username} has never played dungeons on ${data.profileData.cute_name}.` + throw `${username} has never played dungeons on ${data.profileData.cute_name}.`; } - const completions = Object.values(dungeons.catacombs.MASTER_MODE_FLOORS).map( - (floor) => floor.completions - ).reduce((a, b) => a + b, 0) + Object.values(dungeons.catacombs.floors).map( - (floor) => floor.completions - ).reduce((a, b) => a + b, 0); + const completions = + Object.values(dungeons.catacombs.MASTER_MODE_FLOORS) + .map((floor) => floor.completions) + .reduce((a, b) => a + b, 0) + + Object.values(dungeons.catacombs.floors) + .map((floor) => floor.completions) + .reduce((a, b) => a + b, 0); this.send( `/gc ${username}'s Catacombs: ${ - dungeons.catacombs.skill.level > 50 ? dungeons.catacombs.skill.levelWithProgress.toFixed(2) : dungeons.catacombs.skill.level + dungeons.catacombs.skill.level > 50 + ? dungeons.catacombs.skill.levelWithProgress.toFixed(2) + : dungeons.catacombs.skill.level } | Class Average: ${ - (Object.keys(dungeons.classes).map((className) => dungeons.classes[className].level).reduce((a, b) => a + b, 0) / Object.keys(dungeons.classes).length) - } | Secrets Found: ${numberWithCommas( - dungeons.secrets_found || 0 - )} (${ - (dungeons.secrets_found / completions).toFixed(2) - } SPR) | Classes: H - ${dungeons.classes.healer.level} M - ${ - dungeons.classes.mage.level - } B - ${dungeons.classes.berserk.level} A - ${ - dungeons.classes.archer.level - } T - ${dungeons.classes.tank.level}` + Object.keys(dungeons.classes) + .map((className) => dungeons.classes[className].level) + .reduce((a, b) => a + b, 0) / Object.keys(dungeons.classes).length + } | Secrets Found: ${numberWithCommas(dungeons.secrets_found || 0)} (${( + dungeons.secrets_found / completions + ).toFixed(2)} SPR) | Classes: H - ${ + dungeons.classes.healer.level + } M - ${dungeons.classes.mage.level} B - ${ + dungeons.classes.berserk.level + } A - ${dungeons.classes.archer.level} T - ${ + dungeons.classes.tank.level + }` ); } catch (error) { - console.log(error) + console.log(error); - this.send( - `/gc Error: ${error}` - ); + this.send(`/gc Error: ${error}`); } } } diff --git a/src/minecraft/commands/DenickerCommand.js b/src/minecraft/commands/DenickerCommand.js index 50793128..0b3501ab 100644 --- a/src/minecraft/commands/DenickerCommand.js +++ b/src/minecraft/commands/DenickerCommand.js @@ -10,14 +10,21 @@ class DenickerCommand extends minecraftCommand { this.name = "denick"; this.aliases = []; this.description = "Denick username of specified user."; - this.options = ["nick"]; - this.optionsDescription = ["Minecraft Username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } async onCommand(username, message) { try { username = this.getArgs(message)[0]; - const { data } = await axios.get(`${config.api.antiSniperAPI}/denick?key=${config.api.antiSniperKey}&nick=${username}`); + const { data } = await axios.get( + `${config.api.antiSniperAPI}/denick?key=${config.api.antiSniperKey}&nick=${username}` + ); if (data.player?.ign == null) { return this.send("/gc Sorry, I wasn't able to denick this person."); @@ -25,7 +32,11 @@ class DenickerCommand extends minecraftCommand { const player = await hypixel.getPlayer(data.player?.ign); - this.send(`/gc ${player.rank ? `[${player.rank}] ` : ``}${data.player?.ign} is nicked as ${data.player.queried_nick}`); + this.send( + `/gc ${player.rank ? `[${player.rank}] ` : ``}${ + data.player?.ign + } is nicked as ${data.player.queried_nick}` + ); } catch (error) { this.send(`/gc Error: ${error?.response?.data?.error || error}`); } diff --git a/src/minecraft/commands/DuelsStatsCommand.js b/src/minecraft/commands/DuelsStatsCommand.js index 571b91a6..af95fdd2 100644 --- a/src/minecraft/commands/DuelsStatsCommand.js +++ b/src/minecraft/commands/DuelsStatsCommand.js @@ -8,8 +8,35 @@ class DuelsStatsCommand extends minecraftCommand { this.name = "duels"; this.aliases = ["duel"]; this.description = "Duel stats of specified user."; - this.options = ["name", "duel"]; - this.optionsDescription = ["Minecraft Username", "Type of Duel"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + { + name: "duel", + description: "Type of duel", + required: false, + choices: [ + { name: "Blitz", value: "blitz" }, + { name: "UHC", value: "uhc" }, + { name: "Parkour", value: "parkour" }, + { name: "Boxing", value: "boxing" }, + { name: "Bow Spleef", value: "bowspleef" }, + { name: "Spleef", value: "spleef" }, + { name: "Arena", value: "arena" }, + { name: "Mega Walls", value: "megawalls" }, + { name: "OP", value: "op" }, + { name: "Sumo", value: "sumo" }, + { name: "Classic", value: "classic" }, + { name: "Combo", value: "combo" }, + { name: "Bridge", value: "bridge" }, + { name: "No Debuff", value: "nodebuff" }, + { name: "Bow", value: "bow" }, + ], + }, + ] } async onCommand(username, message) { diff --git a/src/minecraft/commands/FairySoulsCommand.js b/src/minecraft/commands/FairySoulsCommand.js index 4340668a..ad933074 100644 --- a/src/minecraft/commands/FairySoulsCommand.js +++ b/src/minecraft/commands/FairySoulsCommand.js @@ -11,8 +11,13 @@ class FairySoulsCommand extends minecraftCommand { this.name = "fairysouls"; this.aliases = ["fs"]; this.description = "Fairy Souls of specified user."; - this.options = ["name"]; - this.optionsDescription = ["Minecraft Username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } async onCommand(username, message) { @@ -21,14 +26,19 @@ class FairySoulsCommand extends minecraftCommand { const data = await getLatestProfile(username); username = formatUsername(username, data.profileData.game_mode); - + const total = data.profileData.game_mode === "island" ? 5 : 238; - this.send(`/gc ${username}'s Fairy Souls: ${data.profile.fairy_souls_collected}/${total} | Progress: ${(data.profile.fairy_souls_collected / total * 100).toFixed(2)}%`); - + this.send( + `/gc ${username}'s Fairy Souls: ${ + data.profile.fairy_souls_collected + }/${total} | Progress: ${( + (data.profile.fairy_souls_collected / total) * + 100 + ).toFixed(2)}%` + ); } catch (error) { this.send(`/gc Error: ${error}`); - } } } diff --git a/src/minecraft/commands/NetWorthCommand.js b/src/minecraft/commands/NetWorthCommand.js index 31c793d6..da2bc559 100644 --- a/src/minecraft/commands/NetWorthCommand.js +++ b/src/minecraft/commands/NetWorthCommand.js @@ -16,8 +16,13 @@ class NetWorthCommand extends minecraftCommand { this.name = "networth"; this.aliases = ["nw"]; this.description = "Networth of specified user."; - this.options = ["name"]; - this.optionsDescription = ["Minecraft Username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ] } async onCommand(username, message) { diff --git a/src/minecraft/commands/SkyWarsStatsCommand.js b/src/minecraft/commands/SkyWarsStatsCommand.js index da1aeb07..f3f2378a 100644 --- a/src/minecraft/commands/SkyWarsStatsCommand.js +++ b/src/minecraft/commands/SkyWarsStatsCommand.js @@ -7,8 +7,13 @@ class SkywarsCommand extends minecraftCommand { this.name = "skywars"; this.aliases = ["sw"]; this.description = "Skywars stats of specified user."; - this.options = ["name"]; - this.optionsDescription = ["Minecraft Username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } async onCommand(username, message) { diff --git a/src/minecraft/commands/SlayersCommand.js b/src/minecraft/commands/SlayersCommand.js index 3c260efc..ef854d76 100644 --- a/src/minecraft/commands/SlayersCommand.js +++ b/src/minecraft/commands/SlayersCommand.js @@ -3,7 +3,10 @@ const { getLatestProfile, } = require("../../../API/functions/getLatestProfile.js"); const getSlayer = require("../../../API/stats/slayer.js"); -const { addCommas, formatUsername } = require("../../contracts/helperFunctions.js"); +const { + addCommas, + formatUsername, +} = require("../../contracts/helperFunctions.js"); const { capitalize } = require("lodash"); class SlayersCommand extends minecraftCommand { @@ -13,31 +16,61 @@ class SlayersCommand extends minecraftCommand { this.name = "slayer"; this.aliases = ["slayers"]; this.description = "Slayer of specified user."; - this.options = ["name", "type"]; - this.optionsDescription = ["Minecraft Username", "Type of Slayer"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + { + name: "slayer", + description: "Slayer type", + required: false, + }, + ]; } async onCommand(username, message) { try { const args = this.getArgs(message); - const slayer = ["zombie", "rev", "spider", "tara", "wolf", "sven", "eman", "enderman", "blaze", "demonlord"]; + const slayer = [ + "zombie", + "rev", + "spider", + "tara", + "wolf", + "sven", + "eman", + "enderman", + "blaze", + "demonlord", + ]; const slayerType = slayer.includes(args[1]) ? args[1] : null; username = args[0] || username; const data = await getLatestProfile(username); - + username = formatUsername(username, data.profileData.cute_name); const profile = getSlayer(data.profile); if (slayerType) { - this.send(`/gc ${username}'s ${capitalize(slayerType)} - ${profile[slayerType].level} Levels | Experience: ${addCommas(profile[slayerType].xp)}`); + this.send( + `/gc ${username}'s ${capitalize(slayerType)} - ${ + profile[slayerType].level + } Levels | Experience: ${addCommas(profile[slayerType].xp)}` + ); } else { - const slayer = Object.keys(profile).reduce((acc, slayer) => `${acc} | ${capitalize(slayer)}: Level: ${profile[slayer].level} | Experience: ${addCommas(profile[slayer].xp)}`, ""); + const slayer = Object.keys(profile).reduce( + (acc, slayer) => + `${acc} | ${capitalize(slayer)}: Level: ${ + profile[slayer].level + } | Experience: ${addCommas(profile[slayer].xp)}`, + "" + ); this.send(`/gc ${username}'s Slayer - ${slayer}`); } - } catch (error) { this.send(`/gc Error: ${error}`); } diff --git a/src/minecraft/commands/UHCStatsCommmand.js b/src/minecraft/commands/UHCStatsCommmand.js index 7578442d..58c7af33 100644 --- a/src/minecraft/commands/UHCStatsCommmand.js +++ b/src/minecraft/commands/UHCStatsCommmand.js @@ -8,8 +8,13 @@ class UHCStatsCommand extends minecraftCommand { this.name = "UHC"; this.aliases = ["uhc"]; this.description = "UHC Stats of specified user."; - this.options = ["name"]; - this.optionsDescription = ["Minecraft Username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } async onCommand(username, message) { diff --git a/src/minecraft/commands/WeightCommand.js b/src/minecraft/commands/WeightCommand.js index ae1fec90..0287ba42 100644 --- a/src/minecraft/commands/WeightCommand.js +++ b/src/minecraft/commands/WeightCommand.js @@ -1,4 +1,4 @@ -const minecraftCommand = require("../../contracts/MinecraftCommand.js"); +const minecraftCommand = require("../../contracts/minecraftCommand.js"); const { getLatestProfile, } = require("../../../API/functions/getLatestProfile.js"); @@ -13,8 +13,13 @@ class StatsCommand extends minecraftCommand { this.name = "weight"; this.aliases = ["w"]; this.description = "Skyblock Weight of specified user."; - this.options = ["name"]; - this.optionsDescription = ["Minecraft Username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } async onCommand(username, message) { @@ -38,8 +43,7 @@ class StatsCommand extends minecraftCommand { )} | Skills: ${Object.keys(profile.senither.skills) .map((skill) => profile.senither.skills[skill].total) .reduce((a, b) => a + b, 0) - .toFixed(2) - } | Dungeons: ${profile.senither.dungeons.total.toFixed(2)}`; + .toFixed(2)} | Dungeons: ${profile.senither.dungeons.total.toFixed(2)}`; this.send(`/gc ${username}'s ${senitherW}`); await delay(690); this.send(`/gc ${username}'s ${lilyW}`); diff --git a/src/minecraft/commands/accessoriesCommand.js b/src/minecraft/commands/accessoriesCommand.js index 55d4d578..76444d18 100644 --- a/src/minecraft/commands/accessoriesCommand.js +++ b/src/minecraft/commands/accessoriesCommand.js @@ -13,8 +13,13 @@ class AccessoriesCommand extends minecraftCommand { this.name = "accessories"; this.aliases = ["talismans", "talisman"]; this.description = "Accessories of specified user."; - this.options = ["name"]; - this.optionsDescription = ["Minecraft Username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } async onCommand(username, message) { @@ -32,19 +37,32 @@ class AccessoriesCommand extends minecraftCommand { .reduce((a, b) => a + b, 0); const recombobulatedCount = Object.keys(talismans.talismans) - .map((rarity) =>talismans.talismans[rarity].filter((talisman) => talisman.recombobulated).length) + .map( + (rarity) => + talismans.talismans[rarity].filter( + (talisman) => talisman.recombobulated + ).length + ) .reduce((a, b) => a + b, 0); const enrichmentCount = Object.keys(talismans.talismans) - .map((rarity) =>talismans.talismans[rarity].filter((talisman) => talisman.enrichment !== undefined).length) + .map( + (rarity) => + talismans.talismans[rarity].filter( + (talisman) => talisman.enrichment !== undefined + ).length + ) .reduce((a, b) => a + b, 0); - this.send(`/gc ${username}'s Accessories » ${talismanCount} | Recombobulated » ${recombobulatedCount} | Enriched » ${enrichmentCount}`); + this.send( + `/gc ${username}'s Accessories » ${talismanCount} | Recombobulated » ${recombobulatedCount} | Enriched » ${enrichmentCount}` + ); await delay(690); - this.send(`/gc ${username}'s Accessories » Common - ${talismans.talismans["common"].length} | Uncommon - ${talismans.talismans["uncommon"].length} | Rare - ${talismans.talismans["rare"].length} | Epic - ${talismans.talismans["epic"].length} | Legendary - ${talismans.talismans["legendary"].length} | Special - ${talismans.talismans["special"].length} | Very Special - ${talismans.talismans["very"].length}`); - + this.send( + `/gc ${username}'s Accessories » Common - ${talismans.talismans["common"].length} | Uncommon - ${talismans.talismans["uncommon"].length} | Rare - ${talismans.talismans["rare"].length} | Epic - ${talismans.talismans["epic"].length} | Legendary - ${talismans.talismans["legendary"].length} | Special - ${talismans.talismans["special"].length} | Very Special - ${talismans.talismans["very"].length}` + ); } catch (error) { this.send(`/gc Error: ${error}`); } diff --git a/src/minecraft/commands/auctionHouseCommand.js b/src/minecraft/commands/auctionHouseCommand.js index 26ae154e..989d261f 100644 --- a/src/minecraft/commands/auctionHouseCommand.js +++ b/src/minecraft/commands/auctionHouseCommand.js @@ -16,8 +16,13 @@ class AuctionHouseCommand extends minecraftCommand { this.name = "auction"; this.aliases = ["ah", "auctions"]; this.description = "Listed Auctions of specified user."; - this.options = ["name"]; - this.optionsDescription = ["Minecraft Username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } async onCommand(username, message) { @@ -27,12 +32,23 @@ class AuctionHouseCommand extends minecraftCommand { username = this.getArgs(message)[0] || username; let string = ""; - const uuid = await getUUID(username); - const response = (await axios.get(`${config.api.hypixelAPI}/skyblock/auction?key=${config.api.hypixelAPIkey}&player=${uuid}`)).data?.auctions || []; - const player = (await axios.get(`${config.api.hypixelAPI}/player?key=${config.api.hypixelAPIkey}&uuid=${uuid}`)).data?.player || {}; + const response = + ( + await axios.get( + `${config.api.hypixelAPI}/skyblock/auction?key=${config.api.hypixelAPIkey}&player=${uuid}` + ) + ).data?.auctions || []; + const player = + ( + await axios.get( + `${config.api.hypixelAPI}/player?key=${config.api.hypixelAPIkey}&uuid=${uuid}` + ) + ).data?.player || {}; - const activeAuctions = response.filter((auction) => auction.end >= Date.now()) + const activeAuctions = response.filter( + (auction) => auction.end >= Date.now() + ); for (const auction of activeAuctions) { const lore = auction.item_lore.split("\n"); @@ -46,29 +62,40 @@ class AuctionHouseCommand extends minecraftCommand { if (auction.bids.length === 0) { lore.push( `§7Starting Bid: §6${addCommas(auction.starting_bid)} coins`, - `§7`, - ) + `§7` + ); } else if (auction.bids.length > 0) { - const bidder = (await axios.get(`${config.api.hypixelAPI}/player?key=${config.api.hypixelAPIkey}&uuid=${auction.bids[auction.bids.length - 1].bidder}`)).data?.player || {}; + const bidder = + ( + await axios.get( + `${config.api.hypixelAPI}/player?key=${ + config.api.hypixelAPIkey + }&uuid=${auction.bids[auction.bids.length - 1].bidder}` + ) + ).data?.player || {}; lore.push( - `§7Bids: §a${auction.bids.length} ${auction.bids.length === 1 ? 'bid' : 'bids'}`, + `§7Bids: §a${auction.bids.length} ${ + auction.bids.length === 1 ? "bid" : "bids" + }`, `§7`, - `§7Top Bid: §6${addCommas(auction.bids[auction.bids.length - 1].amount)} coins`, + `§7Top Bid: §6${addCommas( + auction.bids[auction.bids.length - 1].amount + )} coins`, `§7Bidder: ${getRank(bidder)} ${bidder.displayname}`, - `§7`, - ) + `§7` + ); } } else { lore.push( `§7Buy it now: §6${addCommas(auction.starting_bid)} coins`, - `§7`, - ) + `§7` + ); } lore.push( `§7Ends in: §e${timeSince(auction.end)}`, `§7`, - `§eClick to inspect`, + `§eClick to inspect` ); const renderedItem = await renderLore(` ${auction.item_name}`, lore); @@ -77,10 +104,16 @@ class AuctionHouseCommand extends minecraftCommand { type: "stream", }); - string += string === "" ? upload.data.link : " | " + upload.data.link; + string += string === "" ? upload.data.link : " | " + upload.data.link; } - this.send(`/gc ${string === "" ? "This player does not have any auctions active" : `${username}'s Active Auctions » ${string}`}`); + this.send( + `/gc ${ + string === "" + ? "This player does not have any auctions active" + : `${username}'s Active Auctions » ${string}` + }` + ); } catch (error) { console.log(error); this.send(`/gc [ERROR] ${error}`); diff --git a/src/minecraft/commands/bedwarsWinstreakCommand.js b/src/minecraft/commands/bedwarsWinstreakCommand.js index 338c5ea5..5bae1946 100644 --- a/src/minecraft/commands/bedwarsWinstreakCommand.js +++ b/src/minecraft/commands/bedwarsWinstreakCommand.js @@ -10,8 +10,13 @@ class DenickerCommand extends minecraftCommand { this.name = "winstreak"; this.aliases = ["ws"]; this.description = "Estimated winstreaks of the specified user."; - this.options = ["name"]; - this.optionsDescription = ["Minecraft Username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } async onCommand(username, message) { @@ -40,7 +45,9 @@ class DenickerCommand extends minecraftCommand { ); } catch (error) { if (error.player == null) { - this.send("/gc Error: This player does not exist in AntiSniper database."); + this.send( + "/gc Error: This player does not exist in AntiSniper database." + ); } else { this.send(`/gc Error: ${error?.response?.data?.error}`); } diff --git a/src/minecraft/commands/calculateCommand.js b/src/minecraft/commands/calculateCommand.js index 2d1b7b46..84624bd1 100644 --- a/src/minecraft/commands/calculateCommand.js +++ b/src/minecraft/commands/calculateCommand.js @@ -1,19 +1,29 @@ -const { addCommas, addNotation } = require("../../contracts/helperFunctions.js"); +const { + addCommas, + addNotation, +} = require("../../contracts/helperFunctions.js"); const minecraftCommand = require("../../contracts/minecraftCommand.js"); class CalculateCommand extends minecraftCommand { constructor(minecraft) { super(minecraft); - this.name = "math"; - this.aliases = ["calc", "calculate"]; + this.name = "calculate"; + this.aliases = ["calc", "math"]; this.description = "Calculate."; - this.options = ["calculation"]; - this.optionsDescription = ["Any kind of math equation"]; + this.options = [ + { + name: "calculation", + description: "Any kind of math equation", + required: true, + }, + ]; } onCommand(username, message) { try { - const calculation = this.getArgs(message).join(" ").replace(/[^-()\d/*+.]/g, ""); + const calculation = this.getArgs(message) + .join(" ") + .replace(/[^-()\d/*+.]/g, ""); const answer = eval(calculation); if (answer === Infinity) { @@ -22,9 +32,13 @@ class CalculateCommand extends minecraftCommand { if (answer < 100000) { return this.send(`/gc ${calculation} = ${addCommas(answer)}`); - } - - this.send(`/gc ${calculation} = ${addNotation("oneLetters", answer)} (${addCommas(answer)})`); + } + + this.send( + `/gc ${calculation} = ${addNotation("oneLetters", answer)} (${addCommas( + answer + )})` + ); } catch (error) { this.send(`/gc Error: ${error}`); } diff --git a/src/minecraft/commands/dailyCommand.js b/src/minecraft/commands/dailyCommand.js index 5bba1708..22bbb52f 100644 --- a/src/minecraft/commands/dailyCommand.js +++ b/src/minecraft/commands/dailyCommand.js @@ -11,8 +11,18 @@ class DailyStatsCommand extends minecraftCommand { this.name = "daily"; this.aliases = [""]; this.description = "Get your daily stats."; - this.options = ["name", "gamemode"]; - this.optionsDescription = ["Minecraft Username", "Hypixel Gamemode"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + { + name: "mode", + description: "Gamemode", + required: false, + } + ]; } async onCommand(username, message) { @@ -29,10 +39,21 @@ class DailyStatsCommand extends minecraftCommand { "duel", "d", ]; - const args = this.getArgs(message).map((arg) => arg.replaceAll("/", "")) + const args = this.getArgs(message).map((arg) => arg.replaceAll("/", "")); - const mode = modes.includes(args[0]) ? args[0] : modes.includes(args[1]) ? args[1] : null; - username = (args[0] == mode ? args[1] === "" ? username : args[1] : args[0] === "" ? username : args[0]) || username; + const mode = modes.includes(args[0]) + ? args[0] + : modes.includes(args[1]) + ? args[1] + : null; + username = + (args[0] == mode + ? args[1] === "" + ? username + : args[1] + : args[0] === "" + ? username + : args[0]) || username; try { const uuid = await getUUID(username); diff --git a/src/minecraft/commands/guildCommand.js b/src/minecraft/commands/guildCommand.js index 8b97b1ab..caf8f05d 100644 --- a/src/minecraft/commands/guildCommand.js +++ b/src/minecraft/commands/guildCommand.js @@ -9,17 +9,25 @@ class GuildInformationCommand extends minecraftCommand { this.name = "guild"; this.aliases = ["g"]; this.description = "View information of a guild"; - - this.options = ["name"]; - this.optionsDescription = ["Name of the Guild"]; + this.options = [ + { + name: "guild", + description: "Guild name", + required: true, + }, + ]; } async onCommand(username, message) { try { - const guildName = this.getArgs(message).map((arg) => capitalize(arg)).join(" "); - const guild = await hypixel.getGuild("name", guildName) + const guildName = this.getArgs(message) + .map((arg) => capitalize(arg)) + .join(" "); + const guild = await hypixel.getGuild("name", guildName); - this.send(`/gc Guild ${guildName} | Tag: ${guild.tag} | Members: ${guild.members.length} | Level: ${guild.level} | Weekly GEXP: ${guild.totalWeeklyGexp}`); + this.send( + `/gc Guild ${guildName} | Tag: ${guild.tag} | Members: ${guild.members.length} | Level: ${guild.level} | Weekly GEXP: ${guild.totalWeeklyGexp}` + ); } catch (error) { this.send(`/gc ${error.toString().replace("[hypixel-api-reborn] ", "")}`); } diff --git a/src/minecraft/commands/guildExperienceCommand.js b/src/minecraft/commands/guildExperienceCommand.js index c82fc447..900d7b38 100644 --- a/src/minecraft/commands/guildExperienceCommand.js +++ b/src/minecraft/commands/guildExperienceCommand.js @@ -11,7 +11,13 @@ class GuildExperienceCommand extends minecraftCommand { this.name = "guildexp"; this.aliases = ["gexp"]; this.description = "Guilds experience of specified user."; - this.options = ["name"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } async onCommand(username, message) { @@ -24,14 +30,16 @@ class GuildExperienceCommand extends minecraftCommand { hypixel.getGuild("id", config.minecraft.guildID), ]); - const player = guild.members.find((member) => member.uuid == uuid) + const player = guild.members.find((member) => member.uuid == uuid); // eslint-disable-next-line no-throw-literal if (!player) throw "Player is not in the Guild."; - this.send(`/gc ${username == arg[0] ? `${arg[0]}'s` : `Your`} Weekly Guild Experience » ${addCommas(player.weeklyExperience)}.`); - - + this.send( + `/gc ${ + username == arg[0] ? `${arg[0]}'s` : `Your` + } Weekly Guild Experience » ${addCommas(player.weeklyExperience)}.` + ); } catch (error) { this.send(`/gc ${error.toString().replace("[hypixel-api-reborn] ", "")}`); } diff --git a/src/minecraft/commands/helpCommand.js b/src/minecraft/commands/helpCommand.js index 15969a18..392b1d05 100644 --- a/src/minecraft/commands/helpCommand.js +++ b/src/minecraft/commands/helpCommand.js @@ -8,7 +8,6 @@ class HelpCommand extends minecraftCommand { this.aliases = ["info"]; this.description = "Shows help menu"; this.options = []; - this.optionsDescription = []; } onCommand(username, message) { diff --git a/src/minecraft/commands/kittyCommand.js b/src/minecraft/commands/kittyCommand.js index a8cc8501..e0d8c112 100644 --- a/src/minecraft/commands/kittyCommand.js +++ b/src/minecraft/commands/kittyCommand.js @@ -13,7 +13,6 @@ class KittyCommand extends minecraftCommand { this.aliases = ["cat", "cutecat"]; this.description = "Random image of cute cat."; this.options = []; - this.optionsDescription = []; } async onCommand(username, message) { diff --git a/src/minecraft/commands/megawallsCommand.js b/src/minecraft/commands/megawallsCommand.js index 779ea211..f974b1a0 100644 --- a/src/minecraft/commands/megawallsCommand.js +++ b/src/minecraft/commands/megawallsCommand.js @@ -8,18 +8,30 @@ class EightBallCommand extends minecraftCommand { this.name = "megawalls"; this.aliases = ["mw"]; this.description = "View the Megawalls stats of a player"; - this.options = ["username"]; - this.optionsDescription = ["Minecraft username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } - async onCommand(username, message) { try { - username = this.getArgs(message)[0] || username; + username = this.getArgs(message)[0] || username; const megawalls = (await hypixel.getPlayer(username)).stats.megawalls; - this.send(`/gc ${username}'s Megawalls: Class: ${megawalls.selectedClass || "None"} | FK: ${megawalls.finalKills} | FKDR: ${megawalls.finalKDRatio} | W: ${megawalls.wins} | WLR: ${megawalls.WLRatio} | K: ${megawalls.kills} | KDR: ${megawalls.KDRatio} | A: ${megawalls.assists}`) + this.send( + `/gc ${username}'s Megawalls: Class: ${ + megawalls.selectedClass || "None" + } | FK: ${megawalls.finalKills} | FKDR: ${ + megawalls.finalKDRatio + } | W: ${megawalls.wins} | WLR: ${megawalls.WLRatio} | K: ${ + megawalls.kills + } | KDR: ${megawalls.KDRatio} | A: ${megawalls.assists}` + ); } catch (error) { this.send(`/gc ${error.toString().replace("[hypixel-api-reborn] ", "")}`); } diff --git a/src/minecraft/commands/monthlyCommand.js b/src/minecraft/commands/monthlyCommand.js index 739f683a..ac0913ed 100644 --- a/src/minecraft/commands/monthlyCommand.js +++ b/src/minecraft/commands/monthlyCommand.js @@ -11,8 +11,18 @@ class MonthlyStatsCommand extends minecraftCommand { this.name = "monthly"; this.aliases = [""]; this.description = "Get monthly stats of specified user."; - this.options = ["name", "gamemode"]; - this.optionsDescription = ["Minecraft Username", "Hypixel Gamemode"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + { + name: "gamemode", + description: "Gamemode", + required: false, + } + ] } async onCommand(username, message) { diff --git a/src/minecraft/commands/quickMathsCommand.js b/src/minecraft/commands/quickMathsCommand.js new file mode 100644 index 00000000..3db1f661 --- /dev/null +++ b/src/minecraft/commands/quickMathsCommand.js @@ -0,0 +1,59 @@ +const minecraftCommand = require("../../contracts/minecraftCommand.js"); + +const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); +const getAnswer = (message) => message.split(": ")[1]; + +class QuickMathsCommand extends minecraftCommand { + constructor(minecraft) { + super(minecraft); + + this.name = "quickmaths"; + this.aliases = ["qm"]; + this.description = "Solve the equation in less than 10 seconds! Test your math skills!"; + this.options = []; + } + + async onCommand(username, message) { + try { + const userUsername = username; + const operands = [Math.floor(Math.random() * 10), Math.floor(Math.random() * 10)]; + const operators = ["+", "-", "*"]; + const operator = operators[Math.floor(Math.random() * operators.length)]; + + const equation = `${operands[0]} ${operator} ${operands[1]}`; + const answer = eval(operands.join(operator)); + const headStart = 250; + + this.send(`/gc ${username} What is ${equation}? (You have ${headStart}ms headstart)`); + await delay(headStart); + + const startTime = Date.now(); + let answered = false; + + const listener = (username, message) => { + if (username === bot.username || getAnswer(message) !== answer.toString()) { + return; + } + + answered = true; + this.send(`/gc ${userUsername} Correct! It took you ${(Date.now() - startTime).toLocaleString()}ms`); + bot.removeListener("chat", listener); + }; + + bot.on("chat", listener); + + setTimeout(() => { + bot.removeListener("chat", listener); + + if (!answered) { + this.send(`/gc ${userUsername} Time's up! The answer was ${answer}`); + } + }, 10000); + + } catch (error) { + this.send(`/gc ${username} Error: ${error || "Something went wrong.."}`); + } + } +} + +module.exports = QuickMathsCommand; \ No newline at end of file diff --git a/src/minecraft/commands/renderArmorCommand.js b/src/minecraft/commands/renderArmorCommand.js index 407b2de3..bc23abca 100644 --- a/src/minecraft/commands/renderArmorCommand.js +++ b/src/minecraft/commands/renderArmorCommand.js @@ -5,7 +5,10 @@ const { } = require("../../../API/functions/getLatestProfile.js"); const config = require("../../../config.json"); const imgurClient = new ImgurClient({ clientId: config.api.imgurAPIkey }); -const { decodeData, formatUsername } = require("../../contracts/helperFunctions.js"); +const { + decodeData, + formatUsername, +} = require("../../contracts/helperFunctions.js"); const minecraftCommand = require("../../contracts/minecraftCommand.js"); const { renderLore } = require("../../contracts/renderItem.js"); @@ -16,8 +19,13 @@ class ArmorCommand extends minecraftCommand { this.name = "armor"; this.aliases = []; this.description = "Renders armor of specified user."; - this.options = ["name"]; - this.optionsDescription = ["Minecraft Username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } async onCommand(username, message) { @@ -25,14 +33,16 @@ class ArmorCommand extends minecraftCommand { username = this.getArgs(message)[0] || username; const profile = await getLatestProfile(username); - + username = formatUsername(username, profile.profileData?.game_mode); if (!profile.profile.inv_armor?.data) { return this.send(`/gc This player has an Inventory API off.`); } - - const inventoryData = (await decodeData(Buffer.from(profile.profile.inv_armor.data, "base64"))).i; + + const inventoryData = ( + await decodeData(Buffer.from(profile.profile.inv_armor.data, "base64")) + ).i; let response = ""; for (const piece of Object.values(inventoryData)) { @@ -42,13 +52,20 @@ class ArmorCommand extends minecraftCommand { piece?.tag?.display?.Name, piece?.tag?.display?.Lore ); - const upload = await imgurClient.upload({ image: renderedItem, type: "stream", }); + const upload = await imgurClient.upload({ + image: renderedItem, + type: "stream", + }); - response += response.split(" | ").length == 4 ? upload.data.link: `${upload.data.link} | `; + response += + response.split(" | ").length == 4 + ? upload.data.link + : `${upload.data.link} | `; } - response == "" ? this.send(`/gc ${username} has no armor equiped.`) : this.send(`/gc ${username}'s armor » ${response}`); - + response == "" + ? this.send(`/gc ${username} has no armor equiped.`) + : this.send(`/gc ${username}'s armor » ${response}`); } catch (error) { this.send(`/gc Error: ${error}`); } diff --git a/src/minecraft/commands/renderEquipmentCommand.js b/src/minecraft/commands/renderEquipmentCommand.js index 6a1fe498..84ed116d 100644 --- a/src/minecraft/commands/renderEquipmentCommand.js +++ b/src/minecraft/commands/renderEquipmentCommand.js @@ -5,7 +5,10 @@ const { } = require("../../../API/functions/getLatestProfile.js"); const config = require("../../../config.json"); const imgurClient = new ImgurClient({ clientId: config.api.imgurAPIkey }); -const { decodeData, formatUsername } = require("../../contracts/helperFunctions.js"); +const { + decodeData, + formatUsername, +} = require("../../contracts/helperFunctions.js"); const minecraftCommand = require("../../contracts/minecraftCommand.js"); const { renderLore } = require("../../contracts/renderItem.js"); @@ -16,8 +19,13 @@ class EquipmentCommand extends minecraftCommand { this.name = "equipment"; this.aliases = []; this.description = "Renders equipment of specified user."; - this.options = ["name"]; - this.optionsDescription = ["Minecraft Username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } async onCommand(username, message) { @@ -26,14 +34,18 @@ class EquipmentCommand extends minecraftCommand { const profile = await getLatestProfile(username); - username = formatUsername(username, profile.profileData?.game_mode) + username = formatUsername(username, profile.profileData?.game_mode); if (!profile.profile.equippment_contents?.data) { return this.send(`/gc This player has an Inventory API off.`); } let response = ""; - const inventoryData = (await decodeData(Buffer.from(profile.profile.equippment_contents.data, "base64"))).i; + const inventoryData = ( + await decodeData( + Buffer.from(profile.profile.equippment_contents.data, "base64") + ) + ).i; for (const piece of Object.values(inventoryData)) { if (!piece?.tag?.display?.Name) continue; @@ -42,15 +54,22 @@ class EquipmentCommand extends minecraftCommand { piece?.tag?.display?.Lore ); - const upload = await imgurClient.upload({ image: renderedItem, type: "stream" }); + const upload = await imgurClient.upload({ + image: renderedItem, + type: "stream", + }); - response += response.split(" | ").length == 4 ? upload.data.link : `${upload.data.link} | `; + response += + response.split(" | ").length == 4 + ? upload.data.link + : `${upload.data.link} | `; } - response == "" ? this.send(`/gc ${username} has no equipment equiped.`) : this.send(`/gc ${username}'s Equipment » ${response}`); - + response == "" + ? this.send(`/gc ${username} has no equipment equiped.`) + : this.send(`/gc ${username}'s Equipment » ${response}`); } catch (error) { - this.send(`/gc Error: ${error}`) + this.send(`/gc Error: ${error}`); } } } diff --git a/src/minecraft/commands/renderItemsCommand.js b/src/minecraft/commands/renderItemsCommand.js index 3756d127..086a7e44 100644 --- a/src/minecraft/commands/renderItemsCommand.js +++ b/src/minecraft/commands/renderItemsCommand.js @@ -13,11 +13,21 @@ class RenderCommand extends minecraftCommand { constructor(minecraft) { super(minecraft); - this.name = "inventory"; - this.aliases = ["inv", "i", "render", "i"]; + this.name = "render"; + this.aliases = ["inv", "i", "inventory", "i"]; this.description = "Renders item of specified user."; - this.options = ["name", "slot"]; - this.optionsDescription = ["Minecraft Username", "Number between 1 and 36"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + { + name: "slot", + description: "Slot number of item to render (1-36)", + required: false, + }, + ] } async onCommand(username, message) { diff --git a/src/minecraft/commands/renderPetCommand.js b/src/minecraft/commands/renderPetCommand.js index 8c944e99..088d45b7 100644 --- a/src/minecraft/commands/renderPetCommand.js +++ b/src/minecraft/commands/renderPetCommand.js @@ -2,7 +2,10 @@ const { ImgurClient } = require("imgur"); const config = require("../../../config.json"); const imgurClient = new ImgurClient({ clientId: config.api.imgurAPIkey }); -const { getRarityColor, formatUsername } = require("../../contracts/helperFunctions.js"); +const { + getRarityColor, + formatUsername, +} = require("../../contracts/helperFunctions.js"); const minecraftCommand = require("../../contracts/minecraftCommand.js"); const { renderLore } = require("../../contracts/renderItem.js"); const { @@ -17,8 +20,13 @@ class RenderCommand extends minecraftCommand { this.name = "pet"; this.aliases = ["pets"]; this.description = "Renders active pet of specified user."; - this.options = ["name"]; - this.optionsDescription = ["Minecraft Username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } async onCommand(username, message) { @@ -54,18 +62,26 @@ class RenderCommand extends minecraftCommand { } const renderedItem = await renderLore( - `§7[Lvl ${pet.level}] §${getRarityColor(pet.tier)}${pet.display_name}`, + `§7[Lvl ${pet.level}] §${getRarityColor(pet.tier)}${ + pet.display_name + }`, newLore ); - const upload = await imgurClient.upload({ image: renderedItem, type: "stream" }); - - return this.send(`/gc ${username}'s Active Pet » ${upload.data.link ?? "Something went Wrong.."}`); + const upload = await imgurClient.upload({ + image: renderedItem, + type: "stream", + }); + + return this.send( + `/gc ${username}'s Active Pet » ${ + upload.data.link ?? "Something went Wrong.." + }` + ); } } this.send(`/gc ${username} does not have pet equiped.`); - } catch (error) { this.send(`/gc Error: ${error}`); } diff --git a/src/minecraft/commands/skillsCommand.js b/src/minecraft/commands/skillsCommand.js index 87dd619a..d66844bf 100644 --- a/src/minecraft/commands/skillsCommand.js +++ b/src/minecraft/commands/skillsCommand.js @@ -12,8 +12,13 @@ class SkillsCommand extends minecraftCommand { this.name = "skills"; this.aliases = ["skill"]; this.description = "Skills and Skill Average of specified user."; - this.options = ["name"]; - this.optionsDescription = ["Minecraft Username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } async onCommand(username, message) { @@ -35,13 +40,21 @@ class SkillsCommand extends minecraftCommand { .reduce((a, b) => a + b, 0) / (Object.keys(profile).length - 2) ).toFixed(2) || 0 - } | Farming - ${profile.farming.levelWithProgress.toFixed(2) || 0} | Mining - ${ + } | Farming - ${ + profile.farming.levelWithProgress.toFixed(2) || 0 + } | Mining - ${ profile.mining.levelWithProgress.toFixed(2) || 0 - } | Combat - ${profile.combat.levelWithProgress.toFixed(2) || 0} | Enchanting - ${ + } | Combat - ${ + profile.combat.levelWithProgress.toFixed(2) || 0 + } | Enchanting - ${ profile.enchanting.levelWithProgress.toFixed(2) || 0 - } | Fishing - ${profile.fishing.levelWithProgress.toFixed(2) || 0} | Foraging - ${ + } | Fishing - ${ + profile.fishing.levelWithProgress.toFixed(2) || 0 + } | Foraging - ${ profile.foraging.levelWithProgress.toFixed(2) || 0 - } | Alchemy - ${profile.alchemy.levelWithProgress.toFixed(2) || 0} | Taming - ${ + } | Alchemy - ${ + profile.alchemy.levelWithProgress.toFixed(2) || 0 + } | Taming - ${ profile.taming.levelWithProgress.toFixed(2) || 0 } | Carpentry - ${profile.carpentry.levelWithProgress.toFixed(2) || 0}` ); diff --git a/src/minecraft/commands/skyblockCommand.js b/src/minecraft/commands/skyblockCommand.js index 2c8301cd..5d017972 100644 --- a/src/minecraft/commands/skyblockCommand.js +++ b/src/minecraft/commands/skyblockCommand.js @@ -20,13 +20,18 @@ class SkyblockCommand extends minecraftCommand { this.name = "skyblock"; this.aliases = ["stats", "sb"]; this.description = "Skyblock Stats of specified user."; - this.options = ["name"]; - this.optionsDescription = ["Minecraft Username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } async onCommand(username, message) { try { -username = this.getArgs(message)[0] || username; + username = this.getArgs(message)[0] || username; const data = await getLatestProfile(username); username = data.profileData?.game_mode ? `♲ ${username}` : username; @@ -40,11 +45,10 @@ username = this.getArgs(message)[0] || username; await Promise.all([ getSkills(data.profile), getSlayer(data.profile), - getNetworth( - data.profile, - data.profileData?.banking?.balance || 0, - { cache: true, onlyNetworth: true } - ), + getNetworth(data.profile, data.profileData?.banking?.balance || 0, { + cache: true, + onlyNetworth: true, + }), getWeight(data.profile), getDungeons(data.player, data.profile), getTalismans(data.profile), @@ -52,39 +56,51 @@ username = this.getArgs(message)[0] || username; const senitherWeight = Math.floor(weight?.senither?.total || 0); const lilyWeight = Math.floor(weight?.lily?.total || 0); - const skillAverage = (Object.keys(skills).filter((skill) => !["runecrafting", "social"].includes(skill)).map((skill) => skills[skill].level).reduce((a, b) => a + b, 0) / (Object.keys(skills).length - 2)).toFixed(1) - const slayerXp = addCommas(Object.keys(slayer).map((type) => slayer[type].xp).reduce((a, b) => a + b, 0)) - const catacombsLevel = dungeons.catacombs.skill.level - const classAverage = (Object.keys(dungeons.classes).map((className) => dungeons.classes[className].level).reduce((a, b) => a + b, 0) / Object.keys(dungeons.classes).length) - const networthValue = addNotation("oneLetters", Math.floor(networth.networth || 0)); - const talismanCount = Object.keys(talismans.talismans).map((rarity) => talismans.talismans[rarity].length || 0).reduce((a, b) => a + b, 0) - const recombobulatedCount = Object.keys(talismans.talismans).map((rarity) => talismans.talismans[rarity].filter((talisman) => talisman.recombobulated).length).reduce((a, b) => a + b, 0) - const enrichmentCount = Object.keys(talismans.talismans).map((rarity) => talismans.talismans[rarity].filter((talisman) => talisman.enrichment !== undefined).length).reduce((a, b) => a + b, 0) + const skillAverage = ( + Object.keys(skills) + .filter((skill) => !["runecrafting", "social"].includes(skill)) + .map((skill) => skills[skill].level) + .reduce((a, b) => a + b, 0) / + (Object.keys(skills).length - 2) + ).toFixed(1); + const slayerXp = addCommas( + Object.keys(slayer) + .map((type) => slayer[type].xp) + .reduce((a, b) => a + b, 0) + ); + const catacombsLevel = dungeons.catacombs.skill.level; + const classAverage = + Object.keys(dungeons.classes) + .map((className) => dungeons.classes[className].level) + .reduce((a, b) => a + b, 0) / Object.keys(dungeons.classes).length; + const networthValue = addNotation( + "oneLetters", + Math.floor(networth.networth || 0) + ); + const talismanCount = Object.keys(talismans.talismans) + .map((rarity) => talismans.talismans[rarity].length || 0) + .reduce((a, b) => a + b, 0); + const recombobulatedCount = Object.keys(talismans.talismans) + .map( + (rarity) => + talismans.talismans[rarity].filter( + (talisman) => talisman.recombobulated + ).length + ) + .reduce((a, b) => a + b, 0); + const enrichmentCount = Object.keys(talismans.talismans) + .map( + (rarity) => + talismans.talismans[rarity].filter( + (talisman) => talisman.enrichment !== undefined + ).length + ) + .reduce((a, b) => a + b, 0); this.send( `/gc ${username}'s Level » ${ data.profile.leveling.experience / 100 - } | Senither Weight » ${ - senitherWeight - } | Lily Weight » ${ - lilyWeight - } | Skill Average » ${ - skillAverage - } | Slayer » ${ - slayerXp - } | Catacombs » ${ - catacombsLevel - } | Class Average » ${ - classAverage - } | Networth » ${ - networthValue - } | Accessories » ${ - talismanCount - } | Recombobulated » ${ - recombobulatedCount - } | Enriched » ${ - enrichmentCount - }` + } | Senither Weight » ${senitherWeight} | Lily Weight » ${lilyWeight} | Skill Average » ${skillAverage} | Slayer » ${slayerXp} | Catacombs » ${catacombsLevel} | Class Average » ${classAverage} | Networth » ${networthValue} | Accessories » ${talismanCount} | Recombobulated » ${recombobulatedCount} | Enriched » ${enrichmentCount}` ); } catch (error) { console.log(error); diff --git a/src/minecraft/commands/skyblockLevelCommand.js b/src/minecraft/commands/skyblockLevelCommand.js index bb027a4a..955376f3 100644 --- a/src/minecraft/commands/skyblockLevelCommand.js +++ b/src/minecraft/commands/skyblockLevelCommand.js @@ -11,8 +11,13 @@ class CatacombsCommand extends minecraftCommand { this.name = "level"; this.aliases = ["lvl"]; this.description = "Skyblock Level of specified user."; - this.options = ["name"]; - this.optionsDescription = ["Minecraft Username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } async onCommand(username, message) { @@ -23,13 +28,15 @@ class CatacombsCommand extends minecraftCommand { username = formatUsername(username, data.profileData?.game_mode); - this.send(`/gc ${username}'s Skyblock Level » ${data.profile.leveling.experience / 100}`); - } catch (error) { - console.log(error) - this.send( - `/gc Error: ${error}` + `/gc ${username}'s Skyblock Level » ${ + data.profile.leveling.experience / 100 + }` ); + } catch (error) { + console.log(error); + + this.send(`/gc Error: ${error}`); } } } diff --git a/src/minecraft/commands/warpoutCommand.js b/src/minecraft/commands/warpoutCommand.js new file mode 100644 index 00000000..adf04190 --- /dev/null +++ b/src/minecraft/commands/warpoutCommand.js @@ -0,0 +1,80 @@ +const minecraftCommand = require("../../contracts/minecraftCommand.js"); +const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + +class warpoutCommand extends minecraftCommand { + constructor(minecraft) { + super(minecraft); + + this.name = "warpout"; + this.aliases = ["warp"]; + this.description = "Warp player out of the game"; + this.options = []; + } + + async onCommand(username, message) { + try { + bot.chat("/lobby"); + await delay(1000); + bot.chat("/play skyblock"); + const user = this.getArgs(message)[0]; + + // eslint-disable-next-line no-throw-literal + if (user === undefined) throw "Please provide a username!"; + let warped = false; + + const listener = async (message) => { + message = message.toString(); + + if ( + message.includes( + "You cannot invite that player since they're not online." + ) + ) { + this.send(`/gc ${user} is not online!`); + } + + if (message.includes("You cannot invite that player.")) { + this.send(`/gc ${user} has party requests disabled!`); + } + + if ( + message.includes("invited") && + message.includes("to the party! They have 60 seconds to accept.") + ) { + this.send(`/gc Succesfully invited ${user} to the party!`); + } + + if (message.includes(" joined the party.")) { + this.send( + `/gc ${user} joined the party! Warping him out of the game..` + ); + bot.removeListener("message", listener); + await delay(1100); + + bot.chat("/p warp"); + warped = true; + + await delay(1000); + bot.chat("/p disband"); + } + }; + + await bot.on("message", listener); + bot.chat(`/p ${user}`); + + setTimeout(async () => { + bot.removeListener("message", listener); + + if (!warped) { + this.send("/gc Party timedout"); + await delay(1000); + bot.chat("/p disband"); + } + }, 30000); + } catch (error) { + this.send(`/gc ${username} Error: ${error || "Something went wrong.."}`); + } + } +} + +module.exports = warpoutCommand; diff --git a/src/minecraft/commands/weeklyCommand.js b/src/minecraft/commands/weeklyCommand.js index 72593174..dc666a87 100644 --- a/src/minecraft/commands/weeklyCommand.js +++ b/src/minecraft/commands/weeklyCommand.js @@ -2,7 +2,7 @@ const minecraftCommand = require("../../contracts/minecraftCommand.js"); const { getUUID } = require("../../contracts/API/PlayerDBAPI.js"); const { getStats } = require("../../contracts/helperFunctions.js"); const config = require("../../../config.json"); -const axios = require('axios'); +const axios = require("axios"); class WeeklyStatsCommand extends minecraftCommand { constructor(minecraft) { @@ -11,39 +11,78 @@ class WeeklyStatsCommand extends minecraftCommand { this.name = "weekly"; this.aliases = [""]; this.description = "Get weekly stats of specified user."; - this.options = ["name", "gamemode"]; - this.optionsDescription = ["Minecraft Username", "Hypixel Gamemode"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + { + name: "mode", + description: "Gamemode", + required: false, + }, + ]; } async onCommand(username, message) { - const modes = ["bw", "bedwars", "bedwar", "bws", "sw", "skywars", "skywar", "sws", "duels", "duel", "d"]; - const args = this.getArgs(message).map((arg) => arg.replaceAll("/", "")) + const modes = [ + "bw", + "bedwars", + "bedwar", + "bws", + "sw", + "skywars", + "skywar", + "sws", + "duels", + "duel", + "d", + ]; + const args = this.getArgs(message).map((arg) => arg.replaceAll("/", "")); - const mode = modes.includes(args[0]) ? args[0] : modes.includes(args[1]) ? args[1] : null; - username = (args[0] == mode ? args[1] === "" ? username : args[1] : args[0] === "" ? username : args[0]) || username; + const mode = modes.includes(args[0]) + ? args[0] + : modes.includes(args[1]) + ? args[1] + : null; + username = + (args[0] == mode + ? args[1] === "" + ? username + : args[1] + : args[0] === "" + ? username + : args[0]) || username; try { const uuid = await getUUID(username); - this.send(await getStats(username, uuid, mode, 'weekly')); - + this.send(await getStats(username, uuid, mode, "weekly")); } catch (error) { if (error === "Player not in database") { - this.send(`/gc ${username} is not registered in the database! Adding them now..`); + this.send( + `/gc ${username} is not registered in the database! Adding them now..` + ); const uuid = await getUUID(username); - const res = await axios.post(`https://api.pixelic.de/v1/player/register/${uuid}?key=${config.api.pixelicAPIkey}`) + const res = await axios.post( + `https://api.pixelic.de/v1/player/register/${uuid}?key=${config.api.pixelicAPIkey}` + ); if (res.status == 201) { this.send(`/gc Successfully registered ${username} in the database!`); - } else if (res.status == 400) { - this.send(`/gc Uh oh, somehow this player is already registered in the database! Please try again in few seconds..`); - + this.send( + `/gc Uh oh, somehow this player is already registered in the database! Please try again in few seconds..` + ); } else { - this.send(`/gc Error: ${res.status} ${res?.statusText || "Something went wrong.."}`); + this.send( + `/gc Error: ${res.status} ${ + res?.statusText || "Something went wrong.." + }` + ); } - } else { this.send(`/gc Error: ${error}`); } diff --git a/src/minecraft/commands/woolwarsCommand.js b/src/minecraft/commands/woolwarsCommand.js index 4447ed93..95425eb7 100644 --- a/src/minecraft/commands/woolwarsCommand.js +++ b/src/minecraft/commands/woolwarsCommand.js @@ -4,15 +4,6 @@ const axios = require("axios"); const { toFixed } = require("../../contracts/helperFunctions.js"); const { getUUID } = require("../../contracts/API/PlayerDBAPI.js"); -function getWoolWarsStar(exp) { - const minimalExp = [0, 1e3, 3e3, 6e3, 1e4, 15e3]; - const baseLevel = minimalExp.length; - const baseExp = minimalExp[minimalExp.length - 1]; - if (exp >= baseExp) return (exp - baseExp) / 5e3 + baseLevel; - const lvl = minimalExp.findIndex((x) => exp < x); - return lvl + exp / minimalExp[lvl]; -} - class WoolwarsCommand extends minecraftCommand { constructor(minecraft) { super(minecraft); @@ -20,8 +11,13 @@ class WoolwarsCommand extends minecraftCommand { this.name = "woolwars"; this.aliases = ["ww"]; this.description = "WoolWars stats of specified user."; - this.options = ["name"]; - this.optionsDescription = ["Minecraft Username"]; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; } async onCommand(username, message) { @@ -47,7 +43,10 @@ class WoolwarsCommand extends minecraftCommand { throw "This player has never played WoolWars."; } - const level = getWoolWarsStar(response?.player?.stats?.WoolGames?.progression?.experience) || 0; + const level = + getWoolWarsStar( + response?.player?.stats?.WoolGames?.progression?.experience + ) || 0; this.send( `/gc [${toFixed(level, 0)}✫] ${username} » W: ${ @@ -63,9 +62,18 @@ class WoolwarsCommand extends minecraftCommand { }` ); } catch (error) { - this.send(`/gc Error: ${error}`) + this.send(`/gc Error: ${error}`); } } } +function getWoolWarsStar(exp) { + const minimalExp = [0, 1e3, 3e3, 6e3, 1e4, 15e3]; + const baseLevel = minimalExp.length; + const baseExp = minimalExp[minimalExp.length - 1]; + if (exp >= baseExp) return (exp - baseExp) / 5e3 + baseLevel; + const lvl = minimalExp.findIndex((x) => exp < x); + return lvl + exp / minimalExp[lvl]; +} + module.exports = WoolwarsCommand; diff --git a/src/minecraft/handlers/ChatHandler.js b/src/minecraft/handlers/ChatHandler.js index a01b0a9b..980d8f1d 100644 --- a/src/minecraft/handlers/ChatHandler.js +++ b/src/minecraft/handlers/ChatHandler.js @@ -31,6 +31,13 @@ class StateHandler extends eventHandler { const message = event.toString(); const colouredMessage = event.toMotd(); + if (config.console.debug === true) { + this.minecraft.broadcastMessage({ + fullMessage: colouredMessage, + chat: 'debugChannel' + } + )} + if (this.isLobbyJoinMessage(message)) { return bot.chat('\u00a7') } @@ -121,51 +128,7 @@ class StateHandler extends eventHandler { } } } - - if (this.isGuildListMessage(message)) { - if(!message.includes('Online Members')) { - if (message.includes('Guild Name') || message.includes('Total Members') || message.includes('Online Members')) { - guildInfo.push(message) - } else if (message.includes('--')) { - guildRanks.push(message) - } else { - members.push(message) - } - } else { - guildInfo.push(message) - const guildInfoSplit = guildInfo[0].split(' '); - const guildInfoSplit2 = guildInfo[1].split(' '); - const guildInfoSplit3 = guildInfo[2].split(' '); - for (let i = 0; i < members.length; i++) { - members[i] = replaceAllRanks(members[i]) - members[i] = members[i].replaceAll(' ', ' ') - members[i] = members[i].replaceAll(' ● ', '` ᛫ `') - String.prototype.reverse = function () {return this.split('').reverse().join('')} - String.prototype.replaceLast = function (what, replacement) {return this.reverse().replace(new RegExp(what.reverse()), replacement.reverse()).reverse()} - members[i] = members[i].replaceLast(' ●', '`') - members[i] = members[i].replaceLast('᛫ `', '') - } - let description = `Member Count: **${guildInfoSplit2[2]}/125**\nOnline Members: **${guildInfoSplit3[2]}**\n` - for (let i = 0; i < guildRanks.length; i++) { - description+= `\n` - guildRanks[i] = guildRanks[i].replaceAll('--', '**') - description+= `${guildRanks[i]}\n \`${members[i]}` - } - - this.minecraft.broadcastHeadedEmbed({ - message: `${description}`, - title: guildInfoSplit[2], - icon: `https://hypixel.paniek.de/guild/${config.minecraft.guildID}/banner.png`, - color: 2067276, - channel: 'Guild' - }) - guildInfo = []; - guildRanks = []; - members = []; - } - } - if (this.isLoginMessage(message)) { const data = JSON.parse(fs.readFileSync('config.json')); if (data.discord.joinMessage) { @@ -520,6 +483,15 @@ class StateHandler extends eventHandler { }) } + if (this.isGuildLevelUpMessage(message)) { + const level = message.replace(/\[(.*?)\]/g, '').trim().split(/ +/g)[5] + return this.minecraft.broadcastCleanEmbed({ + message: `${messages.guildLevelUpMessage} ${level}`, + color: 16766720, + channel: 'Guild' + }) + } + /*if (this.isPartyMessage(message)) { this.minecraft.broadcastCleanEmbed({ message: `${message}`, @@ -528,29 +500,32 @@ class StateHandler extends eventHandler { }) }*/ - if (config.console.debug) { - this.minecraft.broadcastMessage({ - fullMessage: colouredMessage, - message: 'debug_temp_message_ignore', - chat: 'debugChannel' - } - )} - - const parts = message.split(':') - const group = parts.shift().trim() + const [group, ...parts] = message.split(':').map(s => s.trim()) const hasRank = group.endsWith(']') - const chat = message.split('>') - const chatType = chat.shift().trim() + const [chatType] = group.split('>').map(s => s.trim()) const userParts = group.split(' ') const username = userParts[userParts.length - (hasRank ? 2 : 1)] - let guildRank = userParts[userParts.length - 1].replace('[', '').replace(']', '') - const playerMessage = parts.join(':').trim() + const guildRank = userParts.pop().replace(/[[\]]/g, '') || 'Member' + let playerMessage = parts.join(':').trim() - if (!this.isGuildMessage(message) && !this.isOfficerChatMessage(message)) return - if (guildRank == username) guildRank = 'Member' - if (this.isMessageFromBot(username)) return - if (playerMessage.length == 0 || this.command.handle(username, playerMessage)) return - if (playerMessage == '@') return + const playerRankColor = colouredMessage.split(' ')[2]?.replace(/[[\]]/g, '')?.split('§')[1] + const playerRankPlusColor = colouredMessage.split(' ')[2]?.replace(/[[\]]/g, '')?.split('§')[2] + const embedColor = playerRankPlusColor?.[0] || playerRankColor?.[0] || '7' + + if (!this.isGuildMessage(message) && !this.isOfficerChatMessage(message) || playerMessage.length == 0) return + + if (this.isMessageFromBot(username)) { + if (config.minecraft.messageRepeatBypass === true) { + const lastString = playerMessage.slice(-config.minecraft.messageRepeatBypassLength) + if (lastString.includes(" ") === false) { + playerMessage = playerMessage.slice(0, -config.minecraft.messageRepeatBypassLength - 2) + } + } + } + + if (this.isMessageFromBot(username) && message.includes(config.minecraft.messageFormat) === true) return + + this.command.handle(username, playerMessage) this.minecraft.broadcastMessage({ fullMessage: colouredMessage, @@ -558,6 +533,7 @@ class StateHandler extends eventHandler { message: playerMessage, guildRank: guildRank, chat: chatType, + color: this.minecraftChatColorToHex(embedColor) }) } @@ -612,14 +588,11 @@ class StateHandler extends eventHandler { isGuildTopMessage(message) { return message.includes('Guild Experience') && !message.includes('●') && !message.includes(':') } + isPartyMessage(message) { return message.includes('has invited you to join their party!') && !message.includes(':') } - isGuildListMessage(message) { - return message.includes('●') || message.includes(' -- ') && message.includes(' -- ') || message.startsWith('Online Members: ') || message.includes('Online Members: ') || message.startsWith('Total Members:') || message.startsWith('Guild Name:') - } - isPromotionMessage(message) { return message.includes('was promoted from') && !message.includes(':') } @@ -641,7 +614,7 @@ class StateHandler extends eventHandler { } isNoPermission(message) { - return (message.includes('You must be the Guild Master to use that command!') || message.includes('You do not have permission to use this command!') || message.includes("I'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is in error.") || message.includes("You cannot mute a guild member with a higher guild rank!") || message.includes("You cannot kick this player!") || message.includes("You can only promote up to your own rank!") || message.includes("You cannot mute yourself from the guild!") || message.includes("is the guild master so can't be demoted!") || message.includes("is the guild master so can't be promoted anymore!")) && !message.includes(":") + return (message.includes('You must be the Guild Master to use that command!') || message.includes('You do not have permission to use this command!') || message.includes("I'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is in error.") || message.includes("You cannot mute a guild member with a higher guild rank!") || message.includes("You cannot kick this player!") || message.includes("You can only promote up to your own rank!") || message.includes("You cannot mute yourself from the guild!") || message.includes("is the guild master so can't be demoted!") || message.includes("is the guild master so can't be promoted anymore!") || message.includes("You do not have permission to kick people from the guild!")) && !message.includes(":") } isIncorrectUsage(message) { @@ -711,6 +684,32 @@ class StateHandler extends eventHandler { isPlayerNotFound(message) { return message.startsWith(`Can't find a player by the name of`) } + + isGuildLevelUpMessage(message) { + return message.includes("The guild has reached Level") && !message.includes(':') + } + + minecraftChatColorToHex(color) { + switch(color) { + case '0': return '#000000' + case '1': return '#0000AA' + case '2': return '#00AA00' + case '3': return '#00AAAA' + case '4': return '#AA0000' + case '5': return '#AA00AA' + case '6': return '#FFAA00' + case '7': return '#AAAAAA' + case '8': return '#555555' + case '9': return '#5555FF' + case 'a': return '#55FF55' + case 'b': return '#55FFFF' + case 'c': return '#FF5555' + case 'd': return '#FF55FF' + case 'e': return '#FFFF55' + case 'f': return '#FFFFFF' + default: return '#FFFFFF' + } + } } module.exports = StateHandler \ No newline at end of file