2014年12月15日 (月)

Minecraft MOD開発 22

Minecraft 1.7.10
Minecraft Forge forge-1.7.10-10.13.2.1230
用の独自ブロック追加MODのサンプルコード。
テクスチャファイルpink_block.pngはforge-1.7.10-10.13.2.1230-src\src\main\resources\assets\nishina\textures\blocksに置く。

仕様:
ブロックが破壊されると標準出力にメッセージを吐く
エンティティが上に乗るとジャンプさせる
クリックされるとチャットメッセージを表示する

上(y+)方向に速度1を与えるようにしたが、結構ジャンプする。落下時に0.5ハートのダメージが入るくらい。

onBlockDestroyedByPlayerとonBlockClickedのメッセージは2回ずつ表示される。@SideOnlyの使い方がまだ分からない。

nishinaCore.java

package nishina;
 
import net.minecraft.block.Block;
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.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;
 
@Mod( modid = "nishinaCore")
public class nishinaCore
{
 public static Block pinkblock;
 
 @EventHandler
 public void preInit( FMLPreInitializationEvent event)
 {
  pinkblock = new pinkBlock();
  GameRegistry.registerBlock( pinkblock, "pinkBlock");
 }
 
 @EventHandler
 public void init( FMLInitializationEvent event)
 {
  LanguageRegistry.addName( pinkblock, "pinkblock");
 }
}

pinkBlock.java

package nishina;
 
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ChatComponentText;
import net.minecraft.world.World;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
 
public class pinkBlock extends Block
{
 
 public pinkBlock()
 {
  super( Material.rock);
  // TODO Auto-generated constructor stub
 
  this.setCreativeTab( CreativeTabs.tabBlock);
  this.setBlockName( "pinkblock");
  this.setBlockTextureName( "nishina:pink_block");
 }
 
 @Override
 public void onBlockDestroyedByPlayer( World world, int x, int y, int z,
   int meta)
 {
  // TODO Auto-generated method stub
  super.onBlockDestroyedByPlayer( world, x, y, z, meta);
 
  System.out.println( "onBlockDestroyedByPlayer is called.");
 }
 
 @Override
 public void onEntityWalking( World world, int x, int y, int z, Entity entity)
 {
  // TODO Auto-generated method stub
  super.onEntityWalking( world, x, y, z, entity);
 
  entity.setVelocity( 0, 1, 0);
 }
 
 @SideOnly( Side.CLIENT)
 @Override
 public void onBlockClicked( World world, int x, int y, int z,
   EntityPlayer player)
 {
  // TODO Auto-generated method stub
  super.onBlockClicked( world, x, y, z, player);
 
  player.addChatMessage( new ChatComponentText(
    "onBlockClicked is called."));
 }
}

2014年5月 3日 (土)

Minecraft MOD開発 21

手に持つと飛行できるアイテムを作ってみる。

NishinaCore.java

package nishina;
 
import net.minecraft.item.Item;
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.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;
 
@Mod(modid = "FlyItem", name = "FlyItem", version = "1.0")
public class NishinaCore
{
 public static Item flyItem;
 public static int itemID = 28000;
 
 @EventHandler
 public void preInit(FMLPreInitializationEvent event)
 {
  flyItem = new flyItem( itemID);
  GameRegistry.registerItem( flyItem, "flyItem");
 }
 
 @EventHandler
 public void init(FMLInitializationEvent event)
 {
  LanguageRegistry.addName( flyItem, "flyItem");
  LanguageRegistry.instance().addNameForObject( flyItem, "ja_JP", "飛行アイテム");
 }
}

flyItem.java

package nishina;
 
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
 
public class flyItem extends Item
{
 public flyItem(int par1)
 {
  super( par1);
  this.setCreativeTab( CreativeTabs.tabMisc);
  this.setUnlocalizedName( "flyItem");
  this.setTextureName( "nishina:fly_item");
  this.setMaxStackSize( 64);
 }
 
 @Override
 public ItemStack onItemRightClick(ItemStack par1ItemStack, World par2World, EntityPlayer par3EntityPlayer)
 {
  // TODO Auto-generated method stub
  par3EntityPlayer.capabilities.allowFlying = !par3EntityPlayer.capabilities.allowFlying;
  return super.onItemRightClick( par1ItemStack, par2World, par3EntityPlayer);
 }
}

