内容附魔
EliteMobs 与 FreeMinecraftModels 通过共享的 MagmaCore 系统提供自定义附魔。每个插件在自己的 enchantments/ 目录中管理定义和 Lua 效果。Minecraft 原版附魔仍使用 minecraft: 命名空间。
更新内置定义
目录会恢复缺失的内置 YAML 和 Lua 文件,并向现有内置定义添加缺少的默认字段。已有配置值和 Lua 源码会保留。即使 enchantments/ 目录已经存在,此机制也会生效。
所属插件可能先归档符合已废弃格式的文件。例如,EliteMobs 会先保留含有 maxLevelV2 的附魔 YAML,再生成当前默认内容。EliteMobs 还会归档较早内置附魔脚本中未经编辑的副本(例如旧的 grappling_hook.lua),以便在原处写入当前默认版本;你编辑过的脚本会保留。在配置归档中检查自定义设置,并使用当前字段重新应用。更新的 DLC 或自定义效果仍需要各自匹配的定义和 Lua 源码。
物品引用
自定义效果使用小写的命名空间 ID 和正整数等级。以下是 FMM 物品定义示例:
enchantments:
- "minecraft:unbreaking,3"
- "elitemobs:critical_strikes,2"
例如,EliteMobs 附魔目录中的 critical_strikes.yml 定义 elitemobs:critical_strikes。FMM 定义使用 freeminecraftmodels:。子目录不会成为 ID 的一部分;内容文件应使用唯一文件名。
EliteMobs 自定义物品 YAML 对原版附魔保留 UNBREAKING,3 等 Bukkit 名称,对自定义效果则要求命名空间 ID。不要在未检查其他插件物品格式的情况下,直接复制 FMM 的原版附魔语法。
已安装的提供方必须识别该 ID。兼容性、物品类型、栏位、冲突和必需能力都来自定义。移除提供方不会把其自定义效果变成原版附魔。
定义格式
以下是 FMM 内置的 Ignition 定义,与同一附魔目录中的 ignition.lua 配套使用:
isEnabled: true
name: Ignition
description: Sets surviving targets on fire after a staff fireball hits.
maxLevel: 3
curse: false
validSlots: [MAINHAND]
itemTypes: [STAFF]
attackKinds: [STAFF_FIREBALL]
requires: []
conflicts: []
stacking: source_item
script: ignition.lua
parameters:
base_ticks: 20
ticks_per_level: 20
return {
api_version = 1,
on_ignition_ticks = function(context)
return math.max(0, math.min(200, context.parameters.base_ticks
+ context.parameters.ticks_per_level * context.enchantment.level))
end
}
此查询向 FMM 返回点燃时长。它不作为摆件脚本或装备物品脚本运行。
| 字段 | 含义 |
|---|---|
isEnabled | 默认为 true;禁用的定义不会加入目录 |
name | 必填的纯文本显示名称 |
description | 可选描述,默认为空 |
maxLevel | 正的附魔等级上限;明确制作的物品可以超过此值 |
curse | 是否为诅咒;默认为 false |
validSlots | 装备栏位:HEAD, CHEST, LEGS, FEET, MAINHAND, OFFHAND |
itemTypes | 接受的类别:SWORD, AXE, PICKAXE, SHOVEL, HOE, BOW, CROSSBOW, TRIDENT, MACE, SPEAR, HELMET, CHESTPLATE, LEGGINGS, BOOTS, SHIELD, FISHING_ROD, SHEARS, ELYTRA, WAND, STAFF, OTHER |
attackKinds | 可选魔法攻击筛选:WAND_MISSILE, STAFF_MELEE, STAFF_FIREBALL |
requires | 对提供方能力的要求 |
conflicts | 其他小写的命名空间附魔 ID |
stacking | 默认为 source_item,也可为 sum_equipped_levels |
script | 必填的小写 .lua 文件名,不包含目录 |
parameters | 命名标量值或按等级排列的标量列表 |
set | 可选。使该附魔成为套装 |
按等级排列的列表必须恰好有 maxLevel 个条目。超过该等级时使用列表最后一个值,但脚本仍会收到实际附魔等级。参数属于具体效果;在这里随意添加一个键不会创建新机制。
未知顶层字段、重复 ID、缺失脚本和不支持的钩子会导致候选目录被拒绝。重新加载前,先修复错误中指出的文件。失败的候选目录不会覆盖当前使用中的目录。
效果归属
以将来负责新定义的插件所附带的效果为起点。它支持的钩子和领域操作决定了效果能做什么。查询钩子返回飞弹数量、暴击率或威胁加成等数值。动作钩子处理已接受的物品输入,可以管理持续一段时间的效果。
旧 FMM context.item API 及其装备、卸下生命周期不适用于这里。附魔脚本使用自己的 context.enchantment、context.parameters、捕获的来源信息和动作操作。不要仅重命名旧物品脚本就假设其上下文兼容。
附魔书与铁砧
自定义附魔书与装备物品使用相同的提供方定义。铁砧会校验来源物品、附魔书和完整结果,包括原版附魔。相同自定义等级合并后升一级;不同等级保留较高值。每个发生变化的自定义附魔会将结果等级加到原版修复成本上。结果等级必须通过定义的铁砧等级限制、栏位、类型、能力和冲突检查。
混合附魔书必须同时转移服务器接受的全部原版条目和自定义条目。如果服务器拒绝某个原版条目,整个自定义操作会被拒绝,不会静默丢弃书中的那部分。无效或不可用的定义也会导致预览被拒绝。取出结果时会再次检查输入和提供方状态;已显示的预览并不保证在目录变更后仍然有效。
Lua 查询参考
数值查询运行全新的脚本实例,并在得到结果后立即关闭。返回一个有限数;没有贡献时返回 nil。状态和计划任务不会在查询结束后保留。失败的定义会被隔离,直到目录成功重载;耗尽调用方剩余预算本身不会导致定义被隔离。
| 上下文 | 内容 |
|---|---|
context.enchantment | id 与实际 level |
context.parameters | 按该等级解析后的定义值 |
context.input | 所属机制提供的标量信息;准确键名请参考内置效果 |
context.target | 目标 Entity 或 Living Entity 表,也可为 nil |
context.player | 查询包含触发玩家时,提供该玩家 |
FMM 提供 on_missile_count、on_missile_damage_factor、on_blast_radius_factor 和 on_ignition_ticks。其他提供方公开各自的数值钩子。定义只能声明其提供方接受的钩子。
Lua 动作参考
动作脚本使用共享的调度器、冷却、世界、区域、玩家和事件表。它们针对一次已接受的输入或攻击运行,后续回调使用捕获的来源。聊天会在聊天事件中保存消息快照,然后在服务器线程分发时捕获装备。可选的 parameters.lifetime_ticks 必须为正整数;未设置时激活实例的寿命为一刻。计划执行的效果需要设置足以完成的寿命。
激活实例会在以下情况停止:寿命结束、执行者死亡、断线或换世界、所属世界卸载、包含其管理实体的区块卸载,或提供方重载或禁用。当最终输入已无剩余管理任务时,也可以提前结束。parameters.stop_on_unequip: true 还会在捕获的物品不再装备时停止实例。局部冷却属于玩家与附魔 ID;全局冷却属于该提供方内的玩家。两种冷却都会在换装备、实例结束、换世界及有效重载后保留,并在断线或提供方关闭时清除。
| 钩子 | 接受的输入 |
|---|---|
on_attack_entity | 使用主手物品成功造成的正值原版近战伤害,或插件明确负责的攻击 |
on_projectile_hit | 捕获的弓箭弹体对活体目标成功造成伤害,每个弹体与目标组合仅分发一次;或插件明确负责的冲击 |
on_take_damage | 玩家受到正值伤害;检查符合条件的装备栏位 |
on_right_click, on_left_click | 未潜行时的手部交互 |
on_shift_right_click, on_shift_left_click | 潜行时的手部交互;替换对应的普通点击钩子 |
on_break_block | 玩家使用主手物品进行的已接受方块破坏 |
on_chat | 已接受的聊天,携带消息快照在服务器线程分发 |
on_sneak | 开始潜行;按定义收集装备贡献 |
on_projectile_launch | 已消耗的附魔弹药通过弓事件作为箭发射 |
on_game_tick | 此激活实例仍有效时的每刻 |
on_zone_enter, on_zone_leave | 玩家跨越此激活实例监视的区域边界 |
这些钩子不会创建装备、卸下脚本运行时。仅处理每刻的定义仍需要输入钩子来启动激活实例。原版攻击、受伤、聊天和挖掘钩子观察的是已接受输入,不能取消原始事件。四种交互钩子提供同步取消标志:context.event:cancel() 拒绝相关物品和方块交互。计划回调不能追溯取消输入。
| 上下文 | 内容 |
|---|---|
context.enchantment | id, level |
context.parameters | 按等级解析的定义参数 |
context.player | 当前执行者的 Player Table |
context.target | 当前受影响的 Living Entity Table,也可为 nil |
context.source | 捕获的信息:item, slot, inventory_slot, equipment, attack_kind, providers;部分输入还提供 ammunition, projectile, message, block, drop_items, sneaking 或 equipped_levels |
context.item | 库存物品仍可定位时,提供捕获栏位的耐久与消耗方法;参阅物品方法 |
context.action | id(攻击 UUID)、instance(激活令牌)、actor(UUID)、world(世界 UUID)及下列方法 |
context.set | 对于套装:id、name、level 和 pieces;否则为 nil |
物品快照包含 material、amount 和 enchantments。它们是数据,不是实时库存对象。来源信息中的 UUID 是字符串。挖掘的 source.block 包含 x、y、z 和小写的 material。
| 动作方法 | 返回值 | 行为 |
|---|---|---|
stop() | nil | 停止此激活实例并清理其管理的任务 |
has_previous() | bool | 检查同一玩家是否存在此附魔的其他活动实例 |
replace_previous() | nil | 停止先前实例,保留当前实例 |
damage_target(target_uuid, amount) | bool | 请求提供方按捕获的来源归属应用正的有限伤害;拒绝时返回 false |
own_entity(uuid) | bool | 将同世界中的有效非玩家实体登记为清理时移除的对象;在生成后使用 |
launch_projectile(location, direction, speed, range, ticks, impact, visual?, protected_path?=false) | bool | 发射受管理的脚本弹体;速度和射程必须为正的有限数,ticks 至少为 1 |
attribute_projectile(uuid, callback, protect?=false) | bool | 将受管理的原版弹体伤害绑定到自定义回调 |
place_block(x, y, z, expected_material, block_data) | bool | 仅在当前材质匹配时,通过玩家方块操作校验放置方块 |
break_block(x, y, z, expected_material, drop_material?, amount?=1) | bool | 通过玩家方块操作校验破坏方块,可指定自定义物品掉落 |
break_naturally(x, y, z, expected_material) | bool | 使用捕获的工具及来源破坏事件的掉落策略破坏方块 |
temporary_block(x, y, z, block_data, ticks?=0) | bool | 临时管理已加载方块,清理时或正数 ticks 后恢复;零表示持续到清理 |
can_own_block(x, y, z) | bool | 检查坐标是否已加载,以及能否临时管理 |
temporary_gravity(uuid, enabled) | bool | 临时管理重力状态,清理时恢复 |
restore_gravity(uuid) | bool | 提前恢复此激活实例临时管理的重力 |
temporary_scale(uuid, scale) | bool | 临时管理活体实体的缩放,持续到清理 |
temporary_potion(uuid, type, ticks, amplifier) | bool | 临时管理药水效果,ticks 为正数,amplifier 非负 |
restore_potion(uuid, type) | bool | 提前恢复此激活实例临时管理的药水效果 |
ride_rails(speed) | bool | 让玩家坐进一辆只有客户端可见的矿车,并以每刻 speed 格(大于 0,不超过 2)的速度,沿玩家所在方块中相连的铁轨、朝其面向的一端驱动它;当那里没有铁轨、玩家已在骑乘,或服务器的 NMS 适配器不可用时返回 false |
铁轨骑行属于其激活实例所管理的工作。潜行、到达轨道尽头、传送、死亡、离开,或任何其他使玩家离开矿车超过一格的情况,都会结束骑行,随后结束该激活实例;玩家会被放在矿车停下的位置,传送、死亡或离开的情况除外。停止该激活实例(包括通过 replace_previous())也会让玩家下车。该激活实例的 lifetime_ticks 仍然适用,因此请给最长的轨道留出足够的时间。
弹体冲击回调收到 (fresh_context, target_or_nil, location);视觉回调收到 (fresh_context, location)。原版弹体伤害回调在下一刻收到 (fresh_context, target, native_damage)。它们替换原版伤害应用,必须明确应用预期伤害,通常通过 fresh_context.action:damage_target(target.uuid, amount)。原版弹体设置 protect=true 时,会过滤受保护的爆炸方块和点燃。脚本弹体设置 protected_path=true 时,穿过受保护或未加载位置的弹体会被吸收。
自动清理仅适用于登记了管理归属的操作。普通 world:spawn_entity、entity:set_gravity 和 world:set_block_at 不会自动纳入动作清理。临时状态方法负责恢复,不能代替对敌对效果或方块编辑是否获准的检查。
套装
set 部分会把一个附魔变成套装。请把同一个附魔放在每一件装备上。当 pieces 下列出的每个栏位都装着带有该附魔的物品时,套装即为完整。完整的套装每次事件只运行一次其钩子。只要缺少任何一件,就不会运行任何内容。
name: Crooked's Full Set
maxLevel: 1
validSlots: [HEAD, CHEST, LEGS, FEET]
itemTypes: [HELMET, CHESTPLATE, LEGGINGS, BOOTS]
script: crooked_set.lua
parameters:
lifetime_ticks: 620
stop_on_unequip: true
set:
pieces:
HEAD: Crooked's Hex-Brim
CHEST: Crooked's Warded Wrap
LEGS: Crooked's Bent Hosen
FEET: Crooked's Wayward Soles
lore:
- "&5Crooked's Full Set &7($equippedPieces/$totalPieces)"
- "$setPieces"
- "&7When damaged, has a 5% chance to grant Regeneration I."
return {
api_version = 1,
on_take_damage = function(context)
-- Runs only while all four pieces are worn, once per hit.
context.action:temporary_potion(context.player.uuid, "REGENERATION", 100, 0)
end
}
| 套装字段 | 含义 |
|---|---|
pieces | 必填。把装备栏位映射到部件名称。设置了 validSlots 时,它必须包含每个部件的栏位 |
name | $setName 使用的名称。默认为附魔的 name,接受 & 颜色代码 |
lore | 套装的描述行。默认为套装名称加上部件数量,然后每个部件一行 |
equippedPiece | 已穿戴部件的行。默认为 &a✔ $pieceName |
missingPiece | 缺少部件的行。默认为 &c✘ $pieceName |
套装描述接受以下占位符:
| 占位符 | 显示内容 |
|---|---|
$setName | 套装名称 |
$equippedPieces | 玩家穿戴了多少个部件 |
$totalPieces | 套装一共有多少个部件 |
$setPieces | 按栏位顺序每个部件一行,来自 equippedPiece 或 missingPiece。占位符前后的文字会在每一行中重复 |
$pieceName, $pieceSlot | 在 equippedPiece 和 missingPiece 内,表示部件名称及其栏位,例如 Head 或 Main Hand |
$ifSetComplete | 仅当所有部件都已穿戴时才显示该行 |
$ifSetIncomplete | 仅当缺少部件时才显示该行 |
套装物品会显示这一部分,而不是自定义附魔列表中的一行。在 EliteMobs 中,请把 $itemSet 放进 ItemSettings.yml 的 itemLoreStructureV2,或放进自定义物品自己的 lore 中。两者都没有时,套装会跟在物品的自定义描述之后。$ifItemSet 只在套装物品上显示结构行。FMM 自定义物品会在包含 $itemSet 的描述行处显示套装,否则显示在其描述之后。
该部分显示的是携带该物品的玩家当前穿戴的情况,并在玩家穿上或脱下部件时重新绘制。存放在玩家物品栏之外的物品,会保留它离开时显示的状态。
套装钩子与普通附魔钩子有几点不同:
- 上表中的每个动作钩子都会触达完整的套装,无论其部件使用哪些栏位。护甲套装可以响应
on_attack_entity或on_break_block。 - 完整性在事件发生时检查。弹体检查的是它落地时玩家穿戴的套装,任何弹体都算,而不只是弓箭。
on_take_damage会在有攻击者时把context.target设为攻击者。context.source.item和context.item是按栏位顺序排列的第一个部件:HEAD、CHEST、LEGS、FEET、MAINHAND、OFFHAND。要读取手持的武器或工具,请使用context.source.equipment.MAINHAND。context.set.level是各部件中最低的等级。context.set.pieces以栏位为键,每个部件带有其name和inventory_slot。stop_on_unequip: true会在任一部件被脱下时停止套装的激活实例。- 数值查询(例如 EliteMobs 的威胁值和暴击率,或 FMM 的施法修正)只在套装完整时才把套装计算一次。
升级现有内容
FMM 会跳过含有非空 scripts: 或已废弃的无命名空间附魔条目的自定义物品。将这些物品定义改为使用命名空间附魔;摆件脚本仍受支持。
EliteMobs 自定义效果现在在提供方 YAML 中使用 maxLevel 和效果专属的 parameters。原版及精英等级附魔配置是另一种格式。请遵循 EliteMobs 附魔参考,不要将旧 maxLevelV2 文件复制到提供方定义中。