提供: Minecraft Modding Wiki
細 |
(初期値未代入によるサーバーエラーを修正) |
||
128行目: | 128行目: | ||
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インスタンスから外部保存時の固有文字列を返す | /*EntityPlayerインスタンスから外部保存時の固有文字列を返す | ||
281行目: | 281行目: | ||
</source> | </source> | ||
+ | |||
===PacketHandlerクラス=== | ===PacketHandlerクラス=== | ||
<source lang = "java"> | <source lang = "java"> |
2014年7月31日 (木) 23:06時点における版
この記事は"Minecraft Forge Universal 10.12.1.1090~"を前提MODとしています。 |
この記事は執筆中です。加筆してくださる人を募集しています。 |
目次
プレイヤーへのカスタムデータの追加
各プレイヤーにカスタムデータを追加する。 方法としては、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.FMLPostInitializationEvent; 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 { //Player毎のIExtendedEntityPropertiesを保存するMap。ダイヤモンド演算子はJava7以降なので注意。 private static final Map<String, NBTTagCompound> extendedEntityData = new HashMap<>(); @EventHandler public void preInit(FMLPostInitializationEvent event) { //Messageの登録呼び出し PacketHandler.init(); } @EventHandler public void init(FMLInitializationEvent event) { //Forge Eventの登録。EntityEvent.EntityConstructingとLivingDeathEventとEntityJoinWorldEvent MinecraftForge.EVENT_BUS.register(this); //FML Eventの登録。PlayerChangedDimensionEventとPlayerRespawnEvent FMLCommonHandler.instance().bus().register(this); } @SubscribeEvent /*IExtendedEntityPropertiesを登録する処理を呼び出す*/ public void onEntityConstructing(EntityEvent.EntityConstructing event) { if (event.entity instanceof EntityPlayer) { 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(event.entity.getCommandSenderName(), playerData); } } @SubscribeEvent /*ワールドに入った時に呼ばれるイベント。ここでIExtendedEntityPropertiesを読み込む処理を呼び出す*/ public void onEntityJoinWorld(EntityJoinWorldEvent event) { if (!event.entity.worldObj.isRemote && event.entity instanceof EntityPlayer) { NBTTagCompound playerData = getEntityData(event.entity.getCommandSenderName()); if (playerData != null) { (event.entity.getExtendedProperties(ExtendedPlayerProperties.EXT_PROP_NAME)).loadNBTData(playerData); } ((ExtendedPlayerProperties)(event.entity.getExtendedProperties(ExtendedPlayerProperties.EXT_PROP_NAME))).loadProxyData((EntityPlayer)event.entity); } } @SubscribeEvent /*リスポーン時に呼ばれるイベント。Serverとの同期を取る*/ public void respawnEvent(PlayerEvent.PlayerRespawnEvent event) { if (!event.player.worldObj.isRemote) { 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); } }
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インスタンスから外部保存時の固有文字列を返す *1.7ではusername変数が使えないので、コマンド送信時の名前で代用 */ private static String getSaveKey(EntityPlayer player) { return player.getCommandSenderName() + ":" + EXT_PROP_NAME; } /*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) {} /*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。 * 使い方としては、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 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(MessagePlayerProperties.class, MessagePlayerProperties.class, 0, Side.CLIENT); } }
MessagePlayerPropertiesクラス
package sampleMod; import cpw.mods.fml.common.network.ByteBufUtils; 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.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; public class MessagePlayerProperties implements IMessage, IMessageHandler<MessagePlayerProperties, IMessage> { private 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); } @Override public IMessage onMessage(MessagePlayerProperties message, MessageContext ctx) { //Client側にIExtendedEntityPropertiesを渡す。 ExtendedPlayerProperties.get(Minecraft.getMinecraft().thePlayer).loadNBTData(message.data); //REPLYは送らないので、nullを返す。 return null; } }
解説
細かい説明はソースコード内に付記したので、そちらを参照のこと。
使用の流れを簡単に書くと、
EntityEvent.EntityConstructingにて、IExtendedEntityPropertiesを登録。
ExtendedPlayerProperties.get(playerインスタンス).getSampleInt()という形でデータを呼び出す。
ExtendedPlayerProperties.get(playerインスタンス).setSampleInt(sample)という形でデータを書き込む。
死亡時等でクライアント側のNBTデータが初期化されるので、LivingDeathEventでデータを保存し、EntityJoinWorldEventで、保存したデータを復帰させる。
PlayerRespawnEventやPlayerChangedDimensionEventでも同期を取っているが、Forgeのビルドによっては修正されているかもしれないので、適宜確認の上、追加削除を行うこと。