Luaスクリプティング: プロップ&アイテムAPI
このページでは、FreeMinecraftModelsのプロップおよびアイテムスクリプトで利用可能なすべてのAPIについて説明します:context.prop、context.item、context.event、context.player、context.world、context.zones、context.scheduler、context.state、およびcontext.log。スクリプティングが初めての場合は、まずはじめにを参照してください。
context.prop
propテーブルは、プロップエンティティの情報とそのアニメーションを制御するメソッドを提供します。これはフック呼び出しごとに新しく再構築されます。
フィールド
| フィールド | 型 | 備考 |
|---|---|---|
prop.model_id | string | 設計図モデル名(例:"torch_01") |
prop.current_location | location テーブル | コンテキストが構築された時点でのプロップの位置 |
locationテーブルには標準フィールドがあります:x、y、z、world、yaw、pitch。
例:propの情報を読み取る
return {
api_version = 1,
on_spawn = function(context)
context.log:info("Prop spawned: " .. (context.prop.model_id or "unknown"))
local loc = context.prop.current_location
if loc then
context.log:info("Location: " .. loc.x .. ", " .. loc.y .. ", " .. loc.z)
end
end
}
prop:play_animation(name, blend, loop)
プロップモデルで名前付きアニメーションを再生します。
| パラメータ | 型 | デフォルト | 備考 |
|---|---|---|---|
name | string | 必須 | モデルファイルで定義されたアニメーション名 |
blend | boolean | true | 現在のアニメーションとブレンドするかどうか |
loop | boolean | true | アニメーションがループするかどうか |
アニメーションが見つかって開始された場合はtrue、それ以外はfalseを返します。
例
return {
api_version = 1,
on_right_click = function(context)
local success = context.prop:play_animation("open", true, false)
if not success then
context.log:warn("Animation 'open' not found on this model!")
end
end
}
prop:stop_animation()
プロップで現在再生中のすべてのアニメーションを停止します。
パラメータなし。
例
return {
api_version = 1,
on_right_click = function(context)
context.prop:stop_animation()
end
}
prop:hurt_visual()
プロップに実際のダメージを与えずに、視覚的なダメージアニメーション(赤いティントフラッシュ)を再生します。
パラメータなし。
例
return {
api_version = 1,
on_left_click = function(context)
-- 殴られた時に赤くフラッシュするが、実際にはダメージを受けない
if context.event then
context.event.cancel()
end
context.prop:hurt_visual()
end
}
prop:pickup()
プロップをワールドから削除し、その場所に配置用の紙アイテムをドロップします。ドロップされたアイテムはブロックを右クリックすることでプロップを再配置できます。
パラメータなし。
例
return {
api_version = 1,
on_right_click = function(context)
-- プレイヤーが右クリックでプロップを拾えるようにする
context.prop:pickup()
end
}
prop:mount(player)
プロップ上の最初の利用可能なマウントポイントシートにプレイヤーを乗せます。モデルにはマウントポイントボーンが定義されている必要があります。
| パラメータ | 型 | 備考 |
|---|---|---|
player | エンティティテーブル | プレイヤーのエンティティテーブル(例:context.event.playerから) |
例
return {
api_version = 1,
on_right_click = function(context)
local player = context.event and context.event.player
if player then
context.prop:mount(player)
end
end
}
prop:dismount(player)
プロップ上のマウントポイントシートからプレイヤーを降ろします。
| パラメータ | 型 | 備考 |
|---|---|---|
player | エンティティテーブル | プレイヤーのエンティティテーブル |
例
return {
api_version = 1,
on_right_click = function(context)
local player = context.event and context.event.player
if player then
-- マウント/ディスマウントをトグル
local passengers = context.prop:get_passengers()
for i = 1, #passengers do
if passengers[i].uuid == player.uuid then
context.prop:dismount(player)
return
end
end
context.prop:mount(player)
end
end
}
prop:get_passengers()
プロップ上の現在の乗員すべてに対するエンティティテーブルのLua配列を返します。
パラメータなし。
例
return {
api_version = 1,
on_game_tick = function(context)
local passengers = context.prop:get_passengers()
if #passengers > 0 then
context.log:info("Prop has " .. #passengers .. " passenger(s)")
end
end
}
prop:has_mount_points()
このプロップがモデルにマウントポイントボーンを定義しているかどうかを返します。
パラメータなし。trueまたはfalseを返します。
例
return {
api_version = 1,
on_right_click = function(context)
local player = context.event and context.event.player
if player and context.prop:has_mount_points() then
context.prop:mount(player)
end
end
}
prop:spawn_elitemobs_boss(filename, x, y, z)
指定された位置にEliteMobsカスタムボスをスポーンします。サーバーにEliteMobsがインストールされている必要があります。
| パラメータ | 型 | 備考 |
|---|---|---|
filename | string | カスタムボスのファイル名(例:"my_boss.yml") |
x | number | X座標 |
y | number | Y座標 |
z | number | Z座標 |
スポーンされたボスのリビングエンティティテーブルを返します。EliteMobsがインストールされていないか、ボスファイルが存在しない場合はnilを返します。
例
return {
api_version = 1,
on_right_click = function(context)
local loc = context.prop.current_location
if loc then
local boss = context.prop:spawn_elitemobs_boss("dungeon_guardian.yml", loc.x, loc.y + 1, loc.z)
if boss then
context.log:info("Spawned boss: " .. (boss.name or "unknown"))
else
context.log:warn("Could not spawn boss -- is EliteMobs installed?")
end
end
end
}
prop:open_inventory(player, title, rows)
プレイヤーに対して永続化されるチェストインベントリGUIを開きます。コンテンツはインベントリが閉じられた際にプロップのPersistentDataContainerに保存され、再度開かれたときに復元されます。
| パラメータ | 型 | デフォルト | 備考 |
|---|---|---|---|
player | エンティティテーブル | 必須 | インベントリを表示するプレイヤー |
title | string | 必須 | インベントリのタイトル(&カラーコードに対応) |
rows | int | 3 | 行数(1-6、6は54スロット=ダブルチェスト) |
インベントリが開かれた場合はtrue、それ以外はfalseを返します。
prop:is_viewing_inventory(player)
指定されたプレイヤーが現在このプロップのインベントリを開いているかどうかを返します。
| パラメータ | 型 | 備考 |
|---|---|---|
player | エンティティテーブル | チェックするプレイヤー |
trueまたはfalseを返します。
例:インベントリが閉じられた時のクローズアニメーション
context.state["task_" .. player.uuid] = context.scheduler:run_repeating(5, 5, function(tick_context)
if not tick_context.prop:is_viewing_inventory(player) then
tick_context.prop:play_animation("close", true, false)
tick_context.scheduler:cancel(tick_context.state["task_" .. player.uuid])
end
end)
prop:place_book(player)
プレイヤーのメインハンドから記入済みまたは書き込み可能な本を取り出して、プロップに保管します。
| パラメータ | 型 | 備考 |
|---|---|---|
player | エンティティテーブル | 本を持っているプレイヤー |
成功した場合はtrueを返します。
prop:read_book(player)
プレイヤーが読むために保管された本を開きます。
| パラメータ | 型 | 備考 |
|---|---|---|
player | エンティティテーブル | 本を表示するプレイヤー |
本が開かれた場合はtrueを返します。
prop:take_book(player)
保管された本をプレイヤーのインベントリに返し、プロップから削除します。
| パラメータ | 型 | 備考 |
|---|---|---|
player | エンティティテーブル | 本を渡すプレイヤー |
成功した場合はtrueを返します。
prop:has_book()
このプロップに本が保管されているかどうかを返します。パラメータなし。
prop:drop_inventory()
保管されたインベントリの内容をすべてプロップの位置にアイテムエンティティとしてドロップし、保管されたデータをクリアします。現在表示中のプレイヤーに対しては自動的にインベントリを閉じます。
パラメータなし。成功した場合はtrueを返します。
prop:drop_book()
保管された本をプロップの位置にアイテムエンティティとしてドロップし、保管された本のデータをクリアします。
パラメータなし。成功した場合はtrueを返します。
prop:set_persistent_data(key, value)
プロップのアーマースタンドのPersistentDataContainerに文字列値を保存します。このデータはサーバー再起動とチャンクアンロードを通じて存続します。
| パラメータ | 型 | 備考 |
|---|---|---|
key | string | 一意のキー名(内部的にfmm_lua_<key>の下に保存されます) |
value | string | 保存する値。数値とブール値にはtostring()を使用してください。 |
成功した場合はtrue、プロップに裏付けのアーマースタンドがない場合はfalseを返します。
prop:get_persistent_data(key)
set_persistent_dataで以前に保存された文字列値を取得します。キーが設定されていない場合はnilを返します。
| パラメータ | 型 | 備考 |
|---|---|---|
key | string | set_persistent_dataで使用されたキー名 |
例:永続的なトグル状態
return {
api_version = 1,
on_spawn = function(context)
local saved = context.prop:get_persistent_data("active")
context.state.active = saved == "true"
end,
on_right_click = function(context)
context.state.active = not context.state.active
context.prop:set_persistent_data("active", tostring(context.state.active))
end
}
context.item
itemテーブルはアイテムスクリプトのみで利用可能です(プロップスクリプトでは利用できません)。カスタムアイテムの情報とそれを操作するメソッドを提供します。このテーブルはフック呼び出しごとに新しく再構築されます。
フィールド
| フィールド | 型 | 備考 |
|---|---|---|
item.id | string | アイテムタイプID(YML設定からのfmm_item_id) |
item:material()
アイテムのマテリアル名を文字列として返します(例:"DIAMOND_SWORD"、"STICK")。
item:get_amount() / item:set_amount(n)
アイテムのスタックサイズを取得または設定します。
| パラメータ | 型 | 備考 |
|---|---|---|
n | int | 新しいスタック量 |
item:consume(n)
アイテムのスタック量をn(デフォルト1)だけ減らします。結果の量が0以下になった場合、アイテムはプレイヤーのインベントリから削除されます。
| パラメータ | 型 | デフォルト | 備考 |
|---|---|---|---|
n | int | 1 | 消費する量 |
item:get_uses() / item:set_uses(n)
アイテムのPersistentDataContainerに保存されたカスタム使用カウンターを取得または設定します。これはバニラ耐久度から独立しており、カスタムの耐久度やチャージシステムを実装するために使用できます。
| パラメータ | 型 | 備考 |
|---|---|---|
n | int | 新しい使用回数 |
item:get_name() / item:set_name(s)
アイテムの表示名を取得または設定します。&によるカラーコードに対応しています。
| パラメータ | 型 | 備考 |
|---|---|---|
s | string | 新しい表示名(例:"&b&lFrost Sword") |
item:get_lore() / item:set_lore(table)
アイテムのロアを取得または設定します。get_lore()は文字列のテーブル(1行につき1つ)を返します。set_lore()は文字列のテーブルを受け取ります。
| パラメータ | 型 | 備考 |
|---|---|---|
table | table | 文字列の配列、1ロア行につき1つ |
例:使用回数を追跡するアイテムスクリプト
return {
api_version = 1,
on_right_click = function(context)
local uses = context.item:get_uses()
if uses <= 0 then
context.player:send_message("&cThis item is out of charges!")
return
end
context.item:set_uses(uses - 1)
context.player:send_message("&aUsed! Charges remaining: " .. (uses - 1))
end
}
item:get_durability()
アイテムのバニラ耐久度を表すcurrentとmaxフィールドを持つテーブルを返します。アイテムに耐久度バーがない場合はnilを返します。
例
local dur = context.item:get_durability()
if dur then
context.player:send_message("Durability: " .. dur.current .. "/" .. dur.max)
end
item:get_durability_percentage()
残りの耐久度を0.0から1.0の比率として返します。アイテムに耐久度バーがない場合はnilを返します。
item:use_durability(amount, can_break)
アイテムのバニラ耐久度を一定量だけ減らします。
| パラメータ | 型 | デフォルト | 備考 |
|---|---|---|---|
amount | int | 必須 | 消費する耐久度ポイント数 |
can_break | boolean | false | trueの場合、耐久度が尽きるとアイテムは破壊されます。falseの場合、耐久度は1で止まります。 |
item:use_durability_percentage(fraction, can_break)
アイテムのバニラ耐久度を最大値の割合で減らします。
| パラメータ | 型 | デフォルト | 備考 |
|---|---|---|---|
fraction | number | 必須 | 消費する最大耐久度の割合(例:0.1は10%) |
can_break | boolean | false | trueの場合、耐久度が尽きるとアイテムは破壊されます。falseの場合、耐久度は1で止まります。 |
context.event
現在のフックのイベントデータ。プロップとアイテムスクリプト両方のクリック、戦闘、インタラクションフックで利用可能です。関連するイベントがないフック(on_spawn、on_game_tick、on_destroy、on_zone_enter、on_zone_leave、on_equip)ではnilを返します。
フィールドとメソッド
| フィールドまたはメソッド | 型 | 備考 |
|---|---|---|
event.player | プレイヤーエンティティテーブル | イベントをトリガーしたプレイヤー。on_left_click、on_right_click、on_projectile_hit(射手がプレイヤーだった場合)で利用可能。すべてのフィールドとメソッドについてはプレイヤーエンティティメソッドを参照してください。 |
event.is_cancelled | boolean | イベントが現在キャンセルされているかどうか |
event.cancel() | function | イベントをキャンセルします(例:ダメージやインタラクションを防ぐ) |
event.uncancel() | function | 以前にキャンセルされたイベントをアンキャンセルします |
すべてのイベントがキャンセル可能ではありません。基底のBukkitイベントがCancellableを実装していない場合、event.cancel()とevent.uncancel()は存在せず、event.is_cancelledは常にfalseになります。
例:プロップを無敵にする
例
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
例:キャンセル状態のチェック
例
return {
api_version = 1,
on_left_click = function(context)
if context.event and not context.event.is_cancelled then
context.event.cancel()
context.log:info("Damage cancelled!")
end
end
}
スケジュール済みコールバック(scheduler:run_later、scheduler:run_repeating)内では、context.eventは常にnilです。イベントの変更はイベントフック自体の間にしか行えません。
context.world
world APIはすべてのNightbreakプラグインで共有されています。完全なリファレンスについてはcontext.worldを参照してください。
FMMのプロップはEliteMobsボスと同じMagmaCore worldテーブルを使用します。グローバルページに記載されているすべてのメソッド(get_block_at、set_block_at、spawn_particle、play_sound、strike_lightning、get_time、set_time、get_nearby_entities、get_nearby_players、spawn_entity、get_highest_block_y、raycast、spawn_firework)がFMMで利用できます。world:raycast()(光線を投射してヒットしたエンティティ/ブロックを検出)およびworld:spawn_firework()(カスタム色と形状で花火ロケットをスポーン)の完全な詳細については、MagmaCore world APIを参照してください。EliteMobsはボス、増援などをスポーンするための追加メソッドでworldテーブルを拡張します -- EliteMobs World & Environmentを参照してください。
プレイヤーエンティティメソッド
プレイヤーエンティティテーブルは、context.event.player、context.world:get_nearby_players()、ゾーンコールバックから返されます。
エンティティテーブル、リビングエンティティメソッド、プレイヤー固有メソッド、プレイヤーUIメソッドはすべてのNightbreakプラグインで共有されています。エンティティ基本フィールド、リビングエンティティのフィールドとメソッド、プレイヤー固有のフィールドとメソッド、プレイヤーUIメソッドを網羅した完全リファレンスは、MagmaCore Luaスクリプティングエンジンを参照してください。新しいプレイヤーメソッドにはplayer:get_target_entity()(レイキャストターゲティング)、player:get_eye_location()、player:get_look_direction()、player:send_block_change()(プレイヤーごとのフェイクブロック)、player:reset_block()が含まれます -- 詳細はプレイヤー固有メソッドを参照してください。
FMM固有のエンティティフィールド
FMMスクリプト内で構築されたすべてのエンティティテーブルは、FMMのLuaEntityEnricherを介してこれらの追加フィールドが自動的に付与されます:
| フィールド | 型 | 備考 |
|---|---|---|
entity.is_modeled | boolean | このBukkitエンティティがModeledEntityの基底のエンティティである場合はtrue |
entity.is_prop | boolean | このエンティティがPropEntityを支えるアーマースタンドである場合はtrue |
entity.model | テーブルまたはnil | is_modeled = trueの場合のみ設定される(下記参照) |
entity.modelが存在する場合、以下が公開されます:
| フィールド / メソッド | 備考 |
|---|---|
model.model_id | 設計図モデル名(例:"dragon") |
model.is_dynamic | DynamicEntityの場合はtrue(リビングエンティティに付属) |
model:play_animation(name, blend, loop) | 名前付きアニメーションを再生します。成功時にtrueを返します |
model:stop_animations() | すべての現在のアニメーションを停止します |
model:remove() | モデル化されたエンティティとそのすべてのボーンを即座に削除します |
on_attack_entity = function(context)
local target = context.event.target
if target and target.is_modeled then
target.model:play_animation("hurt", true, false)
end
end
EliteMobsエンティティフィールド
EliteMobsがインストールされている場合、FMMはEliteMobsのエンリッチャーに転送するため、同じエンティティテーブルが以下も公開します:
| フィールド | 型 | 備考 |
|---|---|---|
entity.is_elite | boolean | エンティティがEliteMobsによって追跡されている場合はtrue |
entity.is_custom_boss | boolean | カスタムボス設定の場合はtrue |
entity.is_significant_boss | boolean | healthMultiplier > 1を持つカスタムボスの場合はtrue(雑魚の名前付きMobをフィルタアウト) |
entity.elite | テーブルまたはnil | is_elite = trueの場合のみ設定される。level、name、health、max_health、health_multiplier、damage_multiplier、is_custom_boss、およびelite:remove()を含む |
context.zones
zones APIはすべてのNightbreakプラグインで共有されています。完全なリファレンスについてはcontext.zonesを参照してください。
context.scheduler
scheduler APIはすべてのNightbreakプラグインで共有されています。完全なリファレンスについてはcontext.schedulerを参照してください。
context.state
state APIはすべてのNightbreakプラグインで共有されています。完全なリファレンスについてはcontext.stateを参照してください。
context.log
logging APIはすべてのNightbreakプラグインで共有されています。完全なリファレンスについてはcontext.logを参照してください。
ランタイムモデル
スクリプトインスタンスごとに1つのランタイム
スクリプトがアタッチされているすべてのプロップエンティティは、独自の独立したLuaランタイムインスタンスを取得します。プロップがスポーンすると、FMMはLuaソースをロードし、新鮮なサンドボックス化された環境で評価し、返されたテーブルを保存します。プロップが削除されると、ランタイムがシャットダウンされます。
アイテムスクリプトの場合、(プレイヤー、アイテムID)ペアごとに1つのランタイムが作成されます。プレイヤーがカスタムアイテムを装備すると、FMMはそのプレイヤーとアイテムタイプ用のスクリプトインスタンスを作成します。アイテムが装備解除されると、ランタイムはシャットダウンされます。
これは以下を意味します:
- ファイルスコープで宣言されたローカル変数は、そのスクリプトインスタンスにプライベートです。
context.stateは、同じスクリプトファイルを共有していても、インスタンス間で完全に分離されています。
スケジュールされたタスクの所有権
context.schedulerを介して作成されたすべてのタスクは、それを作成したランタイムによって所有されます。プロップが削除されると:
- ランタイムがシャットダウンします。
- 所有されているすべてのタスク(ワンショットと繰り返しの両方)が自動的にキャンセルされます。
- すべてのゾーンウォッチがクリアされます。
クールダウンのスコーピング
共有スクリプティングエンジンはcontext.cooldowns:set_local、:check_local、:set_global、:check_globalを公開しています(MagmaCoreクールダウンリファレンス参照)。FMMはこれらのストアを以下のようにスコープします:
| スクリプト型 | ローカルストアスコープ | グローバルストアスコープ |
|---|---|---|
| プロップスクリプト | ScriptInstanceごと(プロップ + スクリプトファイル) | PropEntityごと(そのプロップにバインドされたすべてのスクリプト間で共有) |
| アイテムスクリプト | (player, itemId, scriptFile)トリプルごと — アイテムがアクティブスロットから外れるたびにスクリプトインスタンスが破棄されても、再装備を通じて永続化される | プレイヤーごと(そのプレイヤーが実行するすべてのFMMアイテムスクリプト間で共有) |
アイテムスクリプトは装備/装備解除サイクルごとに破棄され再構築されるため、アイテムクールダウンはScriptInstanceに存続するのではなく、プレイヤーUUIDをキーとする静的マップに保持されます。これが、アイテムをホットバーから出し入れしてもアイテムクールダウンが引き続き適用される理由です。
実行予算
すべてのフック呼び出しとすべてのコールバック呼び出しが計測されます。1回の呼び出しが50ミリ秒を超える場合、スクリプトはコンソール警告と共に無効化されます:
[Lua] my_script.lua took 73ms in 'on_game_tick' (limit: 50ms) -- script disabled to prevent lag.
予算内に収めるには:
- フック内の無限ループを避けます。
on_game_tickハンドラを軽量に保ちます -- それらは毎ティックごとに実行されます。- ティックをまたいで作業を分散するには
context.scheduler:run_repeating(...)を使用します。
完全なフックリファレンス
このテーブルは、プロップとアイテムスクリプト両方で利用可能なすべてのフックをリストしています。
プロップフック(8個)
| フック | 発火するとき | context.event |
|---|---|---|
on_spawn | プロップがワールドにスポーンする | nil |
on_game_tick | 毎サーバーティック(50ms) | nil |
on_destroy | プロップが削除される | nil |
on_left_click | プレイヤーがプロップを左クリック | damageイベント |
on_right_click | プレイヤーがプロップを右クリック | interactionイベント |
on_projectile_hit | 飛び道具がプロップに命中 | projectile hitイベント |
on_zone_enter | プレイヤーが監視中のゾーンに入る | nil |
on_zone_leave | プレイヤーが監視中のゾーンから出る | nil |
アイテムフック(22個)
| フック | カテゴリ | 発火するとき | context.event |
|---|---|---|---|
on_attack_entity | 戦闘 | プレイヤーがエンティティを攻撃 | damageイベント |
on_kill_entity | 戦闘 | プレイヤーがエンティティを倒す | deathイベント |
on_take_damage | 戦闘 | プレイヤーがダメージを受ける | damageイベント |
on_shield_block | 戦闘 | プレイヤーが盾でブロック | damageイベント |
on_shoot_bow | 戦闘 | プレイヤーが弓を射る | bow shootイベント |
on_projectile_hit | 戦闘 | プレイヤーの飛び道具が命中 | projectile hitイベント |
on_projectile_launch | 戦闘 | プレイヤーが飛び道具を発射 | launchイベント |
on_right_click | インタラクション | プレイヤーが右クリック | interactイベント |
on_left_click | インタラクション | プレイヤーが左クリック | interactイベント |
on_shift_right_click | インタラクション | プレイヤーがshift+右クリック | interactイベント |
on_shift_left_click | インタラクション | プレイヤーがshift+左クリック | interactイベント |
on_interact_entity | インタラクション | プレイヤーがエンティティを右クリック | entity interactイベント |
on_equip | 装備 | アイテムがアクティブスロットに入る | nil |
on_unequip | 装備 | アイテムがアクティブスロットから外れる | nil |
on_swap_hands | 装備 | メイン/オフハンドをスワップ | swapイベント |
on_drop | 装備 | プレイヤーがアイテムを落とす | dropイベント |
on_break_block | ユーティリティ | プレイヤーがブロックを壊す | block breakイベント |
on_consume | ユーティリティ | プレイヤーがアイテムを消費 | consumeイベント |
on_item_damage | ユーティリティ | アイテムが耐久度ダメージを受ける | item damageイベント |
on_fish | ユーティリティ | プレイヤーが釣り竿を使用 | fishイベント |
on_death | ユーティリティ | 装備中にプレイヤーが死亡 | deathイベント |
on_game_tick | ライフサイクル | 装備中の毎ティック | nil |
次のステップ
- サンプル&パターン -- ウォークスルー付きのプロップとアイテム向けの完全動作スクリプト
- トラブルシューティング -- 一般的な問題、デバッグのヒント、QCチェックリスト
- はじめに -- ファイル構造、フック、最初のスクリプトのウォークスルー