开发者
共 10 个一级导航项温室
温室比作物嬗变仪简单得多,但它很适合用来理解另一类模块:
- 没有复杂 UI
- 没有单独网络包
- 重点在“自动处理世界中的方块状态”和“把结果存进内部库存”
如果你想看一个偏自动化、偏世界更新驱动的模块,这一页会更有代表性。
模块职责
温室的核心职责是:
- 观察自身下方的作物状态
- 在合适时机触发生长或收获
- 把产物尽量存入内部库存
它并不直接定义新的配方体系,而是复用:
- 原版或作物方块本身的掉落逻辑
- 内部库存与
RepoProxy
所以它更像“一个自动收获与存储模块”,而不是“一个配方机器”。
核心类
Greenhouse- 方块本体
- 负责打开容器、触发收获时机、注册自动化代理
GreenhouseBlockEntity- 持有 9 格库存
- 负责执行具体的收获与存储逻辑
相比其他核心模块,这一组没有单独菜单类和网络包,因为它直接复用了 DispenserMenu 作为容器界面。
内部库存与自动化
GreenhouseBlockEntity 的内部库存是一个 9 格 Container,并通过:
new ContainerRepo<>(this)RepoProxy.item(...)
包装成统一的物品代理。
然后 Greenhouse 在构造时把这个代理注册给 ProxyProvider,这样外部自动化系统就可以把温室当成一个普通物品仓储来访问。
如果你对这层机制不熟,可以回看 Repo API。
这里的实现重点不在“复杂权限控制”,而在“把模块内部库存平稳暴露给外部自动化”。
收获流程
温室的收获不是靠独立 tick 方法驱动,而是主要通过方块更新链条进入:
onPlace(...)updateShape(...)
updateShape(...) 会在服务器侧:
- 读取下方方块状态
- 取出当前方块实体
- 调用
GreenhouseBlockEntity.tryHarvest(...)
而 tryHarvest(...) 会根据下方方块类型分流:
CropBlock- 走
tryHarvestCrop(...)
- 走
AttachedStemBlock- 走
tryHarvestMelon(...)
- 走
这说明温室的核心不是“统一模拟所有植物生长”,而是:
- 识别下方是不是它支持的植物类型
- 再按类型走不同的收获逻辑
普通作物路径
tryHarvestCrop(...) 的流程是:
- 检查作物是否成熟
- 调用
Block.getDrops(...)取得掉落物 - 从掉落中扣掉一个种子,用来模拟“收获后重新种植”
- 尝试把产物存入内部库存
- 如果存入成功,则把下方作物状态改回半熟
这里有两个很值得注意的点:
- 它不是直接销毁再重种,而是通过年龄属性把作物退回到中间阶段
- 只有在库存能接收产物时,才会真正修改世界状态
因此这个模块的稳定性很大程度来自于“先确认能存,再真正收”。
巨果路径
tryHarvestMelon(...) 的思路和普通作物不同:
- 从
AttachedStemBlock.FACING找到连着的果实位置 - 读取果实掉落
- 尝试存入内部库存
- 成功后移除果实方块
这里不需要年龄回退,因为巨果结构本身就是“藤蔓 + 果实”两段式。
所以温室对不同植物的处理重点并不是统一算法,而是:
- 普通作物关注“年龄重置”
- 巨果关注“找到实际果实并收走”
生长加速
除了收获,温室还在 randomTick(...) 中对下方 CropBlock 调用了原版 randomTick(...)。
这意味着温室的行为其实分成两部分:
- 一部分是“帮作物继续生长”
- 一部分是“成熟后自动收获并存储”
因此它不是单纯的容器方块,也不是单纯的收割器,而是一个完整的生长辅助模块。
存储逻辑的边界
GreenhouseBlockEntity.tryDeposit(...) 会遍历掉落列表并尝试通过 RepoProxy 接收物品。
这层实现的意图很清楚:
- 掉落生成逻辑仍然沿用方块自己的掉落
- 温室只负责“是否能把这些掉落吞进去”
开发时要特别注意的一点是:这个模块的可扩展性主要在“收获判定”和“存储策略”上,而不在“生成掉落”本身。掉落来源仍然是世界方块的既有逻辑。
扩展建议
- 如果你要增加温室支持的植物类型,第一步通常是扩展
tryHarvest(...)的分流逻辑。 - 如果你要改存储策略,优先调整
tryDeposit(...),而不是直接改收获流程。 - 如果你要接入更复杂的自动化,优先沿用现有
RepoProxy暴露方式,而不是另写专门的容器兼容逻辑。 - 如果你要研究“如何围绕现有世界方块逻辑做自动处理”,这个模块是一个很好的参考起点。