FreeMinecraftModels API 与开发者指南
FreeMinecraftModels 既是一个独立插件,也是一个面向其他插件的 API 接口。
Maven 仓库
<repository>
<id>magmaguy-repo-releases</id>
<name>MagmaGuy's Repository</name>
<url>https://repo.magmaguy.com/releases</url>
</repository>
<repository>
<id>magmaguy-repo-snapshots</id>
<name>MagmaGuy's Snapshot Repository</name>
<url>https://repo.magmaguy.com/snapshots</url>
</repository>
依赖
<dependency>
<groupId>com.magmaguy</groupId>
<artifactId>FreeMinecraftModels</artifactId>
<version>LATEST.VERSION.HERE</version>
<scope>provided</scope>
</dependency>
请将其作为 compileOnly/provided 使用。不要将插件打包(shade)到您自己的 jar 中。
核心入口点
ModeledEntityManager.modelExists(String)ModeledEntityManager.reload()ModeledEntityManager.getAllEntities()ModeledEntityManager.getDynamicEntities()ModeledEntityManager.propEntities()
核心运行时类型
ModeledEntityStaticEntityDynamicEntityPropEntity
创建实体
StaticEntity preview = StaticEntity.create("example_model", location);
DynamicEntity mobModel = DynamicEntity.create("example_model", livingEntity);
DynamicEntity mount = DynamicEntity.createWithInvisibility("example_model", livingEntity);
PropEntity prop = PropEntity.spawnPropEntity("example_model", location);
如果请求的模型 ID 未加载,所有创建方式都会返回 null。
createWithInvisibility 是一个变体,它使用隐身药水而不是从客户端隐藏实体。这使实体在客户端保持被追踪状态,这对于载具转向是必需的(由 /fmm mount 内部使用)。
常用运行时方法
ModeledEntity#setDisplayName(String)ModeledEntity#setDisplayNameVisible(boolean)ModeledEntity#setLeftClickCallback(...)ModeledEntity#setRightClickCallback(...)ModeledEntity#setHitboxContactCallback(...)ModeledEntity#setModeledEntityHitByProjectileCallback(...)ModeledEntity#playAnimation(String, boolean, boolean)ModeledEntity#stopCurrentAnimations()ModeledEntity#hasAnimation(String)DynamicEntity#setSyncMovement(boolean)Bone#getBoneLocation()
事件接口
通用交互事件:
ModeledEntityLeftClickEventModeledEntityRightClickEventModeledEntityHitboxContactEventModeledEntityHitByProjectileEvent
StaticEntity、DynamicEntity 和 PropEntity 也有对应的类型化变体。
ModeledEntityHitByProjectileEvent 与 OBB 投射物检测
FMM 使用 OBB(定向包围盒)碰撞检测来检测投射物与建模实体的碰撞。当投射物与建模实体的 OBB 碰撞箱相交时,FMM 会触发 ModeledEntityHitByProjectileEvent。这是一个标准的可取消 Bukkit 事件。
关键细节:
- 箭矢伤害的计算支持
POWER附魔加成 PIERCING附魔被尊重 -- 箭矢可以穿透并命中额外目标- 取消事件可以阻止伤害并完全阻挡命中
@EventHandler
public void onProjectileHitModel(ModeledEntityHitByProjectileEvent event) {
ModeledEntity target = event.getModeledEntity();
Projectile projectile = event.getProjectile();
// 取消以阻止伤害
event.setCancelled(true);
}
物品与模型实用工具
ModelItemFactory
用于以编程方式创建与模型相关的 ItemStack 的工厂类。
// 创建道具放置物品(使用 "model_id" PDC 键)
ItemStack placementItem = ModelItemFactory.createModelItem("lamp_post", Material.STICK);
// 从配置创建自定义物品(使用 "fmm_item_id" PDC 键)
PropScriptConfigFields config = ItemScriptManager.getItemDefinitions().get("magic_sword");
ItemStack customItem = ModelItemFactory.createCustomItem("magic_sword", config);
createModelItem(String modelId, Material material)-- 为道具创建放置物品。在 1.21.4+ 上,如果存在展示 JSON,会自动应用展示模型渲染。createCustomItem(String itemId, PropScriptConfigFields config)-- 使用统一配置创建带有名称、描述、附魔和展示模型的自定义物品。formatModelName(String modelId)-- 将模型 ID(如01_em_flame_sword)转换为Flame Sword的实用方法。
DisplayModelRegistry
简单的注册表,跟踪哪些模型有可用的展示 JSON。
// 检查模型是否有注册的展示模型 JSON
boolean has3D = DisplayModelRegistry.hasDisplayModel("magic_sword");
register(String modelId)-- 注册一个模型 ID(在重载期间内部调用)hasDisplayModel(String modelId)-- 如果此模型存在.json展示模型,则返回trueshutdown()-- 清除所有注册
ItemScriptManager
管理自定义物品(YML 配置中设置了 material: 的模型)的每玩家 Lua 脚本的生命周期。
// 获取所有注册的自定义物品定义
Map<String, PropScriptConfigFields> items = ItemScriptManager.getItemDefinitions();
// 获取玩家 + 物品的活跃 Lua 脚本实例
ScriptInstance instance = ItemScriptManager.getActiveScript(playerUUID, "magic_sword");
// 获取玩家的所有活跃脚本
Map<String, ScriptInstance> scripts = ItemScriptManager.getActiveScripts(playerUUID);
scanForCustomItems(File modelsFolder)-- 扫描模型 YML 配置以查找自定义物品updateEquippedScripts(Player player)-- 比较已装备物品与运行中的脚本,触发 equip/unequip 钩子removePlayer(Player player)-- 关闭玩家的所有脚本(退出时调用)getItemDefinitions()-- 返回物品 ID 到PropScriptConfigFields的映射
ScriptedItemAPI
外部插件用于与 FMM 脚本物品系统集成的公共 API。允许其他插件在自己的 ItemStack 上标记 FMM 脚本物品数据(PDC 标签 + 物品模型),使 FMM 的 Lua 脚本钩子能够对这些物品触发,而 FMM 不会覆盖物品的名称、描述或附魔。
// 检查脚本物品定义是否存在
boolean exists = ScriptedItemAPI.isValidItemId("flame_blade");
// 将 FMM 脚本物品数据应用到现有 ItemStack
// 设置内容:
// - fmm_item_id PDC 标签(使 FMM 的脚本系统识别该物品)
// - 物品模型(1.21.4+)来自 FMM 的展示模型注册表
// 不会修改名称、描述、附魔或任何其他物品属性。
boolean success = ScriptedItemAPI.applyScriptedItemData(itemStack, "flame_blade");
// 获取脚本物品的配置
PropScriptConfigFields config = ScriptedItemAPI.getItemConfig("flame_blade");
isValidItemId(String itemId)-- 如果物品 ID 在 FMM 的物品定义中已注册,则返回trueapplyScriptedItemData(ItemStack itemStack, String itemId)-- 在现有 ItemStack 上标记 PDC 标签和物品模型。成功返回true,物品 ID 无效或 ItemStack 无 meta 时返回false。**弓/弩注意:**如果给定的itemId没有展示模型但itemId + "_idle"有(即该物品有弓/弩状态模型),方法会自动使用_idle模型作为展示模型getItemConfig(String itemId)-- 返回给定物品 ID 的PropScriptConfigFields,未找到时返回null
EliteMobs 通过 scriptedItem 配置字段在内部使用此 API。当 EliteMobs 自定义物品设置 scriptedItem: flame_blade 时,EliteMobs 会正常构建物品(名称、描述、附魔、等级),然后调用 ScriptedItemAPI.applyScriptedItemData() 来添加 FMM 的模型和脚本行为。
PropScriptConfigFields
模型 YML 配置文件的统一配置类。道具脚本和自定义物品都使用此类。
# 示例: torch_01.yml
isEnabled: true
scripts:
- torch_glow.lua
material: STICK # 设置后,模型成为自定义物品
name: "&eMagic Torch" # 自定义显示名称(可选)
lore: # 自定义描述行(可选)
- "&7Glows in the dark"
enchantments: # 附魔(可选,格式: NAME,LEVEL)
- "FIRE_ASPECT,1"
关键方法:isCustomItem()、getParsedMaterial()、getParsedEnchantments()、getScripts()。
Lua 脚本
FreeMinecraftModels 通过 MagmaCore 2.0 脚本引擎支持道具和自定义物品的 Lua 脚本。脚本文件放置在 plugins/FreeMinecraftModels/scripts/ 中,并通过模型文件旁边的 YML 配置文件绑定到模型。
道具脚本钩子
| 钩子 | 触发条件 |
|---|---|
on_spawn | 道具被生成到世界中 |
on_game_tick | 道具存活期间的每个刻 |
on_zone_enter | 玩家进入道具的区域 |
on_zone_leave | 玩家离开道具的区域 |
on_destroy | 道具被移除 |
on_left_click | 玩家左键点击道具 |
on_right_click | 玩家右键点击道具 |
on_projectile_hit | 投射物命中道具 |
物品脚本钩子
自定义物品(设置了 material: 的模型)支持 22 个 Lua 钩子:
| 钩子 | 触发条件 |
|---|---|
on_equip | 物品进入被追踪的装备栏位 |
on_unequip | 物品离开被追踪的装备栏位 |
on_game_tick | 物品装备期间的每个刻 |
on_attack_entity | 玩家手持物品攻击实体 |
on_kill_entity | 玩家手持物品击杀实体 |
on_take_damage | 物品装备时玩家受到伤害 |
on_shield_block | 玩家用盾牌格挡 |
on_shoot_bow | 玩家射箭 |
on_projectile_hit | 玩家发射的投射物命中目标 |
on_projectile_launch | 玩家发射投射物 |
on_right_click | 玩家右键点击物品 |
on_left_click | 玩家左键点击物品 |
on_shift_right_click | 玩家 Shift+右键点击物品 |
on_shift_left_click | 玩家 Shift+左键点击物品 |
on_interact_entity | 玩家用物品右键点击实体 |
on_swap_hands | 玩家在双手间交换物品 |
on_drop | 玩家丢弃物品 |
on_break_block | 玩家手持物品破坏方块 |
on_consume | 玩家消耗物品 |
on_item_damage | 物品受到耐久损耗 |
on_fish | 玩家使用钓鱼竿 |
on_death | 物品装备时玩家死亡 |
物品脚本接收 context.item(包含物品 ID 和玩家信息)而非 context.prop。
道具脚本 Context 表
脚本接收一个 context 表。以下是关键 API 的摘要——详细信息请参阅 Lua 道具 API。
context.prop:
model_id-- 蓝图模型名称current_location-- 道具的当前位置play_animation(name, blend, loop)-- 播放指定动画(blend 和 loop 默认为true)stop_animation()-- 停止所有当前动画hurt_visual()-- 在道具上播放受伤(红色闪烁)视觉效果pickup()-- 移除道具并掉落其放置物品mount(player)-- 让玩家骑乘道具dismount(player)-- 将玩家从道具上移除get_passengers()-- 返回当前骑乘道具的玩家列表spawn_elitemobs_boss(filename, x, y, z)-- 在相对于道具的位置生成 EliteMobs Boss
context.event:
- 在
on_left_click、on_right_click和on_projectile_hit中可用 cancel()、uncancel()、is_cancelledplayer-- 触发事件的玩家
context.world:
spawn_entity(entity_type, location)-- 生成原版实体set_block_at(location, material)-- 在世界中设置方块- 还包括粒子、声音、方块查询、闪电和附近实体查找
玩家对象(来自 context.event.player):
get_held_item()-- 返回玩家手持的物品consume_held_item()-- 移除一个手持物品has_item(material)-- 检查玩家是否拥有某物品send_message(text)-- 向玩家发送聊天消息game_mode-- 玩家当前的游戏模式
道具脚本示例
function on_spawn(context)
context.prop.play_animation("idle", true, true)
end
function on_right_click(context)
context.prop.play_animation("activate", false, false)
end
物品脚本示例
function on_equip(context)
context.event.player.send_message("&6You equipped the Flame Blade!")
end
function on_attack_entity(context)
-- 命中时的火焰效果
context.event.player.send_message("&cBurn!")
end
function on_unequip(context)
context.event.player.send_message("&7Flame Blade sheathed.")
end
说明
- FreeMinecraftModels 是作为已安装插件的依赖使用的,而非可嵌入的库。
- 如果您的插件需要新导入的模型,请调用
ModeledEntityManager.reload()而不是尝试自行重建 FreeMinecraftModels 的状态。 - Nightbreak 生态系统中的所有插件现在都依赖于 MagmaCore 2.0.0-SNAPSHOT,其中包括 FreeMinecraftModels 道具脚本和 EliteMobs Lua 技能所使用的共享 Lua 脚本引擎。