Skip to main content
GTMC
  • Preface
    • 00Introduction
    • 01Update Concepts and Update Types
    • 02Continuous Block Updates and Analysis Methods
    • 01Tick and Inter-Tick Timing
    • 02A First Look at Intra-Tick Timing
    • 03Scheduled Ticks and Scheduled Tick Components
    • 05Block Entities
    • 06Block Events
    • 01Masa Gadget
    • 02Litematica Tutorial
  • 附录
  • A.Stacks
  • B.Glossary

Table of contents

  • Preface
    • 00Introduction
    • 01Update Concepts and Update Types
    • 02Continuous Block Updates and Analysis Methods
    • 01Tick and Inter-Tick Timing
    • 02A First Look at Intra-Tick Timing
    • 03Scheduled Ticks and Scheduled Tick Components
    • 05Block Entities
    • 06Block Events
    • 01Masa Gadget
    • 02Litematica Tutorial
  • 附录
  • A.Stacks
  • B.Glossary
Loading article content
Loading
Loading article
GTMC

Graduate Texts in Minecraft

"Curiosity in 'cubic' inch."

Preface

Articles
25
Authors
12
Revised
August 2026

Community

  • About
  • Authors
  • Team
  • QQ Group

Participate

  • Contribute
  • Editorial Policy
  • Issues

Source

  • Repository
  • CC BY-NC-SA 4.0
  • Apache-2.0

Not an official Minecraft product. Not affiliated with Mojang Studios.

Contributors retain copyright. Article content is released under CC BY-NC-SA 4.0 with attribution preserved through article metadata and source history.

© 2024–2026 GTMC Collectiveec529be

GTMC

  • Articles
  • PDF
  • Glossary
  • About
  • Authors
  • Preface
    • 00Introduction
    • 01Update Concepts and Update Types
    • 02Continuous Block Updates and Analysis Methods
    • 01Tick and Inter-Tick Timing
    • 02A First Look at Intra-Tick Timing
    • 03Scheduled Ticks and Scheduled Tick Components
    • 05Block Entities
    • 06Block Events
    • 01Masa Gadget
    • 02Litematica Tutorial
  • 附录
  • A.Stacks
  • B.Glossary

Table of contents

  • Preface
    • 00Introduction
    • 01Update Concepts and Update Types
    • 02Continuous Block Updates and Analysis Methods
    • 01Tick and Inter-Tick Timing
    • 02A First Look at Intra-Tick Timing
    • 03Scheduled Ticks and Scheduled Tick Components
    • 05Block Entities
    • 06Block Events
    • 01Masa Gadget
    • 02Litematica Tutorial
  • 附录
  • A.Stacks
  • B.Glossary
Loading article content
Loading
Loading article
CH 02Micro Timing
Path: MicroTiming/方块实体.zh.md
Molforte+4
Word count: 1,083
Est. read time: 6 min
Last edited: 2026-07-13
Contributors:
  • MMolforte
  • BBFladderbeanawa
  • hhotpad100c
  • SSDU-Little-River
  • ttanhHeng
Created:
2024-12-28
Last edited:
2026-07-13
URL:
https://www.techmc.wiki/en/articles/micro-timing/block-entities
Reuse
CC BY-NC-SA 4.0
Blocks with block entities
Blocks with block entities
Code basisMC 1.20.1
YARN
1 reference

Outdated translation

The latest original revision is 8347bcb. Lag: 2 source commits and 63 days.

05 Block Entities

1 What Are Block Entities

Blocks store data using a limited set of predefined BlockStates, render models through default rendering behavior, and execute logic via update and scheduling systems.
However, this approach has limitations and cannot directly support certain block behaviors required for game interactions.

Block entities solve this problem. They give ordinary blocks three key capabilities:

  • Store data using NBT
  • Custom rendering behavior
  • Update every tick

1.1 Block Entity Contents

Block entities vary by block type, but a basic block entity typically contains:

  • type
  • world (the world it exists in)
  • pos (position)
  • removed (whether it has been removed)
  • cachedState (cached state of the corresponding block)

1.2 Block Entities and Blocks

Block entities are bound to blocks in the world. Each block position can only have one block entity instance.

Only blocks that are specifically declared can have block entities attached.
Block entities are added and removed alongside their blocks. However, through techniques like update suppression, you can retain a block entity even after its block is removed.

