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

Luaスクリプティング:はじめに

このページでは、FreeMinecraftModelsのプロップ用Luaスクリプトを、空のファイルから動作する対話型スクリプトまで順に作ります。フック、コンテキスト、プロップAPI、スクリプトファイルの基本構造を学べます。

基礎に慣れたら、次のページへ進んでください。

実験的機能

Luaプロップスクリプトは実験的機能です。FreeMinecraftModelsの開発に伴い、フック名、ヘルパーメソッド、挙動が変わる可能性があります。本番サーバーで使う前に十分にテストしてください。

EliteMobsのLuaとの関係

FreeMinecraftModelsはMagmaCoreのLuaランタイムを使います。EliteMobsのLuaパワーを書いた経験があれば、テーブルを返すファイル、api_version、フック、context、状態、クールダウン、スケジューリング、サンドボックスは共通の概念です。ただし、フックとコンテキストのメソッド名はプラグインによって異なります。

  • EliteMobsのスクリプトはボス上で動き、on_boss_damaged_by_player、on_enter_combat などを使います。
  • FMMのプロップスクリプトはプロップ上で動き、on_right_click、on_left_click、on_zone_enter などを使います。
  • アイテムのエンチャントには、自作エンチャント専用のコンテキストがあります。

ここで説明する context.world、context.zones、context.scheduler、context.state、context.log はFreeMinecraftModels/MagmaCore版です。EliteMobsのNPCスクリプトは同じ汎用MagmaCoreテーブルに context.npc を加えたものを使います。ボスパワーでは、いくつかのテーブルがボス専用の実装になります。このページはFMMプロップ固有の内容を扱います。


プロップスクリプトとは​

plugins/FreeMinecraftModels/scripts/ に置く独立した .lua ファイルです。モデルの隣のYAML設定から参照され、プロップがワールドに出現すると実行されます。

プロップスクリプトの用途​

次のような動作に使えます。

  • クリックに反応する扉、レバー、ボタン
  • 既定の左クリックダメージを無視する装飾
  • プレイヤーが範囲に入った、または出たことを検出する仕掛け
  • 操作やタイマーでアニメーションを再生するプロップ
  • クリック時や接近時に音を鳴らすプロップ
  • 静的な装飾を超えるロジックが必要な動作

操作を必要としない純粋な装飾なら、スクリプトは不要です。


カスタムアイテムとエンチャント​

カスタムアイテムは引き続きモデルの隣のYAMLで material を指定しますが、効果には名前空間付きエンチャントを使います。旧装備アイテムスクリプトのランタイムは廃止されました。空でない scripts: リストを持つカスタムアイテムは、コンソールに情報メッセージを出して読み飛ばされます。定義自体は変更されません。

scripts/ 内で旧装備アイテムスクリプトと判定されたLuaファイルは、検出前とインポート後に plugins/MagmaCore/outdated files/FreeMinecraftModels/<archive batch>/scripts/ へ保存されます。判定には、on_equip や on_attack_entity などの廃止されたアイテムフックを含む、有効な旧スクリプト定義が必要です。プロップスクリプト、共有フックだけを使うファイル、不正なスクリプト、enchantments/ の現在の効果は対象外です。復旧方法は廃止された設定ファイルを参照してください。

現在のアイテム定義はカスタムアイテムと魔法武器、効果は自作エンチャントを参照してください。プロップの scripts: リストは引き続き使えます。

対象読者​

次の方を対象にしています。

  • EliteMobsのLuaを知っていて、FMM固有のフックとAPIを学びたい方
  • Luaを初めて使い、プロップ用の正確な名称を含むリファレンスが必要な方
  • AIで下書きしたスクリプトに、存在しないAPIが混ざっていないか判断したい方

役立つプロップスクリプトを書くために、Lua全体を習得する必要はありません。多くの場合、次が分かれば十分です。

  • 返すテーブルに有効なフックを置く
  • context から値を読む
  • if ... then return end で早期終了する
  • 必要なヘルパーメソッドを正確に呼ぶ

簡単なLua入門​

ほとんどのスクリプトは、変数(local x = 5)、関数(function foo() end)、条件分岐(if x then ... end)、テーブル({key = value})、nil(値がないこと)を使います。セミコロンは不要で、ブロックは波かっこではなく end で閉じます。

