🧵 生命链接#
本示例展示使用Bookshelf的bs.health模块构建的生命链接系统。该系统将多名玩家的生命值相互绑定,使任一玩家的生命值变化自动同步至所有关联玩家。
原生Minecraft缺乏精确治疗玩家的可靠方法,替代方案常导致时序问题。Bookshelf通过确保生命值更新的一致性解决此问题,允许你在游戏刻的任何时刻获取当前生命值(即使存在待处理变更),无需担心刻安全性问题。
🎯 构建目标#
生命链接系统将实现:
检测玩家生命值变化时刻
查找所有关联玩家
将生命值变化同步至所有关联玩家
📦 准备工作#
开始前请确保具备:
Minecraft Java版
基础Minecraft数据包知识(函数、标签、记分板)
已安装Bookshelf的
bs.health模块(安装指南参见快速入门)@require bookshelf.module.health
🛠️ 分步指南#
1. Prepare the Datapack#
首先创建数据包加载时运行的函数lifestring:load,将其注册到minecraft:load标签中。这个函数用于初始化记分板项。
➔ 创建load函数
@function lifestring:load
scoreboard objectives add lifestring.link dummy
scoreboard objectives add lifestring.health dummy
lifestring.link:存储玩家链接ID。相同ID的玩家共享生命值。lifestring.health:存储玩家上一游戏刻的生命值,用于检测变化。
➔ 注册到load标签
@function_tag minecraft:load
{
"values": [
"lifestring:load"
]
}
将lifestring:load添加至此标签可确保数据包启用或重载时自动运行。
2. Link Players Together#
要使玩家共享生命值,需设置相同的*lifestring.link分数。创建lifestring:create_link_ata函数(“ata”代表“as to at”,即从执行者到执行位置,是Bookshelf中表示在源实体(as)上下文操作目标实体(at*)的命名规范),通过单条命令链接玩家:
execute as <source_players> at <target_player> run function lifestring:create_link_ata
➔ 创建create_link_ata函数
@function lifestring:create_link_ata
execute as @p \
unless score @s lifestring.link matches 1.. \
store result score @s lifestring.link \
run scoreboard players add #counter lifestring.link 1
scoreboard players operation @s lifestring.link = @p lifestring.link
此函数首先检查目标玩家(
@p)是否已有链接ID。若无,则通过递增全局*#counter分数分配新ID。随后将目标玩家的链接ID复制至源玩家(@s*)。
3. Detect Health Changes#
需创建持续检测玩家生命值变化的函数:- lifestring:tick:每游戏刻自调度执行- lifestring:check:为每个玩家执行
lifestring:check函数比较玩家当前生命值与上一刻存储值(@s lifestring.health)。若存在差异则运行lifestring:change。
➔ 更新load函数
@function lifestring:load
scoreboard objectives add lifestring.link dummy
scoreboard objectives add lifestring.health dummy
schedule function lifestring:tick 1t
➔ 创建tick函数
@function lifestring:tick
execute as @a[scores={lifestring.link=1..}] run function lifestring:check
schedule function lifestring:tick 1t
➔ 创建check函数
@function lifestring:check
execute store result score #this lifestring.health run function #bs.health:get_health {scale:1000}
scoreboard players operation #this lifestring.health -= @s lifestring.health
execute unless score #this lifestring.health matches 0 if score @s lifestring.health matches 0.. run function lifestring:change
scoreboard players operation @s lifestring.health += #this lifestring.health
获取当前生命值(按1000倍缩放存储),减去上一刻生命值得出*
#this中的变化量。若非零则运行变更函数。第二次条件检查确保玩家存在lifestring.health*分数,随后将变化量添加至玩家生命值分数。
➔ 创建change函数
@function lifestring:change
say Health Changed!
当关联玩家生命值变化时,lifestring:change函数触发,该玩家将在聊天中发送消息。
4. Find Linked Players#
已知玩家生命值变化时机,需查找具有相同*lifestring.link*分数的其他玩家。可通过谓词实现。
➔ 创建is_linked谓词
@predicate lifestring:is_linked
{
"condition": "minecraft:entity_scores",
"entity": "this",
"scores": {
"lifestring.link": {
"min": {
"type": "minecraft:score",
"target": {
"type": "minecraft:fixed",
"name": "#this"
},
"score": "lifestring.link"
},
"max": {
"type": "minecraft:score",
"target": {
"type": "minecraft:fixed",
"name": "#this"
},
"score": "lifestring.link"
}
}
}
}
此谓词检查被评估实体(
"this")的*lifestring.link分数是否等于临时分数#this*中存储的值。
➔ 更新change函数
@function lifestring:change
scoreboard players operation #this lifestring.link = @s lifestring.link
execute as @a[predicate=lifestring:is_linked] run say Health Changed!
当玩家生命值变化时,所有关联玩家将发送"生命值变化!"消息。但需仅更新其他关联玩家(排除变化源玩家)。可通过临时交换*#this*分数与变化源玩家的链接ID实现。
➔ 更新change函数
@function lifestring:change
scoreboard players operation #this lifestring.link >< @s lifestring.link
execute as @a[predicate=lifestring:is_linked] run say Health Changed!
scoreboard players operation #this lifestring.link >< @s lifestring.link
*
><运算符交换分数值:1. 将#this与玩家链接ID交换2. 查找所有关联玩家(此时原玩家链接ID在#this*中故被排除)3. 发送消息4. 交换回原始分数
5. Update Players Health#
将存储于*#this*的生命值变化量应用于所有关联玩家。通过新建lifestring:update函数调用Bookshelf的#bs.health:add_health实现。
➔ 更新change函数
@function lifestring:change
execute store result storage lifestring:update points double 0.001 run scoreboard players get #this lifestring.health
scoreboard players operation #this lifestring.link >< @s lifestring.link
execute as @a[predicate=lifestring:is_linked] run function lifestring:update
scoreboard players operation #this lifestring.link >< @s lifestring.link
➔ 创建update函数
@function lifestring:update
function #bs.health:add_health with storage lifestring:update
scoreboard players operation @s lifestring.health += #this lifestring.health
此方案存在潜在问题:#bs.health:add_health无法治疗超过玩家最大生命值。由于未限制*lifestring.health*分数,可能超出最大值。需定义分数上限值避免此问题。
➔ 更新update函数
@function lifestring:update
function #bs.health:add_health with storage lifestring:update
scoreboard players operation @s lifestring.health += #this lifestring.health
execute store result score #max lifestring.health run attribute @s minecraft:max_health get 1000
scoreboard players operation @s lifestring.health < #max lifestring.health
<运算符将分数设为最小值,确保@s lifestring.health不超过#max lifestring.health。
✔️ 结语#
本系统是Bookshelf简化复杂任务的典范,实现了关联玩家共享伤害与治疗。你可通过以下方向进一步优化:
差异化初始生命值:若关联玩家初始生命值不同,应同步为相同百分比还是相同具体值?
最大生命值:是否累加关联玩家的最大生命值?若某玩家最大生命值变化(如药水效果),如何影响其他玩家?
玩家登录:关联玩家退出后重进时,是否会保存生命值并与组内同步?
尝试实现这些构想,定制属于你的生命链接系统!
💬 这对你有帮助吗?
欢迎在下方留下你的问题与反馈!