GroupRecipe
GroupRecipe とは
Section titled “GroupRecipe とは”GroupRecipe は CRecipeImpl とは別の CRecipe 実装クラスで、スロットをグループ化して最小配置数を柔軟に制御できる定形レシピです。
通常の定形レシピでは各スロットが必須ですが、GroupRecipe では複数のスロットを 1 つの Context にまとめ、そのグループ内で「最低 N 個のスロットにアイテムが置かれていればよい」という条件を設定できます。
また、スロットに Material.AIR を候補として含む GroupRecipe.Matter を使用することで、空スロットを許容するアイテム条件を作成できます。
コンストラクタ
Section titled “コンストラクタ”open class GroupRecipe @JvmOverloads constructor( override val name: String, override val items: Map<CoordinateComponent, CMatter>, val groups: Set<Context>, override val predicates: List<CRecipePredicate>? = listOf(recipePredicate), override val results: List<ResultSupplier>? = null, override val type: CRecipe.Type = CRecipe.Type.SHAPED) : CRecipe| パラメータ | デフォルト値 | 概要 |
|---|---|---|
name | — | レシピの識別名 |
items | — | 座標とアイテム条件のマッピング |
groups | — | スロットのグループ化設定 (Context の集合) |
predicates | listOf(recipePredicate) | GroupRecipe.recipePredicate を含む必要がある |
results | null | 成果物を生成する ResultSupplier のリスト |
type | SHAPED | 常に CRecipe.Type.SHAPED |
GroupRecipe.Context
Section titled “GroupRecipe.Context”Context はスロットのグループ化設定を表すクラスです。
| フィールド | 型 | 概要 |
|---|---|---|
members | Set<CoordinateComponent> | このグループに属するスロットの座標集合 |
min | Int | クラフト時にアイテムが配置されている必要がある最小スロット数 |
name | String | グループ名 (デフォルトはランダム UUID) |
Context.of()
Section titled “Context.of()”バリデーション付きで Context を生成するファクトリメソッドです。
GroupRecipe.Context.of( members: Set<CoordinateComponent>, min: Int, name: String = UUID.randomUUID().toString()): Contextmembers が空の場合や min が 0 未満の場合は IllegalArgumentException がスローされます。
Context.default()
Section titled “Context.default()”単一の座標に対してデフォルト設定 (min = 1) の Context を生成します。
グループ化が必要ない座標を補完する際に内部的に使われます。
GroupRecipe.Context.default(coordinate: CoordinateComponent): Context// → members: {coordinate}, min: 1Context.isValidGroups()
Section titled “Context.isValidGroups()”Context の集合と items が整合しているかを確認するメソッドです。
GroupRecipe.Context.isValidGroups( groups: Set<Context>, items: Map<CoordinateComponent, CMatter>): Result<Unit>以下の場合に失敗します:
membersが空のContextが存在するmembersに含まれる座標がitemsのキーに存在しない- 複数の
Contextに同じ座標が含まれている (重複) - グループ内の Air 許容 Matter の数が不足している (
members.size - min個必要) itemsの最小インデックス座標の Matter がMaterial.AIRを候補に含んでいる
GroupRecipe.Matter
Section titled “GroupRecipe.Matter”GroupRecipe.Matter は CMatter の特殊な実装で、Material.AIR を候補に含めることができます。
通常の CMatterImpl は Air を候補に含めることができませんが、GroupRecipe.Matter はグループ内のオプションスロットを表現するために Air を許容します。
Matter.of()
Section titled “Matter.of()”既存の CMatter から Matter を生成するファクトリメソッドです。
GroupRecipe.Matter.of( matter: CMatter, includeAir: Boolean = false): Matter| パラメータ | デフォルト値 | 概要 |
|---|---|---|
matter | — | ベースとなる CMatter |
includeAir | false | Material.AIR を候補に追加するかどうか |
matter が既に GroupRecipe.Matter である場合は IllegalArgumentException がスローされます。
生成された Matter は内部的に originalChecker という CMatterPredicate を使用し、
配置されたアイテムが Air でない場合は元の CMatter の predicates チェックに委譲します。
createGroups() ヘルパー
Section titled “createGroups() ヘルパー”GroupRecipe.createGroups() はグループ設定を補完するユーティリティメソッドです。
指定した missingGroups に含まれない座標に対して自動的にデフォルトの Context を作成して追加します。
GroupRecipe.createGroups( items: Map<CoordinateComponent, CMatter>, missingGroups: Set<Context>): Set<Context>内部で Context.isValidGroups() を呼び出してバリデーションを行い、
不正な Context があれば例外をスローします。
recipePredicate
Section titled “recipePredicate”GroupRecipe.recipePredicate は GroupRecipe のグループ検査を担う CRecipePredicate です。
処理の流れ:
CRecipeをGroupRecipeにキャストできない場合はtrueを返す- レシピと入力のオフセット (dx, dy) を計算する
- 各座標に対応するグループを特定し、配置されているアイテムの数をカウントする
- すべてのグループで「実際の配置数 ≥
min」を確認する
GroupRecipe には以下の制約があります:
-
最小座標の Matter は Air 不可 —
itemsの中でCoordinateComponent#toIndex()が最小の座標に対応するCMatterは、Material.AIRを候補に含めることができません。これはレシピのアンカー (基準点) となるためです。 -
グループ内の Air 許容 Matter 数 — グループ内でオプション (省略可能) にできるスロット数は
members.size - min個です。そのため、グループ内に Air を候補に持つ Matter が少なくともmembers.size - min個必要です。 -
座標の重複禁止 — 1 つの座標は複数の
Contextに属することができません。 -
SHAPED のみ —
CRecipe.Type.SHAPELESSには対応していません。
オプションスロットを持つレシピ
Section titled “オプションスロットを持つレシピ”「石 1 個は必須、残り 3 スロットは石が置かれていれば追加で成果物が増える」のような柔軟なレシピを定義する例です。
val stone = CMatterImpl.of(Material.STONE)// Air を含む Matter (オプションスロット用)val optionalStone = GroupRecipe.Matter.of(stone, includeAir = true)
// (0,0) は必須 (Air 不可)// (1,0), (2,0), (0,1) はオプション (0 個以上でよい)val items = mapOf( CoordinateComponent(0, 0) to stone, CoordinateComponent(1, 0) to optionalStone, CoordinateComponent(2, 0) to optionalStone, CoordinateComponent(0, 1) to optionalStone)
val mandatoryGroup = GroupRecipe.Context.of( members = setOf(CoordinateComponent(0, 0)), min = 1, name = "mandatory")
val optionalGroup = GroupRecipe.Context.of( members = setOf( CoordinateComponent(1, 0), CoordinateComponent(2, 0), CoordinateComponent(0, 1) ), min = 0, // 0 個以上なのでオプション name = "optional")
val recipe = GroupRecipe( name = "flexible-stone", items = items, groups = setOf(mandatoryGroup, optionalGroup), results = listOf(ResultSupplier.timesSingle(ItemStack.of(Material.COBBLESTONE))))createGroups() を使った簡潔な記述
Section titled “createGroups() を使った簡潔な記述”グループ設定が済んでいないスロットを自動補完するために createGroups() を使うと便利です。
val stone = CMatterImpl.of(Material.STONE)val optionalStone = GroupRecipe.Matter.of(stone, includeAir = true)
val items = mapOf( CoordinateComponent(0, 0) to stone, // 必須 CoordinateComponent(1, 0) to optionalStone, // オプション CoordinateComponent(0, 1) to optionalStone // オプション)
// オプションスロットのグループのみ手動で定義し、残りは自動補完val optionalGroup = GroupRecipe.Context.of( members = setOf(CoordinateComponent(1, 0), CoordinateComponent(0, 1)), min = 1, // 2 スロット中 1 個以上 name = "optional")
val groups = GroupRecipe.createGroups(items, setOf(optionalGroup))// (0,0) に対して自動的にデフォルト Context (min=1) が追加される
val recipe = GroupRecipe( name = "stone-optional", items = items, groups = groups, results = listOf(ResultSupplier.timesSingle(ItemStack.of(Material.COBBLESTONE))))カスタム predicates を追加する
Section titled “カスタム predicates を追加する”GroupRecipe.recipePredicate を維持しながら追加の検査を行う場合は、リストに含めます。
val recipe = GroupRecipe( name = "op-group-recipe", items = items, groups = groups, predicates = listOf( GroupRecipe.recipePredicate, // 必須: グループチェック CRecipePredicate { ctx -> ctx.player?.isOp ?: false } // OP のみ ), results = listOf(ResultSupplier.single(ItemStack.of(Material.DIAMOND))))