提供: Minecraft Modding Wiki
移動先: 案内検索
(新規作成)
 
(クラス名が明らかにスペルミスだったので修正)
 
(2人の利用者による、間の13版が非表示)
1行目: 1行目:
 
{{前提MOD|reqmod="Minecraft Forge Universal 10.12.1.1090~"}}
 
{{前提MOD|reqmod="Minecraft Forge Universal 10.12.1.1090~"}}
 +
{{ チュートリアル難易度 | difficulty=1|clear=none}}
 +
{{ チュートリアルカテゴリー |difficulty=1|type=Player}}
 
{{stb}}
 
{{stb}}
 
==プレイヤーへのカスタムデータの追加==
 
==プレイヤーへのカスタムデータの追加==
15行目: 17行目:
 
import cpw.mods.fml.common.Mod.EventHandler;
 
import cpw.mods.fml.common.Mod.EventHandler;
 
import cpw.mods.fml.common.event.FMLInitializationEvent;
 
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
+
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
 
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
 
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
 
import cpw.mods.fml.common.gameevent.PlayerEvent;
 
import cpw.mods.fml.common.gameevent.PlayerEvent;
32行目: 34行目:
 
@Mod(modid = "SampleMod", name = "SampleMod", version = "1.0", dependencies = "required-after:Forge@[10.12.1.1090,)", useMetadata = true)
 
@Mod(modid = "SampleMod", name = "SampleMod", version = "1.0", dependencies = "required-after:Forge@[10.12.1.1090,)", useMetadata = true)
 
public class SampleMod {
 
public class SampleMod {
     //Player毎のIExtendedEntityPropertiesを保存するMap。ダイヤモンド演算子はJava7以降なので注意。
+
     @SidedProxy(clientSide = "sampleMod.ClientProxy", serverSide = "sampleMod.CommonProxy")
     private static final Map<String, NBTTagCompound> extendedEntityData = new HashMap<>();
+
     public static CommonProxy proxy;
 
 
 
     @EventHandler
 
