提供: Minecraft Modding Wiki
(新規作成) |
細 (→ExtendedPlayerPropertiesクラス) |
||
209行目: | 209行目: | ||
/*初期化メソッド。今のところ使う必要はない。*/ | /*初期化メソッド。今のところ使う必要はない。*/ | ||
public void init(Entity entity, World world) {} | public void init(Entity entity, World world) {} | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
/*以降、各変数のGetterおよびSetter。 | /*以降、各変数のGetterおよびSetter。 | ||
281行目: | 273行目: | ||
</source> | </source> | ||
+ | |||
===CommonProxyクラス=== | ===CommonProxyクラス=== | ||
2015年3月12日 (木) 23:36時点における版
この記事は"Minecraft Forge Universal 11.14.0~"を前提MODとしています。 |
この記事は執筆中です。加筆してくださる人を募集しています。 |
目次
プレイヤーへのカスタムデータの追加
各プレイヤーにカスタムデータを追加する。 方法としては、EntityクラスのgetEntityDataメソッドの利用か、ForgeのIExtendedEntityPropertiesインターフェースの利用の二通りある。
このチュートリアルでは、IExtendedEntityPropertiesによる実装方法を解説する。
ソースコード
SampleModクラス
package com.example.examplemod; 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; //1.8のforgeを指定 @Mod(modid = "SampleMod", name = "SampleMod", version = "1.0", dependencies = "required-after:Forge@[11.14.0.1296,)", useMetadata = true) 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 public void preInit(FMLPreInitializationEvent 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) { EntityPlayer player = (EntityPlayer)event.entity; PacketHandler.INSTANCE.sendToServer(new MessagePlayerJoinInAnnouncement(player)); } } @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 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インスタンスから外部保存時の固有文字列を返す *playernameは変更可能になったので、UUIDに変更 */ private static String getSaveKey(EntityPlayer player) { return player.getGameProfile().getId().toString() + ":" + 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) {} /*以降、各変数の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 com.example.examplemod; import net.minecraft.entity.player.EntityPlayer; public class CommonProxy { public EntityPlayer getEntityPlayerInstance() {return null;} }
ClientProxyクラス
= 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; } }
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) { 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クラス
ackage 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(); //UUIDからカスタムデータを取得 NBTTagCompound playerData = SampleMod.getEntityData(uuidString); EntityPlayer player = ctx.getServerHandler().playerEntity; if (playerData != null) { //プレイヤーのNBTに書き込む (player.getExtendedProperties(ExtendedPlayerProperties.EXT_PROP_NAME)).loadNBTData(playerData); } //クライアント側にデータを送る return new MessagePlayerProperties(player); } }
解説
細かい説明はソースコード内に付記したので、そちらを参照のこと。
使用の流れを簡単に書くと、
EntityEvent.EntityConstructingにて、IExtendedEntityPropertiesを登録。
ExtendedPlayerProperties.get(playerインスタンス).getSampleInt()という形でデータを呼び出す。
ExtendedPlayerProperties.get(playerインスタンス).setSampleInt(sample)という形でデータを書き込む。
死亡時等でクライアント側のNBTデータが初期化されるので、LivingDeathEventでデータを保存し、EntityJoinWorldEventで、保存したデータを復帰させる。
PlayerRespawnEventやPlayerChangedDimensionEventでも同期を取っているが、Forgeのビルドによっては修正されているかもしれないので、適宜確認の上、追加削除を行うこと。