アイテムを持って右クリックすると飛行可能になる。地上で右クリックすると飛行不可能へ切り替えられる。クラス2つ、メソッド4つで実現できるから簡単だ。

2014年5月 1日 (木)

Minecraft MOD開発 20

Forge 965で環境構築しようとしたら、

Backing up server
Download of minecraft_server.1.6.4.jar failed hash check, deleting abcf286a14f7aee82e8bf89270433509 ba3145656b1480122bd8759cecd7b7a1
Something failed verifying minecraft files, see log for details.
Decompile Exception: 1

というメッセージが出て失敗する。確かに手元にあるminecraft_server.1.6.4.jar(3月に入手したもの)は6,146,939 バイトだが、いまダウンロードすると6,146,738 バイトだから微妙に違う。

英語フォーラムのスレッドによると、Forgeの964を使って

gradlew.bat setupDecompWorkspace
gradlew.bat eclipse

とすると良いらしい。

2014年4月26日 (土)

Minecraft MOD開発 19

BuildCraftのMJとThermal ExpansionのRFの両方に対応した無限発電機の開発に成功した(EUに対応できるかどうかは未テスト)。Universal Electricityのおかげで簡単だった。

はまったのは、このあたり。
・エネルギーのやりとりはTileEntityに実装する必要がある
・@UniversalClassアノテーションを付ける必要がある
・updateEntityで隣接するエンティティにreceiveEnergyしてやる必要がある

onExtractEnergyはいつ呼ばれるのか不明。

NishinaCore.java

package nishina;
 
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
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.registry.GameRegistry;
 
@Mod(modid = "InfinityBattery", name = "InfinityBattery", version = "1.0")
public class NishinaCore
{
 public static Block blockBattery;
 public static int blockID = 3500;
 
 @EventHandler
 public void preInit(FMLPreInitializationEvent event)
 {
  blockBattery = new BlockBattery( blockID, Material.rock);
  GameRegistry.registerBlock( blockBattery, "BatteryBlock");
 }
 
 @EventHandler
 public void init(FMLInitializationEvent event)
 {
  GameRegistry.registerTileEntity( TileEntityBattery.class, "TileEntityBattery");
 }
}

BlockBattery.java

package nishina;
 
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
 
public class BlockBattery extends BlockContainer
{
 public BlockBattery(int id, Material material)
 {
  super( id, material);
  this.setCreativeTab( CreativeTabs.tabBlock);
  this.setUnlocalizedName( "Battery Block");
  this.setTextureName( "nishina:pink_block");
 }
 
 @Override
 public TileEntity createNewTileEntity(World world)
 {
  return new TileEntityBattery();
 }
}

TileEntityBattery.java

package nishina;
 
import java.util.EnumSet;
 
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.ForgeDirection;
import universalelectricity.api.CompatibilityModule;
import universalelectricity.api.UniversalClass;
import universalelectricity.api.energy.IEnergyContainer;
import universalelectricity.api.energy.IEnergyInterface;
import universalelectricity.api.vector.Vector3;
 
@UniversalClass
public class TileEntityBattery extends TileEntity implements IEnergyContainer, IEnergyInterface
{
 
 public TileEntityBattery()
 {
  super();
 }
 
 @Override
 public boolean canConnect(ForgeDirection from, Object source)
 {
  if (from == null || from.equals( ForgeDirection.UNKNOWN))
  {
   return false;
  }
  
  return true;
 }
 
 @Override
 public long onReceiveEnergy(ForgeDirection from, long receive, boolean doReceive)
 {
  return receive;
 }
 
 @Override
 public long onExtractEnergy(ForgeDirection from, long extract, boolean doExtract)
 {
  return extract;
 }
 
 @Override
 public void updateEntity()
 {
  for (ForgeDirection direction : EnumSet.allOf( ForgeDirection.class))
  {
   TileEntity tileEntity = new Vector3( this).translate( direction).getTileEntity( this.worldObj);
   CompatibilityModule.receiveEnergy( tileEntity, direction.getOpposite(), Integer.MAX_VALUE, true);
  }
  super.updateEntity();
 }
 
 @Override
 public void setEnergy(ForgeDirection from, long energy)
 {
 }
 
