メインコンテンツまでスキップ

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 — ダンジョン検出器と保護プロバイダを登録する(Lua em.location.*述語に供給)
  • ScriptedItemAPI — サードパーティのItemStackにFMMスクリプトアイテムメタデータを刻印する

コアランタイム型

  • ModeledEntity
  • StaticEntity
  • DynamicEntity
  • PropEntity

エンティティの作成

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()

イベントサーフェス

汎用インタラクションイベント:

  • ModeledEntityLeftClickEvent
  • ModeledEntityRightClickEvent
  • ModeledEntityHitboxContactEvent
  • ModeledEntityHitByProjectileEvent

StaticEntityDynamicEntityPropEntity用の型付きバリアントも存在します。

ライフサイクルイベント:

  • 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統合

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_dungeonem.location.is_protectedチェック(pickupable.luastorage_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_clickon_right_clickon_projectile_hitで利用可能
  • cancel()uncancel()is_cancelled
  • player -- イベントをトリガーしたプレイヤー

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スクリプティングエンジン、および共有のLocationQueryRegistryWorldFolderResolverを含むMagmaCore 2.2.0-SNAPSHOTに依存するようになりました。
  • FreeMinecraftModelsはWorldGuard、WorldEdit、GriefPrevention、Vaultをsoftdependとして宣言しています。プラグインを起動するのに必須なものはありませんが、特定の機能が解放されます:WorldGuard/WorldEdit/GriefPreventionはLocationAPIに供給され、Vaultは家具ショップを有効化します。