MOD製作チュートリアル > 実績の追加

概要

実績を追加する方法。
※当チュートリアルでは、「イベントの実装」の内容を一部使用しております。
イベントの実装は現在チュートリアルにはありませんが、今後追加予定ですのでしばらくお待ち下さい。

ソースコード

  • AluminiumMod.java
package tutorial.aluminiummod;
 
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
import net.minecraft.block.Block;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.stats.Achievement;
import net.minecraft.world.World;
import net.minecraftforge.common.AchievementPage;
import net.minecraftforge.common.MinecraftForge;
 
@Mod(modid = "AluminiumMod", name = "Aluminium Mod", version = "1.0.0")
public class AluminiumMod {
 
    //追加するアイテム・ブロックの宣言
    public static Item aluminium;
    public static Block blockAluminiumOre;
    //追加する実績の宣言
    public static Achievement getAluminium;
    public static Achievement slayCreeper;
 
    @Mod.EventHandler
    public void preInit(FMLPreInitializationEvent event) {
        //アイテムの実装
        aluminium = new Item() {
            //アイテムがクラフト・精錬されたときに呼ばれるメソッド。
            public void onCreated(ItemStack stack, World world, EntityPlayer player) {
                //Player.triggerAchievement(Statbase)
                //Statbaseには実績のインスタンスを入れる。これにより、未解除の実績が解除される。
                player.triggerAchievement(AluminiumMod.getAluminium);
                super.onCreated(stack, world, player);
            }
        }
        //以下はアイテム・ブロックの実装と同様。
                .setCreativeTab(CreativeTabs.tabMaterials)
                .setUnlocalizedName("aluminium")
                .setTextureName("aluminiummod:aluminium");
        GameRegistry.registerItem(aluminium, "aluminium");
 
        blockAluminiumOre = new AluminiumOre()
                .setBlockName("blockAluminiumOre")
                .setBlockTextureName("aluminiummod:aluminium_ore");
        GameRegistry.registerBlock(blockAluminiumOre, "blockAluminiumOre");
 
        //実績の実装
        //内部名称, 言語名称, 縦の位置, 横の位置, アイコンのアイテム, 親実績
        //縦の位置はマイナスで上 横の位置はマイナスで左
        //Achievement.setSpecial()で、エフェクトを付けられる。
        this.getAluminium = new Achievement("getAluminium", "getAluminium", 0, 0,
                new ItemStack(this.aluminium, 0), null).registerStat();
        this.slayCreeper = new Achievement("slayCreeper", "slayCreeper", 1, -1,
                new ItemStack(Items.skull, 0, 4), this.getAluminium).setSpecial().registerStat();
 
        //実績ページの実装
        //ページ名称, 実績の配列
        AchievementPage.registerAchievementPage(new AchievementPage("AluminiumMod", new Achievement[]{this.getAluminium, this.slayCreeper}));
 
        //イベントクラスの登録
        MinecraftForge.EVENT_BUS.register(new AluminiumEvent());
    }
 
    @Mod.EventHandler
    public void init(FMLInitializationEvent event) {
        //クラフト・精錬レシピの追加
        GameRegistry.addShapelessRecipe(new ItemStack(AluminiumMod.aluminium), AluminiumMod.blockAluminiumOre);
        GameRegistry.addSmelting(AluminiumMod.blockAluminiumOre, new ItemStack(AluminiumMod.aluminium), 0.8F);
    }
 
}
 
 

  • AluminiumOre.java
鉱石の追加 のものと同様。

  • AluminiumEvent.java
package tutorial.aluminiummod;
 
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import net.minecraft.entity.monster.EntityCreeper;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.event.entity.living.LivingDeathEvent;
import net.minecraftforge.event.entity.player.EntityItemPickupEvent;
 
//イベントクラス。詳細の解説は今後実装予定。
public class AluminiumEvent {
 
    //アイテムを拾った時のイベント
    @SubscribeEvent
    public void EntityItemPickUpEvent(EntityItemPickupEvent e) {
        if (e.entityPlayer != null && e.item != null && e.item.getEntityItem() != null
                && e.item.getEntityItem().getItem() == AluminiumMod.aluminium) {
            e.entityPlayer.triggerAchievement(AluminiumMod.getAluminium);
        }
    }
 
    //Entityが倒された時のイベント
    @SubscribeEvent
    public void LivingDeathEvent(LivingDeathEvent e) {
        if (e.entityLiving != null && e.entityLiving instanceof EntityCreeper
                && e.source.getEntity() != null && e.source.getEntity() instanceof EntityPlayer) {
            ((EntityPlayer) e.source.getEntity()).triggerAchievement(AluminiumMod.slayCreeper);
        }
    }
}
 

