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

Luaスクリプティング: プロップ&アイテムAPI

このページでは、FreeMinecraftModelsのプロップおよびアイテムスクリプトで利用可能なすべてのAPIについて説明します:context.propcontext.itemcontext.eventcontext.playercontext.worldcontext.zonescontext.schedulercontext.statecontext.cooldownscontext.log。スクリプティングが初めての場合は、まずはじめにを参照してください。


context.prop

propテーブルは、プロップエンティティの情報とそのアニメーションを制御するメソッドを提供します。FMMはパフォーマンスのためにこのテーブルをプロップごとにキャッシュします。current_locationなどのフィールドは遅延評価のライブ値なので、読み取れば常に現在のプロップの状態が反映されます。

フィールド

フィールド備考
prop.model_idstring設計図モデル名(例:"torch_01"
prop.current_locationlocation テーブルプロップの現在の位置。これは一度きりのスナップショットではなく、遅延評価のライブフィールドです。

locationテーブルには標準フィールドがあります:xyzworldyawpitch

例: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)

プロップモデルで名前付きアニメーションを再生します。

パラメータデフォルト備考
namestring必須モデルファイルで定義されたアニメーション名
blendbooleantrue現在のアニメーションとブレンドするかどうか
loopbooleantrueアニメーションがループするかどうか

アニメーションが見つかって開始された場合は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()

プロップをワールドから削除し、その場所に配置用の紙アイテムをドロップします。ドロップされたアイテムはブロックを右クリックすることでプロップを再配置できます。

パラメータはなく、戻り値もありません。削除とドロップの処理はBukkitのメインスレッドにキューイングされます。

return {
api_version = 1,

on_right_click = function(context)
-- プレイヤーが右クリックでプロップを拾えるようにする
context.prop:pickup()
end
}

prop:mount(player)

プロップ上の最初の利用可能なマウントポイントシートにプレイヤーを乗せます。モデルにはマウントポイントボーンが定義されている必要があります。

パラメータ備考
playerエンティティテーブルプレイヤーのエンティティテーブル(例:context.playercontext.event.playerから)

プレイヤーが見つかり、プロップにマウントポイントがあり、マウント処理がキューイングされた場合はtrueを返します。これらの基本的な参照が有効でない場合はfalseを返します。trueが返っても、キューイングされた処理が実行された時点で最終的にシートが空いていたことまでは保証されません。

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エンティティテーブルプレイヤーのエンティティテーブル

プレイヤーが見つかり、プロップにマウントマネージャーがあり、降車チェックがキューイングされた場合はtrueを返します。これらの基本的な参照が有効でない場合はfalseを返します。

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がインストールされている必要があります。

