コンテンツにスキップ

ワールドロジック type の追加

SDK 1.2 以降、プラグインは ワールドロジック に新しいトリガー・条件・アクションを追加できます。host.AddSceneEvent で登録した type は、内蔵 type とまったく同じように次の場所に表示されます。

表示される場所表示内容
ワールドロジックのフォームトリガー・条件・アクションのメニューの Category グループ、項目の入力
ロジックグラフノードとピン
チェック必須項目・アクターの kind・数値の範囲・enum の値
ルールの 1 行説明Summary テンプレート
プレイ のプレビューSimulate の処理・「発動」ボタン
AI 接続 (MCP)scene_rules section=schema の一覧に [<プラグイン id>] を表示

エディターへの登録は、フォーム・チェック・MCP・プレビュー用です。ゲームサーバーで実際に動かすには、サーバープラグイン NP Scene 側にも同じ type を登録する必要があります。下の「サーバー側」を参照してください。

plugin.json には "sdk": "^1.2" 以上を書きます。項目の種類 ActorList を使う場合は "^1.3" です。

host.AddSceneEvent(new NpSceneEvent(NpSceneEventRole.Trigger, "myquest_npc_talk", "NPC 에게 말 걸 때", "퀘스트", new[]
{
new NpSceneField("npc", NpSceneFieldKind.Actor, Required: true, ActorKinds: new[] { "display", "text", "spawn" }, Label: "NPC"),
new NpSceneField("line", NpSceneFieldKind.Text, Label: "대사 id"),
},
Help: "플레이어가 NPC 와 대화를 시작할 때", Icon: "interact",
Summary: "플레이어가 NPC {npc} 에게 말을 걸면")); // Simulate なし = 「発動」ボタンでのみ
host.AddSceneEvent(new NpSceneEvent(NpSceneEventRole.Action, "myquest_start", "퀘스트 시작", "퀘스트", new[]
{
new NpSceneField("quest", NpSceneFieldKind.Text, Required: true, Label: "퀘스트 id"),
},
Icon: "star", Summary: "퀘스트 {quest} 시작",
Simulate: s => { s.Log($"퀘스트 {s.Str("quest")} 시작 → {s.Player}"); return true; }));

この type を使ったルールは、scene.json に次のように保存されます (ルールの一部)。

{
"trigger": { "type": "myquest_npc_talk", "npc": "npc_guard" },
"actions": [ { "type": "myquest_start", "quest": "q1" } ]
}
public sealed record NpSceneEvent(NpSceneEventRole Role, string Type, string Label, string Category, IReadOnlyList<NpSceneField> Fields,
string Help = "", string Icon = "event", string Summary = "", Func<NpSceneSim, bool>? Simulate = null);
public enum NpSceneEventRole { Trigger, Condition, Action }
項目必須説明
Roleはい役割: Trigger (トリガー)・Condition (条件)・Action (アクション)
Typeはい保存名 (JSON の "type")。前に自分の名前を付けます (下の「命名ルール」)。
Labelはいフォーム・グラフに表示される名前
Categoryいいえメニューのグループ名。空の場合はプラグイン名 (plugin.json の name)
Fieldsはい項目の一覧 (NpSceneField)。項目がなければ空の配列
Helpいいえ説明 (ツールチップ)
Iconいいえアイコン名 (trigger ・ event ・ signal ・ interact ・ logic ・ star …)。既定は event、不明な名前なら既定の画像
Summaryいいえ1 行説明のテンプレート (下の「Summary テンプレート」)。空の場合は Label
Simulateいいえプレイのプレビュー処理 (下の「Simulate」)

プラグインの type は、同じグループ内で内蔵 type の後ろに表示されます。

