提供: Minecraft Modding Wiki
移動先: 案内検索
(誤字及び脱字の修正)
(クライアントとサーバー間での同期と死亡時のデータの扱いの見直し)
34行目: 34行目:
 
@Mod(modid = "SampleMod", name = "SampleMod", version = "1.0", dependencies = "required-after:Forge@[11.14.0.1296,)", useMetadata = true)
 
@Mod(modid = "SampleMod", name = "SampleMod", version = "1.0", dependencies = "required-after:Forge@[11.14.0.1296,)", useMetadata = true)
 
public class SampleMod {
 
public class SampleMod {
    @SidedProxy(clientSide = "sampleMod.ClientProxy", serverSide = "sampleMod.CommonProxy")
 
    public static CommonProxy proxy;
 
    //Player毎のIExtendedEntityPropertiesを保存するMap。ダイヤモンド演算子はJava7以降なので注意。
 
    private static final Map<String, NBTTagCompound> extendedEntityData = new HashMap<>();
 
  
 
     @EventHandler
 
     @EventHandler
47行目: 43行目:
 
     @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>
 +
===
 +
<source lang = "java">
 +
package com.example.examplemod;
 +
 +
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;
 +
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
 +
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
 +
 +
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) {
             ExtendedPlayerProperties.register((EntityPlayer)event.entity);
+
             ExtendedPlayerProperties.register((EntityPlayer) event.entity);
        }
 
    }
 
 
 
    @SubscribeEvent
 
    /*死亡時に呼ばれるイベント。ここで、IExtendedEntityPropertiesを保存する処理を呼び出す*/
 
    public void onLivingDeathEvent(LivingDeathEvent event)  {
 
        if (event.entityLiving instanceof EntityPlayer && !event.entity.worldObj.isRemote) {
 
            NBTTagCompound playerData = new NBTTagCompound();
 
            (event.entity.getExtendedProperties(ExtendedPlayerProperties.EXT_PROP_NAME)).saveNBTData(playerData);
 
            storeEntityData(((EntityPlayer) event.entity).getGameProfile().getId().toString(), playerData);
 
 
         }
 
         }
 
     }
 
     }