     @EventHandler
     public void preInit(FMLPostInitializationEvent event) {
+
     public void preInit(FMLPreInitializationEvent event) {
 
         //Messageの登録呼び出し
 
         //Messageの登録呼び出し
 
         PacketHandler.init();
 
         PacketHandler.init();
43行目: 44行目:
 
     @EventHandler
 
     @EventHandler
 
     public void init(FMLInitializationEvent event) {
 
     public void init(FMLInitializationEvent event) {
 +
      //二箇所に登録するので、先にインスタンスを生成しておく。
 +
        SampleEntityPropertiesEventHandler sampleEntityPropertiesEventHandler = new SampleEntityPropertiesEventHandler();
 
         //Forge Eventの登録。EntityEvent.EntityConstructingとLivingDeathEventとEntityJoinWorldEvent
 
         //Forge Eventの登録。EntityEvent.EntityConstructingとLivingDeathEventとEntityJoinWorldEvent
         MinecraftForge.EVENT_BUS.register(this);
+
         MinecraftForge.EVENT_BUS.register(sampleEntityPropertiesEventHandler);
         //FML Eventの登録。PlayerChangedDimensionEventとPlayerRespawnEvent
+
         //FML Eventの登録。PlayerRespawnEvent
         FMLCommonHandler.instance().bus().register(this);
+
         FMLCommonHandler.instance().bus().register(sampleEntityPropertiesEventHandler);
 
     }
 
     }
 +
}
  
 +
</source>
 +
===SampleEntityPropertiesEventHandlerクラス===
 +
<source lang = "java">
 +
package sampleMod;
 +
 +
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
 +
import cpw.mods.fml.common.gameevent.PlayerEvent;
 +
import net.minecraft.entity.player.EntityPlayer;
 +
import net.minecraft.entity.player.EntityPlayerMP;
 +
import net.minecraft.nbt.NBTTagCompound;
 +
import net.minecraftforge.common.IExtendedEntityProperties;
 +
import net.minecraftforge.event.entity.EntityEvent;
 +
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
 +
 +
public class SampleEntityPropertiesEventHandler {
 +
 +
    /*IExtendedEntityPropertiesを登録する処理を呼び出す*/
 
     @SubscribeEvent
 
     @SubscribeEvent
    /*IExtendedEntityPropertiesを登録する処理を呼び出す*/
 
 
     public void onEntityConstructing(EntityEvent.EntityConstructing event) {
 
     public void onEntityConstructing(EntityEvent.EntityConstructing event) {
 
         if (event.entity instanceof EntityPlayer) {
 
         if (event.entity instanceof EntityPlayer) {
58行目: 78行目:
  
 
     @SubscribeEvent
 
     @SubscribeEvent
     /*死亡時に呼ばれるイベント。ここで、IExtendedEntityPropertiesを保存する処理を呼び出す*/
+
     /*ワールドに入った時に呼ばれるイベント。ここでIExtendedEntityPropertiesを読み込む処理を呼び出す*/
     public void onLivingDeathEvent(LivingDeathEvent event)  {
+
     public void onEntityJoinWorld(EntityJoinWorldEvent event)  {
         if (event.entityLiving instanceof EntityPlayer && !event.entity.worldObj.isRemote) {
+
         if (event.world.isRemote && event.entity instanceof EntityPlayer) {
             NBTTagCompound playerData = new NBTTagCompound();
+
             EntityPlayer player = (EntityPlayer)event.entity;
            (event.entity.getExtendedProperties(ExtendedPlayerProperties.EXT_PROP_NAME)).saveNBTData(playerData);
+
             PacketHandler.INSTANCE.sendToServer(new MessagePlayerJoinInAnnouncement(player));
             storeEntityData(event.entity.getCommandSenderName(), playerData);
 
 
         }
 
         }
 
     }
 
     }
  
    @SubscribeEvent
+
  @SubscribeEvent
     /*ワールドに入った時に呼ばれるイベント。ここでIExtendedEntityPropertiesを読み込む処理を呼び出す*/
+
     //Dimension移動時や、リスポーン時に呼ばれるイベント。古いインスタンスと新しいインスタンスの両方を参照できる。
     public void onEntityJoinWorld(EntityJoinWorldEvent event) {
+
     public void onClonePlayer(net.minecraftforge.event.entity.player.PlayerEvent.Clone event) {
         if (!event.entity.worldObj.isRemote && event.entity instanceof EntityPlayer) {
+
        //死亡時に呼ばれてるかどうか
             NBTTagCompound playerData = getEntityData(event.entity.getCommandSenderName());
+
         if (event.wasDeath) {
             if (playerData != null) {
+
             //古いカスタムデータ
                (event.entity.getExtendedProperties(ExtendedPlayerProperties.EXT_PROP_NAME)).loadNBTData(playerData);
+
            IExtendedEntityProperties oldEntityProperties = event.original.getExtendedProperties(ExtendedPlayerProperties.EXT_PROP_NAME);
             }
+
             //新しいカスタムデータ
             ((ExtendedPlayerProperties)(event.entity.getExtendedProperties(ExtendedPlayerProperties.EXT_PROP_NAME))).loadProxyData((EntityPlayer)event.entity);
+
            IExtendedEntityProperties newEntityProperties = event.entityPlayer.getExtendedProperties(ExtendedPlayerProperties.EXT_PROP_NAME);
 +
            NBTTagCompound playerData = new NBTTagCompound();
 +
            //データの吸い出し
 +
            oldEntityProperties.saveNBTData(playerData);
 +
             //データの書き込み
 +
             newEntityProperties.loadNBTData(playerData);
 +
 
 
         }
 
         }
 
     }
 
     }
85行目: 110行目:
 
             PacketHandler.INSTANCE.sendTo(new MessagePlayerProperties(event.player), (EntityPlayerMP)event.player);
 
             PacketHandler.INSTANCE.sendTo(new MessagePlayerProperties(event.player), (EntityPlayerMP)event.player);
 
         }
 
         }
    }
 
 
    @SubscribeEvent
 
    /*Dimensionを移動した時に呼ばれるイベント。Serverとの同期を取る*/
 
    public void changedDimension(PlayerEvent.PlayerChangedDimensionEvent event) {
 
        if (!event.player.worldObj.isRemote) {
 
            PacketHandler.INSTANCE.sendTo(new MessagePlayerProperties(event.player), (EntityPlayerMP)event.player);
 
        }
 
    }
 
 
    /*PlayerのIExtendedEntityPropertiesをMapに保存*/
 
    public static void storeEntityData(String name, NBTTagCompound compound) {
 
        extendedEntityData.put(name, compound);
 
    }
 
 
    /*PlayerのIExtendedEntityPropertiesをMapから読み込み*/
 
    public static NBTTagCompound getEntityData(String name) {
 
        return extendedEntityData.remove(name);
 
 
     }
 
     }
 
}
 
}
126行目: 133行目:
 