パラメータ備考
filenamestringカスタムボスのファイル名(例:"my_boss.yml"
xnumberX座標
ynumberY座標
znumberZ座標

スポーンされたボスのリビングエンティティテーブルを返します。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エンティティテーブル必須インベントリを表示するプレイヤー
titlestring必須インベントリのタイトル(&カラーコードに対応)
rowsint3行数(1-6、6は54スロット=ダブルチェスト)

プロップとプレイヤーの参照が有効で、オープン処理がキューイングされた場合はtrue、それ以外はfalseを返します。行数はインベントリが作成される前に1〜6の範囲へクランプされます。


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に文字列値を保存します。このデータはサーバー再起動とチャンクアンロードを通じて存続します。

パラメータ備考
keystring一意のキー名(内部的にfmm_lua_<key>の下に保存されます)
valuestring保存する値。数値とブール値にはtostring()を使用してください。

成功した場合はtrue、プロップに裏付けのアーマースタンドがない場合はfalseを返します。


prop:get_persistent_data(key)

set_persistent_dataで以前に保存された文字列値を取得します。キーが設定されていない場合はnilを返します。

パラメータ備考
keystringset_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テーブルはアイテムスクリプトのみで利用可能です(プロップスクリプトでは利用できません)。カスタムアイテムの情報とそれを操作するメソッドを提供します。このテーブルはフック呼び出しごとに新しく再構築されます。

set_amountconsumeset_usesset_nameset_lore、耐久度消費系ヘルパーといったアイテムの書き込みメソッドは、変更をBukkitのメインスレッドにキューイングし、nilを返します。読み取りメソッドは、実行された時点で装備されている該当アイテムの状態を返します。

フィールド

フィールド備考
item.idstringアイテムタイプID(YML設定からのfmm_item_id

item:material()

アイテムのマテリアル名を文字列として返します(例:"DIAMOND_SWORD""STICK")。


item:get_amount() / item:set_amount(n)

アイテムのスタックサイズを取得または設定します。set_amount(n)は変更をキューイングし、nilを返します。

パラメータ備考
nint新しいスタック量

item:consume(n)

アイテムのスタック量をn(デフォルト1)だけ減らす処理をキューイングします。結果の量が0以下になった場合、アイテムはプレイヤーのインベントリから削除されます。nilを返します。

パラメータデフォルト備考
nint1消費する量

item:get_uses() / item:set_uses(n)

アイテムのPersistentDataContainerに保存されたカスタム使用カウンターを取得または設定します。これはバニラ耐久度から独立しており、カスタムの耐久度やチャージシステムを実装するために使用できます。set_uses(n)は変更をキューイングし、nilを返します。

パラメータ備考
nint新しい使用回数

item:get_name() / item:set_name(s)

アイテムの表示名を取得または設定します。&によるカラーコードに対応しています。set_name(s)は変更をキューイングし、nilを返します。

パラメータ備考
sstring新しい表示名(例:"&b&lFrost Sword"

item:get_lore() / item:set_lore(table)

アイテムのロアを取得または設定します。get_lore()は文字列のテーブル(1行につき1つ)を返します。set_lore()は文字列のテーブルを受け取り、変更をキューイングしてnilを返します。

パラメータ備考
tabletable文字列の配列、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()

アイテムのバニラ耐久度を表すcurrentmaxフィールドを持つテーブルを返します。アイテムに耐久度バーがない場合は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)

バニラ耐久度を一定量だけ減らす処理をキューイングし、nilを返します。

パラメータデフォルト備考
amountint必須消費する耐久度ポイント数
can_breakbooleanfalsetrueの場合、耐久度が尽きるとアイテムは破壊されます。falseの場合、耐久度は1で止まります。

item:use_durability_percentage(fraction, can_break)

バニラ耐久度を最大値に対する割合で減らす処理をキューイングし、nilを返します。

パラメータデフォルト備考
fractionnumber必須消費する最大耐久度の割合(例:0.1は10%)
can_breakbooleanfalsetrueの場合、耐久度が尽きるとアイテムは破壊されます。falseの場合、耐久度は1で止まります。

context.event

現在のフックのイベントデータ。プロップとアイテムスクリプトのクリック、戦闘、インタラクション、および汎用ゾーンフックで利用可能です。関連するイベントもプレイヤーのアクターも存在しないフック(on_spawnon_game_tickon_destroyon_equip)ではnilを返します。

以下のフックリファレンス表では、参考として基底のBukkitイベント型を示しています。ただしLuaのラッパーが公開するのは、ここに挙げたフィールドとメソッドだけです。

フィールドとメソッド

フィールドまたはメソッド備考
event.playerプレイヤーエンティティテーブルイベントをトリガーした、または監視中の汎用ゾーン境界を越えたプレイヤー。プロップのon_left_clickon_right_clickon_zone_enteron_zone_leave、およびプレイヤーが原因となるアイテムフックで利用可能です。すべてのフィールドとメソッドについてはプレイヤーエンティティメソッドを参照してください。
event.is_cancelledbooleanコンテキストが構築された時点でのキャンセル状態。このフィールドはcancel()uncancel()を呼び出した後に更新されません。
event.cancel()functionイベントをキャンセルします(例:ダメージやインタラクションを防ぐ)
event.uncancel()function以前にキャンセルされたイベントをアンキャンセルします
備考

すべてのイベントがキャンセル可能ではありません。基底のBukkitイベントがCancellableを実装していない場合、またはフックが背後にBukkitイベントを持たない汎用ゾーンフックである場合、event.cancel()event.uncancel()は存在せず、event.is_cancelledは常にfalseになります。

event.is_cancelledは初期状態のスナップショットとして扱ってください。自分のスクリプトがevent.cancel()event.uncancel()を呼び出し、その変更を同じフック内で後から参照する必要がある場合は、自前のローカルフラグを保持してください。

現在のFMMのeventテーブルは、targetblockprojectileitemといったBukkit固有のフィールドを公開していません。追加のコンテキストが必要な場合は、context.playercontext.event.playerplayer:get_target_entity(range)context.world:raycast(...)、または近傍エンティティのクエリを使用してください。

例:プロップを無敵にする

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_laterscheduler:run_repeating)内では、context.eventは常にnilです。イベントの変更はイベントフック自体の間にしか行えません。


context.world

これはFreeMinecraftModels/MagmaCoreのworld APIです。完全なリファレンスについてはcontext.worldを参照してください。

備考

グローバルページに記載されているすべてのメソッド(get_block_atset_block_atspawn_particleplay_soundstrike_lightningget_timeset_timeget_nearby_entitiesget_nearby_playersspawn_entityget_highest_block_yraycastplace_temporary_blockdrop_itemspawn_firework)がFMMで利用できます。world:raycast()(光線を投射してヒットしたエンティティ/ブロックを検出)、world:place_temporary_block()(一時的なブロック置換)、world:spawn_firework()(カスタム色と形状で花火ロケットをスポーン)の完全な詳細については、MagmaCore world APIを参照してください。EliteMobsのボスパワーは同じworldの基盤から出発し、ボス、増援、落下ブロック、一時ブロックなどをスポーンするためのボス固有のlocationテーブルメソッドを追加します。EliteMobs ワールドと環境を参照してください。

FMM固有のワールド追加機能

FreeMinecraftModelsは、context.worldの上に3つのオプションのEliteMobsルートヘルパーを重ねています。これらは常に存在しますが、EliteMobsがインストールされていない場合はいずれもfalseを返して何もしません:

メソッド備考
world:drop_elitemobs_procedural_loot(player, level, location?)プレイヤー向けに手続き生成されたEliteMobsアイテムを1つドロップします。手続き生成アイテムのドロップが無効の場合はfalseを返します
world:drop_elitemobs_random_loot(player, level, location?)指定レベルでプレイヤー向けにEliteMobsのルートテーブルを回します
world:drop_elitemobs_custom_loot(player, file, level, location?)プレイヤー向けに特定のEliteMobsカスタムアイテムファイルをドロップします。ファイルが解決できない場合はfalseを返します

完全なシグネチャはLua APIリファレンスにあります。ボスに関するプロップ側の対応物は、上記で説明したprop:spawn_elitemobs_boss(...)です。


プレイヤーエンティティメソッド

プレイヤーエンティティテーブルは、context.playercontext.event.playercontext.world:get_nearby_players()から返されます。MagmaCoreの汎用on_zone_enter / on_zone_leaveフックでは、context.playercontext.event.playerに入場または退出したプレイヤーが設定されます。

MagmaCoreのエンティティテーブル

グローバルページに記載されているエンティティテーブル、リビングエンティティメソッド、プレイヤー固有メソッド、プレイヤーUIメソッドが、FMMで使われているMagmaCoreのテーブルです。EliteMobsのボスパワーは似ていますがボス固有のエンティティテーブルを公開しており、ボスとエンティティに記載されています。エンティティ基本フィールド、リビングエンティティのフィールドとメソッド、プレイヤー固有のフィールドとメソッド、プレイヤーUIメソッドを網羅したFMMの完全リファレンスは、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_modeledbooleanこのBukkitエンティティがModeledEntityの基底のエンティティである場合はtrue
entity.is_propbooleanこのエンティティがPropEntityを支えるアーマースタンドである場合はtrue
entity.modelテーブルまたはnilis_modeled = trueの場合のみ設定される(下記参照)

entity.modelが存在する場合、以下が公開されます:

フィールド / メソッド備考
model.model_id設計図モデル名(例:"dragon"
model.is_dynamicDynamicEntityの場合はtrue(リビングエンティティに付属)
model:play_animation(name, blend, loop)名前付きアニメーションを再生します。エンティティモデルブリッジではblendloopのデフォルトはfalseです。成功時にtrueを返します
model:stop_animations()すべての現在のアニメーションを停止します
model:remove()モデル化されたエンティティとそのすべてのボーンを即座に削除します
on_right_click = function(context)
local player = context.event and context.event.player
if not player then return end

local target = player:get_target_entity(8)
if target and target.is_modeled then
target.model:play_animation("hurt", true, false)
end
end

EliteMobsエンティティフィールド

EliteMobsがインストールされている場合、FMMはEliteMobsのエンリッチャーに転送するため、同じエンティティテーブルが以下も公開します:

フィールド備考
entity.is_elitebooleanエンティティがEliteMobsによって追跡されている場合はtrue
entity.is_custom_bossbooleanカスタムボス設定の場合はtrue
entity.is_significant_bossbooleanhealthMultiplier > 1を持つカスタムボスの場合はtrue(雑魚の名前付きMobをフィルタアウト)
entity.eliteテーブルまたはnilis_elite = trueの場合のみ設定される。levelnamehealthmax_healthhealth_multiplierdamage_multiplieris_custom_boss、およびelite:remove()を含む

context.zones

これはFreeMinecraftModels/MagmaCoreのzones APIです。完全なリファレンスについてはcontext.zonesを参照してください。EliteMobsのボスパワーは、EliteMobsネイティブのゾーン定義を持つ別のcontext.zonesテーブルを使用します。EliteMobs ゾーンとターゲティングを参照してください。


context.scheduler

ここに記載しているscheduler APIは、FreeMinecraftModelsのスクリプトとEliteMobsのNPCスクリプトで使われるMagmaCoreのスケジューラーです。EliteMobsスタイルの名前(run_afterrun_everycancel_task)は共有スケジューラー上のエイリアスなので、どちらの命名スタイルでも動作します。ボスパワーもボス固有のコンテキストを通じて同じエイリアスを公開しています。FMMの完全なリファレンスについてはcontext.schedulerを参照してください。


context.state

state APIは、FreeMinecraftModelsのスクリプト、EliteMobsのボスパワー、EliteMobsのNPCスクリプトで共有されています。完全なリファレンスについてはcontext.stateを参照してください。


context.log

ここに記載しているログAPIは、FreeMinecraftModels/MagmaCoreのロガー(infowarnerror)です。EliteMobsのNPCスクリプトも同じロガーを使用します。EliteMobsのボスパワーはinfowarndebugを公開しています。完全なリファレンスについてはcontext.logを参照してください。


context.cooldowns

ここに記載しているクールダウンAPIは、FreeMinecraftModelsのスクリプトとEliteMobsのNPCスクリプトで使われるMagmaCore/FMM共通の引数順です:check_local(key?, duration)。EliteMobsのボスパワーも、ボス固有のバッキングストアを用いて同じ引数順を使用します。完全なリファレンスについてはcontext.cooldownsを参照してください。

メソッド備考
local_ready(key?)ローカルクールダウンが準備完了かどうかをチェックします。
local_remaining(key?)ローカルクールダウンの残りティック数、または0を返します。
check_local(key?, duration)ローカルクールダウンをアトミックにチェックして開始します。
set_local(duration, key?)チェックせずにローカルクールダウンを設定します。
global_ready()スクリプト所有者の共有グローバルクールダウンをチェックします。
set_global(duration)スクリプト所有者の共有グローバルクールダウンを設定します。

通常のプロップやアイテムのアクションのクールダウンにはcontext.cooldowns:check_local("my_key", 40)を使用してください。


ランタイムモデル

スクリプトインスタンスごとに1つのランタイム

スクリプトがアタッチされているすべてのプロップエンティティは、独自の独立したLuaランタイムインスタンスを取得します。プロップがスポーンすると、FMMはLuaソースをロードし、新鮮なサンドボックス化された環境で評価し、返されたテーブルを保存します。プロップが削除されると、ランタイムがシャットダウンされます。

アイテムスクリプトの場合、(プレイヤー、アイテムID)ペアごとに1つのランタイムが作成されます。プレイヤーがカスタムアイテムを装備すると、FMMはそのプレイヤーとアイテムタイプ用のスクリプトインスタンスを作成します。アイテムが装備解除されると、ランタイムはシャットダウンされます。

これは以下を意味します:

  • ファイルスコープで宣言されたローカル変数は、そのスクリプトインスタンスにプライベートです。
  • context.stateは、同じスクリプトファイルを共有していても、インスタンス間で完全に分離されています。

スケジュールされたタスクの所有権

context.schedulerを介して作成されたすべてのタスクは、それを作成したランタイムによって所有されます。プロップが削除されると:

  1. ランタイムがシャットダウンします。
  2. 所有されているすべてのタスク(ワンショットと繰り返しの両方)が自動的にキャンセルされます。
  3. すべてのゾーンウォッチがクリアされます。

クールダウンのスコーピング

共有スクリプティングエンジンは、ローカルクールダウンのヘルパー(local_readylocal_remainingcheck_localset_local)とグローバルクールダウンのヘルパー(global_readyset_global)を公開しています。FMMはこれらのストアを以下のようにスコープします:

スクリプト型ローカルストアスコープグローバルストアスコープ
プロップスクリプトScriptInstanceごと(プロップ + スクリプトファイル)PropEntityごと(そのプロップにバインドされたすべてのスクリプト間で共有)
アイテムスクリプト(player, itemId, scriptFile)トリプルごと — アイテムがアクティブスロットから外れるたびにスクリプトインスタンスが破棄されても、再装備を通じて永続化されるプレイヤーごと(そのプレイヤーが実行するすべてのFMMアイテムスクリプト間で共有)

アイテムスクリプトは装備/装備解除サイクルごとに破棄され再構築されるため、アイテムクールダウンはScriptInstanceに存続するのではなく、プレイヤーUUIDをキーとする静的マップに保持されます。これが、アイテムをホットバーから出し入れしてもアイテムクールダウンが引き続き適用される理由です。

この永続性は、現在のFMMランタイム内に限られます。/fmm reload、プラグインの無効化、サーバー再起動では、スクリプトマネージャのシャットダウンに伴い、アイテムクールダウンストアとプロップのグローバルクールダウンストアの両方がクリアされます。

実行予算

すべてのフック呼び出し、すべてのスケジュール済みコールバック、そしてスクリプトファイル自体の初回評価は、厳格な実行バジェットの下で実行されます。このバジェットはLua VMの内部で強制されるため、実行後に時計を確認するのではなく、コードの実行中に適用されます。

上限
現在のスレッドのCPU時間50 ミリ秒
実行された Lua 命令数250,000

先に到達した方の上限で呼び出しがLuaエラーとともに中断され、そのスクリプトインスタンスが無効化されます。メッセージは次のとおりです:

Lua instruction budget exceeded (250000 instruction limit)
Lua CPU-time budget exceeded (50ms current-thread CPU limit)

チェックは命令単位で行われるため、while true do end がサーバーをフリーズさせることはありません。

バジェットの時間側は、ウォールクロックではなく現在のスレッドのCPU時間として計測されます。そのため、サーバースレッドがスケジュールから外れていた時間はスクリプトに課金されません。現在のスレッドのCPU時間計測が利用できないJVMでは、MagmaCoreは意図的により寛容な250ミリ秒の経過時間の上限(Lua elapsed-time fallback budget exceeded (250ms fallback; current-thread CPU time unavailable))にフォールバックしつつ、同じ250,000命令の上限を維持します。これにより、いずれの場合でも終了しないスクリプトは制限された状態に保たれます。

ネストした呼び出しは1つのバジェットを共有します。フックがコールバックを呼び、そのコールバックがさらに別のものを呼ぶ場合、チェーン全体がCPU時間50ms/250,000命令の1つの割り当てとして計測され、それぞれに割り当てが与えられるわけではありません。

スクリプトファイルの初回評価時にはまだインスタンスが存在しないため、その定義は無効化されるのではなく拒否され、登録されません。

予算内に収めるには:

  • フック内の無限ループを避けます。
  • on_game_tickハンドラを軽量に保ちます -- それらは毎ティックごとに実行されます。
  • ティックをまたいで作業を分散するにはcontext.scheduler:run_repeating(...)を使用します。

完全なフックリファレンス

このテーブルは、プロップとアイテムスクリプト両方で利用可能なすべてのフックをリストしています。

context.event列は、基底となるBukkitイベントのファミリーを示しています。FMMのLuaイベントラッパーが公開するのは、該当する場合のevent.playerevent.is_cancelledevent.cancel()event.uncancel()だけです。

有効なプロップフック(7個)

フック発火するときcontext.event
on_spawnプロップがワールドにスポーンするnil
on_game_tick毎サーバーティック(50ms)nil
on_destroyプロップが削除されるnil
on_left_clickプレイヤーがプロップを左クリックdamageイベント
on_right_clickプレイヤーがプロップを右クリックinteractionイベント
on_zone_enterプレイヤーが監視中のゾーンに入るゾーンのプレイヤーアクター(context.player / context.event.player。キャンセル不可)
on_zone_leaveプレイヤーが監視中のゾーンから出るゾーンのプレイヤーアクター(context.player / context.event.player。キャンセル不可)
予約済みのプロップフック

現在のスクリプトバリデータはプロップスクリプトでon_projectile_hitを受け付けますが、現在のランタイムはまだ飛び道具の命中をプロップスクリプトへディスパッチしません。スクリプト付きアイテムに紐づく飛び道具の挙動にはアイテムのon_projectile_hitを使用し、プラグイン側でモデル化エンティティの飛び道具処理を行う場合はBukkitのModeledEntityHitByProjectileEvent APIを使用してください。

アイテムフック(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

次のステップ

/fmm reload は再構築前にスクリプト所有のタスクとクールダウンを解除します。共有タスクには run_afterrun_everycancel_task、ワールドには raycastplace_temporary_blockdrop_item があります。