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系列插件
|
### Miao系列插件
|
||||||
|
|
||||||
|
- [[综合|前置]MiaoLink —— 喵式映射 用于无公网环境的自动化端口映射[全版本]](https://www.mcbbs.net/thread-1121423-1-1.html)
|
||||||
- [[经济]MiaoReward —— 喵式奖励 让玩家看广告为服务器提供收入吧[1.7.10+全版本]](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)
|
- [[编程]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)
|
- [[编程]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 {
|
export class MiaoPay extends interfaces.Plugin {
|
||||||
@Autowired()
|
@Autowired()
|
||||||
private server: server.Server
|
private server: server.Server
|
||||||
@@ -104,7 +104,11 @@ export class MiaoPay extends interfaces.Plugin {
|
|||||||
enable() {
|
enable() {
|
||||||
if (!this.MiaoReward) { return this.logger.error('当前脚本插件需要 MiaoReward 作为前置脚本插件!') }
|
if (!this.MiaoReward) { return this.logger.error('当前脚本插件需要 MiaoReward 作为前置脚本插件!') }
|
||||||
if (!this.config.id || !this.config.secret) { return this.logger.console('§4尚未配置商户信息 将无法正常收款!') }
|
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) {
|
if (info.code == 200) {
|
||||||
this.appInfo = info.data
|
this.appInfo = info.data
|
||||||
this.config.ratio = this.appInfo.ratio
|
this.config.ratio = this.appInfo.ratio
|
||||||
@@ -114,8 +118,8 @@ export class MiaoPay extends interfaces.Plugin {
|
|||||||
this.config.save()
|
this.config.save()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.logger.console('§4初始化支付系统失败 请检查配置是否正确!')
|
this.logger.console('§4初始化支付系统失败 请检查配置或网络是否正常!')
|
||||||
this.logger.console('§c服务器返回异常: §4' + info.msg)
|
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) {
|
cmdpay(sender: org.bukkit.entity.Player, amount: number = 0) {
|
||||||
if (!sender.getItemInHand) { return this.logger.sender(sender, '§4控制台无法执行此命令!') }
|
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.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())) {
|
if (this.cacheMap.has(sender.getName())) {
|
||||||
this.logger.sender(sender, '§c您有一笔订单尚未完成 请完成支付或等待订单超时!')
|
this.logger.sender(sender, '§c您有一笔订单尚未完成 请完成支付或等待订单超时!')
|
||||||
let sync = this.cacheSyncMap.get(sender.getName())
|
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.scaned = false
|
||||||
sync.left = (sync.paying ? 100 : 55) - (Math.round(Date.now() / 1000) - sync.start)
|
sync.left = (sync.paying ? 100 : 55) - (Math.round(Date.now() / 1000) - sync.start)
|
||||||
let order = this.cacheMap.get(sender.getName())
|
let order = this.cacheMap.get(sender.getName())
|
||||||
@@ -146,7 +153,7 @@ export class MiaoPay extends interfaces.Plugin {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (amount < 1) { return this.logger.sender(sender, `§c充值异常 §4充值金额不得小于 1 ${this.config.coinName}!`) }
|
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充值金额必须为整数!`) }
|
if (amount != Math.round(amount)) { return this.logger.sender(sender, `§c充值异常 §4充值金额必须为整数!`) }
|
||||||
try {
|
try {
|
||||||
this.getPlayerAmount(sender)
|
this.getPlayerAmount(sender)
|
||||||
@@ -341,15 +348,15 @@ export class MiaoPay extends interfaces.Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private preFinishOrder(id: string) {
|
private preFinishOrder(id: string) {
|
||||||
return this.httpPost('/preFinish', { id }, true)
|
return this.httpPost('/preFinish', { id }, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
private errorOrder(id: string, error: string) {
|
private errorOrder(id: string, error: string) {
|
||||||
return this.httpPost('/error', { id, error }, true)
|
return this.httpPost('/error', { id, error }, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
private finishOrder(id: string) {
|
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 {
|
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) {
|
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) {
|
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()
|
let startTime = Date.now()
|
||||||
data.appid = this.config.id
|
data.appid = this.config.id
|
||||||
data.timestamp = Math.round(Date.now() / 1000)
|
data.timestamp = Math.round(Date.now() / 1000)
|
||||||
@@ -393,11 +400,12 @@ CAST TIME : ${Date.now() - startTime}`)
|
|||||||
return result
|
return result
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (retry) {
|
if (retry) {
|
||||||
return this.httpPost(method, data)
|
Thread.sleep(retry * 10)
|
||||||
} else {
|
return this.httpPost(method, data, --retry)
|
||||||
console.console('§4请求支付中心发生异常 请联系管理员处理此问题!')
|
|
||||||
console.ex(error)
|
|
||||||
}
|
}
|
||||||
|
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
|
sync.cancelled = false
|
||||||
let task = this.taskManager.create(() => {
|
let task = this.taskManager.create(() => {
|
||||||
try {
|
try {
|
||||||
|
console.log(JSON.stringify(sync))
|
||||||
if (sync.scaned || !sender.isOnline() || !this.isHoldQrCodeItem(sender) || --sync.left < 0) {
|
if (sync.scaned || !sender.isOnline() || !this.isHoldQrCodeItem(sender) || --sync.left < 0) {
|
||||||
if (sync.left < 0) {
|
if (sync.left < 0) {
|
||||||
this.logger.sender(sender, '§c二维码已过期 请重新获取 如已扫码请忽略!')
|
this.logger.sender(sender, '§c二维码已过期 请重新获取 如已扫码请忽略!')
|
||||||
|
|||||||
@@ -1,41 +1,152 @@
|
|||||||
/// <reference types="@javatypes/bungee-api" />
|
/// <reference types="@javatypes/bungee-api" />
|
||||||
/// <reference types="@javatypes/bukkit-api" />
|
/// <reference types="@javatypes/bukkit-api" />
|
||||||
/// <reference types="@javatypes/sponge-api" />
|
/// <reference types="@javatypes/sponge-api" />
|
||||||
/// <reference types="typescript" />
|
|
||||||
// @ts-ignore
|
import { EventEmitter } from 'events'
|
||||||
require.clear('websocket/client')
|
|
||||||
import { server } from '@ccms/api'
|
import { constants, server } from '@ccms/api'
|
||||||
import { Autowired, Container, ContainerInstance } from '@ccms/container'
|
import { Autowired, JSClass } from '@ccms/container'
|
||||||
import { Cmd, JSPlugin, Tab, interfaces, PluginConfig, Config } from '@ccms/plugin'
|
import { Cmd, JSPlugin, Tab, interfaces, PluginConfig, Config, Listener } from '@ccms/plugin'
|
||||||
import { WebSocket } from '@ccms/websocket'
|
import { WebSocket } from '@ccms/websocket'
|
||||||
|
|
||||||
|
const Thread = Java.type('java.lang.Thread')
|
||||||
|
const ChatColor = Java.type('org.bukkit.ChatColor')
|
||||||
|
|
||||||
const defaultConfig = {
|
const defaultConfig = {
|
||||||
|
version: 1,
|
||||||
address: '',
|
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 {
|
export class MiaoRobot extends interfaces.Plugin {
|
||||||
@Autowired()
|
@Autowired()
|
||||||
private server: server.Server
|
private server: server.Server
|
||||||
|
|
||||||
private client: WebSocket
|
@JSClass('me.clip.placeholderapi.PlaceholderAPI')
|
||||||
|
private PlaceholderAPI: PlaceholderAPI
|
||||||
|
|
||||||
|
private robot: Robot
|
||||||
|
|
||||||
@Config()
|
@Config()
|
||||||
private config: PluginConfig & typeof defaultConfig = defaultConfig
|
private config: PluginConfig & typeof defaultConfig = defaultConfig
|
||||||
|
|
||||||
load() {
|
load() {
|
||||||
}
|
this.logger.prefix = ''
|
||||||
|
|
||||||
private downloadRobot() {
|
|
||||||
//https://api.github.com/repos/Mrs4s/go-cqhttp/releases?per_page=1&page=1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enable() {
|
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() {
|
disable() {
|
||||||
this.cmdclose(this.server.getConsoleSender())
|
if (this.robot) {
|
||||||
|
this.cmdclose(this.server.getConsoleSender())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Cmd({ autoMain: true })
|
@Cmd({ autoMain: true })
|
||||||
@@ -46,50 +157,64 @@ export class MiaoRobot extends interfaces.Plugin {
|
|||||||
return this.logger.sender(sender, '§4错误 请配置服务器地址和Token!')
|
return this.logger.sender(sender, '§4错误 请配置服务器地址和Token!')
|
||||||
}
|
}
|
||||||
this.cmdclose(sender)
|
this.cmdclose(sender)
|
||||||
try {
|
this.initRobot(sender)
|
||||||
this.client = new WebSocket(address, '', { Authorization: `Bearer ${token}` })
|
|
||||||
this.initRobot(this.client)
|
|
||||||
} catch (error) {
|
|
||||||
console.ex(error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private initRobot(client: WebSocket) {
|
initRobot(sender) {
|
||||||
client.onopen = () => {
|
this.robot = new Robot({ ...this.config, timeout: 60 })
|
||||||
this.logger.console(`§3连接到 §b${client.url} §a成功!`)
|
this.robot.on('connect', () => {
|
||||||
}
|
this.logger.sender(sender, '§a机器人链接成功!')
|
||||||
client.onmessage = (event) => {
|
})
|
||||||
let messageEvent = JSON.parse(event.data)
|
this.robot.on('message', (event) => {
|
||||||
switch (messageEvent.post_type) {
|
if (event.message_type == "group" && event.group_id == this.config.group_id) {
|
||||||
case "message":
|
let message: string = event.message
|
||||||
this.logger.console(`§6接收到 §3群 §b${messageEvent.group_id} §2成员 §a${messageEvent.sender.nickname} §6的消息: §r${messageEvent.message}`)
|
message = message.replace(/.*\[CQ:image\,file=(.*),url=(.*),.*]/g, '[图片]')
|
||||||
break
|
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.robot.connect()
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdclose(sender: org.bukkit.entity.Player) {
|
cmdclose(sender: org.bukkit.entity.Player) {
|
||||||
if (this.client && this.client.readyState != WebSocket.CLOSED) {
|
if (this.robot) {
|
||||||
this.client.close(0, 'plugin close socket')
|
this.robot.disconnect()
|
||||||
|
this.logger.sender(sender, '§c机器人已断开链接!')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdsend(sender: org.bukkit.entity.Player, text: string) {
|
cmdsend(sender: org.bukkit.entity.Player, text: string) {
|
||||||
if (this.client) {
|
this?.robot.sendGroupMessage(this.config.group_id, text)
|
||||||
this.client.send(text)
|
this.logger.sender(sender, '§a发送成功!')
|
||||||
this.logger.sender(sender, '§a发送成功!')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tab()
|
@Tab()
|
||||||
tabmbot(_sender: any, _command: string, _args: string[]) {
|
tabmbot(_sender: any, _command: string, _args: string[]) {
|
||||||
return []
|
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)
|
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') }
|
if (!process.env.AccessToken) { return this.i18n(sender, 'deploy.token.not.exists') }
|
||||||
this.taskManager.create(() => {
|
this.taskManager.create(() => {
|
||||||
if (this.checkPlugin(sender, name)) {
|
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 }
|
for (const pl of result.data) { this.packageCache[pl.name] = pl }
|
||||||
this.packageNameCache = Object.keys(this.packageCache)
|
this.packageNameCache = Object.keys(this.packageCache)
|
||||||
this.i18n(sender, 'cloud.update.finish', { length: this.packageNameCache.length })
|
this.i18n(sender, 'cloud.update.finish', { length: this.packageNameCache.length })
|
||||||
|
let updateCount = 0
|
||||||
this.pluginManager.getPlugins().forEach(p => {
|
this.pluginManager.getPlugins().forEach(p => {
|
||||||
let cloudPlugin = this.packageCache[p.description.name]
|
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}
|
//§6插件名称: §b{name}\n§6版本: §a{version}\n§6作者: §3{author}\§6更新时间: §9{updated_at}
|
||||||
if (cloudPlugin && cloudPlugin.version != p.description.version) {
|
if (cloudPlugin && cloudPlugin.version != p.description.version) {
|
||||||
this.i18n(sender, 'cloud.update.exists', {
|
this.i18n(sender, 'cloud.update.exists', {
|
||||||
@@ -557,10 +557,10 @@ return eval(${JSON.stringify(code)});`)
|
|||||||
})
|
})
|
||||||
updateCount++
|
updateCount++
|
||||||
}
|
}
|
||||||
if (updateCount) {
|
|
||||||
this.i18n(sender, 'cloud.update.tip', { count: updateCount })
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
if (updateCount) {
|
||||||
|
this.i18n(sender, 'cloud.update.tip', { count: updateCount })
|
||||||
|
}
|
||||||
}).async().submit()
|
}).async().submit()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -570,7 +570,7 @@ return eval(${JSON.stringify(code)});`)
|
|||||||
this.i18n(sender, 'download.start', { name, version: pluginPkg.version })
|
this.i18n(sender, 'download.start', { name, version: pluginPkg.version })
|
||||||
this.i18n(sender, 'download.url', { url: pluginPkg.url })
|
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')
|
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 })
|
this.i18n(sender, 'download.finish', { name, version: pluginPkg.version })
|
||||||
callback?.()
|
callback?.()
|
||||||
}).async().submit()
|
}).async().submit()
|
||||||
|
|||||||
Reference in New Issue
Block a user