Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The level tick

Verified against Minecraft 26.2 · Part III · A player stands still for one twentieth of a second while a whole dimension advances — weather, scheduled ticks, spawns, every entity, every block entity.

Nobody moves. A wheat crop is one random tick short of ripe, a creeper is walking a fence line, rain has been falling for four minutes and a piston somewhere is halfway through extending. Then ServerLevel.tick runs, once, for this dimension, and all of it advances: the border interpolates, the weather counts down, the scheduled block ticks fire, mobs are counted and spawned, chunks near players get their random ticks, every entity in range runs its Entity.tick, block entities run their tickers, and the block changes that all of that produced are handed to the clients. It is one method on the Server thread, called once per dimension from MinecraftServer.tickChildren (the server tick), overworld first. The order inside it is the whole lecture, because one of the steps is in a place nobody expects: the block-change broadcast runs before the entities tick. ServerChunkCache.broadcastChangedChunks comes before ChunkMap.tick and long before EntityTickList.forEach, so a block a command changed reaches your screen this tick and a block a piston changed reaches it on the next one.

Three ranges, before we need them

Three phrases run through everything below and they are all one number line. A chunk is loaded when it has a ChunkHolder at all; it is block-ticking at level 32 or below (ChunkLevel.BLOCK_TICKING_LEVEL) and entity-ticking at 31 or below (ChunkLevel.ENTITY_TICKING_LEVEL), and those last two answers come from the simulation graph, through DistanceManager.inBlockTickingRange and DistanceManager.inEntityTickingRange. How a chunk gets its level — which tickets put it there and which graph they feed — is Part IV’s tickets and loading; for this page it is enough that block-ticking reaches one chunk further out than entity-ticking, and that both are decided fresh, inside this tick, before anything ticks.

The cast

classwhat it decidesthread
ServerLevelthe order of the tick, and every gate in it — one instance per dimensionServer
ServerChunkCachethe chunk half of the tick: ticket purging, distance updates, spawning, random ticks, the broadcastServer
ChunkMapwhich chunks are candidates for spawning, which are entity-ticking, and every player’s view of every entityServer
ChunkHolderone chunk’s pending block and light changes, and which packet shape they becomeServer
LevelTicksthe two scheduled-tick queues, one LevelChunkTicks per chunk, drained by priorityServer
EntityTickListwhich entities are ticked, and a stable view of that set while it is being walkedServer
PersistentEntitySectionManagerwhich entities exist and which of them are ticking — the tick list’s only editorServer; its inbox is filled by IO threads
TickRateManagerwhether this is a normal tick at all, through TickRateManager.runsNormallyServer

The whole tick, and its three gates

The tick is one method calling its own private methods, so its shape is not a conversation — it is a column with guards down the side. There are three guards, and every step is behind one of them, a combination of them, or nothing: running (TickRateManager.runsNormally, false while /tick freeze holds and no step is pending), not a debug world (Level.isDebug), and the dimension is not empty (ServerLevel.emptyTime below ServerLevel.EMPTY_TIME_NO_TICK, 300).

flowchart TD
    START["MinecraftServer.tickChildren calls ServerLevel.tick, overworld first"]
    ENV["handlingTick goes true, EnvironmentAttributeSystem.invalidateTickCache — no gate"]
    WB["WorldBorder.tick, then advanceWeatherCycle and its game-event packets — running"]
    SLEEP["the sleep check: move the clock, wake the players, reset the weather — no gate"]
    SKY["Level.updateSkyBrightness, read out of the environment attributes — no gate"]
    TIME["ServerLevel.tickTime: gameTime and the schedule queue, overworld only — running"]
    SCHED["ServerLevel.blockTicks then ServerLevel.fluidTicks, 65536 apiece — running, and not a debug world"]
    RAID["Raids.tick — running"]
    SCC["ServerChunkCache.tick, handed the server's time budget — no gate"]
    PURGE["TicketStorage.purgeStaleTickets — running"]
    DIST["ServerChunkCache.runDistanceManagerUpdates: which chunks tick is settled here — no gate"]
    CHUNKS["mob counts, spawning chunks, thunder, spawns, random ticks, custom spawners — running, and not a debug world"]
    CAST["ServerChunkCache.broadcastChangedChunks: block, block-entity and light packets — not a debug world"]
    TRACK["ChunkMap.tick: chunk tracking, and the movement of everything that moved last tick — no gate"]
    UNLOAD["ChunkMap.tick with haveTime: POI saving and chunk unloads, until the budget is spent — no gate"]
    EVENTS["ServerLevel.runBlockEvents, then handlingTick goes false — running"]
    EMPTY["hasActiveTickets resets emptyTime, otherwise it rises — and it rises only while running"]
    DRAGON["EnderDragonFight.tick, the End only — running, and the dimension is not empty"]
    ENT["EntityTickList.forEach: each entity, then its riders — the dimension is not empty"]
    BE["Level.tickBlockEntities — the dimension is not empty, and each ticker fires only while running"]
    EM["PersistentEntitySectionManager.tick: the loading inbox, then the unload set — no gate"]
    DBG["LevelDebugSynchronizers.tick — no gate"]
    START --> ENV --> WB --> SLEEP --> SKY --> TIME --> SCHED --> RAID --> SCC
    SCC --> PURGE --> DIST --> CHUNKS --> CAST --> TRACK --> UNLOAD
    UNLOAD --> EVENTS --> EMPTY --> DRAGON --> ENT --> BE --> EM --> DBG