public sealed record NpSceneField(string Name, NpSceneFieldKind Kind, bool Required = false, string Default = "", string[]? Options = null,
string[]? ActorKinds = null, string Label = "", string Help = "", double? Min = null, double? Max = null);
項目説明
NameJSON キー
Kind項目の種類 (下の表)
Required必須の場合、空ならチェックエラー
Default既定値の文字列。形式は下の表の「Default の書き方」
OptionsEnum の選択肢
ActorKindsActor 項目が受け付けるアクターの kind (trigger ・ blocker ・ display ・ text ・ spawn ・ camera ・ path …)。空の場合は任意の kind
Label ・ Helpフォームに表示される名前・説明
Min ・ MaxNumber の範囲 (チェック)
種類フォームの入力JSON の値Default の書き方SDK
Text文字列文字列"안녕"1.2
Number数値数値"1.5"1.2
Boolチェックtrue / false"true"1.2
Enum選択肢の 1 つ (Options)文字列"none"1.2
Actorアクターの選択 (ActorKinds のみ)アクター id の文字列アクター id1.2
Animアニメーションクリップクリップ id の文字列クリップ id1.2
SoundEventサウンドイベント"ns:path" の文字列"minecraft:block.note_block.bell"1.2
Blockブロックステート文字列 (minecraft:stone)ブロックステートの文字列1.2
Itemアイテム文字列 (minecraft:diamond_sword)アイテム id1.2
Particleパーティクル文字列 (minecraft:happy_villager)パーティクル id1.2
Effectポーション効果文字列 (minecraft:speed)効果 id1.2
Vec3x・y・z[x, y, z]"[0,1,0]"1.2
Signalシグナル名文字列シグナル名1.2
Flagシーンフラグ名文字列フラグ名1.2
ActorList複数のアクターアクター id の配列"cam_a,cam_b"1.3

内蔵 type だけが使う項目の種類が他にもあります: フラグ値・関数 (ロジック関数の呼び出し)・ブロックのマスの一覧 (Cells)。これらの種類はまだ SDK にありません。項目の表示条件・整数のみ・#タグ の許可といった項目オプションも、まだ SDK にありません。

プラグインの type も ロジックグラフ にノードとして表示されます。ピンのルールは内蔵 type と同じです。

ピン接続できる数
実行ピン (白い矢印)1 本のチェーン。ノード 1 つの後ろにノード 1 つ
関数ピン (黄色のひし形)ピン 1 つに線 1 本。既に接続済みのピンにもう一度接続すると置き換わります。
データピン (紫の丸、アクター参照)アクター 1 つを複数の項目に接続できます。
  • Actor 項目はデータピンを受け付けます。グラフでアクターを接続すると ActorKinds をチェックします。
  • 関数ピンは内蔵の「関数を呼ぶ」系にのみあります。プラグインの type は関数ピンを作れません。

0.9.11 以降: 関数を呼ぶ黄色のピンは、ピンごとに線 1 本です。

ルール一覧の 1 行説明に使うテンプレートです。{項目名} の位置にその項目の値が入ります。

テンプレート項目の値表示される文字列
퀘스트 {quest} 시작quest = q1퀘스트 q1 시작
플레이어가 NPC {npc} 에게 말을 걸면npc = npc_guard (名前「경비병」)플레이어가 NPC 「경비병」 에게 말을 걸면
퀘스트 {quest} 가 {state} 일 때state は空、Default = none퀘스트 q1 가 none 일 때
  • Actor 項目は、アクター id の代わりに「アクター名」に置き換わります。
  • 値のない項目は Default で埋めます。

Simulate は、プレイ・シミュレート中にルールをプレビュー実行する関数です。ゲームサーバーでは使いません。

役割Simulate の処理戻り値ない場合
Triggerプレビューの 1 ティックごとに、その type のルールごとに 1 回呼ばれる。起こすには s.Fire(player)無視ワールドロジック・プレイパネルの「発動」ボタンでのみ起こす
Condition真・偽の判定true = 真常に真とみなす
Actionアクションの実行 (記録・自分の状態の変更)無視記録だけを残す

Simulate で例外が発生すると、そのプラグインは隔離されます。そのプラグインの type はすべて取り除かれ、プレビューは動作を続けます。

Simulate が受け取る値です。