 @Override
 public long getEnergy(ForgeDirection from)
 {
  return Integer.MAX_VALUE;
 }
 
 @Override
 public long getEnergyCapacity(ForgeDirection from)
 {
  return Integer.MAX_VALUE;
 }
 
}

2014年4月24日 (木)

Minecraftとビデオカード

ビデオカードを換装したので、ベンチマークを取ってみた。

150fps以上を見ても意味がないので、ばっさりカット。Radeon HD 4870からGeForce GT 610を経由して、750Tiにした意味はあったといえるだろう。影MODが60fpsを超えるので、一応実用になる。

Radeon 4870の性能が低いわけではないが、古いためかAlgodooでメニューが表示されない。それが換装した理由。

ビデオカード以外のスペック
CPU: Intel Core i5-2500K(3.3GHz)
RAM: 8GB(DDR3 @ 533 MHz)
SSD: 240 GB INTEL SSDSC2CT240A3

2014年4月21日 (月)

Minecraft Modding 18

I extends TileEntity and implements IEnergyContainer, IEnergyInterface. canConnect is called. But onExtractEnergy is not called and Minechem 5 doesn's work with my battery. Why?

NishinaCore.java

package nishina;
 
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
 
@Mod(modid = "InfinityBattery", name = "InfinityBattery", version = "1.0")
public class NishinaCore
{
 public static Block blockBattery;
 public static int blockID = 3500;
 
 @EventHandler
 public void preInit(FMLPreInitializationEvent event)
 {
  blockBattery = new BlockBattery( blockID, Material.rock);
  GameRegistry.registerBlock( blockBattery, "BatteryBlock");
 }
 
 @EventHandler
 public void init(FMLInitializationEvent event)
 {
  GameRegistry.registerTileEntity( TileEntityBattery.class, "TileEntityBattery");
 }
}

BlockBattery.java

package nishina;
 
import net.minecraft.block.*;
import net.minecraft.block.material.*;
import net.minecraft.creativetab.*;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import universalelectricity.api.energy.*;
import net.minecraftforge.common.ForgeDirection;
 
public class BlockBattery extends BlockContainer
{
 public BlockBattery(int id, Material material)
 {
  super( id, material);
  this.setCreativeTab( CreativeTabs.tabBlock);
  this.setUnlocalizedName( "Battery Block");
  this.setTextureName( "nishina:pink_block");
 }
 
 @Override
 public TileEntity createNewTileEntity(World world)
 {
  return new TileEntityBattery();
 }
}

TileEntityBattery.java

package nishina;
 
import net.minecraft.tileentity.*;
import net.minecraftforge.common.ForgeDirection;
import universalelectricity.api.*;
import universalelectricity.api.energy.*;
 
@UniversalClass
public class TileEntityBattery extends TileEntity implements IEnergyContainer, IEnergyInterface
{
 
 public TileEntityBattery()
 {
  super();
 }
 
 @Override
 public boolean canConnect(ForgeDirection from, Object source)
 {
  System.out.println( "canConnect called.");
  if (from == null || from.equals( ForgeDirection.UNKNOWN))
  {
   return false;
  }
  
  return true;
 }
 
 @Override
 public long onReceiveEnergy(ForgeDirection from, long receive, boolean doReceive)
 {
  System.out.println( "onReceiveEnergy called.");
  return receive;
 }
 
 @Override
 public long onExtractEnergy(ForgeDirection from, long extract, boolean doExtract)
 {
  System.out.println( "onExtractEnergy called.");
  return extract;
 }
 
 @Override
 public void setEnergy(ForgeDirection from, long energy)
 {
 }
 
 @Override
 public long getEnergy(ForgeDirection from)
 {
  return Integer.MAX_VALUE;
 }
 
 @Override
 public long getEnergyCapacity(ForgeDirection from)
 {
  return Integer.MAX_VALUE;
 }
 
}

STDOUT

Three injection succeeded.

2014-04-21 20:08:45 [情報] [STDOUT] [Universal Electricity] Injected universalelectricity.core.asm.template.tile.TemplateICTile API into: nishina/TileEntityBattery
2014-04-21 20:08:45 [情報] [STDOUT] [Universal Electricity] Injected universalelectricity.core.asm.template.tile.TemplateBCTile API into: nishina/TileEntityBattery
2014-04-21 20:08:45 [情報] [STDOUT] [Universal Electricity] Injected universalelectricity.core.asm.template.tile.TemplateTETile API into: nishina/TileEntityBattery

