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として使用してください。プラグインを自分のjarにシェードしないでください。
コアエントリポイント
ModeledEntityManager.modelExists(String)ModeledEntityManager.reload()ModeledEntityManager.getAllEntities()ModeledEntityManager.getDynamicEntities()ModeledEntityManager.propEntities()DisguiseAPI— プレイヤーをロード済みモデルに変装させる/解除するLocationAPI— ダンジョン検出器と保護プロバイダを登録する(Luaem.location.*述語に供給)ScriptedItemAPI— サードパーティのItemStackにFMMスクリプトアイテムメタデータを刻印する
コアランタイム型
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)ModeledEntity#getEntityID()-- モデルID文字列を返しますModeledEntity#getLocation()-- 現在のLocationを返しますModeledEntity#getWorld()--Worldを返しますModeledEntity#getViewers()-- エンティティが見えるプレイヤーのHashSet<UUID>を返しますModeledEntity#getNametagBones()-- ネームタグボーンのList<Bone>を返します(追加テキストの配置に便利)ModeledEntity#getScaleModifier()/setScaleModifier(double)ModeledEntity#removeWithDeathAnimation()-- 死亡アニメーション付きで削除します(存在する場合)ModeledEntity#removeWithMinimizedAnimation()-- 縮小アニメーション付きで削除しますModeledEntity#remove()-- エンティティとすべてのボーンを即座に削除しますModeledEntity#setTintColor(Color)/getTintColor()-- 革鎧の染色チャネルを介して永続的なティントを適用します。ダメージフラッシュは一時的にティントをオーバーライドし、その後ティントへ戻ります。クリアするにはnullを渡してください。ModeledEntity#setViewDistanceOverride(int)/getEffectiveViewDistance()-- 単一のエンティティに対してDefaultConfig.maxModelViewDistanceをオーバーライドします。プラグイン全体のデフォルトに戻すには-1を渡してください。DynamicEntity#setSyncMovement(boolean)DynamicEntity#isDamagesOnContact()/setDamagesOnContact(boolean)-- エンティティがヒットボックス接触でプレイヤーにダメージを与えるかどうかを制御しますBone#getBoneLocation()
イベントサーフェス
汎用インタラクションイベント:
ModeledEntityLeftClickEventModeledEntityRightClickEventModeledEntityHitboxContactEventModeledEntityHitByProjectileEvent
StaticEntity、DynamicEntity、PropEntity用の型付きバリアントも存在します。
ライフサイクルイベント:
-
ResourcePackGenerationEvent-- FMMがリソースパックの生成または再生成を完了したときに発火します(起動時と/fmm reload時)。生成されたパックでポスト処理をトリガーするにはこれをリッスンしてください。 -
FmmReloadedEvent-- FMMが起動時の初期化シーケンスを完了した後および毎回の/fmm reload後に発火します。常にメインサーバースレッドで発火します。長寿命の
DynamicEntityまたはPropEntity参照を保持するコンシューマプラグイン(EliteMobs、BetterStructuresなど)は、生き残っている基底のエンティティ上でモデルアタッチメントを再作成することによって、このイベントを処理する必要があります。これがないと、コンシューマの参照が現在は古くなっている間にFMMがonDisable中にディスプレイエンティティを破棄したため、それらのエンティティはリロード後に不可視になります。@EventHandler
public void onFmmReloaded(FmmReloadedEvent event) {
for (MyTrackedEntity tracked : myEntities) {
if (tracked.bukkitEntity != null && tracked.bukkitEntity.isValid()) {
tracked.fmmModel = DynamicEntity.create("my_model", tracked.bukkitEntity);
}
}
}
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)--01_em_flame_swordのようなモデルIDをFlame Swordに変換するユーティリティです。
DisplayModelRegistry
どのモデルがディスプレイJSONを利用可能かを追跡するシンプルなレジストリ。
// モデルにディスプレイモデルJSONが登録されているかチェック
boolean has3D = DisplayModelRegistry.hasDisplayModel("magic_sword");
register(String modelId)-- モデルIDを登録します(リロード中に内部的に呼び出されます)hasDisplayModel(String modelId)-- このモデル用の.jsonディスプレイモデルが存在する場合にtrueを返しますgetRegisteredModels()-- ディスプレイモデルが登録されているすべてのモデルIDのイミュータブルSet<String>を返しますshutdown()-- すべての登録をクリアします
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。これにより、他のプラグインはFMMがアイテムの名前、ロア、エンチャントをオーバーライドすることなく、自分のItemStackにFMMスクリプトアイテムデータ(PDCタグ + アイテムモデル)を刻印して、FMMのLuaスクリプトフックがそれらのアイテムで発火するようにできます。
// スクリプトアイテム定義が存在するかチェック
boolean exists = ScriptedItemAPI.isValidItemId("flame_blade");
// 既存のItemStackにFMMスクリプトアイテムデータを適用
// これにより以下が設定されます:
// - fmm_item_id PDCタグ(FMMのスクリプトシステムがアイテムを認識するように)
// - FMMのディスプレイモデルレジストリからのアイテムモデル(1.21.4以降)
// 名前、ロア、エンチャント、その他のアイテムプロパティは変更しません。
boolean success = ScriptedItemAPI.applyScriptedItemData(itemStack, "flame_blade");
// スクリプトアイテムの設定を取得
PropScriptConfigFields config = ScriptedItemAPI.getItemConfig("flame_blade");
isValidItemId(String itemId)-- アイテムIDがFMMのアイテム定義に登録されている場合にtrueを返しますapplyScriptedItemData(ItemStack itemStack, String itemId)-- PDCタグとアイテムモデルを既存のItemStackに刻印します。成功時にtrue、アイテムIDが無効またはItemStackにメタがない場合はfalseを返します。弓/クロスボウに関する注意: 指定されたitemIdがディスプレイモデルを持たないがitemId + "_idle"が持つ場合(つまりアイテムが弓/クロスボウの状態モデルを持つ場合)、メソッドは自動的に_idleモデルをディスプレイモデルとして使用しますgetItemConfig(String itemId)-- 指定されたアイテムIDのPropScriptConfigFieldsを返します。見つからない場合はnullを返します
EliteMobsはscriptedItem設定フィールドを介してこのAPIを内部的に使用します。EliteMobsのカスタムアイテムがscriptedItem: flame_bladeを設定すると、EliteMobsはアイテムを通常通り(名前、ロア、エンチャント、レベル)構築した後、ScriptedItemAPI.applyScriptedItemData()を呼び出してその上にFMMのモデルとスクリプト挙動を追加します。
DisguiseAPI
プレイヤーディスガイズ機能のパブリックエントリポイント。内部リファクタが安全に保たれるように、サードパーティプラグインは内部のDisguiseManagerではなく、このクラスを呼び出すべきです。
import com.magmaguy.freeminecraftmodels.api.DisguiseAPI;
// プレイヤーをロード済みモデルに変装させる。既存のディスガイズをクリーンに置き換える。
boolean ok = DisguiseAPI.disguise(player, "dragon");
// ディスガイズを解除する(ディスガイズが削除された場合true)。
DisguiseAPI.undisguise(player);
// 状態を問い合わせる。
boolean disguised = DisguiseAPI.isDisguised(player);
String modelID = DisguiseAPI.getDisguiseModelID(player); // ディスガイズされていない場合はnull
// 現在ディスガイズ中のすべてのプレイヤーのスナップショット。
Collection<Player> all = DisguiseAPI.getDisguisedPlayers();
disguise(Player, String modelID)-- モデルIDがロードされていない場合falseを返しますundisguise(Player)-- ディスガイズが削除された場合trueを返しますisDisguised(Player)-- クイックブーリアンチェックgetDisguiseModelID(Player)-- アクティブなモデルIDまたはnullを返しますgetDisguisedPlayers()-- ディスガイズされたプレイヤーの変更不可なスナップショット
ディスガイズされたプレイヤーは他者から不可視になり、解除されるまでその状態を保ちます — ミルクバケツ、ビーコンの効果クリア、および類似の操作では透明状態は破られません。
LocationAPI
プラグインがダンジョン検出とリージョン保護チェックに貢献するためのパブリックAPI。登録された述語はFMMのLua em.location.is_in_dungeonとem.location.is_protectedチェック(pickupable.luaやstorage_double.luaなどの既製スクリプトで使用)に供給されます。
プラグインは単純なPredicate<Location>を渡すため、シェード化されたFMM型がプラグインクラスローダーを跨ぐことはありません。
import com.magmaguy.freeminecraftmodels.api.LocationAPI;
// プラグインのenable時、WorldGuard/EliteMobs/などが利用可能になった後。
LocationAPI.registerDungeonLocator("EliteMobs",
location -> EliteMobs.isInsideDungeon(location));
LocationAPI.registerProtectionProvider("WorldGuard",
location -> WorldGuardBridge.isProtected(location));
registerDungeonLocator(String providerName, Predicate<Location> predicate)— 登録された述語のいずれかがtrueを返すと、その場所は「ダンジョン内」とフラグされますregisterProtectionProvider(String providerName, Predicate<Location> predicate)— 登録された述語のいずれかがtrueを返すと、その場所は保護されているとフラグされます
オペレーターは/fmm locationで登録を確認できます。これはライブのプロバイダ数を報告し、現在地で両方の述語をテストします。
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.propの代わりにcontext.item(アイテムIDとプレイヤー情報を持つ)を受け取ります。
プロップスクリプトのコンテキストテーブル
プロップスクリプトは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ボスをスポーンします
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()-- 保持アイテムを1つ削除します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はインストール済みプラグインの依存関係であり、組み込み可能なライブラリではありません。
- プラグインが新しくインポートされたモデルを必要とする場合は、FreeMinecraftModelsの状態を自分で再構築しようとせず、
ModeledEntityManager.reload()を呼び出してください。 - Nightbreakエコシステムのすべてのプラグインは、FreeMinecraftModelsのプロップスクリプトとEliteMobsのLuaパワーで使用される共有Luaスクリプティングエンジン、および共有の
LocationQueryRegistryとWorldFolderResolverを含むMagmaCore 2.2.0-SNAPSHOTに依存するようになりました。 - FreeMinecraftModelsはWorldGuard、WorldEdit、GriefPrevention、Vaultを
softdependとして宣言しています。プラグインを起動するのに必須なものはありませんが、特定の機能が解放されます:WorldGuard/WorldEdit/GriefPreventionはLocationAPIに供給され、Vaultは家具ショップを有効化します。