     public final static String EXT_PROP_NAME = "samplePlayerData";
 
     public final static String EXT_PROP_NAME = "samplePlayerData";
  
     private int sampleInt;
+
     private int sampleInt = 0;
     private double sampleDouble;
+
     private double sampleDouble = 0.0D;
     private boolean sampleBoolean;
+
     private boolean sampleBoolean = false;
     private String sampleString;
+
     private String sampleString = "";
     private ItemStack sampleItemStack;
+
     private ItemStack sampleItemStack = new ItemStack(Items.apple);
 
     private ItemStack[] sampleItemStacks = new ItemStack[10];
 
     private ItemStack[] sampleItemStacks = new ItemStack[10];
     private NBTTagCompound sampleNBTTagCompound;
+
     private NBTTagCompound sampleNBTTagCompound = new NBTTagCompound();
 
 
    /*EntityPlayerインスタンスから外部保存時の固有文字列を返す
 
    *1.7ではusername変数が使えないので、コマンド送信時の名前で代用 */
 
    private static String getSaveKey(EntityPlayer player) {
 
        return player.getCommandSenderName() + ":" + EXT_PROP_NAME;
 
    }
 
  
 
     /*EntityPlayerにIExtendedEntityPropertiesを登録。登録文字列はMOD固有のものを割り当てること*/
 
     /*EntityPlayerにIExtendedEntityPropertiesを登録。登録文字列はMOD固有のものを割り当てること*/
207行目: 208行目:
 
     /*初期化メソッド。今のところ使う必要はない。*/
 
     /*初期化メソッド。今のところ使う必要はない。*/
 
     public void init(Entity entity, World world) {}
 
     public void init(Entity entity, World world) {}
 
    /*ServerのIExtendedEntityPropertiesを読み込んで、Clientに送信するメソッド*/
 
    public void loadProxyData(EntityPlayer player) {
 
        ExtendedPlayerProperties playerData = ExtendedPlayerProperties.get(player);
 
        NBTTagCompound savedData = SampleMod.getEntityData(getSaveKey(player));
 
        if (savedData != null) { playerData.loadNBTData(savedData); }
 
        PacketHandler.INSTANCE.sendTo(new MessagePlayerProperties(player), (EntityPlayerMP)player);
 
    }
 
  
 
     /*以降、各変数のGetterおよびSetter。
 
     /*以降、各変数のGetterおよびSetter。
276行目: 269行目:
 
         this.sampleNBTTagCompound = sampleNBTTagCompound;
 
         this.sampleNBTTagCompound = sampleNBTTagCompound;
 
     }
 
     }
 +
}
 +
 +
</source>
 +
===CommonProxyクラス===
 +
 +
<source lang = "java">
 +
 +
package sampleMod;
 +
 +
import net.minecraft.entity.player.EntityPlayer;
 +
 +
public class CommonProxy {
 +
 +
public EntityPlayer getEntityPlayerInstance() {return null;}
 +
 +
}
 +
 +
</source>
 +
 +
===ClientProxyクラス===
 +
 +
<source lang = "java">
 +
 +
package sampleMod;
 +
 +
import net.minecraft.client.Minecraft;
 +
 +
import net.minecraft.entity.player.EntityPlayer;
 +
 +
public class ClientProxy extends CommonProxy {
 +
 +
@Override
 +
 +
public EntityPlayer getEntityPlayerInstance() {
 +
 +
return Minecraft.getMinecraft().thePlayer;
 +
 +
}
 +
 
}
 
}
  
281行目: 313行目:
 
===PacketHandlerクラス===
 
===PacketHandlerクラス===
 
<source lang = "java">
 
<source lang = "java">
package ak.sampleMod;
+
package sampleMod;
  
 
import cpw.mods.fml.common.network.NetworkRegistry;
 
import cpw.mods.fml.common.network.NetworkRegistry;
298行目: 330行目:
 
         * 第三引数:登録番号。255個まで
 
         * 第三引数:登録番号。255個まで
 
         * 第四引数:ClientとServerのどちらに送るか。送り先*/
 
         * 第四引数:ClientとServerのどちらに送るか。送り先*/
         INSTANCE.registerMessage(MessagePlayerProperties.class, MessagePlayerProperties.class, 0, Side.CLIENT);
+
         INSTANCE.registerMessage(MessagePlayerPropertiesHandler.class, MessagePlayerProperties.class, 0, Side.CLIENT);
 +
        INSTANCE.registerMessage(MessagePlayerJoinInAnoucementHandler.class, MessagePlayerJoinInAnnouncement.class, 1, Side.SERVER);
 
     }
 
     }
 
}
 
}
305行目: 338行目:
 
