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スクリプトアイテムメタデータを刻印する
ModeledEntityManager.getAllEntities()、getDynamicEntities()、propEntities()は、その時点のコピーを返します。返されたセットやマップを変更してもFMMのライブレジストリは変更されません。存在確認には、レジストリ全体を保持して繰り返しコピーするのではなくmodelExists(String)を使用してください。
コアランタイム型
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を返します。
PropEntity.spawnPropEntityはさらに、同じモデルのプロップが対象ブロック上に既にロードされている場合にもnullを返します — 重複は積み重ねられるのではなく拒否され、[FMM Props] Prevented duplicate prop spawn ...の警告がログに出力されます。戻り値は必ずnullチェックしてください。プロップが実際に作成されたことを確認できるのは、null以外が返ってきたときだけです。
createWithInvisibilityは、クライアントからエンティティを隠す代わりに不可視化のポーション効果を適用するバリアントです。これによりエンティティがクライアント側で追跡され続け、乗り物の操舵に必要です(/fmm mountの内部で使用)。
有用なランタイムメソッド
ModeledEntity#setDisplayName(String)-- モデルにtag_ボーンが含まれていない限り、何もせずに終了します(下記の警告を参照)ModeledEntity#setDisplayNameVisible(boolean)-- 同じ要件ModeledEntity#setLeftClickCallback(...)ModeledEntity#setRightClickCallback(...)ModeledEntity#setHitboxContactCallback(...)ModeledEntity#setModeledEntityHitByProjectileCallback(...)ModeledEntity#playAnimation(String, boolean blend, boolean loop)-- 名前が組み込みステートにもモデル内のアニメーションにも一致しない場合はfalseを返します。blendはクロスフェードではなくキューイングを行い、loopはカスタムアニメーションにのみ適用されます。アニメーションを参照してくださいModeledEntity#stopCurrentAnimations()ModeledEntity#hasAnimation(String)ModeledEntity#damage(double)/damage(Entity damager, double)/damage(Entity damager)/damage(Projectile)-- エンティティのDamageableComponentを経由しますModeledEntity#attack(LivingEntity)/attack(LivingEntity, double damage)ModeledEntity#teleport(Location, boolean teleportUnderlyingEntity)ModeledEntity#setUnderlyingEntity(Entity)/ModeledEntity.getModeledEntity(Entity)-- Bukkitエンティティからそれに紐づくモデルへの静的な逆引き。存在しない場合はnullModeledEntity#showUnderlyingEntity(Player)/hideUnderlyingEntity(Player)-- 背後のバニラエンティティのプレイヤーごとの可視性ModeledEntity#getEntityID()-- モデルID文字列を返しますModeledEntity#getModelInstanceId()-- インスタンスごとのUUID。モデルの生存期間中は安定していますModeledEntity#isRemoved()/isDying()-- ライフサイクルフラグModeledEntity#getLocation()-- 現在のLocationを返しますModeledEntity#getSpawnLocation()-- モデルが作成されたLocationを返しますModeledEntity#getWorld()--Worldを返しますModeledEntity#getSkeleton()/getSkeletonBlueprint()/getMountPointManager()-- ランタイム構造へのアクセスModeledEntity#getInteractionComponent()/getHitboxComponent()/getDamageableComponent()/getAnimationComponent()-- 上記の便利メソッドの背後にあるコンポーネントオブジェクトModeledEntity.getLoadedModeledEntities()-- ロード済みのすべてのモデル化エンティティの静的なライブセット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)-- エンティティがヒットボックス接触でプレイヤーにダメージを与えるかどうかを制御しますDynamicEntity.isDynamicEntity(Entity)/DynamicEntity.getDynamicEntity(Entity)-- Bukkitエンティティからの静的な検索DynamicEntity#getBodyLocation()--getLocation()とは異なる、体の向きに基づく位置Bone#getBoneLocation()
PropEntity固有のもの
PropEntity.isPropEntity(ArmorStand)/PropEntity.getPropEntityID(ArmorStand)-- 背後の防具立てからプロップを識別しますPropEntity.hasLoadedPropOnSameBlock(String entityID, Location)--spawnPropEntityが内部で実行する重複チェック。nullチェックではなく事前に分岐したい場合は、先にこれを呼び出してくださいPropEntity.respawnPropEntityFromArmorStand(String entityID, ArmorStand)-- チャンクの再読み込みを生き延びた防具立ての周囲にプロップを再構築しますPropEntity.getPropEntities()-- 防具立てのUUIDをキーとする、ロード済みプロップのライブマップPropEntity#setPersistent(boolean)-- 背後の防具立ての永続性を切り替えますPropEntity#setCustomDataString(NamespacedKey, String)/getCustomDataString(NamespacedKey)-- プロップ上の独自のPDC値を読み書きします。これはLuaのset_persistent_data/get_persistent_dataヘルパーがfmm_lua_<key>名前空間で使用しているのと同じストアですPropEntity#remove()/remove(boolean showRealBlocks)-- モデルを削除しますが、永続エントリは残しますPropEntity#permanentlyRemove()-- モデルおよびその永続エントリを削除しますPropEntity#setVoxelizeConfig(boolean voxelize, boolean solidify)/applySolidify()-- YMLのvoxelize:/solidify:フィールドに相当するランタイム版PropEntity#showFakePropBlocksToPlayer(Player)/showRealBlocksToPlayer(Player)および...ToAllPlayers()バリアント -- solidify済みプロップにクライアント側の当たり判定を与える、パケットのみのバリアブロックを制御します
tag_ bone in the modelsetDisplayNameとsetDisplayNameVisibleはモデルのネームタグボーンを走査しますが、それらは名前がtag_で始まるボーンにしか存在しません。該当するボーンがないモデルではそのリストが空になるため、どちらの呼び出しも成功したうえで何もしません — 例外もログ行も出ません。
フォールバックはありません。DynamicEntityは基盤となるリビングエンティティをクライアントから隠すため、バニラのモブのネームタグも表示されません。結果として、プラグインがエラーなく名前を設定したにもかかわらず、まったく名前のないモブになります。
プラグインがモデルに名前を付ける場合(ボス、NPC、その他ユーザーに見えるもの)、配布するモデルにtag_ボーンを必須とするか、アタッチ時にgetNametagBones().isEmpty()をチェックしてコンテンツ作者に警告してください。モデル作成に関する注記を参照してください。
イベントサーフェス
汎用インタラクションイベント:
ModeledEntityLeftClickEventModeledEntityRightClickEventModeledEntityHitboxContactEventModeledEntityHitByProjectileEvent
4つすべてがキャンセル可能なBukkitイベントであり、FMMの組み込み検出パスはこれらをメインサーバースレッド上でディスパッチします。イベントをキャンセルすると、対応するFMMのコールバック/デフォルト動作が抑止されます。ヒットボックス接触のスキャンは2サーバーティックごとに実行されます。クリックイベントには依然としてプレイヤーごとの短い重複排除ウィンドウがあり、パケットインタラクション経路とOBBレイトレース経路が同じアクションを2回発火させることはありません。
ライフサイクルイベント:
FmmReloadedEvent-- FMMが起動時の初期化シーケンスを完了した後および毎回の/fmm reload後に発火します。常にメインサーバースレッドで発火します。
公開されているインタラクションのインターフェースは、意図的にモデル型に依存しない形になっています。古いStaticEntity*Event、DynamicEntity*Event、PropEntity*Eventのバリアントは、ResourcePackGenerationEventとともに、現在のAPIには含まれていません。代わりに上記4つの汎用モデル化エンティティイベントとFmmReloadedEventを使用してください。
長寿命の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イベントです。
重要な詳細:
- 検出は前ティックからの飛び道具の移動区間全体をスイープするため、高速な矢がサンプル間で薄いモデルをすり抜けることはありません
- その区間上の候補は、モデルレジストリの反復順序とは無関係に、近い順に解決されます
- 貫通しない飛び道具は1つのモデル化ターゲットにのみ振り分けられます。Piercing(貫通)の矢は、飛行順に
貫通レベル + 1個の異なるモデル化ターゲットにヒットでき、OBBとバニラの背後のヒットボックスの両方が観測しても二重発火しません - 動的エンティティのデフォルトハンドラは、衝突時の飛び道具の速度を用いて、その衝撃を実際の飛び道具ダメージイベントとして基盤のリビングエンティティへ転送します。これにより、飛び道具という原因、戦闘プラグインの処理、射手の帰属が保持されます
- イベントをキャンセルするとFMMのコールバック/デフォルトのダメージ動作は抑止されますが、その衝突は依然としてその飛び道具のモデル化ターゲット枠を消費します。したがって、キャンセルされた非貫通のヒットでも飛び道具は消費されます
@EventHandler
public void onProjectileHitModel(ModeledEntityHitByProjectileEvent event) {
ModeledEntity target = event.getModeledEntity();
Projectile projectile = event.getProjectile();
// Cancel to prevent damage
event.setCancelled(true);
}
アイテムとモデルのユーティリティ
ModelItemFactory
モデル関連のItemStackをプログラム的に作成するためのファクトリクラス。
// Create a prop placement item (uses "model_id" PDC key)
ItemStack placementItem = ModelItemFactory.createModelItem("lamp_post", Material.STICK);
// Create a custom item from config (uses "fmm_item_id" PDC key)
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を利用可能かを追跡するシンプルなレジストリ。
// Check if a model has a display model JSON registered
boolean has3D = DisplayModelRegistry.hasDisplayModel("magic_sword");
register(String modelId)-- モデルIDを登録します(リロード中に内部的に呼び出されます)hasDisplayModel(String modelId)-- このモデル用の.jsonディスプレイモデルが存在する場合にtrueを返しますgetRegisteredModels()-- ディスプレイモデルが登録されているすべてのモデルIDのイミュータブルSet<String>を返しますshutdown()-- すべての登録をクリアします
ItemScriptManager
カスタムアイテム(YML設定にmaterial:が設定されたモデル)のプレイヤーごとのLuaスクリプトのライフサイクルを管理します。
// Get all registered custom item definitions
Map<String, PropScriptConfigFields> items = ItemScriptManager.getItemDefinitions();
// Get the active Lua script instance for a player + item
ScriptInstance instance = ItemScriptManager.getActiveScript(playerUUID, "magic_sword");
// Get all active scripts for a player
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スクリプトフックがそれらのアイテムで発火するようにできます。
// Check if a scripted item definition exists
boolean exists = ScriptedItemAPI.isValidItemId("flame_blade");
// Apply FMM scripted item data to an existing ItemStack
// This sets:
// - The fmm_item_id PDC tag (so FMM's script system recognizes the item)
// - The item model (1.21.4+) from FMM's display model registry
// Does NOT modify name, lore, enchantments, or any other item properties.
boolean success = ScriptedItemAPI.applyScriptedItemData(itemStack, "flame_blade");
// Get the config for a scripted item
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;
// Disguise a player as a loaded model. Replaces any existing disguise cleanly.
boolean ok = DisguiseAPI.disguise(player, "dragon");
// Undisguise (returns true if a disguise was removed).
DisguiseAPI.undisguise(player);
// Query state.
boolean disguised = DisguiseAPI.isDisguised(player);
String modelID = DisguiseAPI.getDisguiseModelID(player); // null if not disguised
// Snapshot of all currently disguised players.
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;
// On your plugin's enable, after WorldGuard/EliteMobs/etc. are available.
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で登録を確認できます。これはライブのプロバイダ数を報告し、現在地で両方の述語をテストします。
保護プロバイダとプロップ設置
同じ保護プロバイダはpreventPropPlacementInProtectedRegionsのプロップ設置チェックも駆動しますが、そのチェックは位置のみを見るisProtected(location)ではなくcanBuild(player, location)を呼び出します。この違いは重要です:
| プロバイダ | canBuildの挙動 |
|---|---|
| 組み込みのWorldGuardアダプタ | WorldGuard自身のバイパスを尊重したうえで、WorldGuardのtestBuildに委譲します — そのためリージョンのメンバーやオーナーは通常どおり建築できます |
| 組み込みのGriefPreventionアダプタ | その位置にクレームがなければ許可、クレーム内であればそのプレイヤーに対するGriefPrevention自身の建築権限に委譲します |
LocationAPI.registerProtectionProviderで登録したプロバイダ | !isProtected(location)にフォールバックします — 位置のみの判定で、全員をブロックします(あなたの述語が保護されていると判断した位置において) |
このフォールバックは意図的かつ保守的なものです。Predicate<Location>はプレイヤーごとの権限を表現できないため、FMMがそれを勝手に作り出すことはありません。独自のリージョンシステムで本当にプレイヤーを考慮した挙動が欲しい場合は、MagmaCoreのRegionProtectionProviderを直接実装してcanBuildをオーバーライドし、述語向けの簡易ラッパーを経由せずにLocationQueryRegistry.registerProtectionProviderで登録してください。
さらに知っておくべき挙動が2つあります:
- アダプタの失敗はフェイルクローズします。 建築クエリの途中でプロバイダが例外をスローした場合、設置は拒否され、該当プロバイダ名を含む警告がログに出力されます。黙って「許可」に流れることはありません。
- 登録されたすべてのプロバイダが同意する必要があります。 最初に拒否したプロバイダが勝ちます。
LocationOwnershipを通じて登録された所有権プロバイダは依然として位置のみの判定であり、全員をブロックします。
PropScriptConfigFields
モデルYML設定ファイル用の統合設定クラス。プロップスクリプトとカスタムアイテムの両方で使用されます。
# Example: torch_01.yml
isEnabled: true
scripts:
- torch_glow.lua
material: STICK # If set, model becomes a custom item
name: "&eMagic Torch" # Custom display name (optional)
lore: # Custom lore lines (optional)
- "&7Glows in the dark"
enchantments: # Enchantments (optional, format: NAME,LEVEL)
- "FIRE_ASPECT,1"
主要メソッド:isCustomItem()、getParsedMaterial()、getParsedEnchantments()、getScripts()。
Luaスクリプティング
FreeMinecraftModelsは、MagmaCore 2.0スクリプティングエンジンを介してプロップとカスタムアイテムの両方にLuaスクリプトをサポートします。スクリプトファイルはplugins/FreeMinecraftModels/scripts/に配置され、モデルファイルの隣にある兄弟YML設定を介してモデルにバインドされます。ディスク上のスクリプトファイルは.luaで終わる必要があります。設定エントリでは拡張子を含めても省略しても構いません。
プロップはscripts:に列挙されたすべてのスクリプトを独立したインスタンスとしてバインドします。カスタムアイテムは現在、プレイヤーとアイテムの組み合わせごとにリスト内の最初の有効なスクリプトのみをバインドします。
プロップスクリプトフック
| フック | トリガー |
|---|---|
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)-- 搭乗の試行をキューに入れます。trueが返るのはプレイヤーとマウントマネージャが有効だったという意味であり、最終的に座席が割り当てられたことを意味するわけではありませんdismount(player)-- 降車チェックをキューに入れます。trueが返るのはプレイヤーとマウントマネージャが有効だったという意味ですget_passengers()-- 現在プロップに乗っているプレイヤーのリストを返しますspawn_elitemobs_boss(filename, x, y, z)-- プロップの現在のワールドの絶対座標にEliteMobsボスをスポーンします
context.event:
- プロップの
on_left_click、on_right_click、on_zone_enter、on_zone_leave、およびプレイヤーが原因となるアイテムフックで利用可能です - 基となるフックがキャンセル可能な場合は
cancel()、uncancel()、is_cancelledが使えます player-- イベントをトリガーしたプレイヤー
context.world:
spawn_entity(entity_type, x, y, z)-- バニラエンティティをスポーンします。エンティティタイプが無効な場合はnilを返しますset_block_at(x, y, z, material)-- マテリアルが有効ならブロック変更をキューに入れます。ロードされていないチャンクはスキップされます- パーティクル、サウンド、ブロッククエリ、雷、近隣エンティティの検索も
context.cooldowns:
check_local(key, ticks)-- スクリプトごとのクールダウンをチェックして開始しますglobal_ready()/set_global(ticks)-- プロップまたはプレイヤーのオーナーに対する共有クールダウン
プレイヤーオブジェクト(context.playerまたはcontext.event.playerから):
get_held_item()-- プレイヤーが持っているアイテムを返します。typeは大文字のBukkitマテリアル名ですconsume_held_item()-- 保持アイテムを1つ削除しますhas_item(material)-- プレイヤーがアイテムを持っているかチェックしますsend_message(text)-- プレイヤーにチャットメッセージを送信しますgame_mode-- プレイヤーの現在のゲームモード
プロップスクリプトの例
return {
api_version = 1,
on_spawn = function(context)
context.prop:play_animation("idle", true, true)
end,
on_right_click = function(context)
if context.cooldowns:check_local("activate", 40) then
context.prop:play_animation("activate", false, false)
end
end
}
アイテムスクリプトの例
return {
api_version = 1,
on_equip = function(context)
context.player:send_message("&6You equipped the Flame Blade!")
end,
on_attack_entity = function(context)
-- Fire effect on hit
context.player:send_message("&cBurn!")
end,
on_unequip = function(context)
context.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、floodgate、Geyser-Spigotを
softdependとして宣言しています。プラグインを起動するのに必須なものはありませんが、特定の機能が解放されます:WorldGuard/WorldEdit/GriefPreventionはLocationAPIとプレイヤーを考慮したプロップ設置チェックに供給され、Vaultは家具ショップを、floodgate/Geyser-Spigotはモデル単位のBedrockバックエンドを有効化します。 ModeledEntityManager.reload()はプラグインの完全なリロードサイクル(onDisable/onLoad/onEnable)を実行します。メインサーバースレッドから呼び出してください。ModeledEntityManager.reload()はプラグインの完全なリロードサイクル(onDisable/onLoad/onEnable)を実行します。メインサーバースレッドから呼び出してください。
モデル、プロップ、アイテムのレジストリビューは不変スナップショットであり、変更はメインスレッドへ戻す必要があります。旧 DynamicEntity*Event、StaticEntity*Event、PropEntity*Event ファミリーは API に含まれません。現在の ModeledEntityHitByProjectileEvent などを使用してください。投射物は順序付きスイープを行い、Piercing は最大 pierce level + 1 個の有効対象を貫通します。