詳しい説明と例は MagmaCore Luaスクリプティングエンジン — 簡単なLua入門 を参照してください。Nightbreakの全プラグインで共通の内容です。


ファイルの配置場所​

スクリプトファイル​

.lua ファイルは中央のスクリプトフォルダーに置きます。

plugins/
FreeMinecraftModels/
scripts/
invulnerable.lua
interactive_door.lua
proximity_sound.lua

FMMはスクリプトプロバイダーの初期化時に plugins/FreeMinecraftModels/scripts/ 内を再帰的に検索し、.lua のソースをキャッシュします。関連付けは相対パスではなくファイル名を使うため、サブフォルダー間でも名前を重複させないでください。Luaの追加や編集後は、新しい関連付けを作る前に /fmm reload を成功させてください。プロップの再生成だけではLuaソースを読み直しません。

モデルの scripts: リストには、明確にするため .lua 拡張子を含めてください。省略した場合も内部で補われます。ただし、ディスク上のファイルには .lua 拡張子が必要で、名前は大文字と小文字を区別します。

モデルファイルと設定ファイル​

モデルと同じディレクトリに、対応する .yml 設定ファイルを置けます。

plugins/
FreeMinecraftModels/
models/
torch_01.fmmodel
torch_01.yml <-- script config for torch_01
scripts/
invulnerable.lua <-- referenced by torch_01.yml

この .yml がモデルとスクリプトを結び付けます。


設定ファイルの形式​

モデルの隣のYAMLには、次のフィールドがあります。

isEnabled: true
voxelize: false
solidify: false
scripts:
- invulnerable.lua

プロップ用のフィールドは次のとおりです。

フィールド型既定値説明
isEnabled真偽値true定義を有効にするか
scripts文字列リスト[]scripts/ 内のプロップ用Luaファイル名
voxelize真偽値falseブロック格子と90度単位の回転に配置を合わせる
solidify真偽値falseボクセル化したプロップにパケットのバリアブロックを追加する

リスト内の各プロップスクリプトには独立したインスタンスが作られます。手持ちアイテムには、代わりに material、name、lore、名前空間付き enchantments を定義します。カスタムアイテムを参照してください。

設定ファイルの遅延生成​

プロップ出現時に隣の .yml がなければ、FMMは isEnabled: true と空の scripts: リストを持つ既定の設定を非同期で作ります。初回出現時にはスクリプトが付かず、生成後にファイル名を追記する必要があります。

  1. モデルを models/ に置きます。
  2. プロップを一度出現させ、.yml を生成します。
  3. 生成された .yml にスクリプト名を追加します。
  4. YAMLまたはLuaを編集したら /fmm reload を正常に完了させ、新しいプロップを置いてログや操作を確認してください。プロップ設定、設置判定、メニューのスクリプト一覧は同じ読み込み済みカタログを使います。再生成だけではYAMLを読み直しません。

フックリファレンス​

Luaプロップスクリプトはテーブルを返します。api_version と priority 以外のキーは、次のフックのいずれかでなければなりません。対応するゲームイベントが発生すると関数が呼ばれます。

フック呼ばれるタイミング説明
on_spawnプロップがワールドに出現したとき、またはチャンクとともに再び読み込まれたときスクリプトが関連付けられるたびに一度実行
on_game_tickサーバーティックごと(20 TPSなら50 ms)このフックを定義した場合だけ有効
on_destroyプロップが完全に削除されたとき後始末用。プロップのチャンクがアンロードされたときやFMMのリロード時には呼ばれない
on_left_clickプレイヤーがプロップを左クリックで叩いたときcontext.event にFMMの既定ダメージのキャンセルフラグが入る
on_right_clickプレイヤーがプロップを右クリックしたときcontext.event にFMMの既定操作のキャンセルフラグが入る
on_zone_enterプレイヤーが監視範囲に入ったときゾーンの監視設定が必要
on_zone_leaveプレイヤーが監視範囲を出たときゾーンの監視設定が必要
on_projectile_hit投射物がプロップに当たったときcontext.projectile は投射物、context.event.player は発射者。プロップAPIを参照

アイテムの効果​

旧装備アイテムフックは呼び出されません。効果は、専用のフックとコンテキストを持つ自作エンチャントに定義します。エンチャントのLuaをプロップの scripts: リストに付けたり、旧アイテムスクリプトをそのままコピーしたりしないでください。

