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

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スクリプトアイテムメタデータを刻印する

ModeledEntityManager.getAllEntities()getDynamicEntities()propEntities()は、その時点のコピーを返します。返されたセットやマップを変更してもFMMのライブレジストリは変更されません。存在確認には、レジストリ全体を保持して繰り返しコピーするのではなくmodelExists(String)を使用してください。

コアランタイム型

  • 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を返します。

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エンティティからそれに紐づくモデルへの静的な逆引き。存在しない場合はnull
  • ModeledEntity#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済みプロップにクライアント側の当たり判定を与える、パケットのみのバリアブロックを制御します
Nametags need a tag_ bone in the model

setDisplayNamesetDisplayNameVisibleはモデルのネームタグボーンを走査しますが、それらは名前がtag_で始まるボーンにしか存在しません。該当するボーンがないモデルではそのリストが空になるため、どちらの呼び出しも成功したうえで何もしません — 例外もログ行も出ません。

フォールバックはありません。DynamicEntityは基盤となるリビングエンティティをクライアントから隠すため、バニラのモブのネームタグも表示されません。結果として、プラグインがエラーなく名前を設定したにもかかわらず、まったく名前のないモブになります。

プラグインがモデルに名前を付ける場合(ボス、NPC、その他ユーザーに見えるもの)、配布するモデルにtag_ボーンを必須とするか、アタッチ時にgetNametagBones().isEmpty()をチェックしてコンテンツ作者に警告してください。モデル作成に関する注記を参照してください。

イベントサーフェス

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

  • ModeledEntityLeftClickEvent
  • ModeledEntityRightClickEvent
  • ModeledEntityHitboxContactEvent
  • ModeledEntityHitByProjectileEvent

4つすべてがキャンセル可能なBukkitイベントであり、FMMの組み込み検出パスはこれらをメインサーバースレッド上でディスパッチします。イベントをキャンセルすると、対応するFMMのコールバック/デフォルト動作が抑止されます。ヒットボックス接触のスキャンは2サーバーティックごとに実行されます。クリックイベントには依然としてプレイヤーごとの短い重複排除ウィンドウがあり、パケットインタラクション経路とOBBレイトレース経路が同じアクションを2回発火させることはありません。

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

  • FmmReloadedEvent -- FMMが起動時の初期化シーケンスを完了した後および毎回の/fmm reload後に発火します。常にメインサーバースレッドで発火します。

公開されているインタラクションのインターフェースは、意図的にモデル型に依存しない形になっています。古いStaticEntity*EventDynamicEntity*EventPropEntity*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統合

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_dungeonem.location.is_protectedチェック(pickupable.luastorage_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_clickon_right_clickon_zone_enteron_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スクリプティングエンジン、および共有のLocationQueryRegistryWorldFolderResolverを含む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*EventStaticEntity*EventPropEntity*Event ファミリーは API に含まれません。現在の ModeledEntityHitByProjectileEvent などを使用してください。投射物は順序付きスイープを行い、Piercing は最大 pierce level + 1 個の有効対象を貫通します。