2 Notable Blocks with Block Entities

2.1 Hopper

In Minecraft, the hopper is a block entity that handles automated item transfer.

2.1.1 Hopper Block Entity Data

A hopper block entity stores the following information:

  • inventory storage space (5 slots)
  • transferCooldown cooldown (default is -1)
  • lastTickTime world time of the last tick
  • facing direction

2.1.2 Hopper Block Entity Functions

  • Transfer items to target container
  • Extract items from container
  • Attempt to pick up item entities

2.1.3 Hopper Block Entity Workflow

Every game tick, the hopper executes these steps:

  1. Decrease cooldown (cd)

    • If cd is still greater than 0, the hopper skips all pull and output operations and stops processing.
    • If cd reaches zero, the hopper begins attempting output and pull operations.
  2. Execute item transfer logic

    • First attempt output (place items into target container)
    • Then attempt pull (extract items from container above)
    • If either succeeds, the hopper resets the cooldown and syncs its data.
// IMG_LOAD
Hopper Block Entity Workflow

Now, let's look at the detailed logic for pulling and outputting.

When the hopper is ready to operate, it first attempts to output to the container it's pointing at. Then it tries to extract items from above. Finally, if either operation succeeds, it sets the cooldown and syncs its data.

// IMG_LOAD
When the hopper is ready to operate, it first attempts to output to the container it's pointing at. Then it tries to extract items from above. Finally, if either operation succeeds, it sets the cooldown and syncs its data.

Let's look at output and pull separately.

First, output...
The output operation uses the insert() method, which transfers items from the hopper to the target container and returns a boolean indicating success. If the transfer succeeds, the hopper enters cooldown.

Basic output logic:

  1. Check if the target container is available

    • If the target container is full, output fails.
    • If the target container has available slots, attempt to transfer items.
  2. Attempt to output items

    • Iterate through the hopper's item slots, attempting to transfer items to the target container one by one.
    • If any transfer succeeds, return "success"; otherwise return "failure".
// IMG_LOAD
Hopper Block Entity Workflow

When calling transfer() to move items, it returns an item stack:

  • An empty return value means the items were fully transferred, so output succeeds.
  • A non-empty return value means the items could not be fully transferred, so output fails.
// IMG_LOAD
Hopper Block Entity Workflow

That covers output. Now let's look at pulling.
The pull logic is similar to output, but in the opposite direction:

  • During output: the hopper transfer()s items to the target container.
  • During pull: a container transfer()s items to the hopper.

Since we'll cover transfer() in detail next, we won't repeat it here.

// IMG_LOAD
Since we'll cover transfer() in detail next, we won't repeat it here.

transfer() is the core method that handles item transfer in hoppers. It takes the following parameters:

  • from: item source (can be a hopper or other container)
  • to: transfer target (can be a container or another hopper)
  • itemStack: the item stack to transfer
  • slot: target slot in the target container

Here's how it works:

  1. Check the target slot

    • If the slot is empty, place itemStack directly into it and clear itemStack.
    • If the slot already has items of the same type with remaining space, merge the items and clear itemStack.
  2. Determine if the transfer succeeded

    • After transfer, if itemStack is empty, the transfer succeeded; otherwise it failed.
  3. Special timing for hopper-to-hopper transfers

    • If the target is another hopper, the target hopper receives 8gt of cooldown.
    • If the target hopper to has already ticked before the source hopper from, the target hopper to only receives 7gt of cooldown.

      Note that this only occurs when the target hopper is empty.
      Additionally, even if from ticks after to and applies 8gt of cooldown, to will immediately subtract 1 when it ticks next, leaving only 7gt of cooldown.

// IMG_LOAD
Hopper Block Entity Workflow

That covers the basic hopper mechanism. This foundation will help with the chapters ahead.

2.1.4 Moving Piston

Another important block is moving_piston, commonly known as B36.

2.1.5 Moving Piston Block Entity Data

A moving piston block entity stores the following information:

  • pushedBlock the block being pushed
  • facing direction
  • extending whether the piston is extending (determines animation direction)
  • source whether this is the piston head retracting
  • progress current movement progress
  • savedWorldTime world time when logic was last executed

