Minecraft PI EDTIONのAPIを使ってマップを取得(その1)

mcpi-map
Minecraft PI EDITIONへブロック取得APIと、pythonのvisualライブラリを使って描いた画像です。

Minecraftは始めたばかりで操作もままならず、その真の面白さに到達できる気がしていませんが、APIを使うのは面白いなあと感じております。このままゲームの面白さではなくコマンドライナーとしての面白さを追求していきたいと思っています。
では、Minecraft PI EDITIONをダウンロードして実行します。

pi@raspberrypi:~/Downloads $ wget https://s3.amazonaws.com/assets.minecraft.net/pi/minecraft-pi-0.1.1.tar.gz
pi@raspberrypi:~/Downloads $ tar xzf minecraft-pi-0.1.1.tar.gz -C ~/
pi@raspberrypi:~/Downloads $ cd ~/mcpi
pi@raspberrypi:~/mcpi $ ./minecraft-pi

Minecraftを起動したら、別の端末ウィンドウにて、

pi@raspberrypi:~/mcpi $ cd api/python/mcpi

各APIは、本ディレクトリ内にあるminecraft.pyに記載されています。たとえばブロック関連のAPIを確認するには、’def.*Block’で検索すれば良いです

pi@raspberrypi:~/mcpi/api/python/mcpi $ grep -A3 'def.*Block' minecraft.py
    def pollBlockHits(self):
        """Only triggered by sword => [BlockEvent]"""
        s = self.conn.sendReceive("events.block.hits")
        events = [e for e in s.split("|") if e]
--
    def getBlock(self, *args):
        """Get block (x,y,z) => id:int"""
        return int(self.conn.sendReceive("world.getBlock", intFloor(args)))

    def getBlockWithData(self, *args):
        """Get block with data (x,y,z) => Block"""
        ans = self.conn.sendReceive("world.getBlockWithData", intFloor(args))
        return Block(*map(int, ans.split(",")))
--
    def getBlocks(self, *args):
        """Get a cuboid of blocks (x0,y0,z0,x1,y1,z1) => [id:int]"""
        return int(self.conn.sendReceive("world.getBlocks", intFloor(args)))

    def setBlock(self, *args):
        """Set block (x,y,z,id,[data])"""
        self.conn.send("world.setBlock", intFloor(args))

    def setBlocks(self, *args):
        """Set a cuboid of blocks (x0,y0,z0,x1,y1,z1,id,[data])"""
        self.conn.send("world.setBlocks", intFloor(args))

pi@raspberrypi:~/mcpi/api/python/mcpi $ 

ブロックのIDは、block.pyに書かれています。’スペース2個=’でgrepするとうまい具合に一覧が取得できます。

pi@raspberrypi:~/mcpi/api/python/mcpi $ grep '  =' block.py
AIR                 = Block(0)
STONE               = Block(1)
GRASS               = Block(2)
DIRT                = Block(3)
COBBLESTONE         = Block(4)
WOOD_PLANKS         = Block(5)
SAPLING             = Block(6)
BEDROCK             = Block(7)
WATER_FLOWING       = Block(8)
WATER               = WATER_FLOWING
WATER_STATIONARY    = Block(9)
LAVA_FLOWING        = Block(10)
LAVA                = LAVA_FLOWING
LAVA_STATIONARY     = Block(11)
SAND                = Block(12)
GRAVEL              = Block(13)
GOLD_ORE            = Block(14)
IRON_ORE            = Block(15)
COAL_ORE            = Block(16)
WOOD                = Block(17)
LEAVES              = Block(18)
GLASS               = Block(20)
LAPIS_LAZULI_ORE    = Block(21)
LAPIS_LAZULI_BLOCK  = Block(22)
SANDSTONE           = Block(24)
BED                 = Block(26)
COBWEB              = Block(30)
GRASS_TALL          = Block(31)
WOOL                = Block(35)
FLOWER_YELLOW       = Block(37)
FLOWER_CYAN         = Block(38)
MUSHROOM_BROWN      = Block(39)
MUSHROOM_RED        = Block(40)
GOLD_BLOCK          = Block(41)
IRON_BLOCK          = Block(42)
STONE_SLAB_DOUBLE   = Block(43)
STONE_SLAB          = Block(44)
BRICK_BLOCK         = Block(45)
TNT                 = Block(46)
BOOKSHELF           = Block(47)
MOSS_STONE          = Block(48)
OBSIDIAN            = Block(49)
TORCH               = Block(50)
FIRE                = Block(51)
STAIRS_WOOD         = Block(53)
CHEST               = Block(54)
DIAMOND_ORE         = Block(56)
DIAMOND_BLOCK       = Block(57)
CRAFTING_TABLE      = Block(58)
FARMLAND            = Block(60)
FURNACE_INACTIVE    = Block(61)
FURNACE_ACTIVE      = Block(62)
DOOR_WOOD           = Block(64)
LADDER              = Block(65)
STAIRS_COBBLESTONE  = Block(67)
DOOR_IRON           = Block(71)
REDSTONE_ORE        = Block(73)
SNOW                = Block(78)
ICE                 = Block(79)
SNOW_BLOCK          = Block(80)
CACTUS              = Block(81)
CLAY                = Block(82)
SUGAR_CANE          = Block(83)
FENCE               = Block(85)
GLOWSTONE_BLOCK     = Block(89)
BEDROCK_INVISIBLE   = Block(95)
STONE_BRICK         = Block(98)
GLASS_PANE          = Block(102)
MELON               = Block(103)
FENCE_GATE          = Block(107)
GLOWING_OBSIDIAN    = Block(246)