===MessagePlayerPropertiesクラス===
 
===MessagePlayerPropertiesクラス===
 
<source lang = "java">
 
<source lang = "java">
package ak.sampleMod;
+
package sampleMod;
  
 
import cpw.mods.fml.common.network.ByteBufUtils;
 
import cpw.mods.fml.common.network.ByteBufUtils;
 
import cpw.mods.fml.common.network.simpleimpl.IMessage;
 
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
 
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
 
 
import io.netty.buffer.ByteBuf;
 
import io.netty.buffer.ByteBuf;
import net.minecraft.client.Minecraft;
 
 
import net.minecraft.entity.player.EntityPlayer;
 
import net.minecraft.entity.player.EntityPlayer;
 
import net.minecraft.nbt.NBTTagCompound;
 
import net.minecraft.nbt.NBTTagCompound;
  
public class MessagePlayerProperties implements IMessage, IMessageHandler<MessagePlayerProperties, IMessage> {
+
public class MessagePlayerProperties implements IMessage {
  
     private NBTTagCompound data;
+
     public NBTTagCompound data;
  
 
     public MessagePlayerProperties(){}
 
     public MessagePlayerProperties(){}
337行目: 367行目:
 
         ByteBufUtils.writeTag(buf, data);
 
         ByteBufUtils.writeTag(buf, data);
 
     }
 
     }
 +
}
 +
 +
</source>
 +
 +
===MessagePlayerPropertiesHandlerクラス===
 +
<source lang = "java">
 +
package sampleMod;
 +
 +
import cpw.mods.fml.common.network.simpleimpl.IMessage;
 +
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
 +
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
 +
import io.netty.buffer.ByteBuf;
 +
import net.minecraft.entity.player.EntityPlayer;
 +
import net.minecraft.nbt.NBTTagCompound;
 +
 +
public class MessagePlayerPropertiesHandler implements IMessageHandler<MessagePlayerProperties, IMessage> {
  
 
     @Override
 
     @Override
 
