From be2988fc5882cbbbd06da6bde1f019a2aef2e978 Mon Sep 17 00:00:00 2001 From: MiaoWoo Date: Tue, 22 Jun 2021 15:52:27 +0800 Subject: [PATCH] backup: plugins Signed-off-by: MiaoWoo --- packages/plugins/docs/MiaoLobby.md | 76 ++++++ packages/plugins/docs/MiaoNashorn.md | 22 ++ packages/plugins/docs/MiaoPay.md | 49 +++- packages/plugins/docs/MiaoRebate.md | 114 ++++++++ packages/plugins/src/MiaoChat.ts | 2 +- packages/plugins/src/MiaoChatRGBSupport.ts | 109 ++++++++ packages/plugins/src/MiaoExplorer.ts | 2 +- packages/plugins/src/MiaoPay.ts | 71 +++-- packages/plugins/src/MiaoProtocol.ts | 73 ++++- packages/plugins/src/MiaoRebate.ts | 253 ++++++++++++++++++ .../plugins/src/MiaoScriptPackageManager.ts | 19 +- 11 files changed, 744 insertions(+), 46 deletions(-) create mode 100644 packages/plugins/docs/MiaoLobby.md create mode 100644 packages/plugins/docs/MiaoNashorn.md create mode 100644 packages/plugins/docs/MiaoRebate.md create mode 100644 packages/plugins/src/MiaoChatRGBSupport.ts create mode 100644 packages/plugins/src/MiaoRebate.ts diff --git a/packages/plugins/docs/MiaoLobby.md b/packages/plugins/docs/MiaoLobby.md new file mode 100644 index 00000000..4566f833 --- /dev/null +++ b/packages/plugins/docs/MiaoLobby.md @@ -0,0 +1,76 @@ +# MiaoLobby + +## 插件简介 + +- 用户进入服务器/用户登录后 自动选择大厅进行传送 防止堆积在登录服 +- 支持配置 是否登录后自动分配 或 玩家手动执行随机分配 +- 支持通过 ActionBar 展示传送状态 + +### 插件截图 + +- ![1.png](https://i.loli.net/2021/04/01/3JrtjupKHzAegwm.png) +- ![2.png](https://i.loli.net/2021/04/01/CgTRIHaUbX7uKJ1.png) + +### 插件配置 + +```yaml +#配置文件版本 请勿修改 +Version: 1.5 + +#服务器列表 +Servers: +- lobby1 +- lobby2 +#传送超时时间(单位: Tick) +WaitTime: 35 +#自带传送(如果开启 则Login自动传送失效) +AutoTP: false +#登录自动传送(暂时支持AuthMe) +LoginAutoTP: true +#传送延时(单位: 秒) +AutoTPDelay: 10 +#尝试完毕后是否继续重试 +ReTry: true +#传送提示 +Message: '&a请稍候 正在传送至服务器 %s ...' +TimeOut: '&c传送超时 正在切换到服务器 %s ...' +TPDelay: '&a登陆成功 正在为您匹配服务器 剩余 %s 秒...' +Unavailable: '&4已尝试所有可用服务器 传送失败!' +``` + +### 插件命令 + +``` +插件注册命令: + - MiaoLobby + 别名: ml + 描述: MiaoLobby - Minecraft 服务器插件父项目 + 权限: MiaoLobby.reload + 用法: 使用/MiaoLobby help 查看帮助! +``` + +### 插件权限 + +``` +插件注册权限: + - MiaoLobby.default - MiaoLobby 默认权限! + - MiaoLobby.admin - MiaoLobby 管理员权限! + - MiaoLobby.reload - 重新载入插件! +``` + +### 插件下载 + +[attach]1802025[/attach] + +### Miao系列插件 + +- [[经济]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) +- [[管理]MiaoBind —— 喵式绑定 兼容SoulBound的绑定插件 支持自定义关键词[1.7+全版本]](https://www.mcbbs.net/thread-922072-1-1.html) +- [[信息]MiaoBoard —— 喵式记分板 自定义动态记分板[1.7+全版本]](https://www.mcbbs.net/thread-631482-1-1.html) +- [[聊天]MiaoChat —— 喵式聊天 多功能自定义聊天格式 新增支持跨服[1.7.10+全版本]](https://www.mcbbs.net/thread-631240-1-1.html) +- [[菜单]MiaoMenu —— 喵式菜单 强大的自定义菜单 支持多种自定义操作[1.7+全版本]](https://www.mcbbs.net/thread-860047-1-1.html) +- [[管理]YUM —— 全能的服务器插件管理工具 全自动安装插件 更新插件[1.7.2+全版本]](https://www.mcbbs.net/thread-701333-1-1.html) + +#### 本插件所用所有代码均为原创,不存在借用/抄袭等行为 diff --git a/packages/plugins/docs/MiaoNashorn.md b/packages/plugins/docs/MiaoNashorn.md new file mode 100644 index 00000000..f26a2f66 --- /dev/null +++ b/packages/plugins/docs/MiaoNashorn.md @@ -0,0 +1,22 @@ + [综合|前置]MiaoNashorn —— 喵式犀牛引擎 用于 Java14+ 自动安装脚本引擎[全版本] +# MiaoNashorn + +## 插件介绍 + +> 在Java14+环境下缺少Nashorn 本插件用于自动下载并且加载Nashorn依赖 +> 自动从云端下载依赖 插件仅 8kb 大小 + +## 可用于下列插件 在 Java14+ 环境运行 + +- PlaceholderAPI 的 Javascript 扩展 +- MiaoMenu +- MiaoScript +- TrMenu +- AttributePlus +- 等其他任何需要 Nashorn 引擎的插件 + +## 下载地址 + +[attach]1834431[/attach] + +#### 本插件所用所有代码均为原创,不存在借用/抄袭等行为 diff --git a/packages/plugins/docs/MiaoPay.md b/packages/plugins/docs/MiaoPay.md index 71acfc57..c963890f 100644 --- a/packages/plugins/docs/MiaoPay.md +++ b/packages/plugins/docs/MiaoPay.md @@ -1,14 +1,57 @@ # MiaoPay ## 安装方式 -先按照帖子 + +先按照帖子 ### 网关 + - https://pay.yumc.pw/api +### 请求规范 + +- 除业务参数外 每个请求必须包含下列系统参数 +- 系统级参数 + - 应用 ID `appid` + - 时间戳 `timestamp` 单位: 秒 + - 随机字符串 `nonce` 32 位以内的随机字符串 + +#### 签名生成 + +- 对参数按照字典升序排列 +- 拼接成查询字符串后追加 key=secret +- 获得字符串的 MD5 值 并且转换成大写 + +```php +ksort($data); +$signStr = urldecode(http_build_query($data)).'&key='.\getAppSecret(); +return strtoupper(md5($signStr)); +``` + ### 相关接口 #### 创建订单 + - METHOD: /create -- PARAM: - - +- PARAM: + - 订单标题 `subject` 必填 + - 订单金额 `amount` 必填 单位: 元 + - 用户名 `username` 选填 + - 用户唯一 ID `unionId` 选填 + - 外部订单 ID `outOrderId` 选填 用于三方系统 + - 通知地址 `notifyUrl` 选填 用于三方系统回调 +- RETURN: + - 订单ID `order_id` + - 订单金额 `amount` + - 订单支付地址 `url` + +#### 查询订单 + +- METHOD: /query +- PARAM: + - 订单ID `subject` 必填 + - 订单金额 `amount` 必填 单位: 元 + - 用户名 `username` 选填 + - 用户唯一 ID `uuid` 选填 +- RETURN: + - 订单数据 diff --git a/packages/plugins/docs/MiaoRebate.md b/packages/plugins/docs/MiaoRebate.md new file mode 100644 index 00000000..34a4ffd8 --- /dev/null +++ b/packages/plugins/docs/MiaoRebate.md @@ -0,0 +1,114 @@ +# MiaoRebate + +## 插件简介 + +- 还在为服务器收入不足而倒闭烦恼嘛 +- 还在为肝帝不氪金而烦恼嘛 +- 快来接入 喵式返利 +- 饿了么美团战略合作 玩家点外卖 腐竹拿返利 增加服务器收入 + +### 先来一张 1 块钱吃一餐的图 + +![image.png](https://i.loli.net/2021/06/08/PpZVWLwTBNuravY.png) + +### 再来一张红包兑换的图 + +![image.png](https://i.loli.net/2021/06/07/GmCNXl2pyVnxYt5.png) + +### 限时活动 + +> 即日起 至 7 月 15 日 额外奖励活动 +> 每满 50 人关注公众号 额外奖励 50 元 上不封顶 (当月取消关注不算) +> 请绑定后加 QQ 群 1055983539 参加活动 + +## 插件展示 + +> 多图预警 折叠了 + +`[spoiler]` + +- 命令帮助![image.png](https://i.loli.net/2021/06/07/PGse8CSFxnIR3D5.png) +- 扫码绑定![image.png](https://i.loli.net/2021/06/07/dwNXloU62zcTVkQ.png) +- 个人信息![image.jpg](https://i.loli.net/2021/06/07/8r9xQTnFqjV7ahZ.jpg) +- 兑换列表![image.jpg](https://i.loli.net/2021/06/07/FcjC1qdWMrB3vsR.jpg) + +`[/spoiler]` + +## 插件命令 + +``` +>mre help +[外卖系统]====== [外卖系统] 帮助菜单 ====== +[外卖系统]/mre bind 绑定账号 +[外卖系统]/mre draw <兑换数量> 兑换点券 +[外卖系统]由于您是管理员 以为您展示额外命令 +[外卖系统]/mrd bind server 绑定服务器 +``` + +## 接下来就是赚钱的操作 + +### 服务器准备工作 + +- 本插件依赖于 `MiaoReward` 请前往 [站内帖子](https://www.mcbbs.net/thread-1121423-1-1.html) 完成安装 +- 执行 `/mspm install MiaoRebate` 安装 MiaoRebate 脚本插件 +- 完成安装 + +### 绑定服务器 + +- 执行 `/mre bind server` +- 使用绿色儿的那个 APP 扫码 完成绑定 + +### 玩家绑定账号 + +- 执行 `/mre bind` +- 使用绿色儿的那个 APP 扫码 完成绑定 + +## 使用说明 + +- 玩家可以通过下列方式获取圈币 + - 进入公众号 领取红包 + - 小程序直接点餐或到饿了么/美团 APP 点餐 + - 点餐后 发送订单号 兑换奖励 + - 返利额度约为实付金额的 `1%-3%` 左右 +- 获得的圈币 在服务器使用 `/mre draw 兑换金额` +- 腐竹获得圈币后 在公众号兑换成红包即可 + +## PAPI 兼容 + +- 目前暂不支持 PAPI 变量 后续会支持 + +## 配置文件 + +```yml +# 提示前缀 +prefix: §6[§b外卖系统§6]§r +# 用于检查货币的变量 +check: "%playerpoints_points%" +# 用于充值货币的命令 +command: points give %player_name% %amount% +# 兑换比例 圈币 对应多少 货币 +ratio: 1 +# 货币名称 +coinName: 点券 +# 进服提示 +joinTip: true +# 绑定数据(请勿手动修改 绑定后会自动填写数据) +owner: + userid: + ccid: + openid: +``` + +## 插件源码 + +- [MiaoScript 包管理中心](https://git.yumc.pw/circlecloud/ms/src/branch/master/packages/plugins/src/MiaoRebate.ts) + +## 更新日志 + +- 暂无 + +## Roadmap + +- 绑定服务器(已完成) +- 绑定玩家(已完成) +- 兑换圈币(已完成) diff --git a/packages/plugins/src/MiaoChat.ts b/packages/plugins/src/MiaoChat.ts index 244ed113..d78e4bd3 100644 --- a/packages/plugins/src/MiaoChat.ts +++ b/packages/plugins/src/MiaoChat.ts @@ -50,7 +50,7 @@ class MiaoMessage { } } -@plugin({ version: '1.0.1', author: 'MiaoWoo', source: __filename }) +@plugin({ version: '1.1.0', author: 'MiaoWoo', nativeDepends: ['PlaceholderAPI'], source: __filename }) export class MiaoChat extends interfaces.Plugin { @Autowired() private Server: server.Server diff --git a/packages/plugins/src/MiaoChatRGBSupport.ts b/packages/plugins/src/MiaoChatRGBSupport.ts new file mode 100644 index 00000000..ef6ffd43 --- /dev/null +++ b/packages/plugins/src/MiaoChatRGBSupport.ts @@ -0,0 +1,109 @@ +import { task, server, constants } from "@ccms/api" +import { Autowired, JSClass } from "@ccms/container" +import { interfaces, JSPlugin } from "@ccms/plugin" + +let createPacketAdapterFunction = eval(` +function(cls, plugin, type, onPacketSending){ + return new cls(plugin, type) { + onPacketSending: onPacketSending + } +} +`) +const ChatColor = Java.type('net.md_5.bungee.api.ChatColor') +const Pattern = Java.type('java.util.regex.Pattern') + +@JSPlugin({ prefix: 'MCRS', version: '1.0.0', author: 'MiaoWoo', servers: [constants.ServerType.Bukkit], nativeDepends: ['ProtocolLib'], source: __filename }) +export class MiaoChatRGBSupport extends interfaces.Plugin { + private supportRGB: boolean = false + // 用于匹配 '#FFFFFF' 颜色格式 + private RGBCOLOR_PATTERN = Pattern.compile("(#[a-fA-F0-9]{6}?)([^#?]*)"); + + @JSClass('com.comphenix.protocol.events.PacketAdapter') + private PacketAdapter: any + @JSClass('com.comphenix.protocol.PacketType') + private PacketType: any + @JSClass('com.comphenix.protocol.ProtocolLibrary') + private ProtocolLibrary: any + + private adapter: any + + load() { + try { + ChatColor.of('#FFFFFF').toString() + this.supportRGB = true + this.logger.console('§a检测到兼容RGB的服务端 已启动相关支持...') + } catch (error) { + this.logger.console('§c当前服务端不支持RGB色彩 Error: ' + error) + } + } + + enable() { + if (this.supportRGB) { + this.initPacketAdapter() + } + } + + disable() { + if (this.supportRGB) { + this.ProtocolLibrary.getProtocolManager().removePacketListener(this.adapter) + } + } + + createPacketAdapter(onPacketSending: (event) => void) { + return createPacketAdapterFunction(this.PacketAdapter, base.getInstance(), [this.PacketType.Play.Server.CHAT], onPacketSending) + } + + colorJson(jsonObj) { + if (jsonObj.extra && jsonObj.extra.length) { + for (const extra of jsonObj.extra) { + this.colorJson(extra) + } + } + let text: string = jsonObj.text + var matcher = this.RGBCOLOR_PATTERN.matcher(text) + let colors = [] + let texts = [] + let lastStart = 0 + while (matcher.find()) { + if (lastStart == 0) { + texts.push(text.substr(lastStart, matcher.start())) + lastStart = matcher.end() + } + colors.push(matcher.group(1)) + texts.push(matcher.group(2)) + } + if (colors.length) { + jsonObj.text = '' + let extras = [] + let firstText = texts.shift() + if (firstText) { extras.push({ text: firstText }) } + texts.forEach((value, index) => { + extras.push({ + text: value, + color: colors[index] + }) + }) + if (jsonObj.extra) { + jsonObj.extra = extras.concat(jsonObj.extra) + } else { + jsonObj.extra = extras + } + } + return jsonObj + } + + initPacketAdapter() { + this.adapter = this.createPacketAdapter((event) => { + try { + if (!event.getPlayer().hasPermission('MiaoChatRGBSupport.color')) { return } + let wcc = event.getPacket().getChatComponents().read(0) + if (wcc == null) { return } + wcc.setJson(JSON.stringify(this.colorJson(JSON.parse(wcc.getJson())))) + event.getPacket().getChatComponents().writeSafely(0, wcc) + } catch (error) { + console.ex(error) + } + }) + this.ProtocolLibrary.getProtocolManager().addPacketListener(this.adapter) + } +} diff --git a/packages/plugins/src/MiaoExplorer.ts b/packages/plugins/src/MiaoExplorer.ts index 77d1ab4b..a0ad011e 100644 --- a/packages/plugins/src/MiaoExplorer.ts +++ b/packages/plugins/src/MiaoExplorer.ts @@ -69,7 +69,7 @@ export class MiaoExplorer extends interfaces.Plugin { private readDir(dir) { let children = Java.from(dir.listFiles(new FileFilter({ - accept: file => file.getName().endsWith('.yml') || file.isDirectory() + accept: file => file.getName().endsWith('.yml') || file.getName().endsWith('.js') || file.isDirectory() }))).sort().map(file => { if (file.isDirectory()) { let children = this.readDir(file) diff --git a/packages/plugins/src/MiaoPay.ts b/packages/plugins/src/MiaoPay.ts index ea98c853..9355f8fb 100644 --- a/packages/plugins/src/MiaoPay.ts +++ b/packages/plugins/src/MiaoPay.ts @@ -2,7 +2,7 @@ /// /// -import { plugin, server, task } from '@ccms/api' +import { constants, plugin, server, task } from '@ccms/api' import { Autowired, JSClass } from '@ccms/container' import { Cmd, Config, interfaces, JSPlugin, Listener, PluginConfig, Tab } from '@ccms/plugin' @@ -17,7 +17,12 @@ interface PlayerPointsAPI { give(name: string, amount: number) take(name: string, amount: number) } - +interface App { + appid: string + appname: string + ratio: number + coin_name: string +} interface Order { order_id: string amount: number @@ -73,7 +78,7 @@ const defaultConfig = { } } -@JSPlugin({ version: '1.3.5', author: 'MiaoWoo', source: __filename, depends: ['MiaoReward'], nativeDepends: ['PlaceholderAPI'] }) +@JSPlugin({ version: '1.5.0', author: 'MiaoWoo', source: __filename, servers: [constants.ServerType.Bukkit], depends: ['MiaoReward'], nativeDepends: ['PlaceholderAPI', 'ProtocolLib'] }) export class MiaoPay extends interfaces.Plugin { @Autowired() private server: server.Server @@ -87,28 +92,32 @@ export class MiaoPay extends interfaces.Plugin { private apiGateWay = "https://pay.yumc.pw" private MiaoReward: MiaoReward + private appInfo: App private cacheMap = new Map(); private cacheSyncMap = new Map(); + private checkSet = new Set(); + @Config() private config: PluginConfig & typeof defaultConfig = defaultConfig load() { - let needSave = false - for (const key of Object.keys(defaultConfig)) { - if (!this.config[key]) { - this.config[key] = defaultConfig[key] - needSave = true - } - } - needSave && this.config.save() + this.MiaoReward = this.pluginManager.getPlugin('MiaoReward') as MiaoReward } enable() { - this.MiaoReward = this.pluginManager.getPlugin('MiaoReward') as MiaoReward 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 }) + if (info.code == 200) { + this.appInfo = info.data + this.config.ratio = this.appInfo.ratio + this.config.coinName = this.appInfo.coin_name + } else { + this.logger.console('§4初始化支付系统失败 请检查配置是否正确!') + this.logger.console('§c服务器返回异常: §4' + info.msg) + } } disable() { @@ -123,7 +132,9 @@ 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.MiaoReward.serverInfo) { return this.logger.sender(sender, '§4当前服务器尚未配置 请联系管理员先配置MiaoReward!') } + 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.cacheMap.has(sender.getName())) { this.logger.sender(sender, '§c您有一笔订单尚未完成 请完成支付或等待订单超时!') @@ -136,7 +147,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 > 1000) { return this.logger.sender(sender, `§c充值异常 §4充值金额不得大于 ${this.config.ratio * 1000} ${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 != Math.round(amount)) { return this.logger.sender(sender, `§c充值异常 §4充值金额必须为整数!`) } try { this.getPlayerAmount(sender) @@ -204,17 +215,25 @@ export class MiaoPay extends interfaces.Plugin { } cmdcheck(sender: org.bukkit.entity.Player, force = 1) { + if (this.checkSet.has(sender.getName())) { + return this.logger.sender(sender, '§c检查任务执行中 请稍候...') + } + this.checkSet.add(sender.getName()) this.logger.sender(sender, `§3正在检查需要补单充值的订单 请稍候...`) this.taskManager.create(() => { - let result = this.queryUnconverted(sender.getName(), force) - if (result.code != 200) { return this.logger.sender(sender, `§c订单查询失败: ${result.msg}`) } - let unconverteds = result.data - if (!unconverteds.length) { return this.logger.sender(sender, `§c未发现需要进行补单充值的订单!`) } - this.logger.sender(sender, `§3发现 §a${unconverteds.length}笔 §3未充值订单 §c正在充值 请稍候...`) - for (const unconverted of unconverteds) { - this.logger.sender(sender, `§3正在处理订单 §a${unconverted.order_id} §3请稍候...`) - this.recharge(sender, unconverted) - Thread.sleep(300) + try { + let result = this.queryUnconverted(sender.getName(), force) + if (result.code != 200) { return this.logger.sender(sender, `§c订单查询失败: ${result.msg}`) } + let unconverteds = result.data + if (!unconverteds.length) { return this.logger.sender(sender, `§c未发现需要进行补单充值的订单!`) } + this.logger.sender(sender, `§3发现 §a${unconverteds.length}笔 §3未充值订单 §c正在充值 请稍候...`) + for (const unconverted of unconverteds) { + this.logger.sender(sender, `§3正在处理订单 §a${unconverted.order_id} §3请稍候...`) + this.recharge(sender, unconverted) + Thread.sleep(300) + } + } finally { + this.checkSet.delete(sender.getName()) } }).async().submit() } @@ -287,6 +306,7 @@ export class MiaoPay extends interfaces.Plugin { } private rewardOrder(sender, order_id, point) { + if (!this.config.reward) { return } this.taskManager.callSyncMethod(() => { try { if (this.config.reward['*']) { @@ -355,11 +375,11 @@ export class MiaoPay extends interfaces.Plugin { } private createOrder(sender: org.bukkit.entity.Player, amount: number): Order { - let serverName = this.MiaoReward.serverInfo.name + let serverName = this.appInfo?.appname if (this.config.name) { serverName = `${serverName}(${this.config.name})` } let result = this.httpPost('/create', { subject: `${serverName} 充值 ${amount} ${this.config.coinName}`, - amount: amount / this.config.ratio, + amount: amount / this.appInfo.ratio, username: sender.getName(), unionId: sender.getUniqueId().toString() }) @@ -381,6 +401,7 @@ export class MiaoPay extends interfaces.Plugin { let startTime = Date.now() data.appid = this.config.id data.timestamp = Math.round(Date.now() / 1000) + data.nonce = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'.replace(/x/g, () => (Math.random() * 16 | 0).toString(16)) data.sign = this.sign(data) let url = `${this.apiGateWay}/api${method}` let result = http.post(url, data) diff --git a/packages/plugins/src/MiaoProtocol.ts b/packages/plugins/src/MiaoProtocol.ts index 2f5c3df7..f96dd57b 100644 --- a/packages/plugins/src/MiaoProtocol.ts +++ b/packages/plugins/src/MiaoProtocol.ts @@ -1,6 +1,6 @@ import { task, server, constants } from "@ccms/api" import { Autowired, JSClass } from "@ccms/container" -import { plugin, interfaces } from "@ccms/plugin" +import { plugin, interfaces, Cmd } from "@ccms/plugin" let createPacketAdapterFunction = eval(` function(cls, plugin, type, onPacketSending){ @@ -10,6 +10,13 @@ function(cls, plugin, type, onPacketSending){ } `) +interface PlaceholderAPI { + registerPlaceholderHook: (key: string, onPlaceholderRequest: (player, s) => string) => void + unregisterPlaceholderHook: (key: string) => void + setPlaceholders: (player: any, str: string) => string +} +const Pattern = Java.type('java.util.regex.Pattern') + @plugin({ prefix: 'MPTL', version: '1.0.0', author: 'MiaoWoo', servers: [constants.ServerType.Bukkit], source: __filename }) export class MiaoProtocol extends interfaces.Plugin { @Autowired() @@ -24,9 +31,24 @@ export class MiaoProtocol extends interfaces.Plugin { @JSClass('com.comphenix.protocol.ProtocolLibrary') private ProtocolLibrary + @JSClass('com.comphenix.protocol.wrappers.nbt.NbtFactory') + private NbtFactory + + @JSClass('me.clip.placeholderapi.PlaceholderAPI') + private PlaceholderAPI: PlaceholderAPI + private pipeline: any private adapter: any + @Cmd({ autoMain: true }) + mptl() { + } + + cmdnbt(sender: org.bukkit.entity.Player) { + let nbt = this.NbtFactory.fromItemOptional(sender.getItemInHand()) + console.log(nbt) + } + enable() { let count = 0 let wait = this.taskManager.create(() => { @@ -46,20 +68,49 @@ export class MiaoProtocol extends interfaces.Plugin { } createPacketAdapter(onPacketSending: (event) => void) { - return createPacketAdapterFunction(this.PacketAdapter, base.getInstance(), [this.PacketType.Play.Server.MAP], onPacketSending) + return createPacketAdapterFunction(this.PacketAdapter, base.getInstance(), [this.PacketType.Play.Server.CHAT], onPacketSending) } initPacketAdapter() { this.adapter = this.createPacketAdapter((event) => { - let integers = event.getPacket().getIntegers().getValues() - // console.log(`ProtocolLib onPacketSending filter Map - // Player: ${event.getPlayer()} - // MapId: ${integers.get(0)} - // Short: ${event.getPacket().getShorts().read(0)} - // Bytes: ${event.getPacket().getByteArrays().read(0).length} - // `) - //Size: ${integers.get(3)}x${integers.get(4)} - // org.bukkit.map.MapPalette.imageToBytes() + try { + // let wcc = event.getPacket().getChatComponents().read(0) + // if (wcc == null) { return } + // let json = wcc.getJson() + // console.log(json) + // let jsonObj = JSON.parse(json) + // let result = JSON.stringify(this.colorJson(jsonObj)) + // console.log(result) + // wcc.setJson(result) + // event.getPacket().getChatComponents().writeSafely(0, wcc) + // let packet = event.getPacket() + // let modify = packet.getEntityModifier(event) + // console.log(modify.getValues().get(0).getType().getName()) + // let modify = event.getPacket().getNbtModifier() + // let nbt = modify.read(0) + // let lines = ["Text1", "Text2", "Text3", "Text4"] + // console.log("Before Replace", event.getPlayer().getName(), nbt) + // lines.forEach((s: string) => { + // let origin = nbt.getString(s) + // let replaced = this.PlaceholderAPI.setPlaceholders(event.getPlayer(), origin) + // nbt.put(s, replaced) + // console.log(event.getPlayer(), origin, replaced) + // }) + // // Arrays.asList("Text1", "Text2", "Text3", "Text4").forEach(s -> nbt.put(s, replace(event.getPlayer(), nbt.getString(s)))) + // console.log("After Replace", event.getPlayer().getName(), nbt) + // modify.write(0, nbt) + // let integers = event.getPacket().getIntegers().getValues() + // console.log(`ProtocolLib onPacketSending filter Map + // Player: ${event.getPlayer()} + // MapId: ${integers.get(0)} + // Short: ${event.getPacket().getShorts().read(0)} + // Bytes: ${event.getPacket().getByteArrays().read(0).length} + // `) + //Size: ${integers.get(3)}x${integers.get(4)} + // org.bukkit.map.MapPalette.imageToBytes() + } catch (error) { + console.ex(error) + } }) this.ProtocolLibrary.getProtocolManager().addPacketListener(this.adapter) } diff --git a/packages/plugins/src/MiaoRebate.ts b/packages/plugins/src/MiaoRebate.ts new file mode 100644 index 00000000..7c5c6809 --- /dev/null +++ b/packages/plugins/src/MiaoRebate.ts @@ -0,0 +1,253 @@ +/// +/// +/// + +import { plugin, server, task } from '@ccms/api' +import { Autowired, JSClass } from '@ccms/container' +import { Cmd, Config, interfaces, JSPlugin, Listener, PluginConfig, Tab } from '@ccms/plugin' + +import type { MiaoReward } from './MiaoReward' +import http from '@ccms/common/dist/http' + +interface Sync { + scaned: boolean + start?: number + left?: number + cancelled?: boolean + paying?: boolean +} + +interface PlaceholderAPI { + registerPlaceholderHook: (key: string, onPlaceholderRequest: (player, s) => string) => void + unregisterPlaceholderHook: (key: string) => void + setPlaceholders: (player: any, str: string) => string +} + +const defaultConfig = { + prefix: '§6[§b外卖系统§6]§r', + check: '%playerpoints_points%', + command: 'points give %player_name% %amount%', + ratio: 1, + coinName: '点券', + joinTip: true, + owner: { + userid: '', + ccid: '', + openid: '' + } +} + +@JSPlugin({ version: '1.0.1', author: 'MiaoWoo', source: __filename, depends: ['MiaoReward'], nativeDepends: ['PlaceholderAPI'] }) +export class MiaoRebate extends interfaces.Plugin { + @Autowired() + private server: server.Server + @Autowired() + private taskManager: task.TaskManager + @Autowired() + private pluginManager: plugin.PluginManager + + @JSClass('me.clip.placeholderapi.PlaceholderAPI') + private PlaceholderAPI: PlaceholderAPI + + private apiGateWay = "https://rebate.yumc.pw" + private MiaoReward: MiaoReward + + @Config({ default: defaultConfig }) + private config: PluginConfig & typeof defaultConfig = defaultConfig + + load() { + this.logger.prefix = this.config.prefix + } + + enable() { + this.MiaoReward = this.pluginManager.getPlugin('MiaoReward') as MiaoReward + if (!this.MiaoReward) { return this.logger.error(`当前脚本插件需要 MiaoReward 作为前置脚本插件!`) } + } + + disable() { + } + + @Cmd({ autoMain: true }) + mre() { } + + cmdbind(sender: org.bukkit.entity.Player, server: boolean) { + if (!sender.getItemInHand) { return this.logger.sender(sender, `§c手持物品检测异常 请检查是否在客户端执行命令!`) } + if (server) { return this.bindServer(sender) } + if (!sender.getItemInHand) { return this.logger.sender(sender, `§c手持物品检测异常 请检查是否在客户端执行命令!`) } + if (!this.config.owner.openid || !this.config.owner.userid) { return this.logger.sender(sender, `§4当前服务器尚未绑定管理员账号 请联系管理员完成绑定!`) } + this.MiaoReward.sendTitle(sender, `§a获取二维码中`, `§6请稍候...`) + let scan = this.qrCreate(sender, `绑定成功 请返回游戏查看!`, { + v: 1, + type: "invite", + user: this.config.owner.openid, + userid: this.config.owner.userid, + }) + this.createScanTask(sender, scan.url, `微信扫码绑定账号`, `微信扫码 点击关注 绑定账号`, (sender) => { + this.MiaoReward.sendTitle(sender, `§a绑定成功!`, `§6已绑定用户: §b${this.qrGet(scan.token).user.username}`) + }) + } + + cmddraw(sender: org.bukkit.entity.Player, amount: number) { + if (!sender.getItemInHand) { return this.logger.sender(sender, `§c手持物品检测异常 请检查是否在客户端执行命令!`) } + if (!this.config.owner.openid || !this.config.owner.userid) { return this.logger.sender(sender, `§4当前服务器尚未绑定管理员账号 请联系管理员完成绑定!`) } + amount = Number(amount) + if (!Number.isInteger(amount)) { + return this.logger.sender(sender, `§4兑换金额必须是数字!`) + } + if (amount < 1) { + return this.logger.sender(sender, `§4兑换金额必须大于1!`) + } + this.MiaoReward.sendTitle(sender, `§a获取二维码中`, `§6请稍候...`) + let scan = this.qrCreate(sender, ``, { + v: 1, + type: "draw", + ccid: this.config.owner.ccid, + userid: this.config.owner.userid, + amount + }) + this.createScanTask(sender, scan.url, `微信扫码兑换奖励`, `微信扫码兑换奖励`, (sender) => { + let result = this.qrGet(scan.token) + this.MiaoReward.sendTitle(sender, `§a扫码成功`, `§a兑换奖励中 §b具体结果请查看公众号消息...`) + if (!(result = result.result)) { + return this.sendError(sender, amount, `§4服务器返回数据异常!`) + } + if (!result.success) { + return this.sendError(sender, amount, `§c` + result.message) + } + this.logger.sender(sender, `§a` + result.message) + this.taskManager.callSyncMethod(() => { + let point = this.safeMultiply(amount, this.config.ratio) + let command = this.config.command.replace(`%player_name%`, sender.getName()).replace(`%amount%`, `${point}`) + if (!this.server.dispatchConsoleCommand(command)) { + return this.sendError(sender, amount, `§4充值命令执行异常!`) + } + let nowPoint = this.getPlayerAmount(sender) + this.logger.sender(sender, [ + `§6充值 §a${point} §6${this.config.coinName} §a成功 §6当前账户余额: §3${nowPoint} §6${this.config.coinName}`, + `§c如出现未到账的情况 请联系管理员!` + ]) + }) + }) + this.MiaoReward.clearTitle(sender) + } + private safeMultiply(a: number, b: number) { + return parseFloat((a * b).toFixed(0)) + } + sendError(sender: org.bukkit.entity.Player, amount: number, error: string) { + return this.logger.sender(sender, [ + `§c========== ${this.config.prefix}§4兑换异常 §c==========`, + `§6兑换圈币: §3${amount}`, + `§6异常原因: §4${error}`, + `§6异常账号: §b${sender.getName()}`, + `§6异常时间: §a${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}`, + `§c如果已扣除圈币但${this.config.coinName}未到账 请截图发给腐竹!`, + `§c========== ${this.config.prefix}§4兑换异常 §c==========`, + ]) + } + + private getPlayerAmount(sender: any): number { + let result = this.PlaceholderAPI.setPlaceholders(sender, this.config.check) + let amount = parseFloat(result) + if (isNaN(amount)) { + throw new Error(`§c读取玩家 §3${this.config.coinName} §c异常 §6请检查 §3check §6配置是否正确! +§6数据解析链路: §3${this.config.check} §6=> §3${result} §6=> §3${amount}`) + } + return amount + } + private bindServer(sender: org.bukkit.entity.Player) { + if (!sender.isOp()) { return this.logger.sender(sender, `§4您没有配置服务器的权限!`) } + if (this.config.owner.openid || this.config.owner.userid) { + this.logger.sender(sender, `§c更换管理员账号 历史绑定数据将不会迁移!`) + } + let scan = this.qrCreate(sender, `绑定成功 请返回游戏查看!`) + this.createScanTask(sender, scan.url, `微信扫码绑定账号`, `微信扫码 点击关注 绑定账号`, (sender) => { + let result = this.qrGet(scan.token) + let user = result.user + this.config.owner.userid = user.id + this.config.owner.ccid = user.ccid + this.config.owner.openid = result.openid + this.config.save() + this.MiaoReward.sendTitle(sender, `§a绑定成功!`, `§6已绑定用户: §b${user.username}`) + }) + this.MiaoReward.clearTitle(sender) + } + + private createScanTask(sender: org.bukkit.entity.Player, qrcode: string, name: string, tip: string, task: (sender: org.bukkit.entity.Player) => void) { + let sync: any = { scaned: false, start: Math.round(Date.now() / 1000) } + this.MiaoReward.setItemAndTp(sender, qrcode, sync, name, tip) + this.taskManager.create(() => { + try { + task(sender) + } catch (error) { + if (!sync.cancelled) { + this.logger.sender(sender, `§c` + error) + } + } finally { + sync.scaned = true + sender.updateInventory() + } + }).async().submit() + this.MiaoReward.clearTitle(sender) + } + + @Listener() + private PlayerJoinEvent(event: org.bukkit.event.player.PlayerJoinEvent) { + if (this.config.joinTip) { + this.taskManager.create(() => { + this.logger.sender(event.getPlayer(), [ + `§b本服已和§a饿了么§6美团§c达成战略合作!`, + `§3/mre bind §a扫码§e免费赠送§a外卖红包!` + ]) + }).later(30).submit() + } + } + + @Tab() + tabmre(sender: any, _command: any, args: string | any[]) { + if (args.length === 2 && args[0] === "bind" && sender.isOp()) return [`server`] + } + + private qrCreate(sender: org.bukkit.entity.Player, message: string, data: any = {}) { + let create = this.httpPost(`/qr/create/type/login/message/${encodeURIComponent(message)}`, data) + if (create.code != 200) { + return this.logger.sender(sender, `§c获取链接异常: ` + create.msg) + } + return create.data + } + + private qrGet(token: string) { + let get = this.httpPost('/qr/get', { token }) + if (get.code != 200) { + throw new Error(get.msg) + } + return get.data + } + + private httpPost(method: string, data: any = {}) { + let startTime = Date.now() + let url = `${this.apiGateWay}${method}` + let result = http.post(url, data) + console.debug(` +====== HTTP POST ====== +REQUEST URL : ${url} +REQUEST DATA: ${JSON.stringify(data)} +RESPONSE : ${JSON.stringify(result)} +CAST TIME : ${Date.now() - startTime}`) + return result + } + + private cmdhelp(sender: any) { + let help = [ + `§6====== ${this.config.prefix} §a帮助菜单 §6======`, + `§6/mre bind §a绑定账号`, + `§6/mre draw §e<兑换数量> §a兑换${this.config.coinName}` + ] + if (sender.isOp()) { + help = help.concat([ + `§c由于您是管理员 以为您展示额外命令`, + `§6/mre bind server §a绑定服务器`, + ]) + } + this.logger.sender(sender, help) + } +} diff --git a/packages/plugins/src/MiaoScriptPackageManager.ts b/packages/plugins/src/MiaoScriptPackageManager.ts index d9a00a33..64fd9d33 100644 --- a/packages/plugins/src/MiaoScriptPackageManager.ts +++ b/packages/plugins/src/MiaoScriptPackageManager.ts @@ -46,12 +46,14 @@ let langMap = { 'cloud.update.finish': '§6成功从 §aMiaoScriptPackageCenter §6获取到 §a{length} §6个插件!', 'cloud.not.exists': '§6当前 §aMiaoScriptPackageCenter §c不存在 §a{name} §c插件!', 'cloud.update.exists': '§6插件 §b{name} §6版本 §3{old_version} §a发现更新 §3{new_version} §r{changelog}§6!', + 'cloud.update.tip': `§6发现存在 §b{count}个 §6需要更新的插件 请使用 §aupdate §6或 §cupgrade §6命令更新!`, 'download.start': '§6开始下载插件: §b{name} §6版本 §3{version}', 'download.url': '§6插件下载地址: §b{url}', 'download.finish': '§6插件 §b{name} §6版本 §3{version} §a下载完毕 开始加载 ...', 'install.already': '§6插件 §b{name} §6版本 §3{version} §c已安装在服务器 §3更新请用 update 命令!', 'install.finish': '§6插件 §b{name} §6版本 §3{version} §a安装成功!', - 'update.finish': '§6插件 §b{name} §6版本 §3{version} §a更新成功!', + 'update.finish': '§6插件 §b{name} §6版本 §3{version} §a更新完成!', + 'update.tip': '§6插件 §b{name} §a更新完成 §6请使用 §areload §6命令重载生效!', 'upgrade.confirm': '§6您正在尝试更新 §bMiaoScript §c核心 §6请执行 §b/mpm §aupgrade §cconfirm §6确认执行!', 'upgrade.start': '§6开始§a更新 §bMiaoScript §6核心 §c正在清理 node_modules 请稍候...', 'upgrade.failed': '§6尝试热更新 §bMiaoScript §c核心 §4失败! §6请重启服务器完成更新...', @@ -107,7 +109,7 @@ class SpongeFakeSender extends FakeSender { } } -@JSPlugin({ prefix: 'PM', version: '1.4.0', author: 'MiaoWoo', source: __filename }) +@JSPlugin({ prefix: 'PM', version: '1.5.0', author: 'MiaoWoo', source: __filename }) export class MiaoScriptPackageManager extends interfaces.Plugin { @Autowired() private pluginManager: pluginApi.PluginManager @@ -134,7 +136,6 @@ export class MiaoScriptPackageManager extends interfaces.Plugin { public serverName: string private translate: Translate private channelOff: { off: () => void } - private subCommandCache = [] load() { this.translate = new Translate({ @@ -142,7 +143,6 @@ export class MiaoScriptPackageManager extends interfaces.Plugin { fallbackMap }) this.updateRepo(this.server.getConsoleSender()) - this.subCommandCache = Object.keys(this).filter(c => c.startsWith('cmd') && typeof this[c] == "function") } @enable({ servers: [constants.ServerType.Bukkit, constants.ServerType.Sponge] }) @@ -488,7 +488,11 @@ return eval(${JSON.stringify(code)});`) if (this.checkCloudPlugin(sender, name)) { this.download(sender, name, true, () => { this.i18n(sender, 'update.finish', { name, version: this.packageCache[name].version }) - callback?.() + if (callback) { + callback() + } else { + this.i18n(sender, 'update.tip', { name, version: this.packageCache[name].version }) + } }) } } @@ -530,6 +534,7 @@ return eval(${JSON.stringify(code)});`) this.i18n(sender, 'cloud.update.finish', { length: this.packageNameCache.length }) 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', { @@ -538,6 +543,10 @@ return eval(${JSON.stringify(code)});`) old_version: p.description.version, changelog: cloudPlugin.changelog || '' }) + updateCount++ + } + if (updateCount) { + this.i18n(sender, 'cloud.update.tip', { count: updateCount }) } }) }).async().submit()