Lua Scripting: はじめに
このページでは、FreeMinecraftModels の prop 用の最初の Lua script を、空のファイルから動作するインタラクティブな prop まで段階的に書く方法を説明します。最後まで読めば、hook、context、Prop API、そして prop script ファイルの一般的な構成を理解できるようになります。
基本を理解したら、以下の関連ページに進んでください:
- Prop API --
context.prop、context.event、context.worldなどの context API - サンプルとパターン -- 学習・応用可能な完全に動作する script
- トラブルシューティング -- よくあるエラー、デバッグのヒント、QC チェックリスト
Lua prop script は現在実験的です。hook 名、ヘルパーメソッド、動作は FreeMinecraftModels の進化に伴い変更される可能性があります。本番サーバーで使用する前に十分にテストしてください。
FreeMinecraftModels は EliteMobs と同じ Lua エンジン(Magmacore)を共有しています。既に EliteMobs の Lua パワーを書いている場合、基本概念 -- hook、context、api_version、scheduler、ゾーン、sandbox -- は同一です。違いは以下の通りです:
- EliteMobs の script はボス上で実行され、
on_boss_damaged_by_player、on_enter_combatなどの hook があります。 - FMM の script は prop 上で実行され、
on_right_click、on_left_click、on_projectile_hitなどの hook があります。
context.world、context.zones、context.scheduler、context.state、context.log API は両方の plugin で同一です。このページでは FMM prop に固有の内容のみを扱います。
Prop Script とは
Prop script は plugins/FreeMinecraftModels/scripts/ フォルダにある独立した .lua ファイルです。モデルファイルと同じ場所にある YAML config ファイルから参照され、prop がワールドにスポーンされるたびに実行されます。
Prop Script が得意なこと
Prop script は以下のような場合に力を発揮します:
- プレイヤーのクリックに反応するインタラクティブな prop(ドア、レバー、ボタン)
- プレイヤーに壊されない無敵の装飾用 prop
- プレイヤーがエリアに入ったり出たりしたことを検知する近接トリガー
- インタラクションやタイマーでアニメーションを再生するアニメーション付き prop
- クリックや接近時にサウンドを再生する音声付き prop
- 静的な装飾を超えるロジックを必要とする prop の動作全般
prop が純粋に装飾的でインタラクションが不要な場合、script は必要ありません。
このページの対象読者
このページは3種類の読者を対象に書かれています:
- EliteMobs の Lua scripting を既に知っていて、FMM 固有の hook と API を学びたい人
- Lua scripting が初めてで、prop 用の完全で正確な名前のリファレンスが必要な人
- AI を使って prop script を作成しており、AI が架空のものを作り出した場合に見分けるための十分な詳細が必要な人
有用な prop script を書く前に本格的な Lua 開発者になる必要はありません。ほとんどの実用的な prop script に必要なのは以下だけです:
- 返却テーブルに有効な hook を配置する方法
contextから値を読み取る方法if ... then return endで早期リターンする方法- いくつかのヘルパーメソッドを正確に呼び出す方法
Lua ミニ入門
Lua が完全に初めての場合、必要な最低限の構文を紹介します。
変数
local を使って値を保存します:
local animation_name = "open"
local sound_volume = 1.0
関数
関数は再利用可能なロジックブロックです:
local function log_click(context)
context.log:info("Prop was clicked!")
end
if チェック
何かが特定の条件でのみ発生する場合は if を使います:
if context.event == nil then
return
end
nil
nil は「値なし」を意味します。頻繁にチェックすることになります:
if context.event ~= nil then
context.event.cancel()
end
テーブル
Lua は名前付きキーを持つオブジェクトや、返却する script 定義にテーブルを使用します:
return {
api_version = 1,
on_spawn = function(context)
end
}
コメント
-- を使ってメモを書きます:
-- Cancel the damage event so the prop cannot be broken
context.event.cancel()
より詳しい Lua 入門については、EliteMobs はじめに ページを参照してください。構文の基本は同一です。
ファイルの配置場所
Script ファイル
.lua ファイルは中央の scripts フォルダに配置します:
plugins/
FreeMinecraftModels/
scripts/
invulnerable.lua
interactive_door.lua
proximity_sound.lua
FMM は起動時に plugins/FreeMinecraftModels/scripts/ 内のすべての .lua ファイルを検出します。
モデルファイルと Config ファイル
各モデルファイルは同じディレクトリに .yml config ファイルを持つことができます:
plugins/
FreeMinecraftModels/
models/
torch_01.fmmodel
torch_01.yml <-- torch_01 の script config
scripts/
invulnerable.lua <-- torch_01.yml から参照
.yml config がモデルとその script を接続します。
Config ファイルのフォーマット
モデルファイルの横に置く YAML config ファイルには2つのフィールドがあります:
isEnabled: true
scripts:
- invulnerable.lua
| フィールド | 型 | デフォルト | 備考 |
|---|---|---|---|
isEnabled | boolean | true | この prop の script が有効かどうか |
scripts | 文字列のリスト | [] | scripts/ フォルダ内の .lua ファイル名 |
同じ prop に複数の script を添付できます。各 script はそれぞれ独立したインスタンスです。
Config の遅延生成
prop がスポーンし、対応する .yml ファイルが存在しない場合、FMM は isEnabled: true と空の scripts: リストを持つデフォルト config ファイルを自動的に作成します。これは非同期で行われるため、最初のスポーン時には script が適用されません -- config が作成され、script ファイル名を追加してから有効になります。
つまり:
- モデルファイルを
models/に配置する - prop を一度スポーンさせる(FMM が
.ymlを自動作成) - 生成された
.ymlを編集して script ファイル名を追加する - prop を再スポーンまたはサーバーをリロードする(script が有効になる)
Hook リファレンス
すべての Lua prop script ファイルはテーブルを返します。そのテーブルの各キー(api_version と priority を除く)は、以下にリストされた hook のいずれかでなければなりません。ランタイムは対応するゲームイベントが発生するたびに、一致する関数を呼び出します。
| Hook | 発火タイミング | 備考 |
|---|---|---|
on_spawn | prop がワールドにスポーンされた時 | script がバインドされた時に一度実行 |
on_game_tick | サーバーティックごとに一度(50 ms) | script がこの hook を定義している場合のみ有効 |
on_destroy | prop がワールドから削除された時 | クリーンアップ hook |
on_left_click | プレイヤーが prop を左クリック(攻撃)した時 | context.event はダメージイベント |
on_right_click | プレイヤーが prop を右クリックした時 | context.event はインタラクションイベント |
on_projectile_hit | 飛び道具が prop に当たった時 | context.event は飛び道具ヒットイベント |
on_zone_enter | プレイヤーが監視ゾーンに入った時 | ゾーン監視の設定が必要 |
on_zone_leave | プレイヤーが監視ゾーンから出た時 | ゾーン監視の設定が必要 |
最小ファイル規約
すべての Lua prop script はテーブルを return しなければなりません。
必須およびオプションのトップレベルフィールド
| フィールド | 必須 | 型 | 備考 |
|---|---|---|---|
api_version | はい | Number | 現在は 1 でなければなりません |
priority | いいえ | Number | 実行優先度。値が小さいほど先に実行。デフォルトは 0 |
| サポートされる hook キー | いいえ | Function | Hook リファレンスに記載された正確な hook 名のいずれかを使用 |
バリデーションルール
- ファイルはテーブルを返さなければなりません。
api_versionは必須で、現在は1でなければなりません。priorityは存在する場合、数値でなければなりません。- 追加のトップレベルキーはすべてサポートされている hook 名でなければなりません。
- 各 hook キーは関数を指していなければなりません。
- 不明なトップレベルキーは拒否されます。
ヘルパー関数やローカル定数は最後の return の上に配置し、返却テーブルの中には入れないでください。
最初の動作する Prop Script をゆっくり構築
ステップ1の前に:Config の設定
- モデルファイル(例:
my_prop.fmmodel)をplugins/FreeMinecraftModels/models/に配置する - prop を一度スポーンさせて
.ymlconfig を生成する plugins/FreeMinecraftModels/scripts/first_test.luaに script ファイルを作成するplugins/FreeMinecraftModels/models/my_prop.ymlを編集する:
isEnabled: true
scripts:
- first_test.lua
- prop を再スポーンまたはサーバーをリロードする
ステップ1:ファイルを読み込ませる
return {
api_version = 1,
on_spawn = function(context)
end
}
コンソールにエラーなく読み込まれれば、以下が証明されます:
- ファイルが有効な Lua である
- FMM が
scripts/フォルダで見つけた - config が正しく参照している
- 返却テーブルの形状が正しい
ステップ2:Prop に目に見える動作をさせる
return {
api_version = 1,
on_spawn = function(context)
context.log:info("Prop script loaded for: " .. (context.prop.model_id or "unknown"))
end
}
サーバーコンソールを確認してください。ログメッセージが表示されれば、hook が発火しています。
ステップ3:プレイヤーのクリックに反応する
return {
api_version = 1,
on_right_click = function(context)
context.log:info("Prop was right-clicked!")
end
}
ゲーム内で prop を右クリックしてください。コンソールにメッセージが表示されれば、クリック hook が動作しています。
ステップ4:ダメージをキャンセルして Prop を無敵にする
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
これはプリメイドの invulnerable.lua script で使用されているパターンです。ダメージイベントをキャンセルすることで、prop のバッキング armor stand が破壊されないようにします。
ステップ5:クリック時にアニメーションを再生する
return {
api_version = 1,
on_right_click = function(context)
context.prop:play_animation("open", true, false)
end
}
これは prop モデルで "open" アニメーションをブレンドありループなしで再生します。
context とは
すべての hook 関数は context という引数を1つ受け取ります。これは何かが起きるたびに FMM が渡してくれるツールボックスのようなもので、prop、ワールド、ゾーンなどと対話するために必要なすべてが含まれています。
on_right_click = function(context)
-- context.prop = クリックされた prop
-- context.event = クリックイベント(キャンセル可能)
-- context.world = パーティクル、サウンド、ブロッククエリ用ツール
-- context.state = 独自の永続ストレージ
-- context.log = コンソールログ
-- context.scheduler = 遅延タスクと繰り返しタスク
-- context.zones = 空間ゾーンの作成と監視
end
context は自分で作成するものではありません -- FMM が作成して hook に渡します。
context は hook の呼び出しごとに新しく作成されますが、context.state は例外で、prop の生存期間全体を通じて持続します。つまり、context.state にデータを保存し、後で別の hook で読み取ることができます。
主要な context API
利用可能な機能の概要です。完全な詳細は Prop API を参照してください。
-
context.prop-- Prop エンティティ。model_id、current_location、play_animation()、stop_animation()を提供します。 -
context.event-- この hook をトリガーした Bukkit イベント。on_left_click、on_right_click、on_projectile_hitで利用可能。cancel()、uncancel()、is_cancelledを提供します。イベントのない hook(on_spawnやon_game_tickなど)ではnilです。 -
context.state-- Prop の生存期間中持続するプレーンな Lua テーブル。フラグ、トグル状態、タスク ID など、hook 間で記憶しておく必要があるものを保存するために使用します。 -
context.log--log:info(msg)、log:warn(msg)、log:error(msg)によるコンソールログ。 -
context.scheduler--scheduler:run_later(ticks, callback)とscheduler:run_repeating(delay, interval, callback)による遅延タスクと繰り返しタスク。コールバックは新しい context を受け取ります。scheduler:cancel(taskId)でタスクをキャンセルできます。 -
context.world-- ワールドとの対話:パーティクル、サウンド、ブロッククエリ、雷、近くのエンティティ。完全なメソッドリストは Prop API を参照してください。 -
context.zones-- 空間ゾーン(球、円柱、直方体)の作成と監視。完全なメソッドリストは Prop API を参照してください。
メソッド構文:: vs .
Lua では object:method(arg) は object.method(object, arg) の省略形です。FMM API は両方の形式を受け付けます:
context.log:info("hello")
context.log.info("hello") -- 同じこと
すべてのドキュメントでは一貫して : を使用しています。
コピー&ペースト用テンプレート
最小の有効な Prop Script
return {
api_version = 1,
on_spawn = function(context)
end
}
無敵 Prop テンプレート
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
インタラクティブ Prop テンプレート
return {
api_version = 1,
on_spawn = function(context)
context.state.is_active = false
end,
on_right_click = function(context)
context.state.is_active = not context.state.is_active
if context.state.is_active then
context.prop:play_animation("activate", true, true)
else
context.prop:stop_animation()
end
end
}
より大きなファイルレイアウト
local ANIMATION_NAME = "idle"
local function do_something(context)
context.log:info("Doing something!")
end
return {
api_version = 1,
priority = 0,
on_spawn = function(context)
context.state.task_id = nil
end,
on_right_click = function(context)
do_something(context)
end,
on_destroy = function(context)
if context.state.task_id ~= nil then
context.scheduler:cancel(context.state.task_id)
end
end
}
最初の実践ワークフロー
新しい prop script を作成する際は、この順序で進めてください:
.luaファイルを作成し、on_spawnを動作させる。- script ファイル名を prop の
.ymlconfig に追加する。 - 実際に使いたい hook(例:
on_right_click)に変更する。 - アニメーションやエフェクトの前に、まずログメッセージを追加する。
- 実際のエフェクト(アニメーション、サウンド、パーティクル)を1つ追加する。
- その後に初めて、ヘルパー、state、scheduler ロジック、ゾーンを追加する。
この順序はデバッグを大幅に容易にします。なぜなら、一度に1つのことしか変わらないからです。
プリメイド Script
FMM には1つのプリメイド Lua script が付属しています:
invulnerable.lua-- 左クリックのダメージイベントをキャンセルし、prop を破壊不能にします。これは最もシンプルで実用的な prop script です。
その他の例は サンプルとパターン ページで見つけられます。
Lua Sandbox
Prop script は EliteMobs と同じサンドボックス化された LuaJ 環境内で実行されます。sandbox の制限は同一です。削除されたグローバル変数と利用可能な標準ライブラリ関数の完全なリストについては、EliteMobs Hooks & Lifecycle ページを参照してください。
要約:
- 削除済み:
debug、dofile、io、load、loadfile、luajava、module、os、package、require - 利用可能: すべての
math.*、string.*、table.*関数、pairs、ipairs、type、tostring、tonumber、pcall、printなど
print はサーバーコンソールに出力しますが、出力には context.log:info(msg) を推奨します。ログメッセージには script ファイル名がプレフィックスとして付くため、どの script がメッセージを生成したかを追跡しやすくなります。
次のステップ
- Prop API --
context.prop、context.event、context.world、context.zones、context.schedulerの完全なリファレンス - サンプルとパターン -- 解説付きの完全に動作する script
- トラブルシューティング -- よくある問題、デバッグのヒント、QC チェックリスト
EliteMobs の Lua パワーも書いている場合、共有 API(context.world、context.zones、context.scheduler、context.state、context.log)は同じように動作します。ボス固有の API については EliteMobs Lua ドキュメント を参照してください。