2.1.6 Moving Piston Block Entity Functions

  • Handle piston pushing entities
  • Update animation progress
  • If progress>=1, replace MOVING_PISTON with the block stored in pushedBlock
  • Render animation on the client

2.1.7 Moving Piston Block Entity Workflow

For details, see 5.7.

AdvancedGoes deeper into the underlying mechanicsSkip

3 Timing Between Block Entities

Block entity ticking is managed by two lists in LevelChunk:

  • pendingBlockEntityTickers: block entities added during the current tick cycle.
  • blockEntityTickers: block entities scheduled for ticking.

Both lists are ArrayLists, so traversal order depends on insertion order. Here's the process:

  • tickBlockEntities() first appends pendingBlockEntityTickers to blockEntityTickers, then clears pendingBlockEntityTickers.
  • When iterating through blockEntityTickers, removed entries (isRemoved() returns true) are deleted; others have their tick() method called.

New block entities are added via addBlockEntityTicker(). If ticking is in progress (tickingBlockEntities == true), they go to pendingBlockEntityTickers; otherwise to blockEntityTickers.

When unloading, block entities in the same chunk are stored in a Map<BlockPos, BlockEntity>. On reload, the map is iterated and each entity is added to blockEntityTickers via addBlockEntityTicker(), so execution order follows BlockPos.hashCode() order.

Across chunks, block entity order depends on which chunk loads first.

TL;DR:

Before unloading, block entity tick order matches placement order. After reloading, order within a chunk depends on position hash; across chunks, it depends on chunk load order.

Here's the relevant code (with some irrelevant content removed):

java
MC 1.20.1
YARN
// Used to temporarily store block entities dynamically added during the tickBlockEntities processprivate final List<TickingBlockEntity> pendingBlockEntityTickers = Lists.newArrayList();// List of block entities to be tickedprotected final List<TickingBlockEntity> blockEntityTickers = Lists.newArrayList();private void tickBlockEntities() { this.tickingBlockEntities = true; if (!this.pendingBlockEntityTickers.isEmpty()) { this.blockEntityTickers.addAll(this.pendingBlockEntityTickers); this.pendingBlockEntityTickers.clear(); } // Traverse the list of block entities being ticked Iterator<TickingBlockEntity> iterator = this.blockEntityTickers.iterator(); while (iterator.hasNext()) { TickingBlockEntity tickingBlockEntity = iterator.next(); if (tickingBlockEntity.isRemoved()) { // If the block entity has been removed, remove it from the list iterator.remove(); } else if (this.shouldTickBlocksAt(tickingBlockEntity.getPos())) { // If the position should be ticked, call the tick() method for updating tickingBlockEntity.tick(); } } this.tickingBlockEntities = false;}// Add a block entity's tickerpublic void addBlockEntityTicker(TickingBlockEntity tickingBlockEntity) { (this.tickingBlockEntities ? this.pendingBlockEntityTickers : this.blockEntityTickers) .add(tickingBlockEntity);}// All block entities within the chunkprotected final Map<BlockPos, BlockEntity> blockEntities = Maps.newHashMap();// After chunk loading is complete, register all existing block entities (add them to the tick system)public void registerAllBlockEntitiesAfterLevelLoad() { this.blockEntities.values().forEach(blockEntity -> { // Add a ticker for this block entity, i.e., add it to blockEntityTickers this.updateBlockEntityTicker(blockEntity); });}
// SYNTAX_HIGHLIGHT
End of advanced section
Prev
Scheduled Ticks and Scheduled Tick Components
Next
Block Events
CH 02Micro Timing
Path: MicroTiming/方块实体.zh.md
Molforte+4
Word count: 1,083
Est. read time: 6 min
Last edited: 2026-07-13
Contributors:
  • MMolforte
  • BBFladderbeanawa
  • hhotpad100c
  • SSDU-Little-River
  • ttanhHeng
Created:
2024-12-28
Last edited:
2026-07-13
URL:
https://www.techmc.wiki/en/articles/micro-timing/block-entities
Reuse
CC BY-NC-SA 4.0
Blocks with block entities
Blocks with block entities
Code basisMC 1.20.1
YARN
1 reference

Outdated translation

The latest original revision is 8347bcb. Lag: 2 source commits and 63 days.

05 Block Entities

1 What Are Block Entities

