Luaスクリプティング: Prop API
このページでは、FreeMinecraftModelsのpropスクリプトで利用可能なすべてのAPIを解説します: context.prop、context.event、context.world、context.zones、context.scheduler、context.state、context.log。propスクリプティングが初めての方は、まずはじめにをお読みください。
context.prop
propテーブルは、propエンティティに関する情報とアニメーションを制御するメソッドを提供します。各hookの呼び出しごとに新しく再構築されます。
フィールド
| フィールド | 型 | 備考 |
|---|---|---|
prop.model_id | string | ブループリントのモデル名(例: "torch_01") |
prop.current_location | location table | コンテキスト構築時のpropの位置 |
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)
propモデルで指定された名前のアニメーションを再生します。
| パラメータ | 型 | デフォルト | 備考 |
|---|---|---|---|
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()
propで現在再生中のすべてのアニメーションを停止します。
パラメータはありません。
例
return {
api_version = 1,
on_right_click = function(context)
context.prop:stop_animation()
end
}
context.event
現在のhookのイベントデータ。on_left_click、on_right_click、on_projectile_hitで利用可能です。関連するイベントがないhook(on_spawn、on_game_tick、on_destroy、on_zone_enter、on_zone_leave)では nil を返します。
フィールドとメソッド
| フィールドまたはメソッド | 型 | 備考 |
|---|---|---|
event.is_cancelled | boolean | イベントが現在キャンセルされているかどうか |
event.cancel() | function | イベントをキャンセルします(例: ダメージやインタラクションを防止) |
event.uncancel() | function | 以前キャンセルされたイベントのキャンセルを取り消します |
すべてのイベントがキャンセル可能なわけではありません。基礎となるBukkitイベントが Cancellable を実装していない場合、event.cancel() と event.uncancel() は存在せず、event.is_cancelled は常に false になります。
例: propを無敵にする
例
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 です。イベントの変更はイベントhook自体の中でのみ行えます。
context.world
worldテーブルは、Minecraftのワールドを照会し操作するためのメソッドを提供します。propの現在のワールドから構築されます。
context.world APIはEliteMobsと共有されています。FMMのpropはEliteMobsのボスと同じMagmacoreのworldテーブルを使用します。ここに記載されているメソッドは、Magmacore基本実装で利用可能なものです。完全なリファレンスについては、EliteMobs World & Environmentページを参照してください -- そこにコア context.world APIの一部として記載されているメソッドはFMMでも利用可能です。
world.name
ワールド名を含むstringフィールド。
world:get_block_at(x, y, z)
指定された座標のブロックのマテリアル名を小文字のstringとして返します(例: "stone"、"air")。
| パラメータ | 型 | 備考 |
|---|---|---|
x | int | ブロックのX座標 |
y | int | ブロックのY座標 |
z | int | ブロックのZ座標 |
例
return {
api_version = 1,
on_spawn = function(context)
local loc = context.prop.current_location
if loc then
local block = context.world:get_block_at(
math.floor(loc.x),
math.floor(loc.y) - 1,
math.floor(loc.z)
)
context.log:info("Prop is standing on: " .. block)
end
end
}
world:spawn_particle(particle, x, y, z, count, dx, dy, dz, speed)
指定した場所にパーティクルを生成します。
| パラメータ | 型 | デフォルト | 備考 |
|---|---|---|---|
particle | string | 必須 | BukkitのParticle列挙名、大文字(例: "FLAME"、"DUST") |
x | number | 必須 | X座標 |
y | number | 必須 | Y座標 |
z | number | 必須 | Z座標 |
count | int | 1 | パーティクルの数 |
dx | number | 0 | X方向の拡散/オフセット |
dy | number | 0 | Y方向の拡散/オフセット |
dz | number | 0 | Z方向の拡散/オフセット |
speed | number | 0 | パーティクルの速度 |
例
return {
api_version = 1,
on_right_click = function(context)
local loc = context.prop.current_location
if loc then
context.world:spawn_particle("HEART", loc.x, loc.y + 1, loc.z, 5, 0.3, 0.3, 0.3, 0)
end
end
}
world:play_sound(sound, x, y, z, volume, pitch)
指定した場所でサウンドを再生します。
| パラメータ | 型 | デフォルト | 備考 |
|---|---|---|---|
sound | string | 必須 | BukkitのSound列挙名、大文字(例: "ENTITY_EXPERIENCE_ORB_PICKUP") |
x | number | 必須 | X座標 |
y | number | 必須 | Y座標 |
z | number | 必須 | Z座標 |
volume | number | 1.0 | 音量 |
pitch | number | 1.0 | ピッチ |
例
return {
api_version = 1,
on_right_click = function(context)
local loc = context.prop.current_location
if loc then
context.world:play_sound("BLOCK_NOTE_BLOCK_PLING", loc.x, loc.y, loc.z, 1.0, 1.2)
end
end
}
world:strike_lightning(x, y, z)
指定した場所に雷を落とします(視覚効果とダメージあり)。
| パラメータ | 型 | 備考 |
|---|---|---|
x | number | X座標 |
y | number | Y座標 |
z | number | Z座標 |
例
return {
api_version = 1,
on_projectile_hit = function(context)
local loc = context.prop.current_location
if loc then
context.world:strike_lightning(loc.x, loc.y, loc.z)
end
end
}
world:get_time()
現在のワールド時間をtick単位で返します。
world:set_time(ticks)
ワールド時間を設定します。
| パラメータ | 型 | 備考 |
|---|---|---|
ticks | int | ワールド時間(0 = 夜明け、6000 = 正午、13000 = 夜、18000 = 真夜中) |
world:get_nearby_entities(x, y, z, radius)
指定された座標を中心としたバウンディングボックス内のすべての生存エンティティのエンティティラッパーテーブルの配列を返します。
| パラメータ | 型 | 備考 |
|---|---|---|
x | number | 中心X |
y | number | 中心Y |
z | number | 中心Z |
radius | number | 検索半径(3軸すべてで半分の範囲として使用) |
例
return {
api_version = 1,
on_right_click = function(context)
local loc = context.prop.current_location
if loc then
local entities = context.world:get_nearby_entities(loc.x, loc.y, loc.z, 10)
context.log:info("Found " .. #entities .. " entities nearby")
end
end
}
world:get_nearby_players(x, y, z, radius)
指定された座標を中心としたバウンディングボックス内のすべてのプレイヤーのプレイヤーラッパーテーブルの配列を返します。
| パラメータ | 型 | 備考 |
|---|---|---|
x | number | 中心X |
y | number | 中心Y |
z | number | 中心Z |
radius | number | 検索半径 |
例
return {
api_version = 1,
on_right_click = function(context)
local loc = context.prop.current_location
if loc then
local players = context.world:get_nearby_players(loc.x, loc.y, loc.z, 20)
for i = 1, #players do
context.log:info("Nearby player: " .. (players[i].name or "unknown"))
end
end
end
}
context.zones
zonesテーブルは、空間ゾーンの作成とプレイヤーの入退場イベントの監視を可能にします。ゾーンはスクリプトインスタンスに紐づいており、propが削除されると自動的にクリーンアップされます。
zones:create_sphere(x, y, z, radius)
指定された座標を中心とした球体ゾーンを作成します。数値のゾーンハンドルを返します。
| パラメータ | 型 | 備考 |
|---|---|---|
x | number | 中心X |
y | number | 中心Y |
z | number | 中心Z |
radius | number | 球体の半径 |
zones:create_cylinder(x, y, z, radius, height)
円柱ゾーンを作成します。数値のゾーンハンドルを返します。
| パラメータ | 型 | 備考 |
|---|---|---|
x | number | 中心X |
y | number | 中心Y(底面) |
z | number | 中心Z |
radius | number | 円柱の半径 |
height | number | 円柱の高さ |
zones:create_cuboid(x, y, z, xSize, ySize, zSize)
直方体ゾーンを作成します。数値のゾーンハンドルを返します。
| パラメータ | 型 | 備考 |
|---|---|---|
x | number | 中心X |
y | number | 中心Y |
z | number | 中心Z |
xSize | number | X方向の半分の範囲 |
ySize | number | Y方向の半分の範囲 |
zSize | number | Z方向の半分の範囲 |
zones:watch(handle, onEnterCallback, onLeaveCallback)
ゾーンのプレイヤー入退場イベントの監視を開始します。プレイヤーがゾーンに入るか離れると、対応するhookが発火します(on_zone_enter または on_zone_leave)。
| パラメータ | 型 | 備考 |
|---|---|---|
handle | int | create_* 呼び出しからのゾーンハンドル |
onEnterCallback | function または nil | プレイヤーがゾーンに入った時に呼び出されます |
onLeaveCallback | function または nil | プレイヤーがゾーンを離れた時に呼び出されます |
監視が正常にセットアップされた場合は true、ゾーンハンドルが無効な場合は nil を返します。
ゾーン監視は、同じワールドのすべてのプレイヤーに対して毎サーバーティックチェックされます。パフォーマンスへの影響を避けるため、ゾーンの数を適切に保ってください。
zones:unwatch(handle)
ゾーンの監視を停止し、リソースをクリーンアップします。
| パラメータ | 型 | 備考 |
|---|---|---|
handle | int | 監視を停止するゾーンハンドル |
例: 近接トリガーゾーン
例
return {
api_version = 1,
on_spawn = function(context)
local loc = context.prop.current_location
if loc == nil then return end
-- Create a sphere zone around the prop
local handle = context.zones:create_sphere(loc.x, loc.y, loc.z, 5)
-- Watch for player enter/leave
context.zones:watch(
handle,
function(player)
context.log:info("Player entered zone!")
end,
function(player)
context.log:info("Player left zone!")
end
)
-- Store handle so we can clean up later if needed
context.state.zone_handle = handle
end,
on_destroy = function(context)
if context.state.zone_handle then
context.zones:unwatch(context.state.zone_handle)
end
end
}
context.scheduler
schedulerは、遅延タスクと繰り返しタスクを実行できます。すべてのタスクはスクリプトインスタンスに所有されており、propが削除されると自動的にキャンセルされます。
scheduler:run_later(ticks, callback)
遅延後に一度だけコールバックを実行します。数値のタスクIDを返します。
| パラメータ | 型 | 備考 |
|---|---|---|
ticks | int | サーバーティック単位の遅延(20ティック = 1秒) |
callback | function | 遅延が終了すると新しい context で呼び出されます |
例
return {
api_version = 1,
on_right_click = function(context)
context.log:info("Something will happen in 2 seconds...")
context.scheduler:run_later(40, function(delayed_context)
local loc = delayed_context.prop.current_location
if loc then
delayed_context.world:spawn_particle("EXPLOSION_EMITTER", loc.x, loc.y, loc.z, 1)
end
end)
end
}
scheduler:run_repeating(delay, interval, callback)
固定間隔でコールバックを繰り返し実行します。数値のタスクIDを返します。
| パラメータ | 型 | 備考 |
|---|---|---|
delay | int | 最初の実行前の初期遅延(ティック単位) |
interval | int | 各実行間のティック数 |
callback | function | 各インターバルで新しい context で呼び出されます |
例
return {
api_version = 1,
on_spawn = function(context)
-- Emit particles every second
context.state.particle_task = context.scheduler:run_repeating(0, 20, function(tick_context)
local loc = tick_context.prop.current_location
if loc then
tick_context.world:spawn_particle("FLAME", loc.x, loc.y + 1, loc.z, 3, 0.1, 0.1, 0.1, 0.02)
end
end)
end,
on_destroy = function(context)
if context.state.particle_task then
context.scheduler:cancel(context.state.particle_task)
end
end
}
scheduler:cancel(taskId)
IDを指定してスケジュールされたタスクをキャンセルします。
| パラメータ | 型 | 備考 |
|---|---|---|
taskId | int | run_later または run_repeating が返したタスクID |
繰り返しタスクを開始したら、必ず on_destroy で(または不要になった時に)キャンセルしてください。キャンセルを忘れると、propがサーバーから削除されるまでバックグラウンドタスクが実行され続け、パフォーマンスの無駄やエラーの原因になります。
context.state
propの存続期間全体にわたって保持される単純なLuaテーブルです。フラグ、カウンター、タスクID、トグル状態、hook間で共有する必要があるあらゆるデータの保存に使用してください。
on_spawn = function(context)
context.state.is_open = false
context.state.click_count = 0
context.state.task_id = nil
end,
on_right_click = function(context)
context.state.click_count = (context.state.click_count or 0) + 1
end
hook呼び出し間で保持されるのは context.state のみです。他のすべてのコンテキストテーブル(context.prop、context.world、context.event など)は毎回新しく再構築されます。
context.log
コンソールログメソッド。メッセージはサーバーコンソールでスクリプトファイル名がプレフィックスとして付与されます。
| メソッド | 備考 |
|---|---|
log:info(message) | 情報メッセージ |
log:warn(message) | 警告メッセージ |
log:error(message) | エラーメッセージ(機能的にはwarnと同じ) |
例
return {
api_version = 1,
on_spawn = function(context)
context.log:info("Script loaded!")
end,
on_right_click = function(context)
context.log:warn("Prop was clicked -- this is a debug warning")
end
}
ランタイムモデル
prop1つにつき1つのランタイム
スクリプトが割り当てられたすべてのpropエンティティは、独自の独立したLuaランタイムインスタンスを取得します。propがスポーンすると、FMMはLuaソースコードを読み込み、新しいサンドボックス環境で評価し、返されたテーブルを保存します。propが削除されると、ランタイムはシャットダウンされます。
これは以下を意味します:
- ファイルスコープで宣言されたローカル変数は、そのpropインスタンスに対してプライベートです。
context.stateは、同じスクリプトファイルを共有していても、propインスタンス間で完全に分離されています。
タスクの所有権
context.scheduler を通じて作成されたすべてのタスクは、それを作成したランタイムに所有されます。propが削除されると:
- ランタイムがシャットダウンします。
- すべての所有タスク -- 一回限りのものも繰り返しのものも -- 自動的にキャンセルされます。
- すべてのゾーン監視がクリアされます。
実行バジェット
すべてのhook呼び出しとすべてのコールバック呼び出しは計測されます。1回の呼び出しが50ミリ秒を超えた場合、スクリプトはコンソール警告と共に無効化されます:
[Lua] my_script.lua took 73ms in 'on_game_tick' (limit: 50ms) -- script disabled to prevent lag.
バジェット内に収めるために:
- hook内で無制限のループを避けてください。
on_game_tickハンドラを軽量に保ってください -- 毎ティック実行されます。context.scheduler:run_repeating(...)を使用して、作業を複数のティックに分散してください。
次のステップ
- サンプルとパターン -- ウォークスルー付きの完全なpropスクリプト
- トラブルシューティング -- よくある問題、デバッグのヒント、QCチェックリスト
- はじめに -- ファイル構造、hook、最初のスクリプトのウォークスルー