提供: Minecraft Modding Wiki
Defeatedcrow (トーク | 投稿記録) |
細 |
||
1行目: | 1行目: | ||
{{前提MOD|reqmod="Minecraft Forge Universal 10.13.0.1197~"}} | {{前提MOD|reqmod="Minecraft Forge Universal 10.13.0.1197~"}} | ||
− | + | {{チュートリアル難易度|difficulty=1|clear=none}} | |
+ | {{チュートリアルカテゴリー|difficulty=1|type=Block}} | ||
TileEntity追加のチュートリアルです。 | TileEntity追加のチュートリアルです。 | ||
2014年10月6日 (月) 23:17時点における最新版
この記事は"Minecraft Forge Universal 10.13.0.1197~"を前提MODとしています。 |
TileEntity追加のチュートリアルです。
目次
シンプルなTileEntityの追加[編集]
TileEntityを持つブロックの一例を挙げます。
ここでは、チェストやかまどなどのようにIInventoryインターフェースの実装がなく、 Blockから受け取った情報(String)を保存してNBT・パケットで同期させる、ごく単機能のTileEntityの例とします。
ソースコード[編集]
TutorialCore.java[編集]
- @Modアノテーションを含む、このMODのメインクラス
package tutorial.common; import java.io.IOException; import tutorial.common.block.SimpleBlock; import net.minecraft.block.Block; import net.minecraft.creativetab.CreativeTabs; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.SidedProxy; import cpw.mods.fml.common.Mod.EventHandler; import cpw.mods.fml.common.Mod.Instance; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import cpw.mods.fml.common.registry.GameRegistry; @Mod( modid = "TutorialTiles", name = "TileEntityTutorials", version = "1.7.10_1.0a", dependencies = "required-after:Forge@[10.13.0.1197,)" ) public class TutorialCore { @Instance("TutorialTiles") public static TutorialCore instance; /* * 念の為にプロキシクラスを設定。 * 今回は使用していませんが、TileEntitySpecialRendererを使ってモデルを適用する場合などは、 * client、serverそれぞれで異なるメソッドを使ってTileEntityを登録します。 * (今回は割愛) */ @SidedProxy(clientSide = "tutorial.client.TutorialClientProxy", serverSide = "tutorial.client.TutorialCommonProxy") public static TutorialCommonProxy proxy; /* * 今回追加されるTileEntityを持つブロックです。 */ public static Block simpleTile; /* * ブロックの登録はpreInitで行います。 */ @EventHandler public void preInit(FMLPreInitializationEvent event) { simpleTile = new SimpleBlock().setBlockName("tutorialSimpleBlock").setCreativeTab(CreativeTabs.tabDecorations); GameRegistry.registerBlock(simpleTile, "tutorialSimpleBlock"); } /* * TileEntityの登録をInitで行います。 * ここではプロキシクラスの登録メソッドを呼ぶことで、clientとserverで異なる処理が呼ばれるようにします。 */ @EventHandler public void init(FMLInitializationEvent event) { proxy.registerTileEntity(); } }
TutorialLogger.class[編集]
- ログ出力用クラス。作成は必須でないが、作っておくと開発の役に立つ。
package tutorial.common; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /* * Loggerクラスです。 * 必ず作るべきものでもないのですが、 * 作っておくとデバッグコンソール画面にModID入りのログを出すことができるので、 * 要所要所で出すようにすると、不具合の解決や動作の理解に役立ちます。 */ public class TutorialLogger { public static Logger logger = LogManager.getLogger("TileTutorial"); /* * 以下のメソッドはわざわざ呼び出さなくても、 * TutorialLogger.logger.trace(msg);等で呼び出せば事足りるものではある。 * 出力するログに、定型文やエラーログなどを含めて出したい場合は、以下のようなメソッドを好きにカスタマイズして、 * ログを出したい場所でこのクラスのメソッドを呼ぶようにすると、少し手間を省略できる。 */ public static void trace(String msg) { TutorialLogger.logger.trace(msg); } public static void info(String msg) { TutorialLogger.logger.info(msg); } public static void warn(String msg) { TutorialLogger.logger.warn(msg); } }
TutorialCommonProxy.class[編集]
- Server側のプロキシクラス。TileEntityの登録に使用。
package tutorial.common; import tutorial.common.tile.TutorialSimpleTile; import cpw.mods.fml.common.registry.GameRegistry; import net.minecraft.world.World; public class TutorialCommonProxy { public World getClientWorld() { return null; } /* * TileEntityのserver側登録メソッド。 */ public void registerTileEntity() { GameRegistry.registerTileEntity(TutorialSimpleTile.class, "simpleTile"); } }
TutorialClientProxy.class[編集]
- Client側のプロキシクラス。TileEntityの登録に使用。
package tutorial.client; import cpw.mods.fml.client.FMLClientHandler; import cpw.mods.fml.common.registry.GameRegistry; import net.minecraft.world.World; import tutorial.common.TutorialCommonProxy; import tutorial.common.tile.TutorialSimpleTile; public class TutorialClientProxy extends TutorialCommonProxy{ @Override public World getClientWorld() { return FMLClientHandler.instance().getClient().theWorld; } /* * client側のTileEntity登録メソッド。 * ここでは使用していませんが、TileEntityに独自レンダーを持たせたい場合、 * ClientRegistry.registerTileEntity(TileEntityのクラス名.class, "TileEntityの名前", new TileEntityのレンダ―クラス()); * のように記述して、レンダークラスとTileEntityを登録します。 * * レンダー関係のクラスはクライアント側にしか存在しないため、サーバ側で誤って登録しないよう、(このように)プロキシを通すなどの対策を必ず行います。 */ @Override public void registerTileEntity() { GameRegistry.registerTileEntity(TutorialSimpleTile.class, "simpleTile"); } }
SimpleBlock.class[編集]
- TileEntityを持たせる追加ブロックのクラス。
このブロックは、プレイヤーの右クリックにより以下の様な動作をする。
- プレイヤー未登録時
- プレイヤー名をTileEntityに記憶させる
- プレイヤー名登録済み
- 右クリックしたプレイヤーの名前が登録名に一致するかで、異なるメッセージを出力。
なお、登録した情報は破壊時に消える。
package tutorial.common.block; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import tutorial.common.tile.TutorialSimpleTile; import net.minecraft.block.Block; import net.minecraft.block.BlockContainer; import net.minecraft.block.material.Material; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ChatComponentText; import net.minecraft.world.World; /* * TileEntityを持つブロックです。 * このMODでは、このブロッククラスを通して、ブロックに含まれているTileEntityを操作します。 * チュートリアル用として、比較的client、serverの同期処理に悩まずに済む方法にするためです。 */ public class SimpleBlock extends BlockContainer{ /* * 設置音や素材は羊毛です。 */ public SimpleBlock () { super(Material.cloth); this.setStepSound(Block.soundTypeCloth); } /* * ブロックの右クリックメソッド。 * TileEntityにString(文字列)でプレイヤー名を渡したり、 * 格納されたプレイヤー名を元にアクションを行わせる部分です。 */ public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) { /*プレイヤーの手持ちアイテム*/ ItemStack itemstack = par5EntityPlayer.inventory.getCurrentItem(); /*ブロックと同じ座標にあるTutorialSimpleTileを取得*/ TutorialSimpleTile tile = (TutorialSimpleTile) par1World.getTileEntity(par2, par3, par4); /* * TutorialSimpleTileがちゃんとそこに有る & サーバ側の場合のみ処理を行う。 * * サーバ限定にしている理由ですが、 * 基本的にTileEntityやEntityはサーバ側にのみ存在します。 * * よって、サーバ側でTileEntityを操作した後、何らかの方法でクライアント側に同期させる、という流れで操作します。 * (これを怠ると変化が再ログインでリセットされたり、すぐに戻ってしまったり、TileEntityの変化が見た目に反映されなくなったりします。) */ if (tile != null & !par1World.isRemote) { /*プレイヤーの手持ちアイテムが無いとき*/ if (itemstack == null) { /*Tileに登録されているプレイヤー名。初期状態は「None」*/ String currentName = tile.getString(); /*右クリックしたプレイヤー名*/ String newName = par5EntityPlayer.getDisplayName(); /* * プレイヤー名が未登録状態だった時に限り、最初に右クリックしたプレイヤーをオーナーとして、 * TileEntityにプレイヤー名を登録します。 */ if (currentName.equals("None")) { tile.setString(newName); par5EntityPlayer.addChatMessage(new ChatComponentText("AlartBlock: Registered new owner name! " + newName)); } /*登録済みプレイヤーがもう一度右クリックした時のメッセージ*/ else if (currentName.equals(newName)) { par5EntityPlayer.addChatMessage(new ChatComponentText("AlartBlock: Hello, my owner!")); } /*登録済みの時に、登録者以外のプレイヤーが右クリックした時のメッセージ*/ else { par5EntityPlayer.addChatMessage(new ChatComponentText("AlartBlock: Hello, stranger!")); } } } /* * onBlockActivatedはbooleanですから、trueかfalseを返す必要があります。 * falseだと処理が行われませんので、trueを返します。 * trueの場合、プレイヤーは右クリックで腕を振る動作をします。 * * 動作の条件に一致した時のみtrueを返すやりかたもあります。 * 今回の場合は、クライアントとサーバでbooleanが食い違うことのないよう、すべての場合でtrueになるようにしています。 */ return true; } /* * ブロックの設置時に生成されるTileEntityです。 */ @Override public TileEntity createNewTileEntity(World world, int a) { return new TutorialSimpleTile(); } /* * 紫の羊毛ブロックのテクスチャを流用。 */ @Override @SideOnly(Side.CLIENT) public void registerBlockIcons(IIconRegister par1IconRegister) { this.blockIcon = Blocks.wool.getIcon(1, 2); } }
TutorialSimpleTile.class[編集]
- TileEntityのクラス。ブロックから受け取ったプレイヤー名を保存し、サーバとクライアント間で同期している。
package tutorial.common.tile; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.NetworkManager; import net.minecraft.network.Packet; import net.minecraft.network.play.server.S35PacketUpdateTileEntity; import net.minecraft.tileentity.TileEntity; /* * TileEntityのクラスです。 * TileEntityは、Tick毎に特殊な動作をしたり、複雑なモデルを持ったり、 * NBTを使ってデータを格納したり、色々な用途に使えます。 * * ただしこのクラス内で行われた処理やデータは基本的にサーバ側にしかないので、 * 同期処理についてよく考えて実装する必要があります。 */ public class TutorialSimpleTile extends TileEntity { /* * プレイヤー名を格納するString。初期状態では「None」。 */ private String name = "None"; /* * NBTの読み取り。 * * このメソッドでは、NBTを介してString(文字列)を読み込んでいます。 * 文字列以外に、変数やboolean、ItemStackなども扱えます。 * * NBTを使えば一時的には記録されますが、 * チャンク再生成や再ログイン時にデータが消えてしまいます。 * また、このクラスで行われた処理・サーバ側で行われた処理をクライアント側に反映させるためには、 * 別途パケット処理も必要です。 */ public void readFromNBT(NBTTagCompound par1NBTTagCompound) { super.readFromNBT(par1NBTTagCompound); this.name = par1NBTTagCompound.getString("String"); } /* * こちらはNBTを書き込むメソッド。 */ public void writeToNBT(NBTTagCompound par1NBTTagCompound) { super.writeToNBT(par1NBTTagCompound); par1NBTTagCompound.setString("String", this.name); } /* * パケットの送信・受信処理。 * カスタムパケットは使わず、バニラのパケット送受信処理を使用。 */ @Override public Packet getDescriptionPacket() { NBTTagCompound nbtTagCompound = new NBTTagCompound(); this.writeToNBT(nbtTagCompound); return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, 1, nbtTagCompound); } @Override public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) { this.readFromNBT(pkt.func_148857_g()); } /* * プレイヤー名文字列のゲッターとセッター。 */ public String getString() { return this.name; } public void setString(String par1) { this.name = par1; } public int getMetadata() { return this.worldObj.getBlockMetadata(xCoord, yCoord, zCoord); } }