• 论坛

导航

  • 主页
  • 样式指南
  • 入门
    • 概述
    • Mod的结构
    • Forge更新检查器
    • 依赖管理
    • 调试分析器
  • 概念
    • Sides
    • 资源
    • 注册表
    • Jar签名
    • 国际化和本地化
  • 方块
    • 概述
    • 介绍方块状态
    • 方块互动
  • 动画 API
    • 概述
    • 骨骼
    • 动画状态机
    • 使用API
  • TileEntity
    • 概述
      • 创建 TileEntity
      • TileEntity 连接到方块上
      • 用TileEntity储存数据
      • 通过 BlockStates保存 TileEntity
      • 刷新TileEntities
      • 将数据同步到客户端
    • 特殊渲染器
  • 物品
    • 主页
    • 战利品表
  • 模型
    • 模型概述
    • 模型文件
    • 方块状态
      • 方块状态JSON概述
      • Forge方块状态JSON
    • 绑定模型到方块和物品
    • 彩色纹理
    • 物品属性概述
    • 高级模型(未翻译)
      • 高级模型介绍
      • IModel
      • IModelState and IModelPart
      • IBakedModel
      • Extended Blockstates
      • Perspective
      • ItemOverrideList
      • ICustomModelLoader
  • 渲染
    • TileEntityItemStackRenderer
  • 事件
    • 基本用法
  • 网络
    • 主页
    • 概述
    • SimpleImpl
    • 实体
  • 数据储存
    • 能力系统
    • World Saved Data
    • 拓展实体属性
    • Config注解
  • 工具
    • 合成
    • 矿物词典
    • 权限API
  • 效果
    • 音效
  • 惯例
    • 版本命名
    • 文件位置
    • 加载阶段
  • 参与Forge开发
    • 入门
    • PR指南

TileEntities

Tile Entities就像简化的实体一样,绑定到Block上。 它们用于存储动态数据,执行基于tick的任务以及动态渲染。 原本 Minecraft的一些例子是:处理库存(箱子),熔炉上的冶炼逻辑或信标的区域效应。 mod中存在更高级的示例,例如采石场,分拣机,管道和显示器。

提示

TileEntities不是一切的解决方案,如果使用不当会导致卡顿。 请尽可能不要使用它们。

创建 TileEntity

为了创建TileEntity,你需要继承TileEntity类。 重要的是你的TileEntity有一个默认的构造函数,以便Minecraft可以正确加载它。 创建类后,需要注册TileEntity。 为此你需要调用:

GameRegistry#registerTileEntity(Class<? extends TileEntity> tileEntityClass, ResourceLocation key)

第一个参数是你的TileEntity类,第二个参数是你的TileEntity的注册表名称。 此时,您可以选择在FMLPreInitializationEvent期间或在RegistryEvent.Register <Block>事件期间执行此操作,因为TileEntities还没有自己的注册表事件。

提示

在Forge版本14.23.3.2694之前注册TileEntity的方法是使用String而不是ResourceLocation。 此方法从String创建ResourceLocation。 一定要使用ResourceLocation格式modid:tile_entity来避免它被改为minecraft:tile_entity。

TileEntity 连接到方块上

要将新的TileEntity附加到Block,您需要覆盖Block类中的2个方法。

Block#hasTileEntity(IBlockstate state)

Block#createTileEntity(World world, IBlockState state)
使用这些参数,您可以选择块是否应该具有TileEntity。 通常,您将在第一个方法中返回true,在第二个方法中返回TileEntity的新实例。

用TileEntity储存数据

可以重写这两个方法来储存数据:

TileEntity#writeToNBT(NBTTagCompound nbt)

TileEntity#readFromNBT(NBTTagCompound nbt)
每当包含TileEntity的区块加载/保存NBT数据时,就会调用这些方法。使用它们来读取和写入TileEntity类中的字段。

提示

每当您的数据发生变化时,您需要调用TileEntity#markDirty(),否则在保存世界时可能会跳过包含您的TileEntity的区块。

重要

调用父类方法很重要! 标签名称id,x,y,z,ForgeData和ForgeCaps由父类方法保留。

通过 BlockStates保存 TileEntity

可能存在需要更改BlockState的情况,例如使用原本熔炉,当燃料和内部物品燃烧时,原本熔炉将其状态从lit=false改为lit=true。 通过覆盖以下方法实,现这一点非常简单:

TileEntity#shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newSate)

重要

你应该检查BlockStates而不仅仅是返回false,而要以防止不必要的行为和错误。 特别是当你的Block(State)被另一个取代时,比如说Air,也会调用这个方法。

刷新TileEntities

如果您需要刷新TileEntity,例如为了刷新冶炼过程中的进度,您的TileEntity需要实现net.minecraft.util.ITickable接口。 然后,您可以在其中实现所有计算:

ITickable#update()

提示

每个tick都会调用此方法,因此您应该避免在此处进行复杂的计算。 如果可能的话,您应该在每个X tick处进行更复杂的计算。 (一秒钟内的tick数可能低于20但不会更高)

将数据同步到客户端

有三种方法可以将数据同步到客户端。 同步区块加载,同步区块更新并与自定义网络消息同步。

同步区块加载

首先你需要重写:

TileEntity#getUpdateTag()

TileEntity#handleUpdateTag(NBTTagCompound nbt)

同样,这很简单,第一种方法收集应该发送给客户端的数据,而第二个处理该数据。 如果您的TileEntity不包含太多数据,您可以使用在TileEntity中存储数据部分中的方法。

重要

为TileEntities同步过多或无用的数据可能导致网络拥塞。 您应该通过仅在客户端需要时发送客户端所需的信息来优化您的网络使用。 例如,通常不需要在更新标签中发送TileEntity,因为这可以通过GUI同步。

同步方块更新

这个方法有点复杂,但你只需要重写2个方法。 这是一个很小的示例:

@Override
public SPacketUpdateTileEntity getUpdatePacket(){
    NBTTagCompound nbtTag = new NBTTagCompound();
    //在这里写入NBT数据
    return new SPacketUpdateTileEntity(getPos(), 1, nbtTag);
}

@Override
public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt){
    NBTTagCompound tag = pkt.getNbtCompound();
    //处理你的数据
}
SPacketUpdateTileEntity的构造函数需要:

  • TileEntity的位置.
  • 一个ID,虽然除了原本之外它并没有真正用过,因此你可以在那里放一个1。
  • 一个包含你的数据的NBTTagCompound

除此之外,您现在需要在客户端上生成”BlockUpdate”。

World#notifyBlockUpdate(BlockPos pos, IBlockState oldState, IBlockState newState, int flags)
pos是你的TileEntitiy的位置。 对于oldState和newState,您可以传递当前的BlockState。

flags是一个位掩码,应该包含2,它将把更改同步到客户端。

使用自定义网络消息进行同步

这种同步方式可能是最复杂的方式,但通常也是最优化的方式,因为您可以确保只同步你需要数据。 在尝试此操作之前,您应首先查看网络部分,特别是SimpleImpl。 创建自定义网络消息后,您可以将其发送给加载了“TileEntity”的所有用户:

SimpleNetworkWrapper#sendToAllTracking(IMessage, NetworkRegistry.TargetPoint)

警告

重要的是你进行安全检查,当消息到达玩家时,TileEntity可能已被销毁/替换! 你还应该检查是否加载了区块(World#isBlockLoaded(BlockPos))

基于 MkDocs 使用自定义主题构建. 托管于 Read the Docs.
启用夜间模式