From 75302195e356f23254d810345bdcda5afd3859c9 Mon Sep 17 00:00:00 2001 From: MiaoWoo Date: Thu, 4 Nov 2021 09:08:31 +0800 Subject: [PATCH] backup: plugins Signed-off-by: MiaoWoo --- packages/plugins/docs/MiaoLink.md | 35 +++ packages/plugins/docs/MiaoPlugin.md | 1 + packages/plugins/src/MiaoLink.ts | 155 +++++++++++++ packages/plugins/src/MiaoPay.ts | 46 ++-- packages/plugins/src/MiaoReward.ts | 1 + packages/plugins/src/MiaoRobot.ts | 215 ++++++++++++++---- .../plugins/src/MiaoScriptPackageManager.ts | 12 +- 7 files changed, 395 insertions(+), 70 deletions(-) create mode 100644 packages/plugins/docs/MiaoLink.md create mode 100644 packages/plugins/src/MiaoLink.ts diff --git a/packages/plugins/docs/MiaoLink.md b/packages/plugins/docs/MiaoLink.md new file mode 100644 index 00000000..3eb952b1 --- /dev/null +++ b/packages/plugins/docs/MiaoLink.md @@ -0,0 +1,35 @@ + [综合|前置]MiaoLink —— 喵式映射 用于无公网环境的自动化端口映射[1.7.10+全版本] +# MiaoLink + +## 插件介绍 + +> 自动化端口公网映射 + +## 图片展示 + +- ![启动图片](https://i.loli.net/2021/09/23/vgOlw7p4xCdJPRo.png) + +## 使用方式 + +- 本插件依赖于 `MiaoScript` 请前往 [站内帖子](https://www.mcbbs.net/thread-774401-1-1.html) 完成安装 +- 执行 `/mspm install MiaoLink` 安装 MiaoLink 脚本插件 +- 访问 [圈云映射](https://nps.yumc.pw) 申请一键映射指令 +- ![image.png](https://i.loli.net/2021/09/23/pMISi5RWk74g2PA.png) +- 执行网页上提供的指令 等待客户端上线 +- ![image.png](https://i.loli.net/2021/09/23/aoJqZK1rbWw3G8X.png) +- 使用访问地址即可链接服务器 +- ![image.png](https://i.loli.net/2021/09/23/XqPz7TftarMbmcY.png) + +### Roadmap + +- 支持Bukkit端自动化映射(已完成) +- 支持Bungee端自动化映射(开发中) +- 支持Sponge端自动化映射(开发中) + +### 感谢 + +- [NPS](https://github.com/ehang-io/nps) 开源项目 +- [蓝科数据](https://www.lankodata.com/aff.php?aff=32) 提供的映射节点 +- [AkkoCloud](https://www.akkocloud.com/aff.php?aff=698) 提供的映射节点 + +#### 本插件所用所有代码均为原创,不存在借用/抄袭等行为 diff --git a/packages/plugins/docs/MiaoPlugin.md b/packages/plugins/docs/MiaoPlugin.md index d31d5801..5ddb7672 100644 --- a/packages/plugins/docs/MiaoPlugin.md +++ b/packages/plugins/docs/MiaoPlugin.md @@ -1,5 +1,6 @@ ### Miao系列插件 +- [[综合|前置]MiaoLink —— 喵式映射 用于无公网环境的自动化端口映射[全版本]](https://www.mcbbs.net/thread-1121423-1-1.html) - [[经济]MiaoReward —— 喵式奖励 让玩家看广告为服务器提供收入吧[1.7.10+全版本]](https://www.mcbbs.net/thread-1121423-1-1.html) - [[编程]MiaoBlockly —— 喵式积木 用简单的积木来写插件吧[1.12.2+全版本]](https://www.mcbbs.net/thread-1129411-1-1.html) - [[编程]MiaoConsole —— 喵式终端 通过MC端口直接控制服务器 调试插件[1.12.2+全版本]](https://www.mcbbs.net/thread-1129227-1-1.html) diff --git a/packages/plugins/src/MiaoLink.ts b/packages/plugins/src/MiaoLink.ts new file mode 100644 index 00000000..d8a8a17c --- /dev/null +++ b/packages/plugins/src/MiaoLink.ts @@ -0,0 +1,155 @@ +/// +/// +/// + +import { server, task } from '@ccms/api' +import { Autowired } from '@ccms/container' +import { Cmd, JSPlugin, Tab, interfaces, PluginConfig, Config } from '@ccms/plugin' + +import * as fs from '@ccms/common/dist/fs' +import http from '@ccms/common/dist/http' + +import * as base64 from 'base64-js' + +const Runtime: typeof java.lang.Runtime = Java.type('java.lang.Runtime') +const Thread = Java.type('java.lang.Thread') + +const defaultConfig = { + id: 0, + vkey: '' +} + +@JSPlugin({ name: 'MiaoLink', version: '1.0.2', author: 'MiaoWoo', source: __filename }) +export class MiaoLink extends interfaces.Plugin { + @Autowired(task.TaskManager) + private task: task.TaskManager + @Autowired(server.Server) + private server: server.Server + + @Config() + private config: PluginConfig & typeof defaultConfig = defaultConfig + + private isWindows = false + private clientName: string = 'npc' + private client: string = '' + private port: number = 0 + private npc: any + + load() { + this.isWindows = process.platform == 'win32' || process.platform.toLowerCase().startsWith('windows') + if (this.isWindows) { + this.logger.console('§a当前运行于Windows服务器...') + this.clientName = "npc.exe" + } else { + this.logger.console('§a当前运行于Linux服务器...') + } + } + + bukkitload() { + this.port = org.bukkit.Bukkit.getPort() + } + + spongeload() { + this.logger.console('§4Sponge暂不支持端口映射!') + } + + bungeeload() { + let server: net.md_5.bungee.api.ProxyServer = base.getInstance().getProxyServer() + this.port = server.getConfig().getListeners()[0].getQueryPort() + } + + enable() { + if (!this.config.vkey) { + return this.logger.console('§4服务器尚未绑定 取消自动映射!') + } + this.cmdconnect(this.server.getConsoleSender()) + } + + disable() { + this.cmddisconnect(this.server.getConsoleSender()) + } + + @Cmd({ autoMain: true }) + mlink() { } + + cmdconnect(sender: any, secret?: string) { + if (secret) { + let configStr = String.fromCharCode(...Array.from(base64.toByteArray(secret))) + let config = JSON.parse(configStr) + this.config.id = config.id + this.config.vkey = config.vkey + this.config.save() + } + this.startClient(sender) + } + + cmddisconnect(sender: any) { + if (!this.npc || !this.npc.isAlive()) { + return this.logger.sender(sender, '§4客户端尚未运行 跳过关闭流程...') + } + this.logger.sender(sender, '§6已发送关闭客户端指令...') + this.npc.destroy() + } + + @Tab() + tabmlink(_sender: any, _command: string, _args: string[]) { + } + + startClient(sender: any, id: number = this.config.id, vkey: string = this.config.vkey) { + if (!this.port) { + return this.logger.sender(sender, '§4服务器端口获取失败 取消自动映射!') + } + if (!id || !vkey) { + return this.logger.sender(sender, '§4服务器尚未配置 取消自动映射!') + } + if (this.npc && this.npc.isAlive()) { + this.npc.destroy() + } + this.task.create(() => { + this.logger.sender(sender, `§6获取到服务器端口: §3${this.port} §a开始映射端口!`) + let client = this.query(id, vkey, this.port) + let node = client.node + let tunnel = client.tunnel + this.client = fs.concat(__dirname, 'MiaoLink', this.clientName) + this.download(sender) + try { + this.npc = Runtime.getRuntime().exec(`${this.client} -server=${node.bridge} -vkey=${vkey} -type=tcp`) + this.logger.sender(sender, `§a服务器端口映射成功! §6访问地址: §3${node.address}:${tunnel.port}`) + return this.logger.console(`§4客户端已结束运行 退出代码: ${this.npc.waitFor()} 映射关闭!`) + } catch (error) { + this.logger.sender(sender, `§c服务器端口映射失败! §4ERROR: ${error}`) + console.ex(error) + } + }, this).async().later(5).submit() + } + + download(sender: any) { + try { + if (!fs.exists(this.client)) { + this.logger.sender(sender, '§c客户端文件不存在 开始下载客户端...') + let temp = this.client + '.tmp' + http.download("https://static.c5mc.cn/" + this.clientName, temp) + fs.move(temp, this.client, true) + if (!this.isWindows) { + this.logger.sender(sender, '§a当前处于Linux环境 赋予可执行权限...') + Runtime.getRuntime().exec(`chmod +x ${this.client}`) + } + } + } catch (error) { + Thread.sleep(500) + this.download(sender) + } + } + + query(id: number, vkey: string, target: number) { + let result = this.post(`/client?id=${id}&vkey=${vkey}&target=${target}`) + if (result.code != 200) { + throw new Error('§4客户端查询失败: ' + result.msg) + } + return result.data + } + + post(path, data = {}) { + return http.post("https://nps.yumc.pw/api" + path, data) + } +} diff --git a/packages/plugins/src/MiaoPay.ts b/packages/plugins/src/MiaoPay.ts index 0a6467cd..6d9e3736 100644 --- a/packages/plugins/src/MiaoPay.ts +++ b/packages/plugins/src/MiaoPay.ts @@ -73,7 +73,7 @@ const defaultConfig = { } } -@JSPlugin({ version: '1.6.3', author: 'MiaoWoo', source: __filename, servers: [constants.ServerType.Bukkit], depends: ['MiaoReward'], nativeDepends: ['PlaceholderAPI', 'ProtocolLib'] }) +@JSPlugin({ version: '1.6.6', author: 'MiaoWoo', source: __filename, servers: [constants.ServerType.Bukkit], depends: ['MiaoReward'], nativeDepends: ['PlaceholderAPI', 'ProtocolLib'] }) export class MiaoPay extends interfaces.Plugin { @Autowired() private server: server.Server @@ -104,7 +104,11 @@ export class MiaoPay extends interfaces.Plugin { enable() { if (!this.MiaoReward) { return this.logger.error('当前脚本插件需要 MiaoReward 作为前置脚本插件!') } if (!this.config.id || !this.config.secret) { return this.logger.console('§4尚未配置商户信息 将无法正常收款!') } - let info = this.httpPost('/apps', { id: this.config.id }) + this.initAppInfo() + } + + private initAppInfo() { + let info = this.httpPost('/apps', { id: this.config.id }, 10) if (info.code == 200) { this.appInfo = info.data this.config.ratio = this.appInfo.ratio @@ -114,8 +118,8 @@ export class MiaoPay extends interfaces.Plugin { this.config.save() } } else { - this.logger.console('§4初始化支付系统失败 请检查配置是否正确!') - this.logger.console('§c服务器返回异常: §4' + info.msg) + this.logger.console('§4初始化支付系统失败 请检查配置或网络是否正常!') + this.logger.console('§c返回异常: §4' + info.msg) } } @@ -131,14 +135,17 @@ export class MiaoPay extends interfaces.Plugin { cmdpay(sender: org.bukkit.entity.Player, amount: number = 0) { if (!sender.getItemInHand) { return this.logger.sender(sender, '§4控制台无法执行此命令!') } - if (!this.appInfo) { - return this.logger.sender(sender, '§4当前服务器尚未配置 请联系管理员配置MiaoPay!') - } if (!this.config.id || !this.config.secret) { return this.logger.sender(sender, '§c当前服务器尚未配置 请联系管理员配置支付密钥!') } + if (!this.appInfo) { + this.initAppInfo() + return this.logger.sender(sender, '§6支付系统初始化中 请稍候重试...') + } if (this.cacheMap.has(sender.getName())) { this.logger.sender(sender, '§c您有一笔订单尚未完成 请完成支付或等待订单超时!') let sync = this.cacheSyncMap.get(sender.getName()) - if (!sync.cancelled) { return this.cacheMap.delete(sender.getName()) } + if (sync.scaned) { return } + sync.scaned = true + Thread.sleep(1100) sync.scaned = false sync.left = (sync.paying ? 100 : 55) - (Math.round(Date.now() / 1000) - sync.start) let order = this.cacheMap.get(sender.getName()) @@ -146,7 +153,7 @@ export class MiaoPay extends interfaces.Plugin { return } if (amount < 1) { return this.logger.sender(sender, `§c充值异常 §4充值金额不得小于 1 ${this.config.coinName}!`) } - if (amount / this.config.ratio > 5000) { return this.logger.sender(sender, `§c充值异常 §4充值金额不得大于 ${this.config.ratio * 5000} ${this.config.coinName}!`) } + if (amount / this.config.ratio > 5000) { return this.logger.sender(sender, `§c充值异常 §4充值金额不得大于 ${this.config.ratio * 3000} ${this.config.coinName}!`) } if (amount != Math.round(amount)) { return this.logger.sender(sender, `§c充值异常 §4充值金额必须为整数!`) } try { this.getPlayerAmount(sender) @@ -341,15 +348,15 @@ export class MiaoPay extends interfaces.Plugin { } private preFinishOrder(id: string) { - return this.httpPost('/preFinish', { id }, true) + return this.httpPost('/preFinish', { id }, 3) } private errorOrder(id: string, error: string) { - return this.httpPost('/error', { id, error }, true) + return this.httpPost('/error', { id, error }, 3) } private finishOrder(id: string) { - return this.httpPost('/finish', { id }, true) + return this.httpPost('/finish', { id }, 3) } private createOrder(sender: org.bukkit.entity.Player, amount: number): Order { @@ -368,14 +375,14 @@ export class MiaoPay extends interfaces.Plugin { } private queryOrder(id: string, username: string, uuid: string) { - return this.httpPost('/query', { id, username, uuid }) + return this.httpPost('/query', { id, username, uuid }, 2) } private queryUnconverted(username: string, force: number) { - return this.httpPost('/unconverted', { username, force }) + return this.httpPost('/unconverted', { username, force }, 2) } - private httpPost(method: string, data: any, retry = false) { + private httpPost(method: string, data: any, retry = 0) { let startTime = Date.now() data.appid = this.config.id data.timestamp = Math.round(Date.now() / 1000) @@ -393,11 +400,12 @@ CAST TIME : ${Date.now() - startTime}`) return result } catch (error) { if (retry) { - return this.httpPost(method, data) - } else { - console.console('§4请求支付中心发生异常 请联系管理员处理此问题!') - console.ex(error) + Thread.sleep(retry * 10) + return this.httpPost(method, data, --retry) } + console.console('§4请求支付中心发生异常 请联系管理员处理此问题!') + console.ex(error) + return { code: 500, msg: '本地网络错误: ' + error.message, data: error } } } diff --git a/packages/plugins/src/MiaoReward.ts b/packages/plugins/src/MiaoReward.ts index 4cda0f5f..773ca781 100644 --- a/packages/plugins/src/MiaoReward.ts +++ b/packages/plugins/src/MiaoReward.ts @@ -663,6 +663,7 @@ export class MiaoReward extends interfaces.Plugin { sync.cancelled = false let task = this.taskManager.create(() => { try { + console.log(JSON.stringify(sync)) if (sync.scaned || !sender.isOnline() || !this.isHoldQrCodeItem(sender) || --sync.left < 0) { if (sync.left < 0) { this.logger.sender(sender, '§c二维码已过期 请重新获取 如已扫码请忽略!') diff --git a/packages/plugins/src/MiaoRobot.ts b/packages/plugins/src/MiaoRobot.ts index 6612333b..0abdd1f0 100644 --- a/packages/plugins/src/MiaoRobot.ts +++ b/packages/plugins/src/MiaoRobot.ts @@ -1,41 +1,152 @@ /// /// /// -/// -// @ts-ignore -require.clear('websocket/client') -import { server } from '@ccms/api' -import { Autowired, Container, ContainerInstance } from '@ccms/container' -import { Cmd, JSPlugin, Tab, interfaces, PluginConfig, Config } from '@ccms/plugin' + +import { EventEmitter } from 'events' + +import { constants, server } from '@ccms/api' +import { Autowired, JSClass } from '@ccms/container' +import { Cmd, JSPlugin, Tab, interfaces, PluginConfig, Config, Listener } from '@ccms/plugin' import { WebSocket } from '@ccms/websocket' +const Thread = Java.type('java.lang.Thread') +const ChatColor = Java.type('org.bukkit.ChatColor') + const defaultConfig = { + version: 1, address: '', - token: '' + token: '', + group_id: '', + admin_id: '', + message: { + join: "玩家: %player_name% 加入了服务器!", + quit: "玩家: %player_name% 退出了服务器!", + chat: "%player_name%: ", + group: "&6[&c服务器群&6] &b%sender_nickname%&6(&a%sender_user_id%&6)&r: " + } } -//https://github3.mk-proxy.ml/-----https://github.com/Mrs4s/go-cqhttp/releases/download/v0.9.34/go-cqhttp-v0.9.34-linux-amd64 -@JSPlugin({ version: '1.0.0', author: 'MiaoWoo', source: __filename }) + +interface RobotConfig { + address: string, + token: string, + timeout: number +} + +interface PlaceholderAPI { + registerPlaceholderHook: (key: string, onPlaceholderRequest: (player, s) => string) => void + unregisterPlaceholderHook: (key: string) => void + setPlaceholders: (player: any, str: string) => string +} + +class Robot extends EventEmitter { + private config: RobotConfig + + private websocket: WebSocket + + private invokeCount = 1; + private apiResultCache = []; + + constructor(config: RobotConfig) { + super() + this.config = config + } + + sleep(ms) { + Thread.sleep(ms) + } + + invoke(action, params) { + if (this.websocket.readyState != WebSocket.OPEN) { throw new Error('client not connect!') } + let startTime: number = new Date().getTime() + let request = { action, params, echo: this.invokeCount++ } + this.websocket.send(JSON.stringify(request)) + while (startTime + this.config.timeout > new Date().getTime()) { + if (this.apiResultCache[request.echo]) { + let result = this.apiResultCache[request.echo] + delete this.apiResultCache[request.echo] + if ((result.status === "ok" && result.retcode !== 0) && (result.status === "async" && result !== 1)) { + throw Error(`Invoke API Error! Response ${JSON.stringify(result)}`) + } + return result.data + } + this.sleep(50) + } + throw Error(`Invoke API Timeout! Request ${JSON.stringify(request)}`) + } + + connect() { + this.websocket = new WebSocket(this.config.address, '', { Authorization: `Bearer ${this.config.token}` }) + this.websocket.onopen = () => { + this.emit('connect') + } + this.websocket.onmessage = (event) => { + let robotEvent = JSON.parse(event.data) + if (robotEvent.post_type == "meta_event") { return } + if (robotEvent.post_type) { + this.emit(robotEvent.post_type, robotEvent) + } + } + this.websocket.onclose = (event) => { + this.emit('close', event) + } + this.websocket.onerror = (event) => { + this.emit('error', event) + } + } + + disconnect(reason = '') { + if (this.websocket) { + this.websocket.close(0, reason) + } + } + + sendGroupMessage(group_id, message) { + this.websocket.send(JSON.stringify({ + action: "send_msg", + params: { group_id, message } + })) + } + + sendPrivateMessage(user_id, message) { + this.websocket.send(JSON.stringify({ + action: "send_msg", + params: { user_id, message } + })) + } +} + +@JSPlugin({ version: '1.0.0', author: 'MiaoWoo', servers: [constants.ServerType.Bukkit], source: __filename, nativeDepends: ['PlaceholderAPI'] }) export class MiaoRobot extends interfaces.Plugin { @Autowired() private server: server.Server - private client: WebSocket + @JSClass('me.clip.placeholderapi.PlaceholderAPI') + private PlaceholderAPI: PlaceholderAPI + + private robot: Robot @Config() private config: PluginConfig & typeof defaultConfig = defaultConfig load() { - } - - private downloadRobot() { - //https://api.github.com/repos/Mrs4s/go-cqhttp/releases?per_page=1&page=1 + this.logger.prefix = '' } enable() { + if (this.config.address && this.config.token) { + this.cmdconnect(this.server.getConsoleSender()) + if (!this.config.group_id) { + this.logger.console('§c机器人尚未配置绑定服务器群 部分功能将无法使用!') + } + } else { + this.logger.console('§c机器人尚未配置 请参照帖子内容配置机器人!') + } } disable() { - this.cmdclose(this.server.getConsoleSender()) + if (this.robot) { + this.cmdclose(this.server.getConsoleSender()) + } } @Cmd({ autoMain: true }) @@ -46,50 +157,64 @@ export class MiaoRobot extends interfaces.Plugin { return this.logger.sender(sender, '§4错误 请配置服务器地址和Token!') } this.cmdclose(sender) - try { - this.client = new WebSocket(address, '', { Authorization: `Bearer ${token}` }) - this.initRobot(this.client) - } catch (error) { - console.ex(error) - } + this.initRobot(sender) } - private initRobot(client: WebSocket) { - client.onopen = () => { - this.logger.console(`§3连接到 §b${client.url} §a成功!`) - } - client.onmessage = (event) => { - let messageEvent = JSON.parse(event.data) - switch (messageEvent.post_type) { - case "message": - this.logger.console(`§6接收到 §3群 §b${messageEvent.group_id} §2成员 §a${messageEvent.sender.nickname} §6的消息: §r${messageEvent.message}`) - break + initRobot(sender) { + this.robot = new Robot({ ...this.config, timeout: 60 }) + this.robot.on('connect', () => { + this.logger.sender(sender, '§a机器人链接成功!') + }) + this.robot.on('message', (event) => { + if (event.message_type == "group" && event.group_id == this.config.group_id) { + let message: string = event.message + message = message.replace(/.*\[CQ:image\,file=(.*),url=(.*),.*]/g, '[图片]') + message = this.config.message.group + .replace(/%sender_nickname%/g, event.sender.nickname) + .replace(/%sender_card%/g, event.sender.card) + .replace(/%sender_title%/g, event.sender.title) + .replace(/%sender_user_id%/g, event.sender.user_id) + message + message = ChatColor.translateAlternateColorCodes('&', message) + this.server.getOnlinePlayers().forEach(p => this.logger.sender(p, message)) + this.logger.console(message) } - } - client.onclose = (event) => { - this.logger.console(`§4连接已断开 §6Code: §3${event.code} §6原因: §c${event.reason}!`) - } - client.onerror = (event) => { - this.logger.console(`§4发生错误: §r${event.error}`) - console.ex(event.error) - } + }) + this.robot.connect() } cmdclose(sender: org.bukkit.entity.Player) { - if (this.client && this.client.readyState != WebSocket.CLOSED) { - this.client.close(0, 'plugin close socket') + if (this.robot) { + this.robot.disconnect() + this.logger.sender(sender, '§c机器人已断开链接!') } } cmdsend(sender: org.bukkit.entity.Player, text: string) { - if (this.client) { - this.client.send(text) - this.logger.sender(sender, '§a发送成功!') - } + this?.robot.sendGroupMessage(this.config.group_id, text) + this.logger.sender(sender, '§a发送成功!') } @Tab() tabmbot(_sender: any, _command: string, _args: string[]) { return [] } + + @Listener() + private PlayerJoinEvent(event: org.bukkit.event.player.PlayerJoinEvent) { + if (this.robot && this.config.group_id) { + this.robot.sendGroupMessage(this.config.group_id, this.PlaceholderAPI.setPlaceholders(event.getPlayer(), this.config.message.join)) + } + } + @Listener() + private PlayerQuitEvent(event: org.bukkit.event.player.PlayerQuitEvent) { + if (this.robot && this.config.group_id) { + this.robot.sendGroupMessage(this.config.group_id, this.PlaceholderAPI.setPlaceholders(event.getPlayer(), this.config.message.quit)) + } + } + @Listener() + private AsyncPlayerChatEvent(event: org.bukkit.event.player.AsyncPlayerChatEvent) { + if (this.robot && this.config.group_id) { + this.robot.sendGroupMessage(this.config.group_id, this.PlaceholderAPI.setPlaceholders(event.getPlayer(), this.config.message.chat) + event.getMessage()) + } + } } diff --git a/packages/plugins/src/MiaoScriptPackageManager.ts b/packages/plugins/src/MiaoScriptPackageManager.ts index 00e938df..b827b857 100644 --- a/packages/plugins/src/MiaoScriptPackageManager.ts +++ b/packages/plugins/src/MiaoScriptPackageManager.ts @@ -479,7 +479,7 @@ return eval(${JSON.stringify(code)});`) return tfunc.apply(_this, params) } - cmddeploy(sender: string, name: string, changelog: string) { + cmddeploy(sender: string, name: string, changelog: string = '') { if (!process.env.AccessToken) { return this.i18n(sender, 'deploy.token.not.exists') } this.taskManager.create(() => { if (this.checkPlugin(sender, name)) { @@ -544,9 +544,9 @@ return eval(${JSON.stringify(code)});`) for (const pl of result.data) { this.packageCache[pl.name] = pl } this.packageNameCache = Object.keys(this.packageCache) this.i18n(sender, 'cloud.update.finish', { length: this.packageNameCache.length }) + let updateCount = 0 this.pluginManager.getPlugins().forEach(p => { let cloudPlugin = this.packageCache[p.description.name] - let updateCount = 0 //§6插件名称: §b{name}\n§6版本: §a{version}\n§6作者: §3{author}\§6更新时间: §9{updated_at} if (cloudPlugin && cloudPlugin.version != p.description.version) { this.i18n(sender, 'cloud.update.exists', { @@ -557,10 +557,10 @@ return eval(${JSON.stringify(code)});`) }) updateCount++ } - if (updateCount) { - this.i18n(sender, 'cloud.update.tip', { count: updateCount }) - } }) + if (updateCount) { + this.i18n(sender, 'cloud.update.tip', { count: updateCount }) + } }).async().submit() } @@ -570,7 +570,7 @@ return eval(${JSON.stringify(code)});`) this.i18n(sender, 'download.start', { name, version: pluginPkg.version }) this.i18n(sender, 'download.url', { url: pluginPkg.url }) let pluginFile = update ? fs.concat(root, this.pluginFolder, 'update', name + '.js') : fs.concat(root, this.pluginFolder, name + '.js') - http.download(pluginPkg.url, pluginFile) + http.download(pluginPkg.url + '?t=' + Date.now(), pluginFile) this.i18n(sender, 'download.finish', { name, version: pluginPkg.version }) callback?.() }).async().submit()