Read the gates and most of the page’s surprises fall out of the figure. Sleeping through the night works with the game frozen. A frozen world still loads, sends and unloads chunks — and stops expiring its tickets. A debug world keeps its entities and drops its block updates. And the last two steps run on a dimension with nobody in it.

The cache that is dropped before the border

The first thing the tick does to the world, before the border and before the weather, is EnvironmentAttributeSystem.invalidateTickCache: last tick’s resolved environment attributes are thrown away. That system (environment attributes) is where the old per-dimension and per-biome constants went, and Level.updateSkyBrightness later in this same tick reads EnvironmentAttributes.SKY_LIGHT_LEVEL out of it rather than deriving sky light from the time of day. ServerClockManager invalidates the same cache on every level whenever a clock moves, so the level is not its only owner — it is the first reader of the tick, and it starts clean.

Then WorldBorder.tick advances the interpolated extent, and ServerLevel.advanceWeatherCycle counts the clear, rain and thunder timers down under GameRules.ADVANCE_WEATHER, resampling each from ServerLevel.RAIN_DELAY, ServerLevel.RAIN_DURATION, ServerLevel.THUNDER_DELAY and ServerLevel.THUNDER_DURATION as it expires, and fading Level.rainLevel and Level.thunderLevel by 0.01 a tick, which is why a downpour arrives as a five-second ramp. The countdowns belong to the server: ServerLevel.getWeatherData delegates to MinecraftServer.getWeatherData, one WeatherData shared by every dimension, and the only per-level parts are those two floats and the Level.canHaveWeather test that decides whether this dimension acts on any of it. Every move of a float is a ClientboundGameEventPacket (ClientboundGameEventPacket.RAIN_LEVEL_CHANGE, ClientboundGameEventPacket.THUNDER_LEVEL_CHANGE) to this dimension’s players, and a start or a stop goes to every player in every dimension.

Sleeping is the one thing a freeze cannot stop

SleepStatus.areEnoughSleeping and SleepStatus.areEnoughDeepSleeping (against GameRules.PLAYERS_SLEEPING_PERCENTAGE) decide the night skip, and they are checked outside every gate. If the dimension type has a default clock and GameRules.ADVANCE_TIME is on, ServerClockManager.moveToTimeMarker jumps that clock to ClockTimeMarkers.WAKE_UP_FROM_SLEEP; ServerLevel.wakeUpAllPlayers gets everyone out of bed, and ServerLevel.resetWeatherCycle clears the storm. The ClientboundSetTimePacket that follows is sent by the clock manager, not by the level — day time is not the level’s state in 26.2 at all.

What the level does own is gameTime, and only in the overworld: ServerLevel.tickTime advances it when the level was built with its ServerLevel.tickTime flag set, which MinecraftServer does for the overworld alone, and every other dimension reads that number. The same call advances the server-wide TimerQueue behind /schedule (MinecraftServer.getScheduledEvents), so a scheduled function is timed off overworld gameTime and stands still while the world is frozen.

Scheduled ticks, twice, and a promise to the same block

