
当玩家或命令方块等放置方块时,游戏会通过 BlockSource::setBlock() 函数完成放置流程。
bool BlockSource::setBlock(
const BlockPos &pos,
const Block &block,
int updateFlags,
std::shared_ptr blockEntity,
const ActorBlockSyncMessage *syncMsg,
Actor *blockChangeSource
); pos: 方块坐标
block: 方块对象本身
updateFlags: 一个标记,一般为 3(二进制 11)
blockEntity: 方块的方块实体(可空)
syncMsg: 未知
blockChangeSource: 未知
首先检查 y 坐标,也就是高度限制。然后找到方块所在区块,调用区块的函数 LevelChunk::setBlock(),由该区块完成方块的放置。
const Block &LevelChunk::setBlock(
const ChunkBlockPos &pos,
const Block &block,
BlockSource *issuingSource,
std::shared_ptr blockEntity
); pos: 方块在区块内的坐标
block: 方块对象
issuingSource: BlockSource
blockEntity: 方块的方块实体(可空)
之后调用 BlockSource::_blockChanged(),完成方块更新。
void BlockSource::_blockChanged(
const BlockPos &pos,
uint32_t layer,
const Block &block,
const Block &previousBlock,
int updateFlags,
const ActorBlockSyncMessage *syncMsg,
Actor* blockChangeSource
);
pos: 方块坐标
layer: 层号(共 2 层,第 2 层用于实现含水方块)
block: 放置的方块
previousBlock: 原来的方块
updateFlags: 更新标记
syncMsg: 未知
blockChangeSource: 未知
该函数会先真正放置下方块,同时会完成含水方块的处理。
然后会更新光照,配置方块实体并插入到本区块的方块实体列表中。
接下来调用方块的 onPlace() 函数,由其完成自身的一些更新,比如铁轨的连接;如果自己属于红石元件,也会在这里创建红石元件,添加到红石系统的待添加列表中,并初始化红石设置,比如中继器挡位。
virtual void xxxBlock::onPlace(
BlockSource ®ion,
const BlockPos &pos
) const; 最后调用红石系统的 CircuitSystem::invalidatePos() 函数,处理该方块对周围电路的影响。
void CircuitSystem::invalidatePos(const BlockPos &pos); 该函数内会依次调用六个面的方块的`neighborChanged()`函数,也就是广为人知的 NC 更新。观察者通过此函数检测方块更新。
六个面的更新顺序为:西 东 南 北 上 下
如果自己是红石元件,将自身所有信号源添加到待更新列表中。
如果不是,检查周围六个面是否是红石元件,如果是将其添加到待更新列表中。
然后将该元件的所有信号源添加到待更新列表中。
六个面的遍历顺序与前面不同,为:下 上 北 南 西 东
注意!!:只有生产者和电容器能被添加到待更新列表中,其它类型元件会被直接跳过。

