イベントの追加 (1.19.4)

概要

Minecraft Forgeの機能を利用してバニラの動作に新しい処理を追加します。今回は爆発処理、地形破壊処理、チャット処理及びMOBのスポーン処理についてイベントを設定します。

動作確認

2023年12月13日

  • Minecraft 1.19.4
  • Forge 45.2.0

解説

GitHub

ExampleTNTHooks.java

ExampleTNT/src/main/java/com/tntmodders/exampletnt/ExampleTNTHooks.java


package com.tntmodders.exampletnt;

import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.monster.EnderMan;
import net.minecraft.world.entity.monster.Phantom;
import net.minecraft.world.level.Level;
import net.minecraftforge.event.ServerChatEvent;
import net.minecraftforge.event.entity.EntityMobGriefingEvent;
import net.minecraftforge.event.entity.living.MobSpawnEvent;
import net.minecraftforge.event.level.ExplosionEvent;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;

@Mod.EventBusSubscriber(modid = ExampleTNT.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE)
public class ExampleTNTHooks {

    @SubscribeEvent
    public static void explosionEvent(ExplosionEvent.Detonate event) {
        event.getAffectedEntities().forEach(entity -> {
            if (entity instanceof ItemEntity item && !item.isRemoved() && item.getItem().getItem() == ExampleTNTItems.SMALL_TNT.get()) {
                entity.discard();
                entity.getLevel().explode(null, entity.getX(), entity.getY(), entity.getZ(), 6f, Level.ExplosionInteraction.TNT);
            }
        });
    }

    @SubscribeEvent
    public static void entityMobGriefingEvent(EntityMobGriefingEvent event) {
        if (event.getEntity() instanceof EnderMan) {
            if (!event.getEntity().getLevel().isClientSide()) {
                ((EnderMan) event.getEntity()).addEffect(new MobEffectInstance(MobEffects.GLOWING));
            }
            event.setResult(Event.Result.DENY);
        }
    }

    @SubscribeEvent
    public static void serverChatEvent(ServerChatEvent event) {
        if (event.getRawText().contains("tnt")) {
            event.setCanceled(true);
        }
    }

    @SubscribeEvent
    public static void mobSpawnEvent(MobSpawnEvent.FinalizeSpawn event) {
        if (event.getEntity() instanceof Phantom) {
            event.setSpawnCancelled(true);
        }
    }
}

イベントを設定するクラスにはクラス定義の前にアノテーション@Mod.EventBusSubscriberを付与します。第一引数にはMODID, 第二引数はFORGEを設定する必要があります。
このクラス内部にはpublic static void で定義したメソッドを記述することができます。このメソッドの引数にフックしたいイベントを設定することで、イベントが処理された際にこのメソッドが呼ばれることになります。

例として、このクラスでは最初にExplosionEvent.Detonateを引数としたメソッドを用意しています。このメソッドは爆発で破壊されるブロックや効果を受けるエンティティが設定された直後に呼ばれます。イベントのメソッドで定義した内容が処理され、爆発に巻き込まれたItemEntityのうち内容物がSMALL_TNTであるもののみ誘爆する処理を追加しました。

イベント自体はnet.minecraftforge.event.*のパッケージ内部にそれぞれクラスが存在します。自分の実装したい処理をクラス名から探し、イベントクラス上部にあるコメントからイベントが呼ばれるタイミング等を理解してから使うことをおすすめします。

イベントの中には処理を中断や禁止する事が可能なものもあります。2つ目のメソッドとしてEntityMobGriefingEventを利用します。エンティティの地形破壊が実施できるかを規定するイベントです。このイベントクラスはアノテーション@HasResultが付与されており、このアノテーションがあるイベントではsetResultメソッドを利用して結果を規定することができます。この利用例ではResult.DENYを渡すことでエンダーマンの地形破壊を強制的に失敗にしています。

また、アノテーション@Cancelableが付与されているイベントもあります。3つ目のメソッドではServerChatEventを利用します。サーバーにチャットが送信されたときに呼ばれるイベントです。このアノテーションがあるイベントではsetCanceledメソッドを利用してキャンセルが可能です。この利用例ではチャットに"tnt"を含むメッセージをキャンセルし、表示されないようにしています。

なお、4つ目のメソッドで利用しているMobSpawnEvent.FinalizeSpawnはアノテーション@Cancelableが付与されていますが、setCanceledでキャンセルできるのはスポーン時の追加処理のみであり、setSpawnCancelledを利用することで始めてスポーン自体をキャンセルできます。この利用例ではファントムをスポーンしないように変更しています。このようにイベントクラスごとに特殊な処理が存在しますので、自分が実装したい処理を考えて利用クラスを選ぶとともに、そのクラス上部のドキュメンテーションをよく読んで利用することが大事です。

関連クラス

  • net.minecraftforge.event.*:各種イベントが設定されています。このパッケージ傘下のクラスは@SubscribeEventでフックしたメソッドを用いることでイベント処理を呼ぶために利用できます。

リンク


前:ブロックの追加

次:ビルド