最小ファイル規約​

すべてのLuaプロップスクリプトはテーブルを return します。

必須と任意のトップレベルフィールド​

フィールド必須型説明
api_versionはい数値現在は 1 が必要
priorityいいえ数値指定すれば検証されるが、FMMはこの値で並べ替えない。プロップは scripts: リスト順に実行
対応するフックキーいいえ関数フックリファレンスの正確な名前を使う

検証規則​

  • ファイルは必ずテーブルを返します。
  • api_version は必須で、現在は 1 です。
  • priority を指定するなら数値にします。
  • それ以外のトップレベルキーは対応するフック名に限られます。
  • 各フックの値は関数でなければなりません。
  • 未知のトップレベルキーは拒否されます。
注記

priority はMagmaCore系ランタイム間の可搬性に役立ちますが、FMMの実行順序は設定で決まります。モデルの scripts: リストに実行したい順で並べてください。

ヘルパー関数とローカル定数は、返すテーブルの中ではなく、最後の return より前に定義します。


最初のプロップスクリプトを順に作る​

ステップ1の前に:設定を用意する​

  1. my_prop.fmmodel などのモデルを plugins/FreeMinecraftModels/models/ に置きます。
  2. プロップを一度出現させ、.yml を生成します。
  3. plugins/FreeMinecraftModels/scripts/first_test.lua を作ります。
  4. plugins/FreeMinecraftModels/models/my_prop.yml を編集します。
isEnabled: true
scripts:
- first_test.lua
  1. 下のステップ1のLua内容を保存し、/fmm reload を実行して成功を確認します。必要ならプロップを再生成します。以降の各Lua編集後も、再読み込みの成功を確認してください。

ステップ1:ファイルを読み込ませる​

return {
api_version = 1,

on_spawn = function(context)
end
}

コンソールにエラーがないことは最初の確認になります。次のステップの明示的なログで、以下を確認してください。

  • ファイルが有効なLuaである
  • FMMが scripts/ で発見した
  • 設定が正しく参照している
  • 返すテーブルの構造が正しい

ステップ2:確認できる動作を追加する​

return {
api_version = 1,

on_spawn = function(context)
context.log:info("Prop script loaded for: " .. (context.prop.model_id or "unknown"))
end
}

コンソールにメッセージが出れば、フックが呼ばれています。

ステップ3:クリックに反応する​

return {
api_version = 1,

on_right_click = function(context)
context.log:info("Prop was right-clicked!")
end
}

ゲーム内でプロップを右クリックします。コンソールにメッセージが出ればクリックフックが動いています。

ステップ4:左クリックダメージをキャンセルする​

return {
api_version = 1,

on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}

同梱の invulnerable.lua で使うパターンです。そのクリックに対するFMMの既定ダメージをキャンセルします。基となるエンティティをすべてのダメージ源から保護するわけではありません。

ステップ5:クリックでアニメーションを再生する​

return {
api_version = 1,

on_right_click = function(context)
context.prop:play_animation("open", true, false)
end
}

現在の状態のティック後に、ループしない「open」アニメーションを要求します。モデルにそのアニメーションが必要です。blend はクロスフェードではなく、待機枠は1つなので後の要求が前の要求を置き換えることがあります。終端の死亡状態は要求を拒否する場合があります。受付だけでは再生を証明できないため、ゲーム内で表示を確認してください。


context とは?​

各フックは context という引数を1つ受け取ります。プロップ、ワールド、ゾーンなどを操作するための道具が入っています。

自分で作る必要はなく、FMMが生成して渡します。共有APIの context.state、context.log、context.cooldowns、context.scheduler、context.world、context.zones はMagmaCore Luaスクリプティングエンジンを参照してください。


主な context API​