なお、「バニラのアイテムがクラフトされたとき」などは以下のようなコードをAluminiumEventに追加すれば良い。
+ 追加コード
「アイテム"Skull"でメタデータ"4"に設定されたItemStackがプレイヤーのインベントリ内にあるかどうかチェックする」動作を実装したイベント。
//EntityLivingのアップデートごとに呼ばれるイベント。毎tick呼ばれるので非推奨。
    @SubscribeEvent
    public void LivingUpdateEvent(LivingEvent.LivingUpdateEvent e) {
        if (e.entityLiving instanceof EntityPlayer) {
            for (ItemStack itemStack : ((EntityPlayer) e.entityLiving).inventory.mainInventory) {
                if (itemStack != null && itemStack.getItem() == Items.skull && itemStack.getItemDamage() == 4){
                    ((EntityPlayer) e.entityLiving).triggerAchievement(AluminiumMod.slayCreeper);
                }
            }
        }
    }
 

解説

通常、MinecraftForgeのテスト環境ではユーザー名を毎回振り直すので実績は保存されない。
そのため、プログラム引数に"-username=[ユーザー名]"(例:-username=hogehoge)を渡すことでユーザー名を固定し、テスト環境でも実績を保存できる。
(なお、このような措置を取らなくても実際にMinecraftLauncherから起動した場合はユーザー名通りに実績が保存できる。)
これは、その他のスコアボード、マルチでのテスト等でも使えるテクニックである。

Item

void onCreated(ItemStack stack, World world, EntityPlayer player)

アイテムがクラフト・精錬されたときに呼ばれるメソッド。
作業台・かまどから取り出したときにこのメソッドが呼ばれる。

Achievement

コンストラクタ(String name, String localname, int Xpos, int Ypos, ItemStack stack, Achievement parent)

実績を定義する。コメントの通り引数を渡していく。

void setSpecial()

実績をレアとして設定する。

AchievementPage

コンストラクタ(String name, Achievement[] achievements)

実績ページを定義する。第一引数には名称(のunlocalizedname)、第二引数にはこのページに入れる実績を渡す。

static void registerAchievementPage(AchievementPage page)

実績ページを登録する。

EventBus

register(Object event)

引数にイベントを記述したクラスを渡す。

@SubscribeEvent

イベントを記述したメソッドに必ずつける。これの付いたメソッドには、引数としてフックしたいイベントを渡せるようにする。
詳しくは別ページで解説予定。

EntityPlayer

void triggerAchievement(StatBase stat)

引数に実績を渡すことで、その実績を解除できる。

コメント

この項目に関する質問などをどうぞ。
  • 質問なのですが、バニラアイテムをクラフトしたときに実績を解除する時は - 名無しさん 2016-12-18 20:38:17
    • どのようにすればいいのでしょうか - 名無しさん 2016-12-18 20:38:39
    • 「クラフトしたとき」のイベントはありませんので、上記「追加コード」のようなコードを参照の上、AluminiumEventに追加してください。- Tom Kate 2016-12-20 22:58:41
      • ありがとうございました。 - 名無しさん 2016-12-23 12:42:24
  • このソースをそのまま使うと実績がワールドを出るたびにリセットされるようなのですが保存するにはどうすればよいですか? - 名無しさん 2017-02-20 21:35:01
    • 僕も、同じ症状で困ってます。 - mod初心者 2017-04-05 16:09:16
      • テスト環境では、ユーザー名が毎回変わるため実績が保存されません。EclipseやIDEAを利用しているようでしたらプログラムの起動設定から「プログラム引数(パラメーター)」に-username=[ユーザー名]でユーザー名が固定できますのでお試しください。 - Tom Kate 2017-04-08 13:23:50
        • そうやっても、実績が保存されませんがどうしたら良いのでしょうか? - mod初心者 2017-04-08 14:46:18
        • 開発環境は、Eclipseです。 - mod初心者 2017-04-09 08:38:57
          • コードを修正いたしました。このコードでも変更前でも私の環境では実績が保存されておりますがそちらはどうでしょうか? - Tom Kate 2017-04-09 11:39:08
          • ちゃんと保存されるようになりました!ありがとうございました! - mod初心者 2017-04-10 15:31:02
          • 気になるところがあるのですが、プログラム引数のハイフンの数は2つだったと思うのですが。 - mod初心者 2017-04-10 15:33:53
            • 確認が取りづらいところではありますが、多分どちらの書き方でも明示的に"username"であることが示されているので大丈夫だと思われます。 - Tom Kate 2017-04-10 20:04:11
            • 分かりました。色々答えてくれてありがとうございました! - mod初心者 2017-04-10 20:17:53
最終更新:2017年04月09日 11:40