Screenshots

Versions

Minecraft: 1.6.4
Forge: 1.6.4-9.11.1.965
UE: 3.1.0.87
JDK: jdk-7u55-windows-x64
OS: Windows 7 64bit Pro

Thanks for reading to the end.

Minecraft MOD開発 17

Universal Electricityのホームページを見ると、”Don’t worry about making it work with other systems, that’s our job.”と書いてある。少し希望が出てきた。私がMODを開発しようとした動機は、MinechemでMJエネルギーが使えなかったからなので。

ちょっとUEを使ってみる。ドキュメントにあるようにUniversal-Electricity-3.1.0.87-api.zipを展開したものを、\forge-1.6.4-9.11.1.965-src\forge\mcp\src\minecraftに置く。Universal-Electricity-3.1.0.87-dev.jarを\forge-1.6.4-9.11.1.965-src\forge\mcp\jars\modsに置く。

NishinaCore.java

package nishina;
 
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
 
@Mod(modid = "InfinityBattery", name = "InfinityBattery", version = "1.0")
public class NishinaCore
{
 public static Block blockBattery;
 public static int blockID = 3500;
 
 @EventHandler
 public void preInit(FMLPreInitializationEvent event)
 {
  blockBattery = new BlockBattery( blockID, Material.rock);
  GameRegistry.registerBlock( blockBattery, "BatteryBlock");
 }
}
package nishina;
 
import net.minecraft.block.*;
import net.minecraft.block.material.*;
import net.minecraft.creativetab.*;
import universalelectricity.api.energy.*;
import net.minecraftforge.common.ForgeDirection;
 
public class BlockBattery extends Block implements IEnergyContainer
{
 public BlockBattery(int id, Material material)
 {
  super( id, material);
  this.setCreativeTab( CreativeTabs.tabBlock);
  this.setUnlocalizedName( "Battery Block");
  this.setTextureName( "nishina:pink_block");
 }
 
 @Override
 public long getEnergy(ForgeDirection from)
 {
  return Integer.MAX_VALUE;
 }
 
 @Override
 public long getEnergyCapacity(ForgeDirection from)
 {
  return Integer.MAX_VALUE;
 }
 
 @Override
 public void setEnergy(ForgeDirection from, long energy)
 {
 }
 
}

コンパイルは通るが、Unpoweredと表示されて動作しない。IEnergyInterfaceも継承しないとダメか?


2014年4月20日 (日)

Minecraftが引っかかる

Minecraftが引っかかるようになった。2秒ごとに少しだけ止まる。JREの64bitバージョンを入れたら解決した。

2014年4月14日 (月)

Journey Map

Journey Mapがすごく便利。ブラウザの機能を利用して、Minecraft世界の地図を表示できる。縮尺も変えられない地図で苦労したくない人にはとってもお勧め。

・インストール方法
Minecraft Forgeが入っていれば、jarをmodsフォルダへ置くだけ。バージョン毎に2種類有るけど、私が使っているのはUnlimitedの方。

・起動
ブラウザ(Internet Explorerとか)でhttp://localhost:8080/へアクセスすると地図が表示される。

何をやっているのか分からない人のために簡単に説明しておくと、Journey Mapは自分のパソコンの中で動くホームページのふりをしている。localhostというのは、自分(ブラウザが動いている)パソコン自身という意味。それがGoogle Mapsの機能を使いつつMinecraftの地図を表示させる簡単な方法だったんだろう。

・使い方
その仕組みからいって、Google Mapsと全く同じ。スクロールホイールで5段階に拡大縮小できる。左ドラッグでスクロール。

ボタンは左上から、Journey Map関連ホームページへのリンク、地図の表示を昼間モードと夜間モードへ切り替える、地図の中心を自分自身にする。

右上の歯車のアイコンは、マップに表示するものを選択できる。私はAnimalsとMobsは表示しないように指定している。Rei's Minimapのwaypointを表示できるのがとても便利。

一番右上のアイコンからマップを画像として保存できる。

