---
front:
hard: 入门
time: 分钟
---
# 自定义方块实体
## 概念
方块实体的概念详见[官方wiki](https://zh.minecraft.wiki/w/方块实体)
## 添加自定义方块实体
需要添加netease:block_entity组件才能为自定义方块添加自定义方块实体。
| 键 | 类型 | 默认值 | 解释 |
| ------- | ---- | ------ | ------------------------------------------------------------ |
| tick | bool | false | 为true时,当玩家进入方块tick范围时,该方块每秒会发送**20次**ServerBlockEntityTickEvent事件
为false时,该方块不会发送ServerBlockEntityTickEvent事件 |
| client_tick | bool | false | 为true时,当玩家进入方块tick范围时,该方块每秒会发送**20次**ModBlockEntityTickClientEvent事件
为false时,该方块不会发送ModBlockEntityTickClientEvent事件 |
| movable | bool | true | 为true时,该方块可被粘性活塞拉回
为false时,该方块不可被粘性活塞拉回 |
- **对于已有方块实体的方块,如[自定义刷怪箱](./3-特殊方块/1-自定义刷怪箱.md),将无法再添加自定义方块实体。**
- 添加了自定义方块实体的方块,可通过**服务端blockEntityData组件**来管理方块实体内的数据。
## 相关组件与事件
- GetBlockEntityData接口
可用于管理方块实体内的数据。
- ServerPlaceBlockEntityEvent事件
当玩家手动放置含自定义方块实体的自定义方块时触发,此时可向该方块实体中存储数据。
- ChunkGeneratedServerEvent事件
通过自定义特征放置含自定义方块实体的自定义方块时,在区块生成完毕时触发,其中包含了该区块中自定义方块实体信息列表,此时可向该方块实体中存储数据。
- ServerBlockEntityTickEvent事件
若在netease:block_entity组件中配置tick为true,则当该自定义方块位于模拟范围内时触发。该事件触发频率为**每秒20次**
## demo解释
- 方块配置
[CustomBlocksMod](../../13-模组SDK编程/60-Demo示例.md#CustomBlocksMod)中,`customblocks:customblocks_test_block_entity`方块配置了自定义方块实体,具体配置如下:
即该方块在距离玩家不远时会每秒发送20次ServerBlockEntityTickEvent事件,且无法被粘性活塞拉回。

- 方块放置
customBlocksServer.py中注册了对ServerPlaceBlockEntityEvent事件的监听,在回调里通过blockEntityData组件向每个由玩家手动创建的自定义方块实体中写入数据:
```python
def ServerPlaceBlockEntityEvent(self, args):
print 'ServerPlaceBlockEntityEvent ', args
dimension = args['dimension'] # 该自定义方块实体所在的维度
blockPos = (args['posX'], args['posY'], args['posZ']) # 该自定义方块实体所处位置
blockName = args['blockName'] # 含该自定义方块实体的方块名称
# 创建blockEntityData组件
comp = self.CreateComponent(self.levelId, "Minecraft", "blockEntityData")
# 获取可操作该自定义方块实体的对象
blockEntityData = comp.GetBlockEntityData(dimension, blockPos)
# 在对自定义方块实体内数据进行操作前,要先进行判空处理
if blockEntityData:
# 使用与dict类似的操作方式存入键为"abc"、值为{"1":True,"2":None,"3":"123"}的数据
blockEntityData['abc'] = {"1": True, "2": None, "3": "123"}
```
- 方块交互
监听了ServerBlockUseEvent,在其中判断玩家是否在与customblocks:customblocks_test_block_entity方块进行交互。是则向其中写入数据:
```python
def ServerBlockUseEvent(self, args):
blockName = args['blockName'] # 方块名称
blockPos = (args['x'], args['y'], args['z']) # 方块位置
playerId = args['playerId'] # 玩家id
dimensionComp = serverApi.CreateComponent(playerId, "Minecraft", "dimension")
dimension = dimensionComp.GetPlayerDimensionId() # 获取玩家所在维度
# 判断交互的方块类型
if blockName == 'customblocks:customblocks_test_block_entity':
comp = self.CreateComponent(self.levelId, "Minecraft", "blockEntityData")
blockEntityData = comp.GetBlockEntityData(dimension, blockPos)
if blockEntityData:
# 向方块实体中写入键为"key"、值为[1, 2, 3]的数据
blockEntityData['key'] = [1, 2, 3]
```
- 方块实体tick
```python
def OnBlockEntityTick(self, args):
# 避免在Tick中频繁打印输出,易造成卡顿
# print 'blockEntityTick ', args
pass
```
监听了ServerBlockEntityTickEvent事件,netease:block_entity组件中配置tick为true的自定义方块每秒会触发20次其自定义方块实体tick事件。
- **应避免在诸如tick事件回调等高频函数中进行打印输出,易造成卡顿。**
- **应避免在地图中放置过多netease:block_entity组件配置tick为true的自定义方块,频繁事件调用也可能造成卡顿**
- 方块销毁
监听了ServerPlayerTryDestroyBlockEvent事件,当有玩家尝试摧毁customblocks:customblocks_test_block_entity方块时,会尝试从其自定义方块实体中读取数据并输出。
```python
def ServerPlayerTryDestroyBlockEvent(self, args):
pos = (args["x"], args["y"], args["z"])
playerId = args['playerId']
dimensionComp = serverApi.CreateComponent(playerId, "Minecraft", "dimension")
dimension = dimensionComp.GetPlayerDimensionId()
comp = self.CreateComponent(self.levelId, "Minecraft", "blockEntityData")
blockEntityData = comp.GetBlockEntityData(dimension, pos)
if blockEntityData:
# 根据key获取方块实体中对应的value
value1 = blockEntityData['key']
value2 = blockEntityData['abc']
print 'value of "key" is', value1
print 'value of "abc" is', value2
```
- 对于从未进行过交互的customblocks:customblocks_test_block_entity方块,当玩家尝试摧毁它时,会输出:
```python
# 不存在于方块实体中的数据将返回None
'value of "key" is None'
'value of "abc" is {"1": True, "2": None, "3": "123"}'
```
- 若玩家曾经与该方块进行过交互,会输出:
```python
'value of "key" is [1, 2, 3]'
'value of "abc" is {"1": True, "2": None, "3": "123"}'
```