Blocks store data using a limited set of predefined BlockStates, render models through default rendering behavior, and execute logic via update and scheduling systems.
However, this approach has limitations and cannot directly support certain block behaviors required for game interactions.

Block entities solve this problem. They give ordinary blocks three key capabilities:

  • Store data using NBT
  • Custom rendering behavior
  • Update every tick

1.1 Block Entity Contents

Block entities vary by block type, but a basic block entity typically contains:

  • type
  • world (the world it exists in)
  • pos (position)
  • removed (whether it has been removed)
  • cachedState (cached state of the corresponding block)

1.2 Block Entities and Blocks

Block entities are bound to blocks in the world. Each block position can only have one block entity instance.

Only blocks that are specifically declared can have block entities attached.
Block entities are added and removed alongside their blocks. However, through techniques like update suppression, you can retain a block entity even after its block is removed.

2 Notable Blocks with Block Entities

2.1 Hopper

In Minecraft, the hopper is a block entity that handles automated item transfer.

2.1.1 Hopper Block Entity Data

A hopper block entity stores the following information:

  • inventory storage space (5 slots)
  • transferCooldown cooldown (default is -1)
  • lastTickTime world time of the last tick
  • facing direction

2.1.2 Hopper Block Entity Functions

  • Transfer items to target container
  • Extract items from container
  • Attempt to pick up item entities

2.1.3 Hopper Block Entity Workflow

Every game tick, the hopper executes these steps:

  1. Decrease cooldown (cd)

    • If cd is still greater than 0, the hopper skips all pull and output operations and stops processing.
    • If cd reaches zero, the hopper begins attempting output and pull operations.
  2. Execute item transfer logic

    • First attempt output (place items into target container)
    • Then attempt pull (extract items from container above)
    • If either succeeds, the hopper resets the cooldown and syncs its data.
// IMG_LOAD
Hopper Block Entity Workflow

Now, let's look at the detailed logic for pulling and outputting.

When the hopper is ready to operate, it first attempts to output to the container it's pointing at. Then it tries to extract items from above. Finally, if either operation succeeds, it sets the cooldown and syncs its data.

// IMG_LOAD
When the hopper is ready to operate, it first attempts to output to the container it's pointing at. Then it tries to extract items from above. Finally, if either operation succeeds, it sets the cooldown and syncs its data.

Let's look at output and pull separately.

First, output...
The output operation uses the insert() method, which transfers items from the hopper to the target container and returns a boolean indicating success. If the transfer succeeds, the hopper enters cooldown.

Basic output logic:

  1. Check if the target container is available

    • If the target container is full, output fails.
    • If the target container has available slots, attempt to transfer items.
  2. Attempt to output items

    • Iterate through the hopper's item slots, attempting to transfer items to the target container one by one.
    • If any transfer succeeds, return "success"; otherwise return "failure".
// IMG_LOAD
Hopper Block Entity Workflow

When calling transfer() to move items, it returns an item stack:

  • An empty return value means the items were fully transferred, so output succeeds.
  • A non-empty return value means the items could not be fully transferred, so output fails.
// IMG_LOAD
Hopper Block Entity Workflow

That covers output. Now let's look at pulling.
The pull logic is similar to output, but in the opposite direction:

  • During output: the hopper transfer()s items to the target container.
  • During pull: a container transfer()s items to the hopper.

Since we'll cover transfer() in detail next, we won't repeat it here.

// IMG_LOAD
Since we'll cover transfer() in detail next, we won't repeat it here.

transfer() is the core method that handles item transfer in hoppers. It takes the following parameters:

  • from: item source (can be a hopper or other container)
  • to: transfer target (can be a container or another hopper)
  • itemStack: the item stack to transfer
  • slot: target slot in the target container

Here's how it works:

  1. Check the target slot

    • If the slot is empty, place itemStack directly into it and clear itemStack.
    • If the slot already has items of the same type with remaining space, merge the items and clear itemStack.
  2. Determine if the transfer succeeded

    • After transfer, if itemStack is empty, the transfer succeeded; otherwise it failed.
  3. Special timing for hopper-to-hopper transfers

    • If the target is another hopper, the target hopper receives 8gt of cooldown.
    • If the target hopper to has already ticked before the source hopper from, the target hopper to only receives 7gt of cooldown.

      Note that this only occurs when the target hopper is empty.
      Additionally, even if from ticks after to and applies 8gt of cooldown, to will immediately subtract 1 when it ticks next, leaving only 7gt of cooldown.