・表示
縦横のグリッドはおそらくチャンク境界。

屋根があるところへ行くと、マップ全体が白黒表示になる。

2014年4月 6日 (日)

Minecraft MOD開発 16

次はメタデータとダメージ値を理解することを目標にする。まずは英語Wikiのチュートリアルを参考に、精錬レシピの作成に挑戦。

NishinaCore.java

package nishina;
 
import net.minecraft.block.Block;
import net.minecraft.item.ItemStack;
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.registry.GameRegistry;
 
@Mod(modid = "DirtSmeltingMod", name = "DirtSmeltingMod", version = "1.0")
public class NishinaCore
{
 
 @EventHandler
 public void init(FMLInitializationEvent event)
 {
  GameRegistry.addSmelting( Block.dirt.blockID, new ItemStack( Block.blockDiamond), 0.1f);
 }
 
}

石を焼くとダイヤモンドブロックになった。

では、メタデータを持ったアイテムのレシピに挑戦してみる。メタデータの一覧はMinecraft Wiki(英語)が参考になる。とりあえずsampling(苗木)を作成できるレシピに挑戦してみる。Wikiの表記でも、Not Enough Itemsの表示でも苗木のアイテムIDは6なのだが、ソースコードでは6は矢に割り当てられている。

とりえあず精錬後のアイテムIDは6にする。

NishinaCore.java

package nishina;
 
import net.minecraft.block.Block;
import net.minecraft.item.ItemStack;
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.registry.GameRegistry;
 
@Mod(modid = "DirtSmeltingMod", name = "DirtSmeltingMod", version = "1.0")
public class NishinaCore
{
 @EventHandler
 public void init(FMLInitializationEvent event)
 {
  GameRegistry.addSmelting( Block.dirt.blockID, new ItemStack( 6, 1, 0), 0.1f);
  GameRegistry.addSmelting( Block.stone.blockID, new ItemStack( 6, 1, 1), 0.1f);
 }
}

土を精錬すると樫の苗木になった。

石を精錬すると松の苗木になった。

チュートリアルによると、レシピの材料にダメージ値を指定するのは難しい上に1.7では動かないそうなので、これはパスする。

メタデータは15までしかないはずだが、武器防具のダメージ値はどうやって保持しているのだろうか? ItemSword.javaを読むと、EnumToolMaterialで決められている。EnumToolMaterialは武器防具道具の、素材毎の性能を決めている。鉄のツールは250回使えるので、メタデータとは別に十分な記憶領域が確保されているようだ。

Wikiによると鉄の剣のアイテムIDは267だ。土を精錬すると半分消耗した鉄の剣を生成するようにしてみる。

NishinaCore.java

package nishina;
 
import net.minecraft.block.Block;
import net.minecraft.item.ItemStack;
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.registry.GameRegistry;
 
@Mod(modid = "DirtSmeltingMod", name = "DirtSmeltingMod", version = "1.0")
public class NishinaCore
{
 @EventHandler
 public void init(FMLInitializationEvent event)
 {
  GameRegistry.addSmelting( Block.dirt.blockID, new ItemStack( 267, 1, 125), 0.1f);
 }
}

ダメージ値ありの剣を生成することに成功した。

ダメージ値がいかなる値であっても、クラフトの元にする方法が存在する。この時はダメージ値にShort.MAX_VALUEを指定する。精錬レシピの元にダメージ値を指定するのは上に述べたように難しいので、shapeless recipeを追加する。

NishinaCore.java

package nishina;
 
import net.minecraft.block.Block;
import net.minecraft.item.ItemStack;
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.registry.GameRegistry;
 
@Mod(modid = "DirtSmeltingMod", name = "DirtSmeltingMod", version = "1.0")
public class NishinaCore
{
 @EventHandler
 public void init(FMLInitializationEvent event)
 {
  GameRegistry.addSmelting( Block.dirt.blockID, new ItemStack( 267, 1, 125), 0.1f);
  GameRegistry.addShapelessRecipe( new ItemStack(Item.swordIron), new ItemStack( Item.swordIron, 1, Short.MAX_VALUE));
 }
}

ダメージのある剣をクラフトでダメージ無しにすることができた。

より以前の記事一覧

その他のカテゴリー