方块,以及方块状态
在世界里放置普通方块,方式如下。
world一般是你所调用的接口里包含的。比如,如果想做一个物品“点石成金”,他在背包里时刻都把脚底下变成金块:
这肯定有问题。问题在哪呢?脚底下是空气的时候也变金块,走在空中的话,下不去了,因为即使挖掉刚生成的金块,也会再刷一个金块出来。
一种想法是,我们让这个能力变为可控的,比如只有拿在主手的时候才生效;另一种想法是,我们不把空气变成金块,只改变既有的石头方块。怎么判断世界里某个位置是什么呢?
一个set,一个get,很直白,是不是?
那么,怎么判断脚下是不是石头呢?一时间我会想到很多种方式,并且他们不等价:
第一种,判断方块是不是石头这个Block;第二种,判断方块状态是不是石头的默认状态。
乍一看两者等价,但实际上差的很远。

安山岩、闪长岩、花岗岩,这污染背包三兄弟,以及它们的磨制版本,与石头的注册名相同,这就说明它们是同一方块的不同状态。如果你使用第二种,那么算上石头本身,这七个兄弟都会受到影响。
第三种就更是走远了。

凡是质地是石头的方块都会被算进去,这包括……发射器,附魔台,骨头方块什么的。具体哪些算石头,在游戏里很难看到,只能靠翻源码,查询Material.ROCK的引用。注意是ROCK,不是STONE。方块质地没有STONE。
好,我们现在知道如果只作用于“石头”,那么应该判断state==defaultState,那么,如果我想判断花岗岩这种不是默认状态的,又要怎么办呢?我们看一段BlockStone的代码。
石头类里定义了一个VARIANT对象,它暗示石头会有这么个属性,用来产生变种。注意,这里写了不一定就有,这里没写不一定就没有。关键在于Block里是否重写createBlockState:
石头的长这样,所以说明它只有一个属性,那就是“VARIANT”。这个VARIANT不一定写在石头里,也可以写在别的地方。
我自己写一个方块,也可以用石头的这个VARIANT属性,所以看一个东西有什么属性一定不要看类开头声明了什么成员,一定要看这里。
相应地,如果我只写了个MY_VARIANT对象在那,但是我忘了写进createBlockState,那那个对象就报废了,方块还是没变体。当然,要正确定义一种全新的有变体的方块,还要再写好几个地方,每个都容易犯错,篇幅所限,留到其他专栏里,这里先不展开。
这个是BlockNewLeaf的代码:
你可以看到,这种叶子具有三套子状态,可以排列组合。注意,这个VARIANT是BlockNewLeaf.VARIANT,和石头里的不是同一个,只是同名罢了。毕竟叶子是没有磨制花岗岩这种选项的。
我们再看看红石线(BlockRedStoneWire):
他有五套子状态在这排列组合。
那么,怎么指定子状态,答案已经出来了,就是BlockStone构造函数里那样。
给我们的IBlockState调用成员withProperty,返回新的IBlockState。第一个参数是VARIANT这样的PropertyEnum对象,第二个是对象的值。通俗来说就是,state.withProperty(类型,花岗岩),这样。
对于树叶那种有多个状态的,只能多调用几次,分别指定:
state.withProperty(类型,橡树).withProperty(检查腐烂,不)
不指定的就会按照默认,或者state之前的状态来。
所以,我们想判断是不是磨制花岗岩,可以:
但这还有个问题。有多套子状态时,我只想判断其中一套的话,难道要把其他的几个值都排列组合吗?显然不是。我们可以直接获取某个state子状态的值。你猜这个获取选项值的接口叫啥?getProperty?不好意思答错了,他叫getValue。不对称,是不是很想打人?
总结:
World::setBlockState
World::getBlockState
IBlockState::withProperty
IBlockState::getValue