概要を以下に示します。詳しくはプロップAPIを参照してください。

  • context.prop — プロップスクリプト専用のプロップエンティティ。model_id、current_location、play_animation()、stop_animation() を提供します。

  • context.player — プロップのクリックフックや汎用ゾーンフックを起動したプレイヤー。on_projectile_hit では、プレイヤーが投射物を発射した場合はその発射者です。ライフサイクルフック、予約済みコールバック、プレイヤーが関係しないフックでは nil です。

  • context.event — クリックフックではFMMのキャンセルフラグと実行者、on_projectile_hit では投射物の命中イベントとその発射者、汎用ゾーンフックでは実行者だけを持つテーブルです。event.player、is_cancelled、クリック時と投射物の命中時の cancel() / uncancel() を提供します。Bukkit固有の target、block、projectile、item はありません。on_spawn や on_game_tick など、イベントもプレイヤーもないフックでは nil です。

  • context.projectile — on_projectile_hit での投射物エンティティ。それ以外のすべてのフックでは nil です。on_projectile_hitを参照してください。

  • context.state — スクリプトインスタンスの生存期間中保持されるLuaテーブル。context.stateを参照してください。

  • context.cooldowns — ローカルとグローバルのクールダウン。スクリプト単位では context.cooldowns:check_local("key", ticks) を使います。context.cooldownsを参照してください。

  • context.log — コンソールへのログ。context.logを参照してください。

  • context.scheduler — 遅延と繰り返しタスク。context.schedulerを参照してください。

  • context.world — パーティクル、音、ブロック照会、雷、周辺エンティティなど。context.worldを参照してください。

  • context.zones — 球、円柱、直方体などの範囲を作成・監視。context.zonesを参照してください。


メソッド構文:: と .​

違いはMagmaCore Luaスクリプティングエンジンを参照してください。FMMのAPIはどちらも受け付けます。


コピーして使えるテンプレート​

最小の有効なプロップスクリプト​

return {
api_version = 1,

on_spawn = function(context)
end
}

左クリックダメージのキャンセル​

return {
api_version = 1,

on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}

対話型プロップ​

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
}

最初の実践的な手順​

新しいプロップスクリプトは次の順で作ります。

  1. .lua を作り、on_spawn を動かします。
  2. プロップの .yml にスクリプト名を追加します。
  3. on_right_click など必要なフックに切り替えます。
  4. アニメーションや効果より先にログを追加します。
  5. アニメーション、音、パーティクルなど、実際の効果を1つ追加します。
  6. その後にヘルパー、状態、予約処理、ゾーンを追加します。

Luaを編集するたびに保存し、/fmm reload を成功させてから新しい動作を確認してください。各ステップでは1つだけ変更し、ログや目に見える効果で何が動いたか確認します。


同梱スクリプト​

FMMは4つの標準Luaスクリプトがなければ書き出します。認識した古い標準ソースも置き換えますが、それ以外の既存編集は保持します。現在の標準動作と異なる場合は、インストール済みファイルを確認してください。

  • invulnerable.lua — FMMの既定の左クリックダメージをキャンセルします。すべてのダメージ源を防ぐものではありません。
  • pickupable.lua: 左クリックの既定ダメージを防ぎ、許可された打撃3回で回収を要求します。カウンターは関連付け単位なのでプレイヤー間で共有し、前の打撃から100サーバーティック後のタスクでリセットします。許可された打撃は赤い被ダメージ表示を要求します。保護場所やダンジョンでは、FMMの保護回避権限またはオペレーター状態がない限り操作を阻止します。
  • storage_double.lua: 54スロットのインベントリ、開閉の音とアニメーションを要求します。同じ保護確認とオペレーター例外を使い、閲覧者の追跡を5サーバーティックごとに確認します。プロップのインベントリはすべての閲覧者で共有され、最後の閲覧者が閉じたときかチャンクがアンロードされたときに保存されます。破壊時には drop_inventory() を要求し、これは開いているインベントリを先に保存するため、開いたままのインベントリに置いたアイテムもドロップに含まれます。詳しくはprop:open_inventoryを参照してください。
  • storage_single.lua — 同じ仕組みで、6行ではなく3行、27スロットです。

他の例はサンプルとパターンを参照してください。


Luaサンドボックス​

プロップスクリプトはEliteMobsと同じLuaJサンドボックスで動き、制限も同じです。削除されるグローバルと使用可能な標準ライブラリ関数の一覧はMagmaCore Luaスクリプティングエンジンを参照してください。


次のステップ​

EliteMobsのボス用Luaでも、サンドボックス、api_version、状態テーブル、クールダウン、フックを使う構造は共通です。ただしボスのコンテキストはEliteMobs固有のメソッド名を使います。正確なAPIはEliteMobs Luaドキュメントを参照してください。