     public IMessage onMessage(MessagePlayerProperties message, MessageContext ctx) {
 
     public IMessage onMessage(MessagePlayerProperties message, MessageContext ctx) {
 
         //Client側にIExtendedEntityPropertiesを渡す。
 
         //Client側にIExtendedEntityPropertiesを渡す。
         ExtendedPlayerProperties.get(Minecraft.getMinecraft().thePlayer).loadNBTData(message.data);
+
         ExtendedPlayerProperties.get(SampleMod.proxy.getEntityPlayerInstance()).loadNBTData(message.data);
 
         //REPLYは送らないので、nullを返す。
 
         //REPLYは送らないので、nullを返す。
 
         return null;
 
         return null;
348行目: 394行目:
  
 
</source>
 
</source>
 +
===MessagePlayerJoinInAnnouncementクラス===
 +
<source lang = "java">
 +
package sampleMod;
 +
 +
import cpw.mods.fml.common.network.ByteBufUtils;
 +
import cpw.mods.fml.common.network.simpleimpl.IMessage;
 +
import io.netty.buffer.ByteBuf;
 +
import net.minecraft.entity.player.EntityPlayer;
 +
 +
public class MessagePlayerJoinInAnnouncement implements IMessage {
 +
 +
    private String uuid;
 +
 +
    public MessagePlayerJoinInAnnouncement(){}
 +
 +
    public MessagePlayerJoinInAnnouncement(EntityPlayer player) {
 +
        //PlayerのUUIDを文字列で取得
 +
        this.uuid = player.getGameProfile().getId().toString();
 +
    }
 +
 +
    @Override
 +
    public void fromBytes(ByteBuf buf) {
 +
        this.uuid = ByteBufUtils.readUTF8String(buf);
 +
    }
 +
 +
    @Override
 +
    public void toBytes(ByteBuf buf) {
 +
        ByteBufUtils.writeUTF8String(buf, this.uuid);
 +
    }
 +
 +
    public String getUuid() {
 +
        return uuid;
 +
    }
 +
 +
    public void setUuid(String uuid) {
 +
        this.uuid = uuid;
 +
    }
 +
}
 +
</source>
 +
===MessagePlayerJoinInAnoucementHandlerクラス===
 +
<source lang = "java">
 +
package sampleMod;
 +
 +
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
 +
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
 +
import net.minecraft.entity.player.EntityPlayer;
 +
 +
public class MessagePlayerJoinInAnnouncementHandler implements IMessageHandler<MessagePlayerJoinInAnnouncement, MessagePlayerProperties> {
 +
    @Override
 +
    public MessagePlayerProperties onMessage(MessagePlayerJoinInAnnouncement message, MessageContext ctx) {
 +
        //UUIDの文字列を受け取る
 +
        String uuidString = message.getUuid();
 +
        EntityPlayer player = ctx.getServerHandler().playerEntity;
 +
        //取得したPlayerが同一UUIDを持つか判定
 +
        if (player.getGameProfile().getId().toString().equals(uuidString)) {
 +
            //クライアント側にデータを送る
 +
            return new MessagePlayerProperties(player);
 +
        }
 +
        //UUIDが違っていた場合、同期処理を呼ばない
 +
        return null;
 +
    }
 +
}
 +
</source>
 +
 
==解説==
 
==解説==
 
細かい説明はソースコード内に付記したので、そちらを参照のこと。
 
細かい説明はソースコード内に付記したので、そちらを参照のこと。
355行目: 465行目:
 
ExtendedPlayerProperties.get(playerインスタンス).getSampleInt()という形でデータを呼び出す。<br>
 
ExtendedPlayerProperties.get(playerインスタンス).getSampleInt()という形でデータを呼び出す。<br>
 
ExtendedPlayerProperties.get(playerインスタンス).setSampleInt(sample)という形でデータを書き込む。<br>
 
ExtendedPlayerProperties.get(playerインスタンス).setSampleInt(sample)という形でデータを書き込む。<br>
死亡時等でクライアント側のNBTデータが初期化されるので、LivingDeathEventでデータを保存し、EntityJoinWorldEventで、保存したデータを復帰させる。<br>
+
死亡時等でカスタムデータが初期化されるので、CloneEventでデータを新しいインスタンスに移行し、EntityJoinWorldEventとRespawnEventで、クライアント側にデータを送って同期させている。
PlayerRespawnEventやPlayerChangedDimensionEventでも同期を取っているが、Forgeのビルドによっては修正されているかもしれないので、適宜確認の上、追加削除を行うこと。
 

2018年7月22日 (日) 21:57時点における最新版

この記事は"Minecraft Forge Universal 10.12.1.1090~"を前提MODとしています。

Stone pickaxe.png
中級者向けのチュートリアルです。
C player.png
Playerに関係のあるチュートリアルです。
この記事は執筆中です。加筆してくださる人を募集しています。

プレイヤーへのカスタムデータの追加[編集]

各プレイヤーにカスタムデータを追加する。 方法としては、EntityクラスのgetEntityDataメソッドの利用か、ForgeのIExtendedEntityPropertiesインターフェースの利用の二通りある。

このチュートリアルでは、IExtendedEntityPropertiesによる実装方法を解説する。

ソースコード[編集]

SampleModクラス[編集]

package sampleMod;

import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.PlayerEvent;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.EntityEvent;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.event.entity.living.LivingDeathEvent;

import java.util.HashMap;
import java.util.Map;

//FMLのパケットシステムはForge 10.12.1.1090以降でないと動作しないので、dependenciesでそれ以降を指定すること。
@Mod(modid = "SampleMod", name = "SampleMod", version = "1.0", dependencies = "required-after:Forge@[10.12.1.1090,)", useMetadata = true)
public class SampleMod {
    @SidedProxy(clientSide = "sampleMod.ClientProxy", serverSide = "sampleMod.CommonProxy")
    public static CommonProxy proxy;
    @EventHandler
    public void preInit(FMLPreInitializationEvent event) {
        //Messageの登録呼び出し
        PacketHandler.init();
    }

    @EventHandler
    public void init(FMLInitializationEvent event) {
       //二箇所に登録するので、先にインスタンスを生成しておく。
        SampleEntityPropertiesEventHandler sampleEntityPropertiesEventHandler = new SampleEntityPropertiesEventHandler();
        //Forge Eventの登録。EntityEvent.EntityConstructingとLivingDeathEventとEntityJoinWorldEvent
        MinecraftForge.EVENT_BUS.register(sampleEntityPropertiesEventHandler);
        //FML Eventの登録。PlayerRespawnEvent
        FMLCommonHandler.instance().bus().register(sampleEntityPropertiesEventHandler);
    }
}

SampleEntityPropertiesEventHandlerクラス[編集]

package sampleMod;

import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.PlayerEvent;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.common.IExtendedEntityProperties;
import net.minecraftforge.event.entity.EntityEvent;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;

public class SampleEntityPropertiesEventHandler {

    /*IExtendedEntityPropertiesを登録する処理を呼び出す*/
    @SubscribeEvent
    public void onEntityConstructing(EntityEvent.EntityConstructing event) {
        if (event.entity instanceof EntityPlayer) {
            ExtendedPlayerProperties.register((EntityPlayer)event.entity);
        }
    }

    @SubscribeEvent
    /*ワールドに入った時に呼ばれるイベント。ここでIExtendedEntityPropertiesを読み込む処理を呼び出す*/
    public void onEntityJoinWorld(EntityJoinWorldEvent event)  {
        if (event.world.isRemote && event.entity instanceof EntityPlayer) {
            EntityPlayer player = (EntityPlayer)event.entity;
            PacketHandler.INSTANCE.sendToServer(new MessagePlayerJoinInAnnouncement(player));
        }
    }

   @SubscribeEvent
    //Dimension移動時や、リスポーン時に呼ばれるイベント。古いインスタンスと新しいインスタンスの両方を参照できる。
    public void onClonePlayer(net.minecraftforge.event.entity.player.PlayerEvent.Clone event) {
        //死亡時に呼ばれてるかどうか
        if (event.wasDeath) {
            //古いカスタムデータ
            IExtendedEntityProperties oldEntityProperties = event.original.getExtendedProperties(ExtendedPlayerProperties.EXT_PROP_NAME);
            //新しいカスタムデータ
            IExtendedEntityProperties newEntityProperties = event.entityPlayer.getExtendedProperties(ExtendedPlayerProperties.EXT_PROP_NAME);
            NBTTagCompound playerData = new NBTTagCompound();
            //データの吸い出し
            oldEntityProperties.saveNBTData(playerData);
            //データの書き込み
            newEntityProperties.loadNBTData(playerData);

        }
    }

    @SubscribeEvent
    /*リスポーン時に呼ばれるイベント。Serverとの同期を取る*/
    public void respawnEvent(PlayerEvent.PlayerRespawnEvent event) {
        if (!event.player.worldObj.isRemote) {
            PacketHandler.INSTANCE.sendTo(new MessagePlayerProperties(event.player), (EntityPlayerMP)event.player);
        }
    }
}

ExtendedPlayerPropertiesクラス[編集]

package sampleMod;

import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
import net.minecraftforge.common.IExtendedEntityProperties;
import net.minecraftforge.common.util.Constants;

public class ExtendedPlayerProperties implements IExtendedEntityProperties {
   /* MOD固有の文字列。EntityPlayerに登録時に使用。
   MOD内で複数のIExtendedEntityPropertiesを使う場合は、別の文字列をそれぞれ割り当てること。*/
    public final static String EXT_PROP_NAME = "samplePlayerData";

    private int sampleInt = 0;
    private double sampleDouble = 0.0D;
    private boolean sampleBoolean = false;
    private String sampleString = "";
    private ItemStack sampleItemStack = new ItemStack(Items.apple);
    private ItemStack[] sampleItemStacks = new ItemStack[10];
    private NBTTagCompound sampleNBTTagCompound = new NBTTagCompound();

    /*EntityPlayerにIExtendedEntityPropertiesを登録。登録文字列はMOD固有のものを割り当てること*/
    public static void register(EntityPlayer player) {
        player.registerExtendedProperties(EXT_PROP_NAME, new ExtendedPlayerProperties());
    }
    /*IExtendedEntityPropertiesをEntityPlayerインスタンスから取得する*/
    public static ExtendedPlayerProperties get(EntityPlayer player) {
        return (ExtendedPlayerProperties)player.getExtendedProperties(EXT_PROP_NAME);
    }


    @Override
    public void saveNBTData(NBTTagCompound compound) {
        NBTTagCompound nbt = new NBTTagCompound();
        nbt.setInteger("sampleInt", this.sampleInt);
        nbt.setDouble("sampleDouble", this.sampleDouble);
        nbt.setBoolean("sampleBoolean", this.sampleBoolean);
        nbt.setString("sampleString", this.sampleString);
        nbt.setTag("sampleTag", this.sampleNBTTagCompound);
        //ItemStackの保存
        NBTTagCompound itemNBT = new NBTTagCompound();
        this.sampleItemStack.writeToNBT(itemNBT);
        nbt.setTag("sampleItemStack", itemNBT);
        //ItemStackの配列の保存
        NBTTagList itemsTagList = new NBTTagList();
        for (int i = 0; i < this.sampleItemStacks.length; ++i)
        {
            if (this.sampleItemStacks[i] != null)
            {
                NBTTagCompound var4 = new NBTTagCompound();
                var4.setByte("Slot", (byte)i);
                this.sampleItemStacks[i].writeToNBT(var4);
                itemsTagList.appendTag(var4);
            }
        }
        nbt.setTag("Items", itemsTagList);

        compound.setTag(EXT_PROP_NAME, nbt);
    }

    @Override
    public void loadNBTData(NBTTagCompound compound) {
        NBTTagCompound nbt = (NBTTagCompound)compound.getTag(EXT_PROP_NAME);
        this.sampleInt = nbt.getInteger("sampleInt");
        this.sampleDouble = nbt.getDouble("sampleDouble");
        this.sampleBoolean = nbt.getBoolean("sampleBoolean");
        this.sampleString = nbt.getString("sampleString");
        this.sampleNBTTagCompound = nbt.getCompoundTag("sampleTag");
        //ItemStackの読み込み
        this.sampleItemStack = ItemStack.loadItemStackFromNBT(nbt.getCompoundTag("sampleItemStack"));
        //ItemStackの配列の読み込み
        NBTTagList itemsTagList = nbt.getTagList("Items", Constants.NBT.TAG_COMPOUND);
        this.sampleItemStacks = new ItemStack[10];
        for (int i = 0; i < itemsTagList.tagCount(); ++i)
        {
            NBTTagCompound var4 = itemsTagList.getCompoundTagAt(i);
            int slot = var4.getByte("Slot") & 255;

            if (slot >= 0 && slot < this.sampleItemStacks.length)
            {
                this.sampleItemStacks[slot] = ItemStack.loadItemStackFromNBT(var4);
            }
        }
    }

    @Override
    /*初期化メソッド。今のところ使う必要はない。*/
    public void init(Entity entity, World world) {}

    /*以降、各変数のGetterおよびSetter。
    * 使い方としては、EntityPlayerのインスタンスが取得できるメソッド内で、
    * ExtendedPlayerProperties.get(playerインスタンス).setSampleInt(sample)
    * と呼び出す。*/

    public int getSampleInt() {
        return sampleInt;
    }

    public void setSampleInt(int sampleInt) {
        this.sampleInt = sampleInt;
    }

    public double getSampleDouble() {
        return sampleDouble;
    }

    public void setSampleDouble(double sampleDouble) {
        this.sampleDouble = sampleDouble;
    }

    public boolean isSampleBoolean() {
        return sampleBoolean;
    }

    public void setSampleBoolean(boolean sampleBoolean) {
        this.sampleBoolean = sampleBoolean;
    }

    public String getSampleString() {
        return sampleString;
    }

    public void setSampleString(String sampleString) {
        this.sampleString = sampleString;
    }

    public ItemStack getSampleItemStack() {
        return sampleItemStack;
    }

    public void setSampleItemStack(ItemStack sampleItemStack) {
        this.sampleItemStack = sampleItemStack;
    }

    public ItemStack[] getSampleItemStacks() {
        return sampleItemStacks;
    }

    public void setSampleItemStacks(ItemStack[] sampleItemStacks) {
        this.sampleItemStacks = sampleItemStacks;
    }

    public NBTTagCompound getSampleNBTTagCompound() {
        return sampleNBTTagCompound;
    }

    public void setSampleNBTTagCompound(NBTTagCompound sampleNBTTagCompound) {
        this.sampleNBTTagCompound = sampleNBTTagCompound;
    }
}

CommonProxyクラス[編集]

package sampleMod;

import net.minecraft.entity.player.EntityPlayer;

public class CommonProxy {

public EntityPlayer getEntityPlayerInstance() {return null;}

}

ClientProxyクラス[編集]

package sampleMod;

import net.minecraft.client.Minecraft;

import net.minecraft.entity.player.EntityPlayer;

public class ClientProxy extends CommonProxy {

@Override

public EntityPlayer getEntityPlayerInstance() {

return Minecraft.getMinecraft().thePlayer;

}

}

PacketHandlerクラス[編集]

package sampleMod;

import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import cpw.mods.fml.relauncher.Side;

public class PacketHandler {
    /*MOD固有のSimpleNetworkWrapperを取得。
    * 文字列は他のMODと被らないようにMOD_IDを指定しておくと良い*/
    public static final SimpleNetworkWrapper INSTANCE = NetworkRegistry.INSTANCE.newSimpleChannel("samplemod");

    public static void init() {
        /*Messageクラスの登録。
        * 第一引数:IMessageHandlerクラス
        * 第二引数:送るMessageクラス
        * 第三引数:登録番号。255個まで
        * 第四引数:ClientとServerのどちらに送るか。送り先*/
        INSTANCE.registerMessage(MessagePlayerPropertiesHandler.class, MessagePlayerProperties.class, 0, Side.CLIENT);
        INSTANCE.registerMessage(MessagePlayerJoinInAnoucementHandler.class, MessagePlayerJoinInAnnouncement.class, 1, Side.SERVER);
    }
}

MessagePlayerPropertiesクラス[編集]

package sampleMod;

import cpw.mods.fml.common.network.ByteBufUtils;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;

public class MessagePlayerProperties implements IMessage {

    public NBTTagCompound data;

    public MessagePlayerProperties(){}

    public MessagePlayerProperties(EntityPlayer entityPlayer) {
        this.data = new NBTTagCompound();
        //EntityPlayerからIExtendedEntityPropertiesを取得。
        ExtendedPlayerProperties.get(entityPlayer).saveNBTData(data);
    }

    @Override
    public void fromBytes(ByteBuf buf) {
        data = ByteBufUtils.readTag(buf);
    }

    @Override
    public void toBytes(ByteBuf buf) {
        ByteBufUtils.writeTag(buf, data);
    }
}

MessagePlayerPropertiesHandlerクラス[編集]

package sampleMod;

import cpw.mods.fml.common.network.simpleimpl.IMessage;
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;

public class MessagePlayerPropertiesHandler implements IMessageHandler<MessagePlayerProperties, IMessage> {

    @Override
    public IMessage onMessage(MessagePlayerProperties message, MessageContext ctx) {
        //Client側にIExtendedEntityPropertiesを渡す。
        ExtendedPlayerProperties.get(SampleMod.proxy.getEntityPlayerInstance()).loadNBTData(message.data);
        //REPLYは送らないので、nullを返す。
        return null;
    }
}

MessagePlayerJoinInAnnouncementクラス[編集]

package sampleMod;

import cpw.mods.fml.common.network.ByteBufUtils;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayer;

public class MessagePlayerJoinInAnnouncement implements IMessage {

    private String uuid;

    public MessagePlayerJoinInAnnouncement(){}

    public MessagePlayerJoinInAnnouncement(EntityPlayer player) {
        //PlayerのUUIDを文字列で取得
        this.uuid = player.getGameProfile().getId().toString();
    }

    @Override
    public void fromBytes(ByteBuf buf) {
        this.uuid = ByteBufUtils.readUTF8String(buf);
    }

    @Override
    public void toBytes(ByteBuf buf) {
        ByteBufUtils.writeUTF8String(buf, this.uuid);
    }

    public String getUuid() {
        return uuid;
    }

    public void setUuid(String uuid) {
        this.uuid = uuid;
    }
}

MessagePlayerJoinInAnoucementHandlerクラス[編集]

package sampleMod;

import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
import net.minecraft.entity.player.EntityPlayer;

public class MessagePlayerJoinInAnnouncementHandler implements IMessageHandler<MessagePlayerJoinInAnnouncement, MessagePlayerProperties> {
    @Override
    public MessagePlayerProperties onMessage(MessagePlayerJoinInAnnouncement message, MessageContext ctx) {
        //UUIDの文字列を受け取る
        String uuidString = message.getUuid();
        EntityPlayer player = ctx.getServerHandler().playerEntity;
        //取得したPlayerが同一UUIDを持つか判定
        if (player.getGameProfile().getId().toString().equals(uuidString)) {
            //クライアント側にデータを送る
            return new MessagePlayerProperties(player);
        }
        //UUIDが違っていた場合、同期処理を呼ばない
        return null;
    }
}

解説[編集]

細かい説明はソースコード内に付記したので、そちらを参照のこと。

使用の流れを簡単に書くと、
EntityEvent.EntityConstructingにて、IExtendedEntityPropertiesを登録。
ExtendedPlayerProperties.get(playerインスタンス).getSampleInt()という形でデータを呼び出す。
ExtendedPlayerProperties.get(playerインスタンス).setSampleInt(sample)という形でデータを書き込む。
死亡時等でカスタムデータが初期化されるので、CloneEventでデータを新しいインスタンスに移行し、EntityJoinWorldEventとRespawnEventで、クライアント側にデータを送って同期させている。