From eae80fa30b8f71bc0631a030d3e0340d9103df0f Mon Sep 17 00:00:00 2001 From: MiaoWoo Date: Thu, 24 Sep 2020 13:51:18 +0800 Subject: [PATCH] backup: plugins 2020-09-24 Signed-off-by: MiaoWoo --- packages/plugins/docs/MiaoReward.md | 62 ++++++++- packages/plugins/src/MiaoChat.ts | 26 ++-- packages/plugins/src/MiaoReward.ts | 59 ++++++--- .../plugins/src/MiaoScriptPackageManager.ts | 123 ++++++++++-------- 4 files changed, 181 insertions(+), 89 deletions(-) diff --git a/packages/plugins/docs/MiaoReward.md b/packages/plugins/docs/MiaoReward.md index f309bcea..74a5c52a 100644 --- a/packages/plugins/docs/MiaoReward.md +++ b/packages/plugins/docs/MiaoReward.md @@ -14,7 +14,12 @@ - 玩家兑换公告![image.png](https://i.loli.net/2020/09/12/JWFoUtwXBSP6fcA.png) - 配置兑换比例![image.png](https://i.loli.net/2020/09/12/HpGVWErwZ7YTBxK.png) - 服务器信息查询![image.png](https://i.loli.net/2020/09/12/CbvSDfg4BF39PLI.png) - +- 玩家请求授权![image.png](https://i.loli.net/2020/09/24/QH6Dfp8RYJC5BtL.png) +- 玩家扫码![image.png](https://i.loli.net/2020/09/24/LSuhamJ4ji12EzM.png) +- 玩家扫码确认![image.png](https://i.loli.net/2020/09/24/sKjAl3tImg7buHe.png) +- 玩家扫码兑换完成![image.png](https://i.loli.net/2020/09/24/JG2SBtgHLzNeaEO.png) +- 腐竹扫码确认![image.png](https://i.loli.net/2020/09/24/c7sS18KJvQ3MRuZ.png) +- 腐竹扫码完成![image.png](https://i.loli.net/2020/09/24/RtsoSdV7j6OmE8Q.png) ## 插件命令 ``` >mrd @@ -36,15 +41,66 @@ ## 插件安装/配置 ### 基础准备工作 -- 申请内测服务器账号 - QQ搜索小程序 `圈云盒子` 并登录 +- 申请内测服务器账号 个人中心 => 配置面板 => 圈云盒子客服群 加群申请 + ### 服务器准备工作 - 先安装 `MiaoScript` [站内地址]() -- 执行 `mpm install MiaoReward` + - 可以通过 Yum 快速安装 `/yum install MiaoScript` +- 等待 MiaoScript 引擎启动完成(首次启动可能需要10-20秒 依赖于您的网络环境) +- 执行 `/mspm install MiaoReward` + ### 绑定服务器 - 执行 `/mrd bind server` - 使用QQ扫码 - 选择需要绑定的服务器 - 完成绑定 +- 配置服务器兑换比例 +- 执行 `/mrd ratio 0.001` (最低为 1:0.0001) +- 执行兑换比例确认指令 - 执行 `/mrd server` 查看服务器信息 - 如需绑定多台 可以直接复制绑定之后的 `MiaoScript/plugins/MiaoReward/config.yml` 文件到多台服务器上 然后 `/mrd reload` 重载插件 + +### QQ群配置 +- 打开小程序 +- 登录 +- 个人中心 => 设置面板 => 添加到群应用 => 选择你的QQ群 +- 配置群快捷栏 个人中心 => 设置面板 => 查看设置群快捷栏 +- 配置结果![image.png](https://i.loli.net/2020/09/24/C5ReMOo29mFbVAl.png) + +### 玩家绑定账号 +- 执行 `/mrd bind` +- 使用QQ扫码 +- 完成绑定 + +## 使用说明 +- 玩家可以通过下列方式获取喵币 + - 签到 5-10 喵币 + - 视频广告 5-15 喵币 + - 盒子广告 5-15 喵币 +- 获得的喵币可以在服务器兑换成对应的奖励 +- 腐竹可以在平台将喵币兑换成RMB(兑换比例请加群联系客服详谈) +- 登录小程序后 个人中心 => 配置面板 => 圈云盒子客服群 + +## 配置文件 + +``` yaml +# 服务器ID +serverId: '16' +# 服务器Token +serverToken: d50d3f6e-2a59-460a-2b29-82b66c4bbf52 +# 兑换指令 +drawCommand: 'p give %player_name% %amount%' +# 冷却时间 +drawCooldown: 300 +# 提示前缀 +prefix: '§6[§b广告系统§6]§r' +``` + +## Roadmap +- 绑定服务器(已完成) +- 绑定玩家(已完成) +- 兑换喵币(已完成) +- 自助开通服务器(开发中) +- 自助兑换RMB(开发中) +- 自助提现(开发中) \ No newline at end of file diff --git a/packages/plugins/src/MiaoChat.ts b/packages/plugins/src/MiaoChat.ts index 47c4b187..f8912a9e 100644 --- a/packages/plugins/src/MiaoChat.ts +++ b/packages/plugins/src/MiaoChat.ts @@ -2,8 +2,8 @@ /// /// -import { server, plugin as pluginApi, channel, constants, chat } from '@ccms/api' -import { inject, optional } from '@ccms/container' +import { server, channel, constants, chat } from '@ccms/api' +import { optional, Autowired } from '@ccms/container' import { plugin, interfaces, cmd, listener, tab, config, enable } from '@ccms/plugin' import Tellraw from '@ccms/common/dist/tellraw' @@ -52,12 +52,13 @@ class MiaoMessage { @plugin({ name: 'MiaoChat', version: '1.0.0', author: 'MiaoWoo', source: __filename }) export class MiaoChat extends interfaces.Plugin { - @inject(server.Server) + @Autowired() private Server: server.Server - @inject(chat.Chat) + @optional() + @Autowired() private chat: chat.Chat - @inject(channel.Channel) - @optional() private Channel: channel.Channel + @Autowired() + private Channel: channel.Channel private channelOff: { off: () => void } @@ -169,6 +170,11 @@ export class MiaoChat extends interfaces.Plugin { return string } } + if (!this.chat) { + this.logger.console('§4消息管理器注入失败 请检查当前服务器是否兼容...') + this.AsyncPlayerChatEvent['off']() + this.MessageChannelEvent$Chat['off']() + } } disable() { @@ -227,13 +233,13 @@ export class MiaoChat extends interfaces.Plugin { }) } - @cmd({ servers: ["bungee"] }) + @cmd({ servers: [constants.ServerType.Bungee] }) mct(sender: any, command: string, args: string[]) { this.logger.log(sender, command, args) sender.sendMessage(JSON.stringify({ command, ...args })) } - @cmd({ servers: ["!bungee"] }) + @cmd({ servers: [`!${constants.ServerType.Bungee}`] }) mchat(sender: any, command: string, args: string[]) { this.logger.log(sender, command, args) sender.sendMessage(JSON.stringify({ command, ...args })) @@ -243,12 +249,12 @@ export class MiaoChat extends interfaces.Plugin { tabmchat(_sender: any, _command: string, _args: string[]) { } - @listener({ servers: ['bukkit'] }) + @listener({ servers: [constants.ServerType.Bukkit] }) AsyncPlayerChatEvent(event: org.bukkit.event.player.AsyncPlayerChatEvent) { this.sendChat(event.getPlayer(), event.getMessage(), () => event.setCancelled(true)) } - @listener({ servers: ['sponge'] }) + @listener({ servers: [constants.ServerType.Sponge] }) MessageChannelEvent$Chat(event: org.spongepowered.api.event.message.MessageChannelEvent.Chat) { //@ts-ignore var player = event.getCause().first(org.spongepowered.api.entity.living.player.Player.class).orElse(null) diff --git a/packages/plugins/src/MiaoReward.ts b/packages/plugins/src/MiaoReward.ts index 9de063a1..76be7fcb 100644 --- a/packages/plugins/src/MiaoReward.ts +++ b/packages/plugins/src/MiaoReward.ts @@ -1,9 +1,9 @@ -import { constants, task, server, channel, chat } from "@ccms/api" +import { constants, task, server, channel, chat, proxy } from "@ccms/api" import { JSPlugin, interfaces, Cmd, Tab, Listener, Config } from "@ccms/plugin" import { QRCode, QRErrorCorrectLevel } from '@ccms/common/dist/qrcode' -import { Autowired, JSClass, optional, inject } from '@ccms/container' +import { Autowired, JSClass, optional } from '@ccms/container' import http from '@ccms/common/dist/http' let MapView @@ -54,7 +54,7 @@ interface PlaceholderAPI { setPlaceholders: (player: any, str: string) => string } -@JSPlugin({ prefix: 'MRD', version: '1.2.3', author: 'MiaoWoo', servers: [constants.ServerType.Bukkit], source: __filename }) +@JSPlugin({ prefix: 'MRD', version: '1.3.0', author: 'MiaoWoo', servers: [constants.ServerType.Bukkit], source: __filename }) export class MiaoReward extends interfaces.Plugin { private serverInfo: any private cacheBindUuid = '' @@ -73,10 +73,11 @@ export class MiaoReward extends interfaces.Plugin { private server: server.Server @Autowired() private taskManager: task.TaskManager + @optional() @Autowired() private channel: channel.Channel @Autowired() - private bungee: channel.proxy.BungeeCord + private bungee: proxy.BungeeCord @Config() private config = { @@ -240,6 +241,9 @@ export class MiaoReward extends interfaces.Plugin { } else if (result.data.status == "cancel") { this.chat.sendTitle(sender, '§c已取消授权') cancel?.() + } else if (result.data.status == "scaned") { + this.chat.sendTitle(sender, '§c授权操作超时') + cancel?.() } else { this.chat.sendTitle(sender, "§c未知的结果", result.data.status) } @@ -269,7 +273,7 @@ export class MiaoReward extends interfaces.Plugin { return true } } - if (this.drawCooldown.has(sender.getName()) && !sender.isOp()) { + if (this.drawCooldown.has(sender.getName()) && !sender.hasPermission('mrd.admin')) { let leftTime = cooldown - (Date.now() - this.drawCooldown.get(sender.getName())) / 1000 if (leftTime > 0) { this.logger.sender(sender, `§c扫码功能冷却中 剩余 ${leftTime} 秒!`) @@ -340,7 +344,7 @@ export class MiaoReward extends interfaces.Plugin { this.taskManager.create(() => { let command = this.config.drawCommand.replace('%player_name%', sender.getName()).replace('%amount%', draw.data) if (!this.server.dispatchConsoleCommand(command)) { - return this.sendError(sender, '§6执行命令 §3/' + command + ' §c可能存在异常') + return this.sendError(sender, ...draw.msg.split('\n'), `§6执行结果: §4已扣除 §c${amount} §4喵币`, `§6执行命令: §3/${command} §c可能存在异常`) } this.logger.sender(sender, draw.msg.split('\n')) this.sendBroadcast(sender, `${this.config.prefix}§6玩家 §b${sender.getName()} §6成功将 §a${amount}喵币 §6兑换成 §c${draw.data}点券!`) @@ -348,10 +352,10 @@ export class MiaoReward extends interfaces.Plugin { }).submit() } - private sendError(sender, error) { + private sendError(sender: any, ...error: string[]) { return this.logger.sender(sender, [ `§c========== ${this.config.prefix}§4兑换异常 §c==========`, - error, + ...error, `§6异常账号: §b${sender.getName()}`, `§6异常时间: §a${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}`, `§c如果喵币被扣除且未得到奖励 请截图发往QQ群!`, @@ -411,17 +415,31 @@ export class MiaoReward extends interfaces.Plugin { ]) } if (confirm != 'confirm') return this.logger.sender(sender, `§6请执行 §b/mrd ratio §c${ratio} §econfirm §c确认修改!`) - let result = this.httpPost(`https://reward.yumc.pw/server/ratio`, { - id: this.config.serverId, - token: this.config.serverToken, - ratio + if (this.bindCheck(sender, 60)) return + this.scanAuth(sender, "ratio", { + title: `是否授权 ${this.serverInfo.name} 调整兑换比例`, + content: [ + `操作玩家: ${sender.getName()}`, + `调整前: ${this.serverInfo.ratio}`, + `调整后: ${msg.replace(/§./ig, '')}`, + '调整结果实时生效!', + '跨服端 将自动同步比例!', + '非跨服端 请重载插件同步比例!' + ].join('\n') + }, (token) => { + let result = this.httpPost(`https://reward.yumc.pw/server/ratio`, { + id: this.config.serverId, + token: this.config.serverToken, + ratio, + userToken: token + }) + if (result.code !== 200) { + return this.logger.sender(sender, `§4操作异常 §6服务器返回: §c${result.msg}`) + } + this.logger.sender(sender, `§a操作成功 §6服务器返回: §a${result.msg}`) + this.updateServerInfo(sender) + this.sendBroadcast(sender, `${this.config.prefix} §6当前兑换比例已调整为 ` + msg) }) - if (result.code !== 200) { - return this.logger.sender(sender, `§4操作异常 §6服务器返回: §c${result.msg}`) - } - this.logger.sender(sender, `§a操作成功 §6服务器返回: §a${result.msg}`) - this.updateServerInfo(sender) - this.sendBroadcast(sender, `${this.config.prefix} §6当前兑换比例已调整为 ` + msg) } private ratio2string(ratio) { @@ -454,9 +472,9 @@ export class MiaoReward extends interfaces.Plugin { if (check.code == 200) { this.config.serverId = check.data.serverId this.config.serverToken = check.data.serverToken - // @ts-ignore - this.config.save() + this.config['save']() this.logger.sender(sender, '§a已成功绑定服务器: §b' + check.data.serverName) + this.updateServerInfo() } sync.scaned = true }).async().submit() @@ -514,6 +532,7 @@ export class MiaoReward extends interfaces.Plugin { } private queryUser(sender: org.bukkit.entity.Player, sync = false) { + if (!this.config.serverId || !this.config.serverToken) { return this.logger.sender(sender, '§4当前服务器尚未配置绑定ID 请联系腐竹进行配置!') } return this.httpPost(`https://reward.yumc.pw/server/queryUser`, { id: this.config.serverId, token: this.config.serverToken, diff --git a/packages/plugins/src/MiaoScriptPackageManager.ts b/packages/plugins/src/MiaoScriptPackageManager.ts index 96cb2553..efb3e51a 100644 --- a/packages/plugins/src/MiaoScriptPackageManager.ts +++ b/packages/plugins/src/MiaoScriptPackageManager.ts @@ -1,7 +1,6 @@ -import { plugin as pluginApi, task, server, plugin, channel, constants } from '@ccms/api' - +import { plugin as pluginApi, task, server, channel, constants, proxy } from '@ccms/api' import { Translate } from '@ccms/i18n' -import { inject, DefaultContainer as container, optional, JSClass } from '@ccms/container' +import { DefaultContainer as container, JSClass, Autowired } from '@ccms/container' import { interfaces, JSPlugin, Cmd, Tab, enable, Listener, disable } from '@ccms/plugin' import * as fs from '@ccms/common/dist/fs' @@ -10,16 +9,16 @@ import http from '@ccms/common/dist/http' let help = [ '§6========= §6[§aMiaoScriptPackageManager§6] 帮助 §aBy §bMiaoWoo §6=========', - '§6/mpm §ainstall §e<插件名称> §6- §3安装仓库插件', - '§6/mpm §aload §e<插件名称> §6- §3安装本地插件', - '§6/mpm §aunload §e<插件名称> §6- §3卸载已安装插件', - '§6/mpm §areload §e<插件名称> §6- §3重载已安装插件(无名称则重载自身)', - '§6/mpm §alist [i] §6- §3列出仓库插件[已安装的插件]', - '§6/mpm §aupdate §e[插件名称] §6- §3更新插件(无名称则更新源)', - '§6/mpm §aupgrade §e[插件名称] §6- §3升级插件/框架(§4无名称则升级框架§3)', - '§6/mpm §arun §e §6- §3运行JS代码', - '§6/mpm §adeploy §e<插件名称> §6- §3发布插件', - '§6/mpm §crestart §6- §4重启MiaoScript脚本引擎' + '§6/mspm §ainstall §e<插件名称> §6- §3安装仓库插件', + '§6/mspm §aload §e<插件名称> §6- §3安装本地插件', + '§6/mspm §aunload §e<插件名称> §6- §3卸载已安装插件', + '§6/mspm §areload §e<插件名称> §6- §3重载已安装插件(无名称则重载自身)', + '§6/mspm §alist [i] §6- §3列出仓库插件[已安装的插件]', + '§6/mspm §aupdate §e[插件名称] §6- §3更新插件(无名称则更新源)', + '§6/mspm §aupgrade §e[插件名称] §6- §3升级插件/框架(§4无名称则升级框架§3)', + '§6/mspm §arun §e §6- §3运行JS代码', + '§6/mspm §adeploy §e<插件名称> §6- §3发布插件', + '§6/mspm §crestart §6- §4重启MiaoScript脚本引擎' ] let langMap = { @@ -27,9 +26,15 @@ let langMap = { 'main.command.help.tip': '§6请执行 §b/{command} §ahelp §6查看帮助!', 'main.command.no.permission': '§c你没有此命令的权限!', 'list.install.header': '§6当前 §bMiaoScript §6已安装下列插件:', - 'list.install.body': '§6插件名称: §b{name} §6版本: §a{version}\n§6作者: §3{author} §6来源: §c{from}', + 'list.install.body': `§6┌插件名称: §b{name} +§6├版本: §a{version} +§6├作者: §3{author} +§6└来源: §c{from}`, 'list.header': '§6当前 §bMiaoScriptPackageCenter §6中存在下列插件:', - 'list.body': '§6插件名称: §b{name} §6版本: §a{version}\n§6作者: §3{author} §6更新时间: §9{updated_at}', + 'list.body': `§6┌插件名称: §b{name} +§6├版本: §a{version} +§6├作者: §3{author} +§6└更新时间: §9{updated_at}`, 'plugin.not.exists': '§6插件 §b{name} §c不存在!', 'plugin.unload.start': '§c开始卸载 §6插件 §b{name} §6版本 §3{version}!', 'plugin.unload.finish': '§6插件 §b{name} §6版本 §3{version} §a已卸载!', @@ -66,34 +71,54 @@ class FakeSender { let FakeSenderAdapter = Java.extend(superclass, { getName: () => this.name, isOp: () => true, - sendMessage: (message) => this.plugin.sendBungeeCordMessage(this.name, `§6[§3BPM§6][§a${this.plugin.serverName}§6] ${message}`) + hasPermission: () => true, + sendMessage: (message) => this.sendMessage(message) }) this._proxy = new FakeSenderAdapter() } + + sendMessage(message) { + return this.plugin.sendBungeeCordMessage(this.name, `§6[§3BPM§6][§a${this.plugin.serverName}§6] ${message}`) + } + getHandler() { return this._proxy } } +class BukkitFakeSender extends FakeSender { + constructor(name: string, plugin: MiaoScriptPackageManager) { + super(name, plugin, Java.type('org.bukkit.command.CommandSender')) + } +} + +class SpongeFakeSender extends FakeSender { + constructor(name: string, plugin: MiaoScriptPackageManager) { + super(name, plugin, Java.type('org.spongepowered.api.command.CommandSource')) + } + + sendMessage(message) { + return super.sendMessage(message.content) + } +} + @JSPlugin({ prefix: 'PM', version: '1.3.0', author: 'MiaoWoo', source: __filename }) export class MiaoScriptPackageManager extends interfaces.Plugin { - @inject(plugin.PluginManager) + @Autowired() private pluginManager: pluginApi.PluginManager - @inject(task.TaskManager) + @Autowired() private taskManager: task.TaskManager - @inject(server.ServerType) + @Autowired(server.ServerType) private serverType: string - @inject(server.Server) + @Autowired() private server: server.Server - @inject(pluginApi.PluginFolder) + @Autowired(pluginApi.PluginFolder) private pluginFolder: string - @inject(channel.Channel) - @optional() private channel: channel.Channel + @Autowired() + private channel: channel.Channel + @Autowired() + private bungee: proxy.BungeeCord - @JSClass('java.io.ByteArrayOutputStream') - private ByteArrayOutputStream: any - @JSClass('java.io.DataOutputStream') - private DataOutputStream: any @JSClass('com.google.common.io.ByteStreams') private ByteStreams: any @@ -139,21 +164,12 @@ export class MiaoScriptPackageManager extends interfaces.Plugin { private bungeeCordDetect(player) { if (player) { - let byteArray = new this.ByteArrayOutputStream() - let out = new this.DataOutputStream(byteArray) - out.writeUTF("GetServer") - this.channel.send(player, "BungeeCord", byteArray.toByteArray()) + this.bungee.for(player).getServer().send() } } private bungeeCordForward(player, command) { if (player) { - let byteArray = new this.ByteArrayOutputStream() - let out = new this.DataOutputStream(byteArray) - out.writeUTF("Forward") - out.writeUTF("ALL") - out.writeUTF("MiaoScriptPackageManager") - out.writeUTF(JSON.stringify(command)) - this.channel.send(player, "BungeeCord", byteArray.toByteArray()) + this.bungee.for(player).forward("ALL", "MiaoScriptPackageManager", command).send() } } private readForward(input) { @@ -166,9 +182,9 @@ export class MiaoScriptPackageManager extends interfaces.Plugin { private getProxySender(name: string) { switch (this.serverType) { case constants.ServerType.Bukkit: - return new FakeSender(name, this, Java.type('org.bukkit.command.CommandSender')).getHandler() + return new BukkitFakeSender(name, this).getHandler() case constants.ServerType.Sponge: - return new FakeSender(name, this, Java.type('org.spongepowered.api.command.CommandSource')).getHandler() + return new SpongeFakeSender(name, this).getHandler() default: return this.server.getConsoleSender() } @@ -193,12 +209,7 @@ export class MiaoScriptPackageManager extends interfaces.Plugin { sendBungeeCordMessage(sender, message) { let players = this.server.getOnlinePlayers() if (players.length) { - let byteArray = new this.ByteArrayOutputStream() - let out = new this.DataOutputStream(byteArray) - out.writeUTF("Message") - out.writeUTF(sender) - out.writeUTF(message) - this.channel.send(players[0], "BungeeCord", byteArray.toByteArray()) + this.bungee.for(players[0]).message(sender, message).send() } } @@ -207,23 +218,23 @@ export class MiaoScriptPackageManager extends interfaces.Plugin { } @Cmd({ servers: [`!${constants.ServerType.Bungee}`] }) - bmpm(sender: any, command: string, args: string[]) { - if (!sender?.isOp()) { return this.i18n(sender, 'main.command.no.permission') } - if (!this.isBungeeCord) return this.logger.sender(sender, '§c当前服务器尚未检测到BungeeCord链接...') + gmspm(sender: any, command: string, args: string[]) { + if (!sender.hasPermission('mspm.admin')) { return this.i18n(sender, 'main.command.no.permission') } + if (!this.isBungeeCord) return this.logger.sender(sender, '§c当前服务器尚未检测到 BungeeCord 链接...') this.taskManager.create(() => this.main(sender, command, args)).async().submit() this.bungeeCordForward(sender, { sender: sender.getName(), command, args }) this.logger.sender(sender, `§6[§3BPM§6][§a${this.serverName}§6] §6命令 §b/mpm ${args.join?.(' ')} §a发布成功!`) } @Cmd({ servers: [constants.ServerType.Bungee] }) - mpmanager(sender: any, command: string, args: string[]) { - if (!sender?.isOp()) { return this.i18n(sender, 'main.command.no.permission') } + bungeemspm(sender: any, command: string, args: string[]) { + if (!sender.hasPermission('mspm.admin')) { return this.i18n(sender, 'main.command.no.permission') } this.taskManager.create(() => this.main(sender, command, args)).async().submit() } @Cmd({ servers: [`!${constants.ServerType.Bungee}`] }) - mpm(sender: any, command: string, args: string[]) { - if (!sender?.isOp()) { return this.i18n(sender, 'main.command.no.permission') } + mspm(sender: any, command: string, args: string[]) { + if (!sender.hasPermission('mspm.admin')) { return this.i18n(sender, 'main.command.no.permission') } this.taskManager.create(() => this.main(sender, command, args)).async().submit() } @@ -404,7 +415,7 @@ if (this.serverType == "spring") { var db = dbm.getMainDatabase() var df = base.getInstance().getAutowireCapableBeanFactory() } -return '§a返回结果: §r'+ eval(${JSON.stringify(code)});`) +return ''+ eval(${JSON.stringify(code)});`) return tfunc.apply(this, params) + '' } @@ -433,8 +444,8 @@ return '§a返回结果: §r'+ eval(${JSON.stringify(code)});`) } } - @Tab({ alias: ['bmpm'] }) - tabmpm(sender: any, command: any, args: string | any[]) { + @Tab({ alias: ['gmspm', 'bungeemspm'] }) + tabmspm(args: string | any[]) { if (args.length === 1) { return ['list', 'install', 'update', 'upgrade', 'reload', 'restart', 'run', 'help', 'create', 'deploy'] } if (args.length > 1) { switch (args[0]) {