LevelTicks.tick is called twice — ServerLevel.blockTicks, then ServerLevel.fluidTicks — each with the current gameTime and a budget of ServerLevel.MAX_SCHEDULED_TICKS_PER_TICK, 65536, and both skipped entirely in a debug world. Each call collects every LevelChunkTicks container whose head is due and whose chunk passes ServerLevel.isPositionTickingWithEntitiesLoaded, drains them in ScheduledTick.INTRA_TICK_DRAIN_ORDER — priority, then submission order, with no time term, because a container is only collected once its head is already due, and ScheduledTick.DRAIN_ORDER, which does compare times, orders each chunk’s own queue — and hands each drained tick to ServerLevel.tickBlock or ServerLevel.tickFluid.

Both of those check that what is at the position is still what the tick was scheduled for: ServerLevel.tickBlock the Block, before BlockBehaviour.BlockStateBase.tick; ServerLevel.tickFluid the Fluid, before FluidState.tick. That check is the whole cancellation mechanism: replace a block and its pending ticks evaporate, with nothing anywhere removing them. The queue itself, and what schedules into it, is scheduled ticks.

The chunk source does five things in one call

ServerChunkCache.tick receives the server’s MinecraftServer.haveTime supplier — the level never looks at it, it only passes it on — and does five things in order.

It purges stale tickets, but only while running, so a frozen world holds on to expired portal and pearl tickets indefinitely. It runs ServerChunkCache.runDistanceManagerUpdates, ungated, which is where chunks change ticking state: the reason an entity starts or stops ticking this tick is decided here, several steps before the entity loop reads it. Then, if this is not a debug world, it does the spawning and random-ticking work below and broadcasts the block changes; it updates entity tracking; and finally it spends whatever time is left on POI saving and chunk unloads.

That last step is the only part of the whole level tick that yields to the clock, and even it does not yield completely: ChunkMap.processUnloads force-drains anything over two thousand queued unloads whatever the budget says.

Two chunk sets, and two different mob caps

NaturalSpawner.createState walks ServerLevel.getAllEntities — every entity in the dimension, skipping mobs that require persistence — and counts them per MobCategory, using the chunk each one stands in to charge a spawn-potential field and to feed a LocalMobCapCalculator. That count is then read two different ways. Globally, NaturalSpawner.SpawnState.canSpawnForCategoryGlobal allows a category while its count is under MobCategory.getMaxInstancesPerChunk × DistanceManager.getNaturalSpawnChunkCount ÷ 289 (NaturalSpawner.MAGIC_NUMBER, 17²) — the mob cap everyone argues about. Locally, LocalMobCapCalculator.canSpawn applies the raw, unscaled MobCategory.getMaxInstancesPerChunk per player close enough to the chunk, so a category can sit well under the server-wide cap and still refuse to spawn beside one crowded player. Persistent categories — the animals — are considered only on a tick where gameTime divides by 400, and the whole spawning half is behind GameRules.SPAWN_MOBS.

Two chunk sets are then walked, and they are not the same set. ChunkMap.collectSpawningChunks gathers the spawning chunks: the radius-8 tracker’s candidates that have a ticking chunk and at least one non-spectating player within 128 blocks (ChunkMap.playerIsCloseEnoughForSpawning). They are shuffled, and each then gets ChunkAccess.incrementInhabitedTime, then ServerLevel.tickThunder if it is also entity-ticking — a 1-in-100000 roll per chunk per tick while raining and thundering, whose bolt prefers a lightning rod, then a mob that can see the sky, then the heightmap, and which brings a trap skeleton horse along at effective difficulty × 1 % — and then NaturalSpawner.spawnForChunk if ServerLevel.canSpawnEntitiesInChunk.

The second set is ChunkMap.forEachBlockTickingChunk, which despite its name walks DistanceManager.forEachEntityTickingChunk — the entity-ticking set, level 31 and below. Each of those chunks gets ServerLevel.tickChunk.

Random ticks are counted per section, and empty sections are free

ServerLevel.tickChunk does two things with one number, GameRules.RANDOM_TICK_SPEED (default 3). It rolls that many 1-in-48 chances at ServerLevel.tickPrecipitation — the ice and snow layer, using Biome.shouldFreeze, Biome.shouldSnow and GameRules.MAX_SNOW_ACCUMULATION_HEIGHT — and then, for every LevelChunkSection in the chunk that reports LevelChunkSection.isRandomlyTicking, picks that many random positions and rolls both BlockBehaviour.BlockStateBase.randomTick and the fluid’s at each. LevelChunkSection.isRandomlyTicking is a counter maintained on every block change, so a section of solid stone costs nothing at all: the loop over sections is a loop over the chunk’s interesting height. Set the rule to zero and both halves stop, ice and snow included.