メンバー型説明
Role ・ TypeNpSceneEventRole ・ string現在処理中の役割・type
RuleIdstringルール id
Playerstring?トリガーした人。トリガーの処理では null
PlayersIReadOnlyList<string>現在のプレイヤーたち
Nowdoubleプレビューの時刻 (秒)
ArgsIReadOnlyDictionary<string, string>ノードの項目値 (すべて文字列)
Str(string key, string fallback = "")string項目値の文字列
Num(string key, double fallback = 0)double項目値の数値
Bool(string key, bool fallback = false)bool項目値 "true" / "false"
PositionOf(string player)NpVec3?プレイヤーの足の位置。なければ null
Log(string text)voidプレビューの記録 1 行 ([<id>] …)
Fire(string? player)void(Trigger の処理のみ) このルールを起こす。他の役割では何も起きない

Args の値の文字列形式です。

項目の値Args の文字列
文字列そのまま
数値"1.5" (ドット区切りの小数、カルチャーに依存しない)
真・偽"true" / "false"
配列・オブジェクト (Vec3 ・ ActorList)JSON 文字列 ("[0,1,0]")。ActorList はカンマ区切りの文字列で保存されたものもそのまま渡されます。
host.AddSceneEvent(new NpSceneEvent(NpSceneEventRole.Trigger, "myquest_near_spawn", "스폰 가까이 올 때", "퀘스트", new[]
{
new NpSceneField("r", NpSceneFieldKind.Number, Default: "5", Label: "반경", Min: 1, Max: 64),
},
Summary: "스폰 {r}칸 안에 들어오면",
Simulate: s =>
{
foreach (var p in s.Players)
if (s.PositionOf(p) is { } pos && Math.Abs(pos.X) + Math.Abs(pos.Z) < s.Num("r", 5)) s.Fire(p);
return true;
}));
  • この関数はプレビューのティックごとに呼ばれます。軽い処理にしてください。
  • フィルター (1 回のみ・クールダウンなど) と条件は、Fire の後にエディターが評価します。

例: 状態を記憶する条件・アクション

Section titled “例: 状態を記憶する条件・アクション”
private readonly Dictionary<string, string> _quests = new(); // プレイヤー:クエスト → 状態
// 条件: クエストの状態
Simulate: s => Get(s.Player, s.Str("quest")) == s.Str("state", "none")
// アクション: クエスト開始
Simulate: s => { _quests[(s.Player ?? "") + ":" + s.Str("quest")] = "active"; s.Log("시작"); return true; }
// 新しいワールドではクリア
host.WorldChanged += _ => _quests.Clear();

全体のコードは サンプル: event_example にあります。

ルール理由
Type の前に自分の名前を付けます (myquest_start)。同じ役割に同じ type が既にあると (内蔵を含む) 登録時に例外 → そのプラグインを隔離
小文字・数字・_ で書きます。サーバープラグイン・JSON と合わせやすくなります。
一度使った Type は変更しません。保存済みのルールがその名前を使っています。
内蔵 type の名前 (cinematic ・ enter ・ sound …) を使いません。内蔵と重なるとプラグインが有効になりません。内蔵の一覧は ワールドロジック type 一覧 にあります。
  • そのプラグインの type がメニュー・グラフのパレットから取り除かれます。
  • その type を使うルールは削除されません。「不明な type」の注意になり、項目の値はそのまま残ります。
  • プレビューでは、不明なトリガーはそのルールをスキップし、不明な条件は偽、不明なアクションはそのアクションだけをスキップします。

ゲームでルールを実行するのは、サーバープラグイン NP Scene (Paper) です。エディタープラグインはサーバーでは動作しません。

  1. 同じ type のハンドラーを Paper プラグインとして作ります。
  2. Bukkit の ServicesManager から NP Scene の SceneEventsApi を取得し、その type を登録します。
  3. 項目名と値の形式 (JSON) を、エディター側の NpSceneField とまったく同じに合わせます。

サーバーが知らない type は、警告を 1 回出してスキップします (トリガー = ルールをスキップ、条件 = 偽、アクション = そのアクションだけをスキップ)。そのため、サーバーのハンドラーがなくてもマップは開けますが、そのルールは動作しません。