getBlock(x,y,z)を使い、指定座標のブロックIDを取得してみます。

pi@raspberrypi:~/mcpi/api/python/mcpi $ python -c'
> import minecraft
> mc=minecraft.Minecraft.create()
> print mc.getBlock(0,0,0)
> '
1
pi@raspberrypi:~/mcpi/api/python/mcpi $ 

結果に1が表示されましたが、これがブロックIDです。上でgrepしたように、1はSTONEのブロックです。
getBlockを使い、連続で100個ほど取得してみましょう。

pi@raspberrypi:~/mcpi/api/python/mcpi $ python -c'
> import minecraft
> mc=minecraft.Minecraft.create()
> for x in range(0,100):
>   print mc.getBlock(x,0,0)
> ' | pr -t10 | expand
1      1      1      1      1      1      1      1      1      3
1      1      1      1      1      1      1      1      1      1
1      1      1      1      1      1      1      1      1      1
1      1      1      1      1      1      1      1      1      1
1      1      1      1      1      1      1      1      1      1
1      1      1      1      1      1      1      1      1      1
1      1      1      1      1      1      15     3      1      1
1      1      1      1      1      1      1      1      1      1
1      1      1      1      1      1      1      1      1      1
1      1      1      1      1      1      1      1      1      1
pi@raspberrypi:~/mcpi/api/python/mcpi $ 

あれ、何か変です。実際にやってみると分かりますが、少し重たく感じます。
出力をしないようにして、時間計測してみます。

pi@raspberrypi:~/mcpi/api/python/mcpi $ time python -c'
> import minecraft
> mc=minecraft.Minecraft.create()
> for x in range(0,100):
>  mc.getBlock(x,0,0)
'

real	0m5.086s
user	0m0.240s
sys	0m0.030s
pi@raspberrypi:~/mcpi/api/python/mcpi $ 

5秒かかりました。
5秒ぐらい、と思うかもしれませんが、Minecraftのマップは3次元ですので、
yもzも100個分とすると、 5秒 x 100 x 100 =

~$ bc <<< '5*100*100'
50000
~$ !!'/60/60'
bc <<< '5*100*100''/60/60'
13
~$ 

上記コマンドの結果のとおり、50000秒、つまり13時間となります。

取得する空間を小さくして実験してみましょう。

pi@raspberrypi:~/mcpi/api/python/mcpi $ time python -c'
> import minecraft
> mc=minecraft.Minecraft.create()
> for x in range(0,10):
>   for y in range(0,10):
>     for z in range(0,10):
>       print mc.getBlock(x,y,z)
' | pr -t10 | expand > data.txt

real	0m50.165s
user	0m1.250s
sys	0m0.350s
pi@raspberrypi:~/mcpi/api/python/mcpi $ 

約50秒でした。これぐらいなら待てます。
取得したデータを確認してみます。

pi@raspberrypi:~/mcpi/api/python/mcpi $ head data.txt
1      1      1      1      1      1      1      1      1      1
1      1      1      1      1      1      1      1      1      1
1      1      1      1      1      1      1      1      1      1
1      1      1      1      1      1      1      1      1      1
1      1      1      1      1      1      1      1      1      1
1      1      1      1      1      1      1      1      1      1
1      1      1      1      1      1      1      1      1      1
1      1      1      1      1      1      1      1      1      1
1      1      1      1      1      1      1      1      1      1
1      1      1      1      1      1      1      1      1      1
pi@raspberrypi:~/mcpi/api/python/mcpi $ 

ブロックは同じ種類のIDが固まって地形を形成していますので、このように冗長なデータとなります。

(その2へ続く)

8 responses to “Minecraft PI EDTIONのAPIを使ってマップを取得(その1)

  1. Thanks, I was doing a google search and your site came up for homes for rent in Altamonte Springs, FL but anyway, I have enjoyed reading it, keep it up!

  2. I told my kids we’d play after I found what I neddee. Damnit.

  3. I must say you have very interesting articles here.
    Your blog should go viral. You need initial traffic only.
    How to get it? Search for: Etorofer’s strategies

  4. Thanks for sharing, this is a fantastic blog post.Thanks Again. Awesome.

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA