import { constants, task, server, channel, chat, proxy } from "@ccms/api" import { JSPlugin, interfaces, Cmd, Tab, Listener, Config, PluginConfig } from "@ccms/plugin" import { QRCode, QRErrorCorrectLevel } from '@ccms/common/dist/qrcode' import { Autowired, JSClass, optional } from '@ccms/container' 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 registerExpansion: (expansion: PlaceholderExpansion) => void unregisterPlaceholderHook: (key: string) => void setPlaceholders: (player: any, str: string) => string } interface PlaceholderExpansion { getIdentifier: () => string getAuthor: () => string getVersion: () => string persist: () => string onPlaceholderRequest: (player, s) => string } interface UserInfo { balance: number sign: string video: string box: string block: string } interface ServerInfo { // 16, id: number // "圈云大陆", name: string // 1, owner: number // 48200, score: number // 1, ratio: number // 1, audit: number // 2, status: number // 0 today: number } let createPacketAdapterFunction = eval(` function(cls, plugin, type, onPacketSending){ return new cls(plugin, type) { onPacketSending: onPacketSending } }`) const defaultConfig = { prefix: '§6[§b广告系统§6]§r', serverId: '', serverToken: '', drawCommand: 'points give %player_name% %amount%', coinName: '点券', joinTip: true } @JSPlugin({ prefix: 'MRD', version: '1.6.0', author: 'MiaoWoo', servers: [constants.ServerType.Bukkit], nativeDepends: ['ProtocolLib', 'PlaceholderAPI'], source: __filename }) export class MiaoReward extends interfaces.Plugin { public serverInfo: ServerInfo private notifyError = true private cacheBindUuid = '' private zeroMapView = undefined private playerImageCache = new Map() private playerTaskCache = new Map() private playerInfoCache = new Map() private downgrade = false private subversion = 0 @Autowired() private chat: chat.Chat @Autowired() private server: server.Server @Autowired() private taskManager: task.TaskManager @Autowired() private channel: channel.Channel @Autowired() private bungee: proxy.BungeeCord @Config() private config: PluginConfig & typeof defaultConfig = defaultConfig @JSClass('org.bukkit.Bukkit') private Bukkit: any @JSClass('me.clip.placeholderapi.PlaceholderAPI') private PlaceholderAPI: PlaceholderAPI @JSClass('me.clip.placeholderapi.PlaceholderHook') private PlaceholderHook: any @JSClass('me.clip.placeholderapi.expansion.PlaceholderExpansion') private PlaceholderExpansion: any private expansion: any @JSClass('com.comphenix.protocol.ProtocolLibrary') private ProtocolLibrary: any @JSClass('com.comphenix.protocol.PacketType') private PacketType: any @JSClass('com.comphenix.protocol.events.PacketAdapter') private PacketAdapter: any private adapter: any private itemStackArrayLength: number private isBungeeCord = undefined private channelOff: { off: () => void } load() { this.config.prefix = this.config.prefix || '§6[§b广告系统§6]§r' this.config.drawCommand = this.config.drawCommand || 'p give %player_name% %amount%' if (this.config.coinName == undefined) { this.config.coinName = '点券' this.config.save() } if (this.config.joinTip == undefined) { this.config.joinTip = true this.config.save() } //@ts-ignore this.logger.prefix = this.config.prefix this.downgrade = this.Bukkit.server.class.name.split('.')[3] == "v1_7_R4" this.subversion = parseInt(this.Bukkit.server.class.name.split('.')[3].split('_')[1]) this.updateServerInfo(null, () => this.updateOnlinePlayersInfo()) } private updateServerInfo(player?: any, cb?: () => void) { this.taskManager.create(() => { if (this.config.serverId) { let result = this.httpPost(`https://reward.yumc.pw/server/server`, { id: this.config.serverId, token: this.config.serverToken }) 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() } private updateOnlinePlayersInfo() { Java.from(this.server.getOnlinePlayers()).forEach(player => this.updatePlayerInfo(player)) } private updatePlayerInfo(player: org.bukkit.entity.Player) { this.taskManager.create(() => this.queryUser(player)).async().submit() } @JSClass('com.google.common.io.ByteStreams') private ByteStreams: any enable() { this.initPlaceholderAPI() this.initBungeeCord() this.initZeroMap() } private initBungeeCord() { this.channelOff = this.channel?.listen(this, 'BungeeCord', (data) => { if (!this.isBungeeCord) { this.isBungeeCord = true } let input = this.ByteStreams.newDataInput(data) let subChannel = input.readUTF() switch (subChannel) { case "GetServer": this.isBungeeCord = true let serverName = input.readUTF() break case "MiaoReward": this.readForward(input) break } }) let players = this.server.getOnlinePlayers() if (players.length) this.bungeeCordDetect(players[0]) } private readForward(input) { let message = JSON.parse(input.readUTF()) console.log(message) switch (message.type) { case "updateServerInfo": this.serverInfo = message.data console.console(this.config.prefix, '§6兑换比例已更新为:§a', message.data.ratio) break } } private initPlaceholderAPI() { if (!this.PlaceholderAPI) { console.console("§cCan't found me.clip.placeholderapi.PlaceholderAPI variable will not be replaced!") } else { this.expansion = new this.PlaceholderExpansion({ getIdentifier: () => 'mrd', persist: () => true, getAuthor: () => 'MiaoWoo', getVersion: () => '1.0.0', onPlaceholderRequest: this.onPlaceholderRequest.bind(this) }) this.taskManager.create(() => this.expansion.register()).submit() } } private onPlaceholderRequest(player: any, s: string) { if (!this.playerInfoCache.has(player.getName())) { return '数据加载中' } let data = this.playerInfoCache.get(player.getName()) if (!data) { return '用户未绑定' } switch (s.toLowerCase()) { case "balance": return data.balance case "sign": return data.sign case "video": return data.video case "box": return data.box case "block": return data.block default: return "未知的参数: " + s } } private initZeroMap() { this.taskManager.create(() => { this.zeroMapView = this.Bukkit.getMap(0) || this.Bukkit.createMap(this.Bukkit.getWorlds()[0]) this.zeroMapView.setScale(org.bukkit.map.MapView.Scale.FARTHEST) this.zeroMapView.getRenderers().clear() }).submit() var minecraftVersion = this.ProtocolLibrary.getProtocolManager().getMinecraftVersion() this.itemStackArrayLength = minecraftVersion.getMinor() < 9 ? 45 : 46 this.initPacketAdapter() } private createPacketAdapter(onPacketSending: (event) => void) { return createPacketAdapterFunction(this.PacketAdapter, base.getInstance(), [this.PacketType.Play.Server.MAP], onPacketSending) } private initPacketAdapter() { if (!this.ProtocolLibrary) { return this.logger.console(`§4服务器未安装 ProtocolLib 无法扫码功能 请安装后重试!`) } let writer = undefined if (this.downgrade) { writer = (packet, bytes) => { // let xbytes = new Bytes(131) let origin = packet.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]] } packet.getByteArrays().write(0, origin) } } else if (this.subversion < 17) { writer = (packet, bytes) => { packet.getByteArrays().write(0, bytes) packet.getIntegers().write(3, 128) packet.getIntegers().write(4, 128) } } else if (this.subversion > 16) { writer = (packet, bytes) => { let b = packet.getModifier().read(4) if (b) { let bi = Java.type(b.class.name) packet.getModifier().write(4, new bi(b.a, b.b, 128, 128, bytes)) } } } if (writer) { this.adapter = this.createPacketAdapter(this.getPacketAdapter(writer)) this.ProtocolLibrary.getProtocolManager().addPacketListener(this.adapter) } else { console.console('§4当前服务器不支持虚拟地图发包 将无法使用扫码功能!') } } private getPacketAdapter(writer: (packet: any, bytes: number[]) => void) { return (event) => { let integers = event.getPacket().getIntegers().getValues() let mapId = integers.get(0) let player = event.getPlayer() if (mapId == this.zeroMapView.getId() && this.playerImageCache.has(player.getName())) { writer(event.getPacket(), this.playerImageCache.get(player.getName())) } } } private sendWindowItems(player: org.bukkit.entity.Player, mapItem: any) { var protocolManager = this.ProtocolLibrary.getProtocolManager() try { let ItemStackArray = Java.type('org.bukkit.inventory.ItemStack[]') let arritemStack = new ItemStackArray(this.itemStackArrayLength) java.util.Arrays.fill(arritemStack, new org.bukkit.inventory.ItemStack(org.bukkit.Material.AIR)) arritemStack[36 + player.getInventory().getHeldItemSlot()] = mapItem var packetContainer = protocolManager.createPacket(this.PacketType.Play.Server.WINDOW_ITEMS) try { packetContainer.getItemArrayModifier().write(0, arritemStack) } catch (error) { try { packetContainer.getItemListModifier().write(0, java.util.Arrays.asList(arritemStack)) } catch (error) { if (this.notifyError) { console.console('§4发送虚拟物品包失败 可能是ProtocolLib版本不兼容!') console.ex(error) this.notifyError = false return } } } protocolManager.sendServerPacket(player, packetContainer) } catch (ex) { console.ex(ex) } } disable() { try { this.expansion?.unregister() } catch (error) { } this.adapter && this.ProtocolLibrary.getProtocolManager().removePacketListener(this.adapter) Java.from(this.server.getOnlinePlayers()).forEach(p => this.checkAndClear(p)) this.channelOff?.off() } @Cmd() private mrd(sender: any, command: string, args: string[]) { let cmd = args[0] || 'help' let cmdKey = 'cmd' + cmd if (!this[cmdKey]) { console.sender(sender, '§4未知的子命令: §c' + cmd) console.sender(sender, `§6请执行 §b/${command} §ahelp §6查看帮助!`) return } args.shift() this.taskManager.create(() => this[cmdKey](sender, ...args)).async().submit() } public scanAuth(sender: org.bukkit.entity.Player, scanType: string, scanObj: { title: string, content: string }, success: (token: string, user: any) => void, cancel?: () => void) { this.logger.sender(sender, '§a正在获取授权二维码...') let scan = this.httpPost('https://reward.yumc.pw/auth/scan', { ...scanObj, type: scanType }) if (scan.code == 200) { let sync = { scaned: false } this.logger.sender(sender, `§a授权二维码获取成功 §c如地图无法扫描 §6请点击链接\n§3§n${scan.data.qrcode}`) this.taskManager.create(() => { let result = this.httpPost('https://reward.yumc.pw/auth/scanCheck', { token: scan.data.token, type: scanType, status: 'noscan' }) sync.scaned = true if (result.code == 200 && result.data.status == "scaned") { this.sendTitle(sender, "§3已扫码", "§a请在手机上确认") let result = this.httpPost('https://reward.yumc.pw/auth/scanCheck', { token: scan.data.token, type: scanType, status: 'scaned' }) if (result.code == 200) { if (result.data.status == "confirm") { this.sendTitle(sender, '§3扫码完成') success(scan.data.token, result.data.user) } else if (result.data.status == "cancel") { this.sendTitle(sender, '§c已取消授权') cancel?.() } else if (result.data.status == "scaned") { this.sendTitle(sender, '§c授权操作超时') cancel?.() } else { this.sendTitle(sender, "§c未知的结果", result.data.status) } } else { this.sendTitle(sender, "§4扫码异常", result.msg) } } sync.scaned = true }).async().submit() this.setItemAndTp(sender, scan.data.url, sync) this.sendTitle(sender, '') } else { this.logger.sender(sender, '§4授权二维码获取失败!') } } private bindCheck(sender: org.bukkit.entity.Player) { if (!this.ProtocolLibrary) { return this.logger.sender(sender, `§4服务器未安装 ProtocolLib 无法扫码功能 请安装后重试!`) } let scanning = this.playerTaskCache.has(sender.getName()) if (scanning) { this.logger.sender(sender, "§4当前正在进行扫码 请稍候重试!") } return scanning } private 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() } private cmdbind(sender: org.bukkit.entity.Player, server: boolean) { if (!sender.getItemInHand) { return this.logger.sender(sender, '§c手持物品检测异常 请检查是否在客户端执行命令!') } if (this.bindCheck(sender)) return if (server) { this.bindServer(sender) } else { this.bindUser(sender) } } private cmddraw(sender: org.bukkit.entity.Player, amount: number) { if (!sender.getItemInHand) { return this.logger.sender(sender, '§c手持物品检测异常 请检查是否在客户端执行命令!') } if (!this.playerInfoCache.get(sender.getName())) { return this.logger.sender(sender, '§c当前用户尚未绑定服务器玩家账号 请先执行 /mrd bind 绑定账号!') } amount = Number(amount) if (!Number.isInteger(amount)) { return this.logger.sender(sender, '§4金额必须是数字!') } if (amount % 100 !== 0) { return this.logger.sender(sender, '§4金额必须是100倍数!') } if (this.bindCheck(sender)) { return } this.scanAuth(sender, 'draw', { title: '兑换授权', content: [ "是否授权 " + this.serverInfo.name + " 兑换喵币", "兑换玩家: " + sender.getName(), "兑换数量: " + amount, "兑换比例: " + this.serverInfo.ratio, "预计到帐: " + (amount * this.serverInfo.ratio).toFixed(0), "注意: 数据可能更新不及时 请以实际到账金额为准!" ].join('\n') }, (token: string) => { this.drawCoin(sender, amount, token) }) } private drawCoin(sender: org.bukkit.entity.Player, amount: number, token: string) { if (!token) return let draw = this.httpPost('https://reward.yumc.pw/server/draw', { id: this.config.serverId, token: this.config.serverToken, uuid: sender.getUniqueId().toString(), username: sender.getName(), amount, userToken: token }) if (draw.code !== 200) { return this.sendError(sender, `§4兑换异常 §6服务器返回: §c${draw.msg}`) } let drawAmount = draw.data if (!drawAmount) { return this.sendError(sender, '§c服务器返回金额 ' + draw.data + ' 可能存在异常') } this.taskManager.create(() => { let command = this.config.drawCommand.replace('%player_name%', sender.getName()).replace('%amount%', draw.data) if (!this.server.dispatchConsoleCommand(command)) { return this.sendError(sender, ...draw.msg.split('\n').map(s => s.replace('点券', this.config.coinName)), `§6执行结果: §4已扣除 §c${amount} §4喵币`, `§6执行命令: §3/${command} §c可能存在异常`) } this.logger.sender(sender, draw.msg.split('\n').map(s => s.replace('点券', this.config.coinName))) this.sendBroadcast(sender, `${this.config.prefix}§6玩家 §b${sender.getName()} §6成功将 §a${amount}喵币 §6兑换成 §c${draw.data}${this.config.coinName}!`) this.sendBroadcast(sender, `${this.config.prefix}§c/mrd help §b查看广告系统帮助 §6快来一起看广告赚${this.config.coinName}吧!`) this.queryUser(sender) }).submit() } private sendError(sender: any, ...error: string[]) { return this.logger.sender(sender, [ `§c========== ${this.config.prefix}§4兑换异常 §c==========`, ...error, `§6异常账号: §b${sender.getName()}`, `§6异常时间: §a${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}`, `§c如果喵币被扣除且未得到奖励 请截图发往QQ群!`, `§c========== ${this.config.prefix}§4兑换异常 §c==========`, ]) } private cmdrank(sender: any, boardcast: boolean) { if (!sender.isOp()) { return this.logger.sender(sender, '§4你没有此命令的权限!') } let result = this.httpPost(`https://reward.yumc.pw/server/rank`, { id: this.config.serverId, token: this.config.serverToken }) if (result.code !== 200) { return this.logger.sender(sender, `§c今日未查询到数据!`) } let ranks = [ `§6====== ${this.config.prefix} §a喵币兑换排行 §6======`, ...result.data.map((e, i) => `§6${i + 1}. §a${e.username} §6兑换 §3${e.count} §6次 §c${e.amount} §6喵币`), `§6====== ${this.config.prefix} §a喵币兑换排行 §6======`, ] if (boardcast) { ranks.forEach(l => this.sendBroadcast(sender, l)) } else { this.logger.sender(sender, ranks) } } private cmdserver(sender: any) { if (!sender.isOp()) { return this.logger.sender(sender, '§4你没有此命令的权限!') } let result = this.httpPost(`https://reward.yumc.pw/server/server`, { id: this.config.serverId, token: this.config.serverToken }) if (result.code !== 200) { return this.logger.sender(sender, `§4操作异常 §6服务器返回: §c${result.msg}`) } let data = result.data this.logger.sender(sender, [ `§6====== ${this.config.prefix} §a服务器信息 §6======`, `§6服务器: §a${data.name}`, `§6喵币余额: §b${data.score} §6喵币`, `§6喵币比例: §b${data.ratio}`, `§6今日收入: §b${data.today} §6喵币`, `§6====== ${this.config.prefix} §a服务器信息 §6======`, ]) } private cmdratio(sender: any, ratioStr: string, confirm: string) { if (!sender.isOp()) { return this.logger.sender(sender, '§4你没有此命令的权限!') } if (!sender.getItemInHand) { return this.logger.sender(sender, '§c手持物品检测异常 请检查是否在客户端执行命令!') } let [ratio, mbr, msg] = this.ratio2string(ratioStr) if (!confirm) { return this.logger.sender(sender, [ `§4警告: 您正在设置服务器喵币/${this.config.coinName}兑换比例 设置后将实时生效!`, `§6您设置的兑换比例为 ` + msg, `§6玩家至少需要 §a${mbr}喵币 §6才可以兑换${this.config.coinName}!`, `§6请执行 §b/mrd ratio §c${ratio} §econfirm §c确认修改!` ]) } if (confirm != 'confirm') return this.logger.sender(sender, `§6请执行 §b/mrd ratio §c${ratio} §econfirm §c确认修改!`) this.scanAuth(sender, "ratio", { title: `是否授权 ${this.serverInfo.name} 调整兑换比例`, content: [ `操作玩家: ${sender.getName()}`, `调整前: ${this.serverInfo.ratio}`, `调整后: ${msg.replace(/§./ig, '')}`, '调整结果实时生效!', '跨服端 将自动同步比例!', '非跨服端 请重载插件同步比例!' ].join('\n') }, (token) => { let result = this.httpPost(`https://reward.yumc.pw/server/ratio`, { id: this.config.serverId, token: this.config.serverToken, ratio, userToken: token }) if (result.code !== 200) { return this.logger.sender(sender, `§4操作异常 §6服务器返回: §c${result.msg}`) } this.logger.sender(sender, `§a操作成功 §6服务器返回: §a${result.msg}`) this.updateServerInfo(sender) this.sendBroadcast(sender, `${this.config.prefix} §6当前兑换比例已调整为 ` + msg) }) } private cmdreload() { this.config.reload() } private ratio2string(ratio) { ratio = parseFloat(ratio) if (ratio > 1) { return [ratio, 1, `§c${ratio} §6就是 §a1喵币 §6=> §c${ratio}${this.config.coinName}!`] } let mbr = Math.round(1 / ratio * 10000) / 10000 return [ratio, mbr, `§c${ratio} §6就是 §a${mbr}喵币 §6=> §c1${this.config.coinName}!`] } private sendBroadcast(player, message) { if (!this.isBungeeCord) { return org.bukkit.Bukkit.broadcastMessage(message) } this.bungee.for(player).broadcast(message).send() } 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) { return this.logger.sender(sender, '§c获取服务器绑定码失败! Error: ' + scanObj.msg) } this.cacheBindUuid = scanObj.data.uuid let sync = { scaned: false } this.taskManager.create(() => { let check = this.httpPost(`https://reward.yumc.pw/server/check`, { token: this.cacheBindUuid, sync: true }) if (check.code == 200) { this.config.serverId = check.data.serverId this.config.serverToken = check.data.serverToken this.config.save() this.logger.sender(sender, '§a已成功绑定服务器: §b' + check.data.serverName) this.updateServerInfo(sender) this.updateOnlinePlayersInfo() } sync.scaned = true }).async().submit() this.setItemAndTp(sender, scanObj.data.url, sync) } private bindUser(sender: org.bukkit.entity.Player) { 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 }) if (check.code !== 200) { return this.logger.sender(sender, '§4获取绑定参数异常! §cError: ' + check.msg) } let queryUser = this.queryUser(sender) if (queryUser.code == 200) { 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(() => { let queryUser = this.queryUser(sender, true) if (queryUser.code == 200) { this.sendResult(sender, '绑定成功', queryUser.data) sync.scaned = true } }).async().submit() this.setItemAndTp(sender, bindUrl, sync) } public sendActionBar(sender, message) { if (!this.downgrade) { this.chat.sendActionBar(sender, message) } } public sendTitle(sender: any, title: string, subtitle: string = '', fadeIn: number = 20, time: number = 100, fadeOut: number = 20) { if (!title) return if (this.downgrade) { this.logger.sender(sender, `${title}${subtitle ? ` ${subtitle}` : ''}`) } else { this.chat.sendTitle(sender, title, subtitle, fadeIn, time, fadeOut) } } public clearTitle(sender) { this.chat.clearTitle(sender) } public setItemAndTp(sender: org.bukkit.entity.Player, content: string, sync: { scaned: boolean, left?: number, cancelled?: boolean }, name: string = '手机QQ扫描二维码', tip: string = '手机QQ扫描二维码') { this.taskManager.create(() => { if (!sync.left) { sync.left = 55 } sync.cancelled = false let task = this.taskManager.create(() => { try { if (sync.scaned || !sender.isOnline() || !this.isHoldQrCodeItem(sender) || --sync.left < 0) { if (sync.left < 0) { this.logger.sender(sender, '§c二维码已过期 请重新获取 如已扫码请忽略!') task.cancel() } this.cancelTask(sender) sync.cancelled = true return } this.sendActionBar(sender, `§c§l${tip} 剩余 ${sync.left} 秒...`) } catch (error) { console.ex(error) } }, this).async().later(20).timer(20).submit() this.playerTaskCache.set(sender.getName(), task) if (this.downgrade) { this.downgradeTask(sender) } 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) } this.sendWindowItems(sender, this.createQrCodeMapItem(name)) sender.sendMap(this.zeroMapView) this.taskManager.create(() => this.sendWindowItems(sender, this.createQrCodeMapItem(name))).later(20).async().submit() }).submit() } private downgradeTask(sender) { this.logger.sender(sender, '§c低版本客户端 二维码渲染中 请等待 3 秒 稍候扫码!') let waitTask = this.taskManager.create(() => { let temp = sender.getLocation() temp.setPitch(-90) sender.teleport(temp) }, this).later(0).timer(20).submit() this.taskManager.create(() => { waitTask.cancel() let temp = sender.getLocation() temp.setPitch(90) sender.teleport(temp) }).later(80).submit() } private queryUser(sender: org.bukkit.entity.Player, sync = false) { 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, uuid: sender.getUniqueId().toString(), username: sender.getName(), sync }) this.playerInfoCache.set(sender.getName(), result?.code == 200 ? result.data : null) return result } private cmdquery(sender: org.bukkit.entity.Player) { let info = this.queryUser(sender) if (info.code !== 200) { return this.logger.sender(sender, '§4查询异常! §cError: ' + info.msg) } this.sendResult(sender, '查询结果', info.data) } private sendResult(sender: any, title: string, data: any) { this.playerInfoCache.set(sender.getName(), data) this.logger.sender(sender, [ `§6====== ${this.config.prefix} §a${title} §6======`, `§6用 户 名: §a${sender.getName()}`, `§6U U I D: §b${sender.getUniqueId().toString()}`, `§6喵 币: §b${data.balance}`, `§6签 到: §b${data.sign}`, `§6视频广告: §b${data.video}`, `§6盒子广告: §b${data.box}`, `§6积木广告: §b${data.block}`, '§6===========================' ]) } public httpPost(url, data) { let startTime = Date.now() 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 createQrCodeMapItem(name: string = '手机QQ扫描二维码') { let item: org.bukkit.inventory.ItemStack item = new org.bukkit.inventory.ItemStack(org.bukkit.Material.FILLED_MAP || org.bukkit.Material.MAP) let meta = item.getItemMeta() if (meta.setMapView) { meta.setMapView(this.zeroMapView) } else if (meta.setMapId) { meta.setMapId(this.zeroMapView.getId()) } else { item.setDurability(this.zeroMapView.getId()) } meta.setDisplayName(`§c${name}`) meta.setLore(["QRCODE"]) item.setItemMeta(meta) return item } private createQrcode(content: string) { let bufferedImage = new BufferedImage(128, 128, BufferedImage.TYPE_INT_RGB) let graphics2D = bufferedImage.getGraphics() graphics2D.setPaint(Color.WHITE) graphics2D.fillRect(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight()) let qrcode = this.js2qr(content) let startPoint = Math.round((bufferedImage.getWidth() - qrcode.getWidth()) / 2) graphics2D.drawImage(qrcode, startPoint, startPoint, null) graphics2D.dispose() return bufferedImage } private js2qr(contents: string) { let qrcode = new QRCode(14, QRErrorCorrectLevel.H) qrcode.addData(contents) qrcode.make() let length = qrcode.getModuleCount() let image: java.awt.image.BufferedImage = new BufferedImage(length, length, BufferedImage.TYPE_INT_RGB) for (let x = 0; x < length; x++) { for (let y = 0; y < length; y++) { image.setRGB(x, y, qrcode.isDark(x, y) ? 0xFF000000 : 0xFFFFFFFF) } } return image } private bungeeCordDetect(player) { if (this.isBungeeCord === undefined && player) { this.bungee.for(player).getServer().send() } } @Listener() private PlayerJoinEvent(event: org.bukkit.event.player.PlayerJoinEvent) { const player = event.getPlayer() this.bungeeCordDetect(player) this.updatePlayerInfo(player) if (this.config.joinTip) { this.taskManager.create(() => this.logger.sender(player, `§a本服已使用喵式奖励 §3可以看广告赚${this.config.coinName} §c/mrd help §b查看帮助!`)).later(50).submit() } } @Listener() private PlayerDropItemEvent(event: org.bukkit.event.player.PlayerDropItemEvent) { if (this.checkAndClear(event.getPlayer())) { event.setCancelled(true) } } @Listener() private PlayerItemHeldEvent(event: org.bukkit.event.player.PlayerItemHeldEvent) { this.checkAndClear(event.getPlayer()) } @Listener() private PlayerQuitEvent(event: org.bukkit.event.player.PlayerQuitEvent) { this.checkAndClear(event.getPlayer()) } public cancelTask(player) { if (!this.playerTaskCache.has(player.getName())) { return } this.checkAndClear(player) this.sendActionBar(player, "") player.updateInventory() this.playerTaskCache.get(player.getName()).cancel() this.playerTaskCache.delete(player.getName()) this.playerImageCache.delete(player.getName()) } private isHoldQrCodeItem(player: org.bukkit.entity.Player) { return this.playerImageCache.has(player.getName()) } private checkAndClear(player: org.bukkit.entity.Player) { if (this.isHoldQrCodeItem(player)) { this.playerImageCache.delete(player.getName()) return true } return false } private cmdhelp(sender: any) { 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}` ] if (sender.isOp()) { help = help.concat([ `§c由于您是管理员 以为您展示额外命令`, `§6/mrd bind server §a绑定服务器`, `§6/mrd ratio §e<兑换比例> §a设置喵币/${this.config.coinName}兑换比例`, `§6/mrd statistic §3近期收入统计`, `§6/mrd rank (是否公告) §2今日兑换排行`, `§6/mrd server §c当前服务器信息`, `§6兑换比例设置说明: §b默认比例为 0.001 §6=> §a1000喵币 §6兑换 §c1${this.config.coinName}`, `§c注意 设置比例后 玩家兑换${this.config.coinName}数量不能少于 1${this.config.coinName}`, `§c比如 设置了0.001 那就是 玩家至少 1000喵币 才能兑换!` ]) } this.logger.sender(sender, help) } @Tab() private tabmrd(sender: any, _command: any, args: string | any[]) { if (args.length === 1) return ['help', 'bind', 'show', 'statistic', 'query', 'draw', 'ratio', 'rank', 'server'] if (args.length === 2 && args[0] === "bind" && sender.isOp()) return ['server'] } }