The position itself does not come from Level.random. Level.getBlockRandomPos advances Level.randValue, a plain linear congruential generator, and unpacks x, y and z out of one integer. Everything the block then does with that position — the crop-growth roll, fire spreading, every implementation of BlockBehaviour.BlockStateBase.randomTick — takes Level.random, which is also what the ice and snow rolls, the lightning roll and the spawning-chunk shuffle use.

The custom spawners come last inside this step. ServerLevel.tickCustomSpawners runs the overworld’s PhantomSpawner, PatrolSpawner, CatSpawner, VillageSiege and WanderingTraderSpawner — a list only the overworld is constructed with. Three of the five carry a game rule of their own (GameRules.SPAWN_PHANTOMS, GameRules.SPAWN_PATROLS, GameRules.SPAWN_WANDERING_TRADERS); cats and sieges answer only to GameRules.SPAWN_MOBS, which gates the whole call.

The broadcast, which is why entities are a tick behind

Almost nothing in the game sends a block update at the moment a block changes — a landing FallingBlockEntity is the exception worth knowing, and it is dealt with at the end of this section. ServerLevel.sendBlockUpdated calls ServerChunkCache.blockChanged, which finds the ChunkHolder, records the position in that holder’s per-section set, and — the first time a holder gains a changed section — adds it to ServerChunkCache.chunkHoldersToBroadcast. Then it returns. The packets are built once, later, in the chunk source’s step.

sequenceDiagram
    participant SL as ServerLevel
    participant SCC as ServerChunkCache
    participant CH as ChunkHolder
    participant CM as ChunkMap
    participant Wire as the network

    Note over SL,CM: before the tick — a command changed a hundred blocks
    SL->>SCC: sendBlockUpdated, once per block
    SCC->>CH: blockChanged, one entry in that section's set
    CH-->>SCC: nothing leaves, the holder is only marked
    Note over SL,Wire: this tick, inside ServerChunkCache.tick
    SCC->>CH: broadcastChangedChunks walks every marked holder
    CH->>Wire: ClientboundLightUpdatePacket first, to the border players only
    CH->>Wire: ClientboundBlockUpdatePacket for a section with one change
    CH->>Wire: ClientboundSectionBlocksUpdatePacket for a section with several
    CH->>Wire: BlockEntity.getUpdatePacket beside any changed position that has one
    SCC->>CM: ChunkMap.tick, the movement of everything that moved last tick
    Note over SL,Wire: still this tick, several steps later
    SL->>SL: tickBlockEntities, PistonMovingBlockEntity finishes a push and changes a block
    SL->>SCC: sendBlockUpdated, marked, and it waits for the next tick

ChunkHolder.broadcastChanges asks two different questions of two different audiences, and it asks the light one first: if either light filter has anything in it, ChunkHolder.PlayerProvider.getPlayers is called with the border-only flag set and one ClientboundLightUpdatePacket goes to the players on the edge of their tracked area, before a single block packet is built. The blocks are then emitted per 16³ section, to everyone tracking the chunk, and the shape depends on how many blocks in that section changed: one ClientboundBlockUpdatePacket for a single change, one ClientboundSectionBlocksUpdatePacket for several, plus BlockEntity.getUpdatePacket for any changed position that carries a block entity. A hundred blocks changed by one command are therefore a handful of packets, one per affected section — not a hundred.

Then ChunkMap.tick runs — chunk tracking for each player, and ChunkMap.TrackedEntity for each entity, which is where ServerEntity.sendChanges turns last tick’s movement into packets. Blocks first, entities second, and the entity loop only after both. The ordering is visible from a client: a player’s /setblock lands in the tick the command was typed in, because a command packet is handled before MinecraftServer.tickChildren even starts, while a piston head lands in the tick after the one that moved it.

Falling sand is the exception that proves the rule, and it is deliberate. FallingBlockEntity calls Level.setBlock and then, on the very next line, ChunkMap.sendToTrackingPlayers with a ClientboundBlockUpdatePacket of its own — so the block the client sees appear is sent in the same tick the entity that placed it vanished, rather than a tick behind it. A handful of other places do the same thing to one player rather than to everyone tracking the chunk. What the client does with all of this is what the client is told.

Block events close the handlingTick window