// IMG_LOAD
Hopper Block Entity Workflow

That covers the basic hopper mechanism. This foundation will help with the chapters ahead.

2.1.4 Moving Piston

Another important block is moving_piston, commonly known as B36.

2.1.5 Moving Piston Block Entity Data

A moving piston block entity stores the following information:

  • pushedBlock the block being pushed
  • facing direction
  • extending whether the piston is extending (determines animation direction)
  • source whether this is the piston head retracting
  • progress current movement progress
  • savedWorldTime world time when logic was last executed

2.1.6 Moving Piston Block Entity Functions

  • Handle piston pushing entities
  • Update animation progress
  • If progress>=1, replace MOVING_PISTON with the block stored in pushedBlock
  • Render animation on the client

2.1.7 Moving Piston Block Entity Workflow

For details, see 5.7.

AdvancedGoes deeper into the underlying mechanicsSkip

3 Timing Between Block Entities

Block entity ticking is managed by two lists in LevelChunk:

  • pendingBlockEntityTickers: block entities added during the current tick cycle.
  • blockEntityTickers: block entities scheduled for ticking.

Both lists are ArrayLists, so traversal order depends on insertion order. Here's the process:

  • tickBlockEntities() first appends pendingBlockEntityTickers to blockEntityTickers, then clears pendingBlockEntityTickers.
  • When iterating through blockEntityTickers, removed entries (isRemoved() returns true) are deleted; others have their tick() method called.

New block entities are added via addBlockEntityTicker(). If ticking is in progress (tickingBlockEntities == true), they go to pendingBlockEntityTickers; otherwise to blockEntityTickers.

When unloading, block entities in the same chunk are stored in a Map<BlockPos, BlockEntity>. On reload, the map is iterated and each entity is added to blockEntityTickers via addBlockEntityTicker(), so execution order follows BlockPos.hashCode() order.

Across chunks, block entity order depends on which chunk loads first.

TL;DR:

Before unloading, block entity tick order matches placement order. After reloading, order within a chunk depends on position hash; across chunks, it depends on chunk load order.

Here's the relevant code (with some irrelevant content removed):

java
MC 1.20.1
YARN
// Used to temporarily store block entities dynamically added during the tickBlockEntities processprivate final List<TickingBlockEntity> pendingBlockEntityTickers = Lists.newArrayList();// List of block entities to be tickedprotected final List<TickingBlockEntity> blockEntityTickers = Lists.newArrayList();private void tickBlockEntities() { this.tickingBlockEntities = true; if (!this.pendingBlockEntityTickers.isEmpty()) { this.blockEntityTickers.addAll(this.pendingBlockEntityTickers); this.pendingBlockEntityTickers.clear(); } // Traverse the list of block entities being ticked Iterator<TickingBlockEntity> iterator = this.blockEntityTickers.iterator(); while (iterator.hasNext()) { TickingBlockEntity tickingBlockEntity = iterator.next(); if (tickingBlockEntity.isRemoved()) { // If the block entity has been removed, remove it from the list iterator.remove(); } else if (this.shouldTickBlocksAt(tickingBlockEntity.getPos())) { // If the position should be ticked, call the tick() method for updating tickingBlockEntity.tick(); } } this.tickingBlockEntities = false;}// Add a block entity's tickerpublic void addBlockEntityTicker(TickingBlockEntity tickingBlockEntity) { (this.tickingBlockEntities ? this.pendingBlockEntityTickers : this.blockEntityTickers) .add(tickingBlockEntity);}// All block entities within the chunkprotected final Map<BlockPos, BlockEntity> blockEntities = Maps.newHashMap();// After chunk loading is complete, register all existing block entities (add them to the tick system)public void registerAllBlockEntitiesAfterLevelLoad() { this.blockEntities.values().forEach(blockEntity -> { // Add a ticker for this block entity, i.e., add it to blockEntityTickers this.updateBlockEntityTicker(blockEntity); });}
// SYNTAX_HIGHLIGHT
End of advanced section
Prev
Scheduled Ticks and Scheduled Tick Components
Next
Block Events