目次
概要
進捗の追加処理とMOD固有の進捗解除処理を追加します。
動作確認
2024年01月01日
- Minecraft 1.19.4
- Forge 45.2.0
解説
ExampleTNT.java
ExampleTNT/src/main/java/com/tntmodders/exampletnt/ExampleTNT.java
package com.tntmodders.exampletnt;
import com.tntmodders.exampletnt.provider.*;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.PackOutput;
import net.minecraftforge.common.data.ExistingFileHelper;
import net.minecraftforge.data.event.GatherDataEvent;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
@Mod(ExampleTNT.MOD_ID)
public class ExampleTNT {
public static final String MOD_ID = "exampletnt";
public ExampleTNT() {
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
modEventBus.addListener(this::registerProviders);
ExampleTNTBlocks.register(modEventBus);
ExampleTNTItems.register(modEventBus);
}
private void registerProviders(GatherDataEvent event) {
DataGenerator gen = event.getGenerator();
PackOutput packOutput = gen.getPackOutput();
ExistingFileHelper fileHelper = event.getExistingFileHelper();
gen.addProvider(event.includeClient(), new ExampleTNTItemModelProvider(packOutput, fileHelper));
gen.addProvider(event.includeClient(), new ExampleTNTBlockStateProvider(packOutput, fileHelper));
gen.addProvider(event.includeClient(), new ExampleTNTLangProvider.ExampleTNTLangUS(gen.getPackOutput()));
gen.addProvider(event.includeClient(), new ExampleTNTLangProvider.ExampleTNTLangJP(gen.getPackOutput()));
gen.addProvider(event.includeServer(), new ExampleTNTRecipeProvider(gen.getPackOutput()));
gen.addProvider(event.includeServer(), new ExampleTNTAdvancementProvider(packOutput, event.getLookupProvider(), fileHelper));
}
}
ExampleTNTAdvancementProvider.java
ExampleTNT/src/main/java/com/tntmodders/exampletnt/provider/ExampleTNTAdvancementProvider.java
package com.tntmodders.exampletnt.provider;
import com.tntmodders.exampletnt.ExampleTNT;
import com.tntmodders.exampletnt.ExampleTNTBlocks;
import com.tntmodders.exampletnt.ExampleTNTItems;
import net.minecraft.advancements.Advancement;
import net.minecraft.advancements.AdvancementRewards;
import net.minecraft.advancements.FrameType;
import net.minecraft.advancements.critereon.ImpossibleTrigger;
import net.minecraft.advancements.critereon.InventoryChangeTrigger;
import net.minecraft.advancements.critereon.PlacedBlockTrigger;
import net.minecraft.core.HolderLookup;
import net.minecraft.data.PackOutput;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Blocks;
import net.minecraftforge.common.data.ExistingFileHelper;
import net.minecraftforge.common.data.ForgeAdvancementProvider;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
public class ExampleTNTAdvancementProvider extends ForgeAdvancementProvider {
public ExampleTNTAdvancementProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries, ExistingFileHelper existingFileHelper) {
super(output, registries, existingFileHelper, List.of(new ExampleTNTAdvancementGenerator()));
}
public static class ExampleTNTAdvancementGenerator implements AdvancementGenerator {
@Override
public void generate(HolderLookup.Provider registries, Consumer<Advancement> saver, ExistingFileHelper helper) {
Advancement root = Advancement.Builder.advancement()
.display(new ItemStack(Blocks.TNT), Component.literal("ExampleTNT"), Component.translatable("block.minecraft.tnt"), new ResourceLocation(ExampleTNT.MOD_ID, "textures/block/large_tnt.png"), FrameType.TASK, true, false, true)
.addCriterion("has_tnt", InventoryChangeTrigger.TriggerInstance.hasItems(Blocks.TNT))
.save(saver, new ResourceLocation(ExampleTNT.MOD_ID, "root"), helper);
Advancement large_tnt = Advancement.Builder.advancement()
.display(new ItemStack(ExampleTNTBlocks.LARGE_TNT.get()), Component.translatable("block.exampletnt.large_tnt"), Component.translatable("block.exampletnt.large_tnt"), null, FrameType.CHALLENGE, true, true, false)
.addCriterion("place_large_tnt", PlacedBlockTrigger.TriggerInstance.placedBlock(ExampleTNTBlocks.LARGE_TNT.get()))
.addCriterion("has_large_tnt", InventoryChangeTrigger.TriggerInstance.hasItems(ExampleTNTBlocks.LARGE_TNT.get()))
.parent(root)
.save(saver, new ResourceLocation(ExampleTNT.MOD_ID, "large_tnt"), helper);
Advancement small_tnt = Advancement.Builder.advancement()
.display(new ItemStack(ExampleTNTItems.SMALL_TNT.get()), Component.translatable("item.exampletnt.small_tnt"), Component.translatable("item.exampletnt.small_tnt"), null, FrameType.GOAL, true, true, true)
.addCriterion("toss_small_tnt", new ImpossibleTrigger.TriggerInstance())
.rewards(AdvancementRewards.Builder.loot(new ResourceLocation("chests/spawn_bonus_chest")))
.parent(root)
.save(saver, new ResourceLocation(ExampleTNT.MOD_ID, "small_tnt"), helper);
}
}
}
ForgeAdvancementProvider
を継承することで進捗を生成することができます。他のプロバイダーと同様にregisterProviders
で登録を行う必要があります。
AdvancementProvider.generate()
内でAdvancement.Builder
の処理を行うことで、各進捗を生成することが可能です。
Advancement.Builder
の各処理について説明します。
display()
進捗のアイコンや説明文などを定義します。
第1引数はアイコンに使うアイテムをItemStack
型で渡します。
第2引数、第3引数はそれぞれタイトルと説明文をComponent
型で渡します。翻訳が必要なければliteral, 翻訳が必要ならtranslatableを使うことをおすすめします。
第4引数は進捗タブの背景を設定します。ResourseLocation
型として、ネームスペースとパスを指定する必要があります。この引数はroot,つまり進捗の一番最初のもののみに渡す必要があるため、rootでない進捗にはnullを渡して問題ありません。
第5引数はFrameType
を指定します。TASK, CHALLENGE, GOALの三種類があり、それぞれ進捗タブでの見た目や進捗達成時の音などが変わります。
第6引数は達成時にトースト通知を出すか否か、第7引数は達成時にチャット通知を(全プレイヤーに)出すか否か、第8引数は進捗未達成時に進捗タブに表示されるか否かをそれぞれ指定しています。
なお、display()
メソッドは2つ存在しますが、もう一つはここまでの第1-8引数を一つのDisplayInfo
クラスに統合して渡すものになります。
addCriterion()
進捗達成条件(Criterion)を設定します。このCriterionは複数設定することができ、その場合はその都度このメソッドを呼び登録して下さい。large_tnt
は2つのCriterionを登録しており、この2つともが達成された場合に進捗を開放するようにしています。
第1引数はCriterion名を登録しています。これは固有の名称にするようにして下さい。複数のCriterionを登録する際に同じ名称を重複させることはできません。コマンドや後述のaward()
メソッドで利用できます。
第2引数でCriterionの達成条件を設定します。パッケージnet.minecraft.advancements.critereon
に配置されているCriterionTriggerInstance
継承オブジェクトを渡すことが可能です。進捗/JSONフォーマット - Minecraft wikiなどを参考に、対応するインスタンスを利用して下さい。
本記事では、以下の3つを利用しましたが、これら以外にも複数のトリガーが存在します。
InventoryChangeTrigger
インベントリに変化が起きたときに判定を行います。基本的に特定のアイテムを入手した際に進捗を達成する場合に利用します。hasItems()
メソッドに判定したいアイテムを渡すことでインスタンスを生成できます。
PlacedBlockTrigger
ブロックを設置したときに判定を行います。placedBlock
メソッドに判定したいブロックを渡すことでインスタンスを生成できます。
ImpossibleTrigger
バニラの処理では達成されないCriterionです。後述のMOD側処理での解除で利用します。
parent()
その進捗の親を設定します。ここでは、rootとして定義した進捗を引数として渡すことで親として設定できます。進捗タブでツリー状に表示するなどに利用できます。
rewards()
進捗達成時の報酬を設定できます。AdvancementRewards.Builder
に設定されているように、経験値、ルートテーブル、レシピ、ファンクションを設定できます。今回はsmall_tnt
が達成されたときにボーナスチェストの内容をプレイヤーに取得させる処理を登録しています。
save()
ここまでBuilderで設定した内容を設定したResourceLocation上に保存します。必ず最後に呼んで下さい。このメソッドを呼ぶことで、ここまでBuilder
型で処理していた内容をjsonファイルに書き出すとともに、Advancement
型で渡すことが可能になります。このメソッドの返り値を変数に保存することでparent()
メソッドなどを利用しやすくなるため、本記事ではローカル変数として取得しています。
ExampleTNTHooks.java
ExampleTNT/src/main/java/com/tntmodders/exampletnt/ExampleTNTHooks.java
package com.tntmodders.exampletnt;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
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.item.ItemTossEvent;
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 itemTossEvent(ItemTossEvent event) {
if (event.getEntity().getItem().is(ExampleTNTItems.SMALL_TNT.get()) && event.getPlayer() instanceof ServerPlayer serverPlayer) {
serverPlayer.getAdvancements().award(serverPlayer.getServer().getAdvancements().getAdvancement(new ResourceLocation(ExampleTNT.MOD_ID, "small_tnt")), "toss_small_tnt");
}
}
}
本記事では、ServerPlayer.getAdvancements()
を利用してバニラで定義されている進捗達成トリガー以外の任意の場所をトリガーとする方法を紹介します。
この処理ではaward()
メソッドを用いて、特定のCriterionをコマンドで行う手法と同様に達成させることが可能です。第1引数にAdvancementを、第2引数に達成させたいCriterionの名称を指定することで解除させています。Impossibleとして設定したCriterionをイベントなどの場所から解除させることで自由に進捗を達成させることができます。ここでは、ItemTossEvent
からSMALL_TNTを投げたことを確認した場合にCriterionを達成しています。注意点として、この方法はServerPlayer
からしか呼ぶことができないメソッドを利用しているため、必ずサーバー側で処理を行って下さい。
リンク
次:タグの追加