35
									
								
								packages/plugins/docs/MiaoLink.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								packages/plugins/docs/MiaoLink.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
 [综合|前置]MiaoLink —— 喵式映射 用于无公网环境的自动化端口映射[1.7.10+全版本] 
 | 
			
		||||
# MiaoLink
 | 
			
		||||
 | 
			
		||||
## 插件介绍
 | 
			
		||||
 | 
			
		||||
> 自动化端口公网映射
 | 
			
		||||
 | 
			
		||||
## 图片展示
 | 
			
		||||
 | 
			
		||||
- 
 | 
			
		||||
 | 
			
		||||
## 使用方式
 | 
			
		||||
 | 
			
		||||
- 本插件依赖于 `MiaoScript` 请前往 [站内帖子](https://www.mcbbs.net/thread-774401-1-1.html) 完成安装
 | 
			
		||||
- 执行 `/mspm install MiaoLink` 安装 MiaoLink 脚本插件
 | 
			
		||||
- 访问 [圈云映射](https://nps.yumc.pw) 申请一键映射指令
 | 
			
		||||
- 
 | 
			
		||||
- 执行网页上提供的指令 等待客户端上线
 | 
			
		||||
- 
 | 
			
		||||
- 使用访问地址即可链接服务器
 | 
			
		||||
- 
 | 
			
		||||
 | 
			
		||||
### 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) 提供的映射节点
 | 
			
		||||
 | 
			
		||||
#### 本插件所用所有代码均为原创,不存在借用/抄袭等行为
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										155
									
								
								packages/plugins/src/MiaoLink.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								packages/plugins/src/MiaoLink.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,155 @@
 | 
			
		||||
/// <reference types="@javatypes/bungee-api" />
 | 
			
		||||
/// <reference types="@javatypes/bukkit-api" />
 | 
			
		||||
/// <reference types="@javatypes/sponge-api" />
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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 }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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二维码已过期 请重新获取 如已扫码请忽略!')
 | 
			
		||||
 
 | 
			
		||||
@@ -1,41 +1,152 @@
 | 
			
		||||
/// <reference types="@javatypes/bungee-api" />
 | 
			
		||||
/// <reference types="@javatypes/bukkit-api" />
 | 
			
		||||
/// <reference types="@javatypes/sponge-api" />
 | 
			
		||||
/// <reference types="typescript" />
 | 
			
		||||
// @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())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user