-
Notifications
You must be signed in to change notification settings - Fork 7
create effect
- 1. 事前に済ませてね
- 2. テンプレートを作成する
- 3. エフェクトの基本情報の設定
- 4. エフェクトの処理を記述する
- 5. Fieldを使ったカスタムデータ
- 6. 継承 (extends) の仕組み
- 7. エフェクトの付与・削除 (APIから呼ぶ側)
- 8. ハマりポイント
エフェクトは、 Mob やプレイヤーに一定期間 / 永続で効果を付与する仕組みだよ。Asset/data/asset/functions/effect/<ID>.<エフェクト名>/に実装が置かれていて、 ID で参照する。
神器のEquipment.Effectsから自動で付与されたり、api:entity/mob/effect/giveから手動で付与したりするよ。
- TSBリポジトリのクローン, ブランチを切っている状態
- 推奨拡張機能の導入
- スプレッドシートの ID 欄からエフェクト ID を取得
MCDatapackUtilityを利用してエフェクトアセットのテンプレートを作成するよ。
Datapack: Create Datapack templateを実行してね。デフォルトだとShift + Alt + D -> Shift + Alt + Tを押すと動作するよ。
下記のメニューが出てくるからデータパックにテンプレートを追加するを選択してね。

データパックはAssetフォルダを指定。命名規則は神器・モブと同じ。
テンプレートの種別では「エフェクト/テンプレート」を選んでね。さらに必要な処理 (given/tick/end/remove/re-given) のチェックも入れる。
これでテンプレートがAsset/data/asset/functions/effect/<エフェクト名>/~に生成されてるはずだよ。生成されるファイル構成はおおまかにこんな感じ:
asset/functions/effect/<エフェクト名>/
register.mcfunction # ID/Name/Duration等の基本情報定義
_/register.mcfunction # context.idで自分宛か判別するdispatcher
_/given.mcfunction # dispatcher (given用)
_/tick.mcfunction # dispatcher (tick用)
_/end.mcfunction # dispatcher (end用)
_/remove.mcfunction # dispatcher (remove用)
_/re-given.mcfunction # dispatcher (re-given用)
given/.mcfunction # 実装本体 (付与時)
tick/.mcfunction # 実装本体 (毎tick)
end/.mcfunction # 実装本体 (効果時間終了時)
remove/.mcfunction # 実装本体 (外部からの削除)
re-given/.mcfunction # 実装本体 (再付与)
_/*.mcfunctionはテンプレート生成時に自動で作られて、asset:context idが自分の ID と一致するかチェックして本体を呼ぶ仕組み。基本的に触る必要はないよ。
注: ここから先基本的に function 名は下記のような省略した形で記載するよ
Asset/data/asset/functions/effect/<エフェクト名>/register.mcfunction->~/register.mcf
生成されたテンプレートの~/register.mcfを編集していくよ。
| 設定名 | 必須 | 設定する型 | 説明 | デフォルト | 例 |
|---|---|---|---|---|---|
| ExtendsSafe | × | boolean | 他のエフェクトから継承されることを許可するか | false |
… value true |
| ID | o | int | エフェクトの ID スプレッドシートの ID 欄の物 |
- | … value 31 |
| Name | o | TextComponent | エフェクトの名前 | - | … value '{"text":"低速落下"}' |
| Description | o | TextComponent[] | エフェクトの説明文 | - | … value ['{"text":"落下速度が低下する"}'] |
| Duration | o* | int | 効果時間 (tick)。 *API 呼び出し側で指定するなら省略可能 |
- | … value 200 |
| Stack | × | int | 初期スタック数 | 1 |
… value 3 |
| DurationOperation | × | string | 再付与時の効果時間の計算方法 "replace"/"add"/"forceReplace" |
"replace" |
… value "add" |
| StackOperation | × | string | 再付与時のスタックの計算方法 "replace"/"add"/"forceReplace" |
"replace" |
… value "forceReplace" |
| MaxDuration | × | int | 最大効果時間 | 2147483647 |
… value 1200 |
| MaxStack | × | int | 最大スタック数 (フルセット防具用なら 4 にする) | 2147483647 |
… value 4 |
| IsBadEffect | o | boolean | 悪い効果か (UI の色分け用) | - | … value true |
| ProcessOnDied | × | string | 死亡時のエフェクト処理 ("remove" / "keep") | "remove" |
… value "keep" |
| RequireClearLv | × | int | 解除難易度 (運用上は 1 〜 3 、 4 は未使用領域) | 1 |
… value 3 |
| Visible | × | boolean | エフェクト一覧 UI に表示するか | true |
… value false |
| StackVisible | × | boolean | スタック数を UI に表示するか | true |
… value false |
| Field | × | compound | カスタムフィールド (given/tick 時にasset:context this.<key>で参照可能) |
{} |
… value {Power:3,Color:16777215} |
再付与時 (= 既に同じエフェクトが付いてる状態で再度付与された時) の値の決め方を指定する。
| 値 | 動作 |
|---|---|
"replace" |
既存値と新規値の大きい方を採用 (デフォルト) |
"add" |
既存値に新規値を加算 |
"forceReplace" |
新規値で強制上書き |
例: Duration:"add"を指定したエフェクトに、 Duration=100 で 2 回付与すると、合計 200tick になる。
プレイヤーや Mob が死亡した時、そのエフェクトをどう扱うかを決める。
| 値 | 動作 |
|---|---|
"remove" |
死亡時に即座に削除 (デフォルト) |
"keep" |
死亡しても継続。リスポーン後もそのまま残る |
フルセット防具用の EffectAsset は"keep"にすることが多いよ (装備が外れない限り効果を維持したいので)。
エフェクトの「解除難易度」。 api:entity/mob/effect/remove/from_level で Argument.ClearLv を指定したエフェクト削除 API でのみ消える (= RequireClearLv <= Argument.ClearLv のエフェクトが削除対象)。牛乳 (UsedMilk スコアが立つ操作) で消えるのは RequireClearLv:1 のみ。
| 値 | 解除条件 | デバフの想定 | バフの想定 |
|---|---|---|---|
| 1 | 牛乳 or レベル 1 以上の解除 API で消える | 雑に敵から付与される一般デバフ | (未使用領域) |
| 2 | レベル 2 以上の解除 API でのみ消える | 雑魚の中でも強い敵や天使から付与されるデバフ | (未使用領域) |
| 3 | レベル 3 以上の解除 API でのみ消える (基本的に解除されない) | 解除不可デバフ (主に神器で付与、解除されない想定) | バフはすべて Lv3 固定 (解除されない想定) |
| 4 | (内部対応はあるが、運用上未使用) | - | - |
- Lv3 はバフ・デバフ共に「解除されない」 想定 : デバフ側は神器付与の解除不可デバフ、バフ側は装備中ずっと続くもの (フルセット効果等)。どちらも Lv3 で書く
- Lv1 / Lv2 のバフは未使用領域 : バフは Lv3 固定運用
- Lv1 デバフも実質解除困難 : 牛乳は TSB の世界で Asset 内のものしか入手できないため、 Lv1 でも普通には消えない (= 通常プレイで「牛乳で解除可能」 という想定は成立しにくい)
-
Lv4 は使わない : 内部実装上は
ClearLv:4の API 呼び出しで消せるが、運用では使用しない領域 - 専用の解除アイテム・解除イベント等で
api:entity/mob/effect/remove/from_levelを呼ぶ設計にする時は、対象 Lv を考えて呼び出す
処理ごとに実装ファイル (given/.mcf, tick/.mcf 等) を書いていくよ。実行コンテキストは全部 as 対象エンティティ at @s。必要なデータは asset:context 経由で参照する。
| イベント | 呼ばれるタイミング | 実装ファイル |
|---|---|---|
given |
初回付与時 (まだそのエフェクトを持っていない状態からの付与) | given/.mcfunction |
re-given |
再付与時 (既に持っている状態に再付与、スタック変化を含む) | re-given/.mcfunction |
tick |
毎 tick (持っている間ずっと) | tick/.mcfunction |
end |
効果時間が 0 になった時 | end/.mcfunction |
remove |
外部から削除された時 (api:entity/mob/effect/remove/* 等) |
remove/.mcfunction |
実行コンテキストでは以下が参照可能:
-
@s= 対象エンティティ -
storage asset:context this= Field の中身 (このエフェクト個体のデータ) -
storage asset:context Stack= 現在のスタック数 -
storage asset:context Duration= 現在の残り時間 -
storage asset:context PreviousField= re-given 時のみ、 1 つ前の Field の状態
初回付与時の処理。主にバニラエフェクトの付与や、状態の初期化に使う。
#> asset:effect/0031.slow_falling/given/
#
# Effectが付与された時の処理
#
# @within function asset:effect/0031.slow_falling/_/given
# バニラの低速落下を付与
effect give @s slow_falling 1 0 trueエフェクトに合わせて、バニラエフェクトの付与 / particle での初期演出 / scoreboard の初期化 などを書く。
既に付与された状態で再度同じエフェクトが付与された時に呼ばれる。
re-given で「直前の状態」 と「今の状態」 を比較するために、 Field に PrevStack を持たせて手動で記録するパターン。これを動かすには given 側でも同じ記録処理が必要なので、セットで書く。
#> asset:effect/0233.flame_armor/given/
# 初回付与時にもフルセット判定 (4部位を一度に装備した場合)
execute if data storage asset:context {Stack:4} run function asset:effect/0233.flame_armor/fullset/equip
# 現在のスタックを Field に記録 (次回 re-given 時の PreviousField として使う)
data modify storage asset:context this.PrevStack set from storage asset:context Stack#> asset:effect/0233.flame_armor/re-given/
# フルセットだった状態から崩れた → フルセット効果を解除
execute if data storage asset:context PreviousField{PrevStack:4} unless data storage asset:context {Stack:4} run function asset:effect/0233.flame_armor/fullset/dis_equip
# フルセットでなかった状態から成立 → フルセット効果を発動
execute unless data storage asset:context PreviousField{PrevStack:4} if data storage asset:context {Stack:4} run function asset:effect/0233.flame_armor/fullset/equip
# 現在のスタックを Field に記録 (次回の re-given で PreviousField として参照される)
data modify storage asset:context this.PrevStack set from storage asset:context Stackstorage asset:context PreviousField には、 1 つ前の Field の中身 (このエフェクトが直前に持っていた状態) が入ってる。これと現在の Stack を比較することで、「フルセット成立」 「フルセット崩壊」 のエッジを検出できる。
該当エフェクトが付与されている間、毎 tick で呼ばれる処理。重い処理を書きすぎると負荷が重くなるので注意。
#> asset:effect/0031.slow_falling/tick/
# 低速落下を付与 (effect give は重ねがけしてもduration1tickなので軽量)
effect give @s slow_falling 1 0 true#> asset:effect/0307.bleeding/tick/
# 毎tickダメージ (神器のtriggerを発火させない = IsDoT扱い)
execute if score @s Sec matches 20 run function asset:effect/0307.bleeding/tick/damage
# 1秒に1回だけ実行する用のカウンタ
scoreboard players add @s Sec 1
execute if score @s Sec matches 21.. run scoreboard players set @s Sec 0#> asset:effect/0307.bleeding/tick/damage
data modify storage api: Argument.Damage set value 2.0f
data modify storage api: Argument.AttackType set value "Magic"
data modify storage api: Argument.ApplyTrigger set value false # ← DoT 扱いにする
function api:damage/
function api:damage/resetDurationが 0 になって効果時間が終了した時の処理。バニラエフェクトの解除など、後片付けを書く。
#> asset:effect/0031.slow_falling/end/
effect clear @s slow_fallingAPI や牛乳等で外部から削除された時の処理。
#> asset:effect/0031.slow_falling/remove/
effect clear @s slow_fallingendとremoveで同じ処理を書きたい場合、共通処理を別の mcfunction に切り出して、 end/.mcf と remove/.mcf の両方からそれを function で呼ぶ設計にしてね。
Attribute 補正 (攻撃力、魔法耐性 等) を付けたい場合、 given で api:modifier/<カテゴリ>/<種類>/add を呼んで補正を加え、 remove (および必要なら end) で対応する remove API を呼んで取り除く。識別は Argument.UUID で行うよ。
[I;1,3,<エフェクトID>,0]
| 位置 | 値 | 意味 |
|---|---|---|
| 1 | 1 |
固定 |
| 2 | 3 |
エフェクト由来を示すマーカー |
| 3 | <エフェクトID> |
このエフェクトの ID |
| 4 | 0 |
固定 |
つまり ID 272 のエフェクトなら [I;1,3,272,0] 。
慣例として modifier/add.mcfunction と modifier/remove.mcfunction をエフェクト直下に切り出して、各処理側からは function 呼びにする。
例: 0272.inspiration (物理攻撃 +20%)
#> asset:effect/0272.inspiration/modifier/add
# 物理攻撃 +20%
data modify storage api: Argument.UUID set value [I;1,3,272,0]
data modify storage api: Argument.Amount set value 0.2
data modify storage api: Argument.Operation set value "multiply"
function api:modifier/attack/physical/add#> asset:effect/0272.inspiration/modifier/remove
# 物理攻撃 +20% を解除
data modify storage api: Argument.UUID set value [I;1,3,272,0]
function api:modifier/attack/physical/removegiven/.mcfunction から modifier/add を、 remove/.mcfunction (および必要なら end/.mcfunction) から modifier/remove を呼ぶ。
modifier API を複数並べる。 UUID は 全部同じ [I;1,3,<エフェクトID>,0] で OK ── modifier 種別 (attack/physical / receive_heal 等) が違うので別管理される。
例: 0231.wandering_dream (魔法耐性 +12% / 被回復量 +12%)
#> asset:effect/0231.wandering_dream/modifier/add
# 魔法耐性
data modify storage api: Argument.UUID set value [I;1,3,231,0]
data modify storage api: Argument.Amount set value 0.12
data modify storage api: Argument.Operation set value "multiply"
function api:modifier/defense/magic/add
# 被回復量
data modify storage api: Argument.UUID set value [I;1,3,231,0]
data modify storage api: Argument.Amount set value 0.12
data modify storage api: Argument.Operation set value "multiply"
function api:modifier/receive_heal/addremove 側もペアで両方の API を順番に呼ぶ。 UUID は付与時と同じ。
register.mcfでFieldを定義しておくと、各エフェクト個体に固有のデータを持たせられるよ。 tick などからasset:context this.<キー>で参照可能。
#> asset:effect/0999.colored_light/register
data modify storage asset:effect ID set value 999
data modify storage asset:effect Name set value '{"text":"灯火"}'
data modify storage asset:effect Description set value ['{"text":"色を持つ灯り"}']
data modify storage asset:effect Duration set value 200
data modify storage asset:effect IsBadEffect set value false
# カスタムフィールドの定義
data modify storage asset:effect Field set value {Color:16777215, Intensity:5}tick の中で Field の値をコマンド引数として使いたい時 (例: particle ... <個数> の <個数> に Field の値を入れたい等) は、そのままでは書けないから マクロ関数 にしてね。マクロ関数の中では $(Intensity) のような書き方で値を差し込めるよ。
#> asset:effect/0999.colored_light/tick/
# Field の値をマクロ引数として渡す
function asset:effect/0999.colored_light/tick/m with storage asset:context this#> asset:effect/0999.colored_light/tick/m
#
# @input args
# Intensity: int
# Intensity 個の particle を出す ($(Intensity) で個数を差し込む)
$particle dust 1.0 0.5 0.2 ~ ~1 ~ 0.3 0.3 0.3 0 $(Intensity) force @aマクロ関数の決まりごと :
- ファイル名末尾を
m.mcfunctionまたは.m.mcfunctionにする (例:tick/m.mcfunction、summon/m.mcfunction) - 値を差し込みたい行の 冒頭 に
$を付ける - 差し込む値は
$(<キー>)の形で書く - 呼び出し側は
function <パス> with storage <storage> <パス>で引数 storage を渡す
api:entity/mob/effect/giveのArgument.FieldOverrideで、個別の付与時に Field を上書きできる。
data modify storage api: Argument.ID set value 999
data modify storage api: Argument.Duration set value 100
data modify storage api: Argument.FieldOverride set value {Color:16711680, Intensity:10} # 赤色、強度10
execute as <target> run function api:entity/mob/effect/give
function api:entity/mob/effect/reset # 必須re-given 時には、storage asset:context PreviousFieldに「直前の Field の内容」が自動で入る。これを使って、状態遷移の検出ができるよ。
# 直前のStackが3未満で、今回4以上になった → 何か発動
execute if data storage asset:context PreviousField{Stack:3} if data storage asset:context {Stack:4} run …フルセット防具やシナジー系のエフェクトで多用するパターン。
他のエフェクトを継承して、共通処理を親に集約できる。神器のシリーズ (例: 同じ陣営の装備全部) で共通効果を持たせたい時に便利。
ただし ExtendsSafe: true、要するに継承元はスコアボードを使わない設計にしなければならない(これはコアシステムの都合によるもの)。
#> asset:effect/0500.flame_base/register
data modify storage asset:effect ExtendsSafe set value true # ← 継承可能にする
data modify storage asset:effect ID set value 500
data modify storage asset:effect Name set value '{"text":"炎の祝福"}'
data modify storage asset:effect IsBadEffect set value false
data modify storage asset:effect Duration set value -1#> asset:effect/0501.flame_strong/register
# 継承宣言
data modify storage asset:effect Extends append value 500
function asset:effect/extends
# 自分の情報を上書き
data modify storage asset:effect ID set value 501
data modify storage asset:effect Name set value '{"text":"強化された炎の祝福"}'tick 等の各実装ファイルでsuper.tick相当を呼びたい時は、function asset:effect/super.tickを実行する。
#> asset:effect/0501.flame_strong/tick/
# 親の tick も呼ぶ
function asset:effect/super.tick
# 子独自の処理
particle flame ~ ~1.5 ~ 0.3 0.3 0.3 0.05 5詳細はAPIを参照。簡単な使い方だけ:
# 付与 (例 : 範囲内の敵全員にデバフを付与)
data modify storage api: Argument.ID set value 31 # エフェクトID
data modify storage api: Argument.Duration set value 200 # 効果時間 (tick) -- register側で指定済みなら省略可
execute as @e[type=#lib:living_without_player,tag=Enemy,distance=..8] run function api:entity/mob/effect/give
function api:entity/mob/effect/reset # 必須
# 削除 (IDから)
data modify storage api: Argument.ID set value 31
execute as <target> run function api:entity/mob/effect/remove/from_id
function api:entity/mob/effect/reset # 必須
# 削除 (解除レベルから)
data modify storage api: Argument.ClearLv set value 3
execute as <target> run function api:entity/mob/effect/remove/from_level
function api:entity/mob/effect/reset # 必須重要 (reset): 上記 3 つ (
give/remove/from_id/remove/from_level) は 複数対象への連続適用 を想定して内部で Argument を消さない設計なので、呼び出し後にapi:entity/mob/effect/resetを呼ぶ責任がある (1 回 set → 複数対象に execute as で適用 → 最後に reset、という流れ)。一方get/*は内部で自動 remove するので reset 不要。
神器のEquipment.Effectsで指定したエフェクトは、装備時に自動で api:entity/mob/effect/give 経由で付与される。詳細は 神器の作り方 - 装備時効果 を参照。
-
given と re-given を取り違える → 初回付与は
given、再付与・スタック変化はre-given。両方で同じ処理が必要な場合は共通処理を別ファイルに切り出して両方から呼ぶ - end と remove の片方しか書かない → 効果時間終了 (end) と外部からの削除 (remove) のうち、書いてない方のケースで後片付けが走らない。
-
modifier の UUID を間違える / 揃え忘れる → 形式は
[I;1,3,<エフェクトID>,0]固定。付与時と削除時で UUID がズレると remove API が「対象なし」 で何もせず、補正が残り続ける。共通化のためにmodifier/remove.mcfunctionに切り出すのが定型 -
give/remove/*のresetを呼び忘れる → これらは複数対象への連続適用を想定して内部で Argument を自動 remove しない設計。呼び出し後にfunction api:entity/mob/effect/resetを必ず実行する。忘れると次の呼び出しにDuration/Stack/FieldOverrideなどの前回値が混ざる (get/*は自動 remove なので reset 不要) - tick で重い処理を書く → 全プレイヤー × 持ってるエフェクト数だけ毎 tick 実行される。 1 秒に 1 回でいい処理は scoreboard カウンタで間引く
-
DoT で神器が連発される →
api:damage/を呼ぶ前にArgument.ApplyTrigger:falseで IsDoT 扱いに (神器の作り方 - IsDoT / IsHoT のルール参照) - PreviousField を見ずに re-given を書く → Stack が変化したことを検出できず、フルセット効果がうまく動かない原因に
-
ProcessOnDied を指定し忘れる → 死亡で消えるのが嫌なエフェクトは
"keep"を明示する