74行目: 78行目:
 
     /*ワールドに入った時に呼ばれるイベント。ここでIExtendedEntityPropertiesを読み込む処理を呼び出す*/
 
     /*ワールドに入った時に呼ばれるイベント。ここでIExtendedEntityPropertiesを読み込む処理を呼び出す*/
 
     public void onEntityJoinWorld(EntityJoinWorldEvent event)  {
 
     public void onEntityJoinWorld(EntityJoinWorldEvent event)  {
         if (event.entity.worldObj.isRemote && event.entity instanceof EntityPlayer) {
+
         if (event.world.isRemote && event.entity instanceof EntityPlayer) {
 
             EntityPlayer player = (EntityPlayer)event.entity;
 
             EntityPlayer player = (EntityPlayer)event.entity;
 
             PacketHandler.INSTANCE.sendToServer(new MessagePlayerJoinInAnnouncement(player));
 
             PacketHandler.INSTANCE.sendToServer(new MessagePlayerJoinInAnnouncement(player));
81行目: 85行目:
  
 
     @SubscribeEvent
 
     @SubscribeEvent
     /*リスポーン時に呼ばれるイベント。Serverとの同期を取る*/
+
     //Dimension移動時や、リスポーン時に呼ばれるイベント。古いインスタンスと新しいインスタンスの両方を参照できる。
     public void respawnEvent(PlayerEvent.PlayerRespawnEvent event) {
+
     public void onClonePlayer(net.minecraftforge.event.entity.player.PlayerEvent.Clone event) {
         if (!event.player.worldObj.isRemote) {
+
        //死亡時に呼ばれてるかどうか
             PacketHandler.INSTANCE.sendTo(new MessagePlayerProperties(event.player), (EntityPlayerMP)event.player);
+
         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
 
     @SubscribeEvent
     /*Dimensionを移動した時に呼ばれるイベント。Serverとの同期を取る*/
+
     /*リスポーン時に呼ばれるイベント。Serverとの同期を取る*/
     public void changedDimension(PlayerEvent.PlayerChangedDimensionEvent event) {
+
     public void respawnEvent(PlayerEvent.PlayerRespawnEvent event) {
 
         if (!event.player.worldObj.isRemote) {
 
         if (!event.player.worldObj.isRemote) {
 
             PacketHandler.INSTANCE.sendTo(new MessagePlayerProperties(event.player), (EntityPlayerMP)event.player);
 
             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);
 
 
     }
 
     }
 
}
 
}
  
 
</source>
 
</source>
 
+
SampleEntityPropertiesEventHandlerクラス===
 
===ExtendedPlayerPropertiesクラス===
 
===ExtendedPlayerPropertiesクラス===
 
<source lang = "java">
 
<source lang = "java">
135行目: 139行目:
 
     private ItemStack[] sampleItemStacks = new ItemStack[10];
 
     private ItemStack[] sampleItemStacks = new ItemStack[10];
 
     private NBTTagCompound sampleNBTTagCompound = new NBTTagCompound();
 
     private NBTTagCompound sampleNBTTagCompound = new NBTTagCompound();
 
    /*EntityPlayerインスタンスから外部保存時の固有文字列を返す
 
    *playernameは変更可能になったので、UUIDに変更 */
 
    private static String getSaveKey(EntityPlayer player) {
 
        return player.getGameProfile().getId().toString() + ":" + EXT_PROP_NAME;
 
    }
 
  
 
     /*EntityPlayerにIExtendedEntityPropertiesを登録。登録文字列はMOD固有のものを割り当てること*/
 
     /*EntityPlayerにIExtendedEntityPropertiesを登録。登録文字列はMOD固有のものを割り当てること*/
274行目: 272行目:
 
</source>
 
</source>
  
===CommonProxyクラス===
 
 
<source lang = "java">
 
 
package com.example.examplemod;
 
 
import net.minecraft.entity.player.EntityPlayer;
 
 
public class CommonProxy {
 
 
public EntityPlayer getEntityPlayerInstance() {return null;}
 
 
}
 
 
</source>
 
 
===ClientProxyクラス===
 
 
<source lang = "java">
 
 
package com.example.examplemod;
 
 
import net.minecraft.client.Minecraft;
 
 
import net.minecraft.entity.player.EntityPlayer;
 
 
public class ClientProxy extends CommonProxy {
 
 
@Override
 
 
public EntityPlayer getEntityPlayerInstance() {
 
 
return Minecraft.getMinecraft().thePlayer;
 
 
}
 
 
}
 
 
</source>
 
 
===PacketHandlerクラス===
 
===PacketHandlerクラス===
 
<source lang = "java">
 
<source lang = "java">
412行目: 371行目:
  
 
     public MessagePlayerJoinInAnnouncement(EntityPlayer player) {
 
     public MessagePlayerJoinInAnnouncement(EntityPlayer player) {
 +
        //PlayerのUUIDを文字列で取得
 
         this.uuid = player.getGameProfile().getId().toString();
 
         this.uuid = player.getGameProfile().getId().toString();
 
     }
 
     }
444行目: 404行目:
 
         //UUIDの文字列を受け取る
 
         //UUIDの文字列を受け取る
 
         String uuidString = message.getUuid();
 
         String uuidString = message.getUuid();
        //UUIDからカスタムデータを取得
 
        NBTTagCompound playerData = SampleMod.getEntityData(uuidString);
 
 
         EntityPlayer player = ctx.getServerHandler().playerEntity;
 
         EntityPlayer player = ctx.getServerHandler().playerEntity;
         if (playerData != null) {
+
        //取得したPlayerが同一UUIDを持つか判定
             //プレイヤーのNBTに書き込む
+
         if (player.getGameProfile().getId().toString().equals(uuidString)) {
             (player.getExtendedProperties(ExtendedPlayerProperties.EXT_PROP_NAME)).loadNBTData(playerData);
+
             //クライアント側にデータを送る
 +
             return new MessagePlayerProperties(player);
 
         }
 
         }
         //クライアント側にデータを送る
+
         //UUIDが違っていた場合、同期処理を呼ばない
         return new MessagePlayerProperties(player);
+
         return null;
 
     }
 
     }
 
}
 
}
463行目: 422行目:
 
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のビルドによっては修正されているかもしれないので、適宜確認の上、追加削除を行うこと。
 

2015年3月17日 (火) 22:08時点における版

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

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

プレイヤーへのカスタムデータの追加

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

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

ソースコード

SampleModクラス

package com.example.examplemod;

import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.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;

//1.8のforgeを指定
@Mod(modid = "SampleMod", name = "SampleMod", version = "1.0", dependencies = "required-after:Forge@[11.14.0.1296,)", useMetadata = true)
public class SampleMod {

    @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);
    }
}

=

package com.example.examplemod;

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;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent;

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);
        }
    }
}

SampleEntityPropertiesEventHandlerクラス===

ExtendedPlayerPropertiesクラス

package com.example.examplemod;

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;
    }
}

PacketHandlerクラス

package com.example.examplemod;

import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import net.minecraftforge.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 com.example.examplemod;

import net.minecraftforge.fml.common.network.ByteBufUtils;
import net.minecraftforge.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 com.example.examplemod;

import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.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 com.example.examplemod;

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

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;
    }
}

MessagePlayerJoinInAnnouncementHandlerクラス

package com.example.examplemod;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;

public class MessagePlayerJoinInAnoucementHandler 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で、クライアント側にデータを送って同期させている。