今天写了一个kubejs的伤害占比脚本给我服务器的玩家用:D
这个脚本可以检测稀有度为 传说、神话、boss的怪并且在聊天栏广播所有对其造成伤害的玩家输出的伤害占比~
测试过应该没什么问题了。脚本如下。(如果需要.js文件可以QQ找咱,这里发不了= =,而且好像会有缩进问题)
// 《幻想物语RE》整合包服务器伤害统计脚本(基于kubejs)
// 作者:shiny_Asuna 有问题联系:719759587@qq.com
// 想要加载此脚本请把这个脚本放在服务端这个路径:kubejs/server_scripts/boss_dmg_brd.js
// 测试环境:forge服务端,整合包版本1.0.8b2 测试通过
// 声明:
// 本人只开源脚本代码,不对如何使用脚本以及脚本产生的影响负任何责任(不过如果找我提问,附带全套信息我可能能帮你)
// 由于Rhino对于const有非常严格的要求所以我使用 var 替代 const(我也想优化,但是没办法,用const老是有已声明报错)
// 然后挖砍似乎会连续触发death事件,
// 并且entity.uuid 返回的是一个 UUID对象,不是字符串。JavaScript中,两个内容相同的对象 { } !== {}
// 所以脚本中使用普通对象而不是Map,否则每次受伤会创建一个新的记录,反正挺抽象的。
//---------------------------【配置区】----------------------------------
var CLEANUP_TICKS = 20 * 60 * 5 // 5分钟清理(对于一个boss的伤害记录只保留 此分钟 数值)
var MAX_DISTANCE = 256 // 消息广播范围(同一维度内,距离boss多少格玩家会收到聊天栏消息)
// Boss稀有度关键词
var BOSS_RARITY_TYPES = ['boss', 'mythic', 'legendary'] //统计这些稀有度的怪物数值(检测的是怪物的稀有度词条)
var MIN_BOSS_HP = 100000 //统计的怪物血量需大于此数值,否则不统计
//--------------------------【脚本主体】---------------------------------
console.info('[BDTracker] Boss伤害统计脚本已加载|written by shiny_Asuna')
// 存储Boss伤害记录
var bossDamageRecords = {}
var deadBosses = {}
// 特殊字符和装饰
var DECORATIONS = {
separator: "══════════════════════════════",
star: "✦",
diamond: "♦",
arrow: "➤",
crown: "♔",
fire: "♨",
sword: "⚔",
heart: "❤",
shield: "⛨",
skull: "☠",
star_filled: "★",
star_empty: "☆",
dot: "•",
line: "|",
corner_tl: "╔",
corner_tr: "╗",
corner_bl: "╚",
corner_br: "╝",
line_h: "═",
line_v: "║",
cross: "╬",
t_right: "╠",
t_left: "╣",
t_down: "╦",
t_up: "╩"
}
// 颜色定义
var COLORS = {
reset: "§r",
black: "§0",
dark_blue: "§1",
dark_green: "§2",
dark_aqua: "§3",
dark_red: "§4",
dark_purple: "§5",
gold: "§6",
gray: "§7",
dark_gray: "§8",
blue: "§9",
green: "§a",
aqua: "§b",
red: "§c",
light_purple: "§d",
yellow: "§e",
white: "§f",
bold: "§l",
italic: "§o",
underline: "§n",
strikethrough: "§m"
}
// 稀有度配置
var RARITY_CONFIG = {
'boss': {
name: "首领",
primary_color: COLORS.red + COLORS.bold, // 红色加粗
secondary_color: COLORS.gold, // 金色
accent_color: COLORS.yellow, // 黄色
icon: DECORATIONS.crown + " ", // 王冠
border_color: COLORS.dark_red, // 深红边框
bar_filled: COLORS.red, // 进度条填充色
bar_empty: COLORS.dark_gray // 进度条空白色
},
'mythic': {
name: "神话",
primary_color: COLORS.light_purple + COLORS.bold, // 粉色加粗,移除魔法效果
secondary_color: COLORS.dark_purple, // 紫色
accent_color: COLORS.aqua, // 水色
icon: DECORATIONS.star + " ", // 星星
border_color: COLORS.dark_purple, // 紫色边框
bar_filled: COLORS.light_purple, // 进度条填充色
bar_empty: COLORS.dark_purple // 进度条空白色
},
'legendary': {
name: "传说",
primary_color: COLORS.gold + COLORS.bold, // 金色加粗
secondary_color: COLORS.yellow, // 亮黄色
accent_color: COLORS.red, // 红色
icon: DECORATIONS.fire + " ", // 火焰
border_color: COLORS.gold, // 金色边框
bar_filled: COLORS.yellow, // 进度条填充色
bar_empty: COLORS.gold // 进度条空白色
},
'unknown': {
name: "未知",
primary_color: COLORS.white + COLORS.bold,
secondary_color: COLORS.gray,
accent_color: COLORS.aqua,
icon: DECORATIONS.skull + " ",
border_color: COLORS.dark_gray,
bar_filled: COLORS.aqua,
bar_empty: COLORS.dark_gray
}
}
// 辅助函数:获取UUID字符串
function getUUIDString(uuidObj) {
if (!uuidObj) return ''
if (typeof uuidObj === 'string') return uuidObj
if (uuidObj.toString) {
var str = uuidObj.toString()
if (str && str.length > 0) {
return str
}
}
return String(uuidObj)
}
// 辅助函数:从NBT中获取稀有度
function getRarityFromNBT(entity) {
try {
if (entity.nbt) {
var nbt = entity.nbt
if (nbt.ForgeCaps && nbt.ForgeCaps['mmorpg:entity_data']) {
var mmorpgData = nbt.ForgeCaps['mmorpg:entity_data']
if (mmorpgData.rarity) {
return mmorpgData.rarity.toLowerCase()
}
}
}
try {
var persistentData = entity.persistentData
if (persistentData) {
if (persistentData.get('rarity')) {
return persistentData.get('rarity').toLowerCase()
}
if (persistentData.get('Rarity')) {
return persistentData.get('Rarity').toLowerCase()
}
}
} catch (e) {}
} catch (e) {
console.error('[BDTracker] 获取NBT时出错:', e)
}
return null
}
// 辅助函数:检查实体是否为Boss
function isBoss(entity) {
if (!entity || !entity.isLiving()) return false
var rarity = getRarityFromNBT(entity)
if (rarity) {
for (var i = 0; i < BOSS_RARITY_TYPES.length; i++) {
if (rarity === BOSS_RARITY_TYPES[i]) {
return true
}
}
}
return false
}
// 辅助函数:创建边框消息
function createBorderedMessage(title, config, width) {
var lines = []
var border = config.border_color + DECORATIONS.line_h
var topBorder = config.border_color + DECORATIONS.corner_tl +
border.repeat(width - 2) +
DECORATIONS.corner_tr
var bottomBorder = config.border_color + DECORATIONS.corner_bl +
border.repeat(width - 2) +
DECORATIONS.corner_br
var sideBorder = config.border_color + DECORATIONS.line_v
lines.push(topBorder)
// 标题行
var titleContent = config.icon + config.primary_color + title
var padding = Math.max(0, width - titleContent.length - 4)
var titleLine = sideBorder + " " + titleContent + " ".repeat(padding) + " " + sideBorder
lines.push(titleLine)
// 分隔行
var separatorLine = config.border_color + DECORATIONS.t_right +
border.repeat(width - 2) +
DECORATIONS.t_left
lines.push(separatorLine)
return {
header: lines,
footer: [separatorLine, bottomBorder],
sideBorder: sideBorder
}
}
// 辅助函数:创建进度条
function createProgressBar(percentage, config) {
var barLength = 10
var filledBars = Math.round((percentage / 100) * barLength)
var emptyBars = barLength - filledBars
return config.primary_color + "[" +
config.bar_filled + "▮".repeat(filledBars) +
config.bar_empty + "▯".repeat(emptyBars) +
config.primary_color + "]"
}
// 监听实体受伤事件
EntityEvents.hurt(event => {
var target = event.entity
if (!isBoss(target)) return
var bossUUID = getUUIDString(target.uuid)
if (!bossUUID || deadBosses[bossUUID]) return
var bossRecord = bossDamageRecords[bossUUID]
if (!bossRecord) {
bossRecord = {
total: 0,
players: {},
lastUpdate: Date.now(),
bossType: target.type.toString(),
bossName: target.getName() ? target.getName().getString() : 'Boss',
rarity: getRarityFromNBT(target) || 'unknown'
}
bossDamageRecords[bossUUID] = bossRecord
}
var attacker = event.source.actual
if (!attacker || !attacker.isPlayer()) return
var playerUUID = getUUIDString(attacker.uuid)
var playerName = attacker.name.getString()
if (!playerUUID || playerUUID === '') return
var amount = event.damage !== undefined ? event.damage : (event.getAmount ? event.getAmount() : 0)
if (isNaN(amount) || amount <= 0) return
var playerRecord = bossRecord.players[playerUUID]
if (!playerRecord) {
playerRecord = {
name: playerName,
damage: 0
}
bossRecord.players[playerUUID] = playerRecord
}
bossRecord.total += amount
playerRecord.damage += amount
bossRecord.lastUpdate = Date.now()
})
// 监听实体死亡事件
EntityEvents.death(event => {
var entity = event.entity
if (!isBoss(entity)) return
var bossUUID = getUUIDString(entity.uuid)
var bossRecord = bossDamageRecords[bossUUID]
if (!bossRecord || deadBosses[bossUUID]) return
deadBosses[bossUUID] = true
var bossName = bossRecord.bossName || (entity.getName() ? entity.getName().getString() : 'Boss')
var bossRarity = bossRecord.rarity || getRarityFromNBT(entity) || 'unknown'
var config = RARITY_CONFIG[bossRarity] || RARITY_CONFIG['unknown']
// 构建炫酷的广播消息
var lines = []
var borderWidth = 40 // 增加宽度以容纳更长的内容
// 1. 创建带边框的标题
var borderedMsg = createBorderedMessage(bossName + " - 伤害统计", config, borderWidth)
lines = lines.concat(borderedMsg.header)
// 2. 稀有度信息
var rarityInfo = config.secondary_color + "稀有度: " + config.primary_color + config.name
var rarityPadding = Math.max(0, borderWidth - rarityInfo.length - 4)
var rarityLine = borderedMsg.sideBorder + " " + rarityInfo + " ".repeat(rarityPadding) + " " + borderedMsg.sideBorder
lines.push(rarityLine)
// 3. 伤害统计
var damageArray = []
for (var playerUUID in bossRecord.players) {
if (bossRecord.players.hasOwnProperty(playerUUID)) {
var playerRecord = bossRecord.players[playerUUID]
if (playerRecord.damage > 0) {
damageArray.push({
name: playerRecord.name,
damage: playerRecord.damage,
percentage: 0
})
}
}
}
if (damageArray.length === 0) {
var noDamageLine = borderedMsg.sideBorder + " " +
config.accent_color + DECORATIONS.dot + " 无有效伤害记录" +
" ".repeat(borderWidth - 18) + " " + borderedMsg.sideBorder
lines.push(noDamageLine)
} else {
// 计算百分比并排序
for (var i = 0; i < damageArray.length; i++) {
damageArray[i].percentage = ((damageArray[i].damage / bossRecord.total) * 100).toFixed(1)
}
damageArray.sort(function(a, b) {
return b.damage - a.damage
})
// 添加伤害排名
var rankIcons = [DECORATIONS.star_filled + " ", DECORATIONS.star_empty + " ", DECORATIONS.diamond + " "]
for (var i = 0; i < damageArray.length; i++) {
var player = damageArray[i]
var rankIcon = i < 3 ? rankIcons[i] : " "
// 创建玩家伤害行
var progressBar = createProgressBar(player.percentage, config)
var playerInfo = config.secondary_color + rankIcon +
config.accent_color + player.name + ": " +
config.primary_color + player.percentage + "% " +
progressBar
var playerPadding = Math.max(0, borderWidth - playerInfo.length - 4)
var playerLine = borderedMsg.sideBorder + " " + playerInfo + " ".repeat(playerPadding) + " " + borderedMsg.sideBorder
lines.push(playerLine)
// 显示具体伤害值(缩进显示)
var damageValue = Math.round(player.damage).toLocaleString()
var damageInfo = " " + config.secondary_color + DECORATIONS.arrow + " 伤害: " +
config.accent_color + damageValue
var damagePadding = Math.max(0, borderWidth - damageInfo.length - 4)
var damageLine = borderedMsg.sideBorder + damageInfo + " ".repeat(damagePadding) + " " + borderedMsg.sideBorder
lines.push(damageLine)
}
// 4. 分隔线
var separatorLine = borderedMsg.sideBorder + " " +
config.border_color + DECORATIONS.line_h.repeat(borderWidth - 2) +
" " + borderedMsg.sideBorder
lines.push(separatorLine)
// 5. 总伤害信息
var totalDamage = Math.round(bossRecord.total).toLocaleString()
var totalLine = borderedMsg.sideBorder + " " +
config.primary_color + DECORATIONS.sword + " 总伤害: " +
config.accent_color + totalDamage +
" ".repeat(borderWidth - 14 - totalDamage.length) + " " + borderedMsg.sideBorder
lines.push(totalLine)
// 6. 参与玩家数量
var playerCountLine = borderedMsg.sideBorder + " " +
config.primary_color + DECORATIONS.heart + " 参与者: " +
config.accent_color + damageArray.length + " 名玩家" +
" ".repeat(borderWidth - 20) + " " + borderedMsg.sideBorder
lines.push(playerCountLine)
}
// 添加底部边框
lines = lines.concat(borderedMsg.footer)
// 控制台输出汇总信息
console.info([BDTracker] ${bossName} (${bossRarity}) 死亡,伤害统计:)
console.info([BDTracker] 总伤害: ${Math.round(bossRecord.total).toLocaleString()})
console.info([BDTracker] 玩家数量: ${damageArray.length})
for (var i = 0; i < damageArray.length; i++) {
var player = damageArray[i]
console.info([BDTracker] ${player.name}: ${player.percentage}% (${Math.round(player.damage).toLocaleString()}))
}
// 广播给附近玩家
var players = entity.level.players
for (var i = 0; i < players.size(); i++) {
var player = players.get(i)
var dx = player.x - entity.x
var dy = player.y - entity.y
var dz = player.z - entity.z
if (dx * dx + dy * dy + dz * dz <= MAX_DISTANCE * MAX_DISTANCE) {
for (var j = 0; j < lines.length; j++) {
player.tell(lines[j])
}
}
}
delete bossDamageRecords[bossUUID]
})
// 定期清理过期记录
ServerEvents.tick(event => {
if (event.server.tickCount % 20 !== 0) return
var now = Date.now()
var cleanupTime = CLEANUP_TICKS * 50
for (var bossUUID in bossDamageRecords) {
if (bossDamageRecords.hasOwnProperty(bossUUID)) {
var record = bossDamageRecords[bossUUID]
if (deadBosses[bossUUID] || (now - record.lastUpdate > cleanupTime)) {
delete bossDamageRecords[bossUUID]
delete deadBosses[bossUUID]
}
}
}
})