ServerLevel.runBlockEvents drains ServerLevel.blockEvents — the note-block plays, piston pushes and chest-lid counts raised anywhere in this tick — completely, calling BlockBehaviour.BlockStateBase.triggerEvent after re-checking that the block at the position is still the one the event was raised for, the same promise a scheduled tick makes. When the block returns true, a ClientboundBlockEventPacket goes to players within 64 blocks. Because the set is a linked hash set, two identical events in one tick collapse into one; and an event whose chunk is not block-ticking is parked on ServerLevel.blockEventsToReschedule and re-queued rather than dropped.

ServerLevel.handlingTick went true at the very top of the tick and goes false here, so the whole entity half runs outside that window. Its one reader in the game is PistonBaseBlock, which uses it to tell a piston update raised inside the tick from one raised outside it.

An empty dimension skips exactly three things

ServerChunkCache.hasActiveTickets — really TicketStorage.shouldKeepDimensionActive, which is the players’ simulation tickets and a handful of others — resets ServerLevel.emptyTime. Otherwise the counter rises, and it rises only while running, so a frozen dimension never falls asleep. Past ServerLevel.EMPTY_TIME_NO_TICK, 300 ticks, the level skips the dragon fight, the entity loop and the block entities. That is the entire skip: the weather, the scheduled ticks, the chunk source, the block events, the entity manager’s load and unload drain and the debug feed all keep running on a dimension nobody has visited for fifteen seconds.

Every entity, and then its riders

EntityTickList.forEach walks the tick list. An entity is skipped if it has been removed, or if TickRateManager.isEntityFrozen says so — frozen, and neither a player nor something carrying one. Otherwise it gets Entity.checkDespawn, and then ticks only if it is a ServerPlayer or its chunk answers DistanceManager.inEntityTickingRange. A passenger whose vehicle is alive and still lists it is passed over here and ticked by the vehicle instead; a stale link is broken with Entity.stopRiding. ServerLevel.tickNonPassenger records the old position, bumps Entity.tickCount and calls Entity.tick, then ServerLevel.tickPassenger runs Entity.rideTick for each rider that is a Player or in the tick list, recursively down the stack. Level.guardEntityTick wraps each one in a crash report titled Ticking entity, so a mob that throws names itself.

The list stays stable under all of that by construction. Membership changes during the loop — a spawner’s mob, a fired arrow, a lightning bolt — arrive through ServerLevel.EntityCallbacks.onTickingStart immediately. EntityTickList allows exactly one EntityTickList.forEach at a time and, on any add or remove while it is iterating, copies into its EntityTickList.passive map and swaps that with EntityTickList.active: the running loop keeps walking the view it started with, and the new entity waits for the next tick. Which entities are in the list at all is PersistentEntitySectionManager’s answer, through Visibility.fromFullChunkStatus — only FullChunkStatus.ENTITY_TICKING maps to a ticking visibility — with one override, Player.isAlwaysTicking, which keeps a player ticking whatever its chunk is doing and makes the ServerPlayer test inside the loop a second, redundant guard. Entities are Part VI’s subject: entity lifecycle.

Block entities reach one chunk further than mobs

Level.tickBlockEntities walks Level.blockEntityTickers, dropping removed tickers as it goes and running the rest — but only those whose position passes ServerLevel.shouldTickBlocksAt, which is the block-ticking range, and only while TickRateManager.runsNormally. That single condition is why a furnace keeps smelting one chunk further out than a zombie keeps walking. A block entity created mid-tick — a chest a piston just pushed — lands on Level.pendingBlockEntityTickers instead, because Level.tickingBlockEntities is true, and is merged in at the top of the next tick. Block entities has the rest.

The two steps that always run

PersistentEntitySectionManager.tick drains PersistentEntitySectionManager.loadingInbox, a concurrent queue that chunk storage fills from IO threads — entities from freshly loaded chunks join the world here — and then processes PersistentEntitySectionManager.chunksToUnload. The ServerLevel.EntityCallbacks it fires (ServerLevel.EntityCallbacks.onTickingStart, ServerLevel.EntityCallbacks.onTickingEnd) are exactly what add and remove entries in the tick list the previous step walked.

Last, LevelDebugSynchronizers.tick pushes this tick’s neighbour updates, brains, paths, POIs and raids to any client subscribed through DebugSubscriptions — and, just before it, arms or clears the neighbour listener on CollectingNeighborUpdater depending on whether anyone is subscribed to DebugSubscriptions.NEIGHBOR_UPDATES at all. It is the one step of the level tick whose entire output is diagnostic, and it is outside every gate.

What leaves the level, and when

the packetthe step that sends itto whom
ClientboundGameEventPacket, rain and thunder levelsServerLevel.advanceWeatherCyclethis dimension’s players
ClientboundGameEventPacket, start and stop rainingthe same step, on a transitionevery player in every dimension
ClientboundSetTimePacketServerClockManager.moveToTimeMarker, from the sleep skipeveryone, sent by the clock manager
ClientboundBlockUpdatePacket · ClientboundSectionBlocksUpdatePacketChunkHolder.broadcastChanges, per 16³ sectioneveryone tracking the chunk
BlockEntity.getUpdatePacketthe same walk, beside a changed position that has oneeveryone tracking the chunk
ClientboundLightUpdatePacketthe same walk, before the blocksthe players on their tracked area’s border
entity add, move and removeChunkMap.TrackedEntity, inside ChunkMap.tickwhoever tracks that entity
ClientboundBlockEventPacketServerLevel.runBlockEventsplayers within 64 blocks

None of them go out when they are written. Every one is queued behind the suspended flush that MinecraftServer.tickChildren opens around all the levels, and leaves on the wire at the end of the server tick (the server tick).

Questions players ask

Does /tick freeze stop the server doing work? Barely, on the chunk side. Distance updates, the block-change broadcast, entity tracking and chunk unloads all run every tick regardless. Two things inside the chunk source are frozen and are easy to miss: the spawning and random-ticking step, and TicketStorage.purgeStaleTickets — so a frozen world accumulates expired tickets and never releases the chunks they hold.

Why does my furnace keep going after the mobs around it stop? Two thresholds, one chunk apart. Block entities are gated on block-ticking range (ChunkLevel.BLOCK_TICKING_LEVEL, 32) and entities on entity-ticking range (ChunkLevel.ENTITY_TICKING_LEVEL, 31), and a chunk on the boundary is in one and not the other.

Why did replacing a block cancel its scheduled tick? Because a scheduled tick is a promise to that block: ServerLevel.tickBlock compares the Block at the position with the one scheduled, and a mismatch runs nothing.

Why does /weather rain in the Nether change the overworld? There is one WeatherData on the MinecraftServer and every dimension advances the same countdowns. Only the fade of Level.rainLevel and Level.thunderLevel is per level, and only where Level.canHaveWeather.

Why does a mob that spawns this tick not move until the next one? EntityTickList swapped its maps the moment the mob was added, so the loop that is running kept the view it started with. The mob is in the list — it is just not in this walk of it.

Why is a dimension with nobody in it still burning CPU? Because going empty skips three things and nothing else: past 300 ticks with no active ticket the dragon fight, the entity loop and the block entities stop, and the weather, scheduled ticks, chunk source, block events and entity manager carry on.

Where did the day–night cycle go? Out of the level. Time is a set of WorldClocks owned by ServerClockManager and ticked by the server; ServerLevel.tickTime advances gameTime only, only in the overworld, and every other dimension reads the overworld’s number.

Where to look

ServerLevel.tick · ServerLevel.advanceWeatherCycle · ServerLevel.tickTime · ServerLevel.tickBlock · ServerLevel.tickChunk · ServerLevel.tickThunder · ServerLevel.tickCustomSpawners · ServerLevel.runBlockEvents · ServerLevel.tickNonPassenger · ServerLevel.tickPassenger · ServerChunkCache.tick · ServerChunkCache.tickChunks · ServerChunkCache.broadcastChangedChunks · ServerChunkCache.blockChanged · ChunkHolder.broadcastChanges · ChunkMap.collectSpawningChunks · ChunkMap.forEachBlockTickingChunk · ChunkMap.tick · ChunkMap.processUnloads · DistanceManager.inEntityTickingRange · ChunkLevel.fullStatus · LevelTicks.tick · NaturalSpawner.createState · LocalMobCapCalculator.canSpawn · EntityTickList.forEach · PersistentEntitySectionManager.tick · Level.tickBlockEntities · Level.getBlockRandomPos · WeatherData · ServerClockManager.moveToTimeMarker · SleepStatus.areEnoughSleeping · EnvironmentAttributeSystem.invalidateTickCache · LevelDebugSynchronizers.tick


Rules: names, never code · how the system works, not how the code reads · newest version only · every backticked name passes tools/verify_names.py.