インターフェイスインジェクション

これは、特定の既存のクラスにメソッドを追加するために Loom 0.11 で導入された新しい手法です。 より具体的には、インターフェイスを作成し、このインターフェイスをクラスに注入できます。 その結果、ターゲットクラスは、インターフェイスのすべてのメソッドを、常に持っているかのように取得します。 インターフェイスインジェクションはコンパイル時のみの機能です。これは、ミックスインを使用してインターフェイスをターゲットクラスに実装する必要があることを意味します。

これはライブラリで特に便利です。これにより、既存のクラスに新しいメソッドを追加して、毎回インターフェイスをキャストまたは再実装する必要なくそれらを使用できます。

例を挙げて説明しましょう:

この例のスコープは、次のメソッドを net.minecraft.fluid.FlowableFluid に追加して、バケツが空になったときの音を取得することです。 net.minecraft.fluid.FlowableFluid には同様のメソッドがないため、通常、これは不可能です。

Optional<SoundEvent> getBucketEmptySound()

メソッドをクラスに追加するには、まず最初にそれとのインターフェースを作成する必要があります:

package net.fabricmc.example;
 
public interface BucketEmptySoundGetter {
	// 注入されたインターフェースのメソッドは default でなければなりません。
	// そうでなければ、それらを参照するコードはコンパイルされません!
	default Optional<SoundEvent> getBucketEmptySound() {
		return Optional.empty();
	}
}

ここで、インターフェースを実装するミックスインを使用して、このインターフェースを net.minecraft.fluid.FlowableFluid に実装する必要があります:

@Mixin(FlowableFluid.class)
public class MixinFlowableFluid implements BucketEmptySoundGetter {
	@Override
	public Optional<SoundEvent> getBucketEmptySound() {
	    // これは、BucketItem クラスからコピーされたデフォルトのサウンドを取得する方法です。
	    return Optional.of(((FlowableFluid) (Object) this).isIn(FluidTags.LAVA) ? SoundEvents.ITEM_BUCKET_EMPTY_LAVA : SoundEvents.ITEM_BUCKET_EMPTY);
	}
}

最後に、インターフェイスを net.minecraft.fluid.FlowableFluid に注入する必要があります。 次のスニペットを fabric.mod.json ファイルに追加して、 net.minecraft.fluid.FlowableFluid クラスに 1 つ以上のインターフェイスを追加できます。 ここでのすべてのクラス名は、ドットの代わりにスラッシュを使用する “internal names” 〔内部名〕を使用する必要があることに注意してください(例: path/to/my/Class)。

{
	"custom": {
		"loom:injected_interfaces": {
			"net/minecraft/class_3609": ["net/fabricmc/example/BucketEmptySoundGetter"]
		}
	}
}

これで、新しいメソッドを使用できます:

Optional<SoundEvent> sound = mytestfluid.getBucketEmptySound();

FlowableFluid を拡張するクラスでこのメソッドをオーバーライドして、カスタム動作を実装することもできます。