diff --git a/packages/plugins/package.json b/packages/plugins/package.json index 453b5c05..1ce2debd 100644 --- a/packages/plugins/package.json +++ b/packages/plugins/package.json @@ -20,6 +20,9 @@ "test": "echo \"Error: run tests from root\" && exit 1" }, "devDependencies": { + "@javatypes/bukkit-api": "^0.0.3", + "@javatypes/bungee-api": "^0.0.3", + "@javatypes/sponge-api": "^0.0.3", "@javatypes/spring-data-redis": "^0.0.3", "@javatypes/spring-web": "^0.0.3", "@javatypes/tomcat": "^0.0.3", diff --git a/packages/plugins/src/McbbsPlugin.ts b/packages/plugins/src/McbbsPlugin.ts new file mode 100644 index 00000000..d256ce98 --- /dev/null +++ b/packages/plugins/src/McbbsPlugin.ts @@ -0,0 +1,78 @@ +/// +/// +/// + +import { plugin, server } from '@ccms/api' +import { Autowired } from '@ccms/container' +import { Cmd, interfaces, JSPlugin, Tab } from '@ccms/plugin' +import { Server as SocketIOServer, Socket as SocketIOSocket, Namespace } from '@ccms/websocket' + +import * as fs from '@ccms/common/dist/fs' + +const FileFilter = Java.type('java.io.FileFilter') +const ByteArrayInputStream = java.io.ByteArrayInputStream +const ByteArrayOutputStream = java.io.ByteArrayOutputStream +const StandardCharsets = Java.type("java.nio.charset.StandardCharsets") +const GZIPInputStream = Java.type('java.util.zip.GZIPInputStream') +const ByteArray = Java.type("byte[]") + +@JSPlugin({ version: '1.0.0', author: 'MiaoWoo', source: __filename }) +export class McbbsPlugin extends interfaces.Plugin { + @Autowired() + private Server: server.Server + @Autowired() + private pluginManager: plugin.PluginManager + + private namespace: any + + load() { + } + + enable() { + let consolePlugin: any = this.pluginManager.getPlugin('MiaoConsole') + if (consolePlugin.socketIOServer) { + this.startWebSocketServer(consolePlugin.socketIOServer) + } else { + process.on('websocket.create', (server: SocketIOServer) => { + this.startWebSocketServer(server) + }) + } + } + + private startWebSocketServer(server: SocketIOServer) { + this.namespace = server.of('/McbbsPlugin') + this.namespace.on('connect', (client: SocketIOSocket) => { + this.initWebSocketClient(client) + this.logger.console(`§6客户端 §b${client.id} §a新建连接...`) + }) + } + + disable() { + this.namespace.close() + } + + private initWebSocketClient(client: SocketIOSocket) { + client.on('ungzip', (content) => { + + }) + + client.on('error', (error) => { + this.logger.console(`§6客户端 §b${client.id} §c触发异常: ${error}`) + this.logger.error(error) + }) + client.on('disconnect', () => { + this.logger.console(`§6客户端 §b${client.id} §c断开连接...`) + }) + } + + @Cmd() + msme(sender: any, command: string, args: string[]) { + this.logger.log(sender, command, args) + sender.sendMessage(JSON.stringify({ command, ...args })) + } + + @Tab() + tabmsme(_sender: any, _command: string, _args: string[]) { + return ['world'] + } +} diff --git a/packages/plugins/src/MiaoConsole.ts b/packages/plugins/src/MiaoConsole.ts index 6f58938f..eb1a6199 100644 --- a/packages/plugins/src/MiaoConsole.ts +++ b/packages/plugins/src/MiaoConsole.ts @@ -1,8 +1,8 @@ /// import { plugin as pluginApi, server, task, constants, command } from '@ccms/api' -import { plugin, interfaces, cmd, tab, enable, config, disable } from '@ccms/plugin' -import { inject, ContainerInstance, Container } from '@ccms/container' +import { plugin, interfaces, cmd, tab, enable, config, disable, PluginConfig } from '@ccms/plugin' +import { ContainerInstance, Container, Autowired } from '@ccms/container' import io, { Server as SocketIOServer, Socket as SocketIOSocket } from '@ccms/websocket' import * as fs from '@ccms/common/dist/fs' import * as reflect from '@ccms/common/dist/reflect' @@ -19,22 +19,22 @@ let help = [ '§6/mconsole §areload §6- §3重载插件', ] -@plugin({ name: 'MiaoConsole', prefix: 'Console', version: '1.0.0', author: 'MiaoWoo', servers: ['!nukkit'], source: __filename }) +@plugin({ prefix: 'Console', version: '1.0.0', author: 'MiaoWoo', servers: ['!nukkit'], source: __filename }) export class MiaoConsole extends interfaces.Plugin { - @inject(ContainerInstance) + @Autowired(ContainerInstance) private container: Container - @inject(server.ServerType) + @Autowired(server.ServerType) private serverType: string - @inject(server.Server) - private server: server.Server - @inject(command.Command) - private command: command.Command - @inject(task.TaskManager) - private task: task.TaskManager - @inject(pluginApi.PluginManager) - private pluginManager: pluginApi.PluginManager - @inject(pluginApi.PluginFolder) + @Autowired(pluginApi.PluginFolder) private pluginFolder: string + @Autowired() + private server: server.Server + @Autowired() + private command: command.Command + @Autowired() + private task: task.TaskManager + @Autowired() + private pluginManager: pluginApi.PluginManager private token: string private instance: any @@ -46,7 +46,7 @@ export class MiaoConsole extends interfaces.Plugin { private logCache: string[] = [] @config() - private secret = { token: undefined } + private secret: PluginConfig = { token: undefined } load() { if (this.secret.token) { @@ -90,6 +90,7 @@ export class MiaoConsole extends interfaces.Plugin { cmdtoken(sender: any, sub: string, token: string) { if (sub == "set") { this.secret.token = this.token = token + this.secret.save() this.logger.sender(sender, '§a已保存§6服务器登录Token:§3', this.token, '§4请勿分享给其他人 防止服务器被攻击!') return } @@ -216,6 +217,7 @@ export class MiaoConsole extends interfaces.Plugin { root: fs.concat(root, 'wwwroot') }) this.container.bind(io.Instance).toConstantValue(this.socketIOServer) + process.emit('websocket.create', this.socketIOServer) } startSocketIOServer() { @@ -224,20 +226,19 @@ export class MiaoConsole extends interfaces.Plugin { namespace.on('connect', (client: SocketIOSocket) => { if (!this.token) { this.logger.console(`§6客户端 §b${client.id} §a请求连接 §4服务器尚未设置 Token 无法连接!`) - client.emit('unauthorized') - client.disconnect(true) + client.emit('unauthorized', () => client.disconnect(true)) return } if (this.token != client.handshake.query.token) { this.logger.console(`§6客户端 §b${client.id} §c无效请求 §4请提供正确Token后再次连接!`) - client.emit('unauthorized') - client.disconnect(true) + client.emit('unauthorized', () => client.disconnect(true)) return } this.initWebSocketClient(client) this.logCache.forEach(msg => client.emit('log', msg)) this.logger.console(`§6客户端 §b${client.id} §a新建连接 ${this.rootLogger ? '启动日志转发' : '§4转发日志启动失败'}...`) }) + process.emit('websocket.start', this.socketIOServer) } private initWebSocketClient(client: SocketIOSocket) { @@ -280,7 +281,7 @@ export class MiaoConsole extends interfaces.Plugin { if (!dir.isDirectory()) { return fn(undefined, `${file} 不是一个目录!`) } - fn(fs.list(dir)) + fn(fs.list(dir).map(f => f.name)) }) client.on('error', (error) => { this.logger.console(`§6客户端 §b${client.id} §c触发异常: ${error}`) diff --git a/packages/plugins/src/MiaoExplorer.ts b/packages/plugins/src/MiaoExplorer.ts new file mode 100644 index 00000000..cad09116 --- /dev/null +++ b/packages/plugins/src/MiaoExplorer.ts @@ -0,0 +1,175 @@ +/// +/// +/// + +import { plugin, server } from '@ccms/api' +import { Autowired } from '@ccms/container' +import { Cmd, interfaces, JSPlugin, Tab } from '@ccms/plugin' +import { Server as SocketIOServer, Socket as SocketIOSocket, Namespace } from '@ccms/websocket' + +import * as fs from '@ccms/common/dist/fs' + +const FileFilter = Java.type('java.io.FileFilter') +const ByteArrayInputStream = java.io.ByteArrayInputStream +const ByteArrayOutputStream = java.io.ByteArrayOutputStream +const StandardCharsets = Java.type("java.nio.charset.StandardCharsets") +const GZIPInputStream = Java.type('java.util.zip.GZIPInputStream') +const ByteArray = Java.type("byte[]") + +@JSPlugin({ prefix: 'Explorer', version: '1.0.0', author: 'MiaoWoo', source: __filename }) +export class MiaoExplorer extends interfaces.Plugin { + @Autowired() + private Server: server.Server + @Autowired() + private pluginManager: plugin.PluginManager + + private token: string + private namespace: any + private chunkCacheMap: Map> + + load() { + this.chunkCacheMap = new Map() + } + + enable() { + let consolePlugin: any = this.pluginManager.getPlugin('MiaoConsole') + if (consolePlugin.socketIOServer) { + this.startWebSocketServer(consolePlugin.socketIOServer) + } else { + process.on('websocket.create', (server: SocketIOServer) => { + this.startWebSocketServer(server) + }) + } + } + + private startWebSocketServer(server: SocketIOServer) { + let consolePlugin: any = this.pluginManager.getPlugin('MiaoConsole') + this.token = consolePlugin.token + this.namespace = server.of('/MiaoExplorer') + this.namespace.on('connect', (client: SocketIOSocket) => { + if (!this.token) { + this.logger.console(`§6客户端 §b${client.id} §a请求连接 §4服务器尚未设置 Token 无法连接!`) + client.emit('unauthorized', () => client.disconnect(true)) + return + } + if (this.token != client.handshake.query.token) { + this.logger.console(`§6客户端 §b${client.id} §c无效请求 §4请提供正确Token后再次连接!`) + client.emit('unauthorized', () => client.disconnect(true)) + return + } + this.initWebSocketClient(client) + this.logger.console(`§6客户端 §b${client.id} §a新建连接...`) + }) + } + + disable() { + this.namespace.removeAllListeners('connect') + this.namespace.close() + } + + private readDir(dir) { + let children = Java.from(dir.listFiles(new FileFilter({ + accept: file => file.getName().endsWith('.yml') || file.isDirectory() + }))).sort().map(file => { + if (file.isDirectory()) { + let children = this.readDir(file) + if (!children.length) { return null } + return { + label: file.getName(), + value: fs.path(file), + children, + disabled: true + } + } + return { + label: file.getName(), + value: fs.path(file), + creatable: true, + editable: true, + removable: true, + deleteApi: "delete" + } + }) + return children.filter(s => s) + } + + private initWebSocketClient(client: SocketIOSocket) { + client.on('ls', (fn) => { + var pluginDirs = Java.from(fs.file('./plugins').listFiles(new FileFilter({ + accept: dirs => dirs.isDirectory() + }))) + let result = { + options: pluginDirs.sort().map(f => { + let node: any = { + label: f.getName(), + value: fs.path(f) + } + let children = this.readDir(f) + if (!children.length) { + return null + } + node.children = children + node.disabled = true + return node + }) + } + fn && fn(result.options.filter(s => s)) + }) + client.on('read', (file, callback) => { + callback?.(base.read(file)) + }) + client.on('chunk', (file, index, content, callback) => { + if (!this.chunkCacheMap.has(file)) { + this.chunkCacheMap.set(file, []) + } + this.chunkCacheMap.get(file)[index] = content + callback?.(true) + }) + client.on('ungzip', (content) => { + try { + console.log(content) + let baos = new ByteArrayOutputStream() + let byte = java.util.Base64.getDecoder().decode(content) + let gzip = new GZIPInputStream(new ByteArrayInputStream(byte)) + let buffer = new ByteArray(1024) + let n: number + while ((n = gzip.read(buffer)) != -1) { + baos.write(buffer, 0, n) + } + gzip.close() + baos.close() + content = baos.toString(StandardCharsets.UTF_8.name()) + this.logger.log(content) + } catch (error) { + console.ex(error) + } + }) + client.on('save', (file, callback) => { + if (!this.chunkCacheMap.has(file)) { + return callback?.(false) + } + let content = this.chunkCacheMap.get(file).join('') + this.chunkCacheMap.delete(file) + base.save(file, content) + callback?.(true) + }) + client.on('error', (error) => { + this.logger.console(`§6客户端 §b${client.id} §c触发异常: ${error}`) + this.logger.error(error) + }) + client.on('disconnect', () => { + this.logger.console(`§6客户端 §b${client.id} §c断开连接...`) + }) + } + + @Cmd() + msme(sender: any, command: string, args: string[]) { + this.logger.log(sender, command, args) + sender.sendMessage(JSON.stringify({ command, ...args })) + } + + @Tab() + tabmsme(_sender: any, _command: string, _args: string[]) { + return ['world'] + } +} diff --git a/packages/plugins/src/MiaoProtocol.ts b/packages/plugins/src/MiaoProtocol.ts index d00770cb..2f5c3df7 100644 --- a/packages/plugins/src/MiaoProtocol.ts +++ b/packages/plugins/src/MiaoProtocol.ts @@ -52,12 +52,13 @@ export class MiaoProtocol extends interfaces.Plugin { 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)} -Size: ${integers.get(3)}x${integers.get(4)} -Bytes: ${event.getPacket().getByteArrays().read(0).length} -`) + // 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() }) this.ProtocolLibrary.getProtocolManager().addPacketListener(this.adapter) diff --git a/packages/plugins/src/MiaoReward.ts b/packages/plugins/src/MiaoReward.ts index b2a2f577..8076cec2 100644 --- a/packages/plugins/src/MiaoReward.ts +++ b/packages/plugins/src/MiaoReward.ts @@ -8,6 +8,7 @@ import http from '@ccms/common/dist/http' const BufferedImage = Java.type('java.awt.image.BufferedImage') const Color = Java.type('java.awt.Color') +const Bytes = Java.type('byte[]') interface PlaceholderAPI { registerPlaceholderHook: (key: string, onPlaceholderRequest: (player, s) => string) => void @@ -29,7 +30,7 @@ function(cls, plugin, type, onPacketSending){ } }`) -@JSPlugin({ prefix: 'MRD', version: '1.4.1', author: 'MiaoWoo', servers: [constants.ServerType.Bukkit], source: __filename }) +@JSPlugin({ prefix: 'MRD', version: '1.4.2', author: 'MiaoWoo', servers: [constants.ServerType.Bukkit], source: __filename }) export class MiaoReward extends interfaces.Plugin { private serverInfo: any private cacheBindUuid = '' @@ -97,11 +98,10 @@ export class MiaoReward extends interfaces.Plugin { //@ts-ignore this.logger.prefix = this.config.prefix this.downgrade = this.Bukkit.server.class.name.split('.')[3] == "v1_7_R4" - this.updateServerInfo() - this.updateOnlinePlayersInfo() + this.updateServerInfo(null, () => this.updateOnlinePlayersInfo()) } - private updateServerInfo(player?: any) { + private updateServerInfo(player?: any, cb?: () => void) { this.taskManager.create(() => { if (this.config.serverId) { let result = this.httpPost(`https://reward.yumc.pw/server/server`, { @@ -111,6 +111,7 @@ export class MiaoReward extends interfaces.Plugin { if (result.code == 200) { this.serverInfo = result.data if (player) this.bungee.for(player).forward("ALL", "MiaoReward", { type: "updateServerInfo", data: result.data }).send() + cb?.() } } }).async().submit() @@ -206,9 +207,21 @@ export class MiaoReward extends interfaces.Plugin { let mapId = integers.get(0) let player = event.getPlayer() if (mapId == this.zeroMapView.getId() && this.playerImageCache.has(player.getName())) { - event.getPacket().getByteArrays().write(0, org.bukkit.map.MapPalette.imageToBytes(this.playerImageCache.get(player.getName()))) - event.getPacket().getIntegers().write(3, 128) - event.getPacket().getIntegers().write(4, 128) + let bytes = this.playerImageCache.get(player.getName()) + if (!this.downgrade) { + event.getPacket().getByteArrays().write(0, bytes) + event.getPacket().getIntegers().write(3, 128) + event.getPacket().getIntegers().write(4, 128) + } else { + // let xbytes = new Bytes(131) + let origin = event.getPacket().getByteArrays().read(0) + // xbytes[1] = origin[1] + // xbytes[2] = origin[2] + for (let y = 0; y < 128; ++y) { + origin[y + 3] = bytes[y * 128 + origin[1]] + } + event.getPacket().getByteArrays().write(0, origin) + } } }) this.ProtocolLibrary.getProtocolManager().addPacketListener(this.adapter) @@ -307,14 +320,20 @@ export class MiaoReward extends interfaces.Plugin { return scanning } - cmdbind(sender: org.bukkit.entity.Player, server: boolean) { + cmdopen(sender: org.bukkit.entity.Player) { if (this.bindCheck(sender)) return + this.logger.sender(sender, '§a正在获取小程序二维码...') + let sync = { scaned: false } + this.setItemAndTp(sender, 'https://m.q.qq.com/a/p/1110360279?s=' + encodeURIComponent(`pages/my/index`), sync) + this.taskManager.create(() => sync.scaned = true).later(20 * 50).submit() + } + + cmdbind(sender: org.bukkit.entity.Player, server: boolean) { if (!sender.getItemInHand) { return this.logger.sender(sender, '§c手持物品检测异常 请检查是否在客户端执行命令!') } + if (this.bindCheck(sender)) return if (server) { - if (!sender.isOp()) { return this.logger.sender(sender, '§4您没有配置服务器的权限!') } this.bindServer(sender) } else { - if (!this.serverInfo) { return this.logger.sender(sender, '§4当前服务器尚未配置绑定ID 请联系腐竹进行配置!') } this.bindUser(sender) } } @@ -484,6 +503,7 @@ export class MiaoReward extends interfaces.Plugin { } private bindServer(sender: org.bukkit.entity.Player) { + if (!sender.isOp()) { return this.logger.sender(sender, '§4您没有配置服务器的权限!') } this.logger.sender(sender, '§a正在请求二维码 请稍候...') let scanObj = http.get(`https://reward.yumc.pw/server/scan`) if (scanObj.code !== 200) { @@ -510,8 +530,7 @@ export class MiaoReward extends interfaces.Plugin { } private bindUser(sender: org.bukkit.entity.Player) { - if (!this.config.serverId || !this.config.serverToken) { return this.logger.sender(sender, '§4当前服务器尚未配置绑定ID 请联系腐竹进行配置!') } - this.logger.sender(sender, '§a正在请求二维码 请稍候...') + if (!this.serverInfo) { return this.logger.sender(sender, '§4当前服务器尚未配置绑定ID 请联系腐竹进行配置!') } let check = this.httpPost(`https://reward.yumc.pw/server/query`, { id: this.config.serverId, token: this.config.serverToken @@ -521,8 +540,10 @@ export class MiaoReward extends interfaces.Plugin { } let queryUser = this.queryUser(sender) if (queryUser.code == 200) { - return this.logger.sender(sender, ['§4当前用户已绑定! §c如需解绑 请联系腐竹!', '§b如需看广告请进QQ群 §a点击聊天框上的圈云盒子!']) + this.logger.sender(sender, ['§a当前用户已绑定! §3如需看广告请扫码进入!']) + return this.cmdopen(sender) } + this.logger.sender(sender, '§a正在请求二维码 请稍候...') let bindUrl = 'https://m.q.qq.com/a/p/1110360279?s=' + encodeURIComponent(`pages/my/index?bindType=user&serverId=${this.config.serverId}&uuid=${sender.getUniqueId().toString()}&username=${sender.getName()}`) let sync = { scaned: false, timeout: false } this.taskManager.create(() => { @@ -569,21 +590,22 @@ export class MiaoReward extends interfaces.Plugin { } }, this).async().later(20).timer(20).submit() this.playerTaskCache.set(sender.getName(), task) - this.playerImageCache.set(sender.getName(), this.createQrcode(content)) if (this.downgrade) { - this.logger.sender(sender, '§c低版本客户端 二维码渲染中 请等待 6 秒 稍候扫码!') + this.logger.sender(sender, '§c低版本客户端 二维码渲染中 请等待 3 秒 稍候扫码!') let waitTask = this.taskManager.create(() => { let temp = sender.getLocation() temp.setPitch(-90) sender.teleport(temp) - }, this).later(20).timer(20).submit() + }, this).later(0).timer(20).submit() this.taskManager.create(() => { waitTask.cancel() let temp = sender.getLocation() temp.setPitch(90) sender.teleport(temp) - }).later(150).submit() - } else { + }).later(80).submit() + } + this.playerImageCache.set(sender.getName(), org.bukkit.map.MapPalette.imageToBytes(this.createQrcode(content))) + if (!this.downgrade) { let temp = sender.getLocation() temp.setPitch(90) sender.teleport(temp) @@ -594,7 +616,7 @@ export class MiaoReward extends interfaces.Plugin { } private queryUser(sender: org.bukkit.entity.Player, sync = false) { - if (!this.config.serverId || !this.config.serverToken) { return this.logger.sender(sender, '§4当前服务器尚未配置绑定ID 请联系腐竹进行配置!') } + if (!this.serverInfo) { return this.logger.sender(sender, '§4当前服务器尚未配置绑定ID 请联系腐竹进行配置!') } let result = this.httpPost(`https://reward.yumc.pw/server/queryUser`, { id: this.config.serverId, token: this.config.serverToken, @@ -696,6 +718,7 @@ CAST TIME : ${Date.now() - startTime}`) const player = event.getPlayer() this.bungeeCordDetect(player) this.updatePlayerInfo(player) + this.taskManager.create(() => this.logger.sender(player, `§a本服已使用喵式奖励 §3可以看广告赚${this.config.coinName} §c/mrd help §b查看帮助!`)).later(50).submit() } @Listener() @@ -741,6 +764,7 @@ CAST TIME : ${Date.now() - startTime}`) let help = [ `§6====== ${this.config.prefix} §a帮助菜单 §6======`, `§6/mrd bind §a绑定圈云盒子`, + `§6/mrd open §a打开圈云盒子`, `§6/mrd query §a查询当前账户`, `§6/mrd draw §e<兑换数量> §a兑换${this.config.coinName}` ] diff --git a/packages/plugins/src/MiaoSpring.ts b/packages/plugins/src/MiaoSpring.ts index d395e12a..692b10c2 100644 --- a/packages/plugins/src/MiaoSpring.ts +++ b/packages/plugins/src/MiaoSpring.ts @@ -94,7 +94,7 @@ export class MiaoSpring extends interfaces.Plugin { preHandle: (ctx: Context) => { const index = foundMap.indexOf(ctx.request.getRequestURI()) if (index != -1) { - return this.ResponseEntity.status(this.HttpStatus.FOUND).header('Location', foundMap[index + 1]).build() + return this.ResponseEntity.status(org.springframework.http.HttpStatus.FOUND).header('Location', foundMap[index + 1]).build() } } })