Chapter four was the heater. This one is everything that noticed you built it. Five creatures, all of them shipped inside thirteen days, and not one of them was designed as a monster. They were designed as answers to the same question you are asking: where is the last warm thing, and what do I have to survive to reach it.
Five creatures arrived, and every one of them is built around your fire. Four of them burn if they get too close. One of them sits on it.
Let the heater do the work. Most of them will kill themselves reaching you. The trick is knowing which ones will not.
The most dangerous thing here cannot hurt you at all. It has no attack. It climbs on, holds you still, and lets the cold finish it.
Every creature in this chapter is defined by how close it can get to a lit heater.
I did not plan that. I wrote five entities over two weeks and only saw the pattern when I put their proximity checks next to each other.
Four of them catch fire near a heater and one of them is immune, and the exact distance at which each one starts to cook is the whole personality of the creature. Light the heater and let them come.
The damage, the distances and what the mites cost you are the game's own numbers. Walking speed is sped up so it all fits on one screen.
It does not chase. It waits, it faces you, and it blinks. Cross sixteen blocks and it starts copying you.
Two things are worth taking out of that before you read any further. The first is that the Hollow dies further from your heater than anything else in the game, and it is the only creature here that cannot do you a single point of damage. The second is that the Returned does not care. It takes the burn, it arrives, and the fire goes out.
Five creatures, written days apart, and every one of them asks your fire the same question: how close can I get?
Five creatures, five files, written days apart. All five of them open the same registry and ask the same question.
A lit heater is not just light. The world keeps a running list of every heater that is currently burning, and all five of these things read that list. The only difference between them is what they do about it.
A heater in Frozen Dawn is not a light source and it is not a block the world tracks for you. It is an entry in HeaterRegistry, a set of positions that know they are currently lit. I built that registry in chapter four so the temperature maths could find warm spots quickly. Then I wrote the Frostbitten, and without really thinking about it I reached for the same set.
Hit is the ATTACK_DAMAGE attribute. Burn distance is the literal radius in each entity's own tick handler.
Here is the Frostbitten's copy of it. Every twenty ticks it walks the registry, and the moment it is inside four blocks of anything lit, it takes two damage and catches fire for two seconds.
// Heater burn: 2 damage per second within 4 blocks if (gameTick %20 ==0 ) { Set<BlockPos> heaters = HeaterRegistry.getHeaters (level());for (BlockPos heaterPos : heaters) {if (blockPosition().closerToCenterThan (heaterPos.getCenter(),4.0 )) {hurt (damageSources().onFire(),2.0f );setRemainingFireTicks (40 );break ; } } }
The Hollow is the odd one out. It starts burning from eight blocks instead of four, at twice the rate, and it never actually catches fire. It just stops.
The Hollow's copy is the same shape with two numbers changed, and one line missing. It burns from eight blocks instead of four, at four damage a second instead of two, and there is no setRemainingFireTicks call at all. It does not catch fire. It just stops.
I never sat down and designed a burn distance for each creature. I wrote the first one, copied it four times, and changed the numbers to whatever felt right for that specific thing. The ecology is an accident of copy and paste, and it is the most coherent part of the mod.
That last one is the Frostmite, and its absence is the interesting part. It has no heater burn because it is the answer to heaters. Everything else in this chapter has to decide whether your fire is worth dying for. The mite just climbs on.
One of them is what is left of a person. The other is five hit points of pure economics.
Thirty health, six damage, four armour, and it hits with Slowness I for two seconds so you cannot simply walk away from it. It cannot be frozen, and it is immune in three separate places: it reports that it cannot freeze, it reports zero frozen ticks, and its damage handler rejects anything tagged IS_FREEZING outright. The world it lives in cannot touch it.
Five health. One damage. No armour, no knockback resistance, and any hit at all clears its latch and usually kills it. It is not supposed to survive a fight. It is supposed to arrive before you notice and cost you the fight you have later.
The Frostbitten pays for that. It takes fire at double, which is why it dies at a heater in fifteen seconds while an ordinary zombie would shrug it off. It is a creature built entirely out of the cold, so the one thing left in the world that is not cold takes it apart.
There is also a detail I put in on the first day and have never touched since.
If a Frostbitten ends up in water it freezes the whole three by three block of water around itself solid, twice a second. It does not do this as an attack. It does it because it cannot not do it.
// Water behavior: sink and freeze surrounding water every 10 ticks if (isInWater() && gameTick %10 ==0 ) { BlockPos pos = blockPosition();for (BlockPos nearby : BlockPos.betweenClosed (pos.offset(-1 ,-1 ,-1 ), pos.offset(1 ,1 ,1 ))) {if (level().getBlockState(nearby).is(Blocks.WATER)) { level().setBlock (nearby, Blocks.ICE.defaultBlockState(),3 ); } } }
The Frostmite is the only creature in this chapter whose effect on you is a number rather than an event. It finds a lit heater within eighteen blocks, walks to within 1.2 blocks of it, latches, and then orbits the block doing nothing visible for up to ten seconds. Up to ten of them can hold one heater at a time.
What they are doing is being counted. Your heater looks at how many are sitting on it, and the answer costs you twice: it shrinks how far the warmth reaches, and it burns your fuel faster.
What they are doing is being counted. The heater block entity asks the mite class two questions every time it recalculates, and both answers come straight off the head count.
public static int getHeaterRadiusPenalty (Level level, BlockPos heaterPos) {int attached =countLatchedToHeater (level, heaterPos);if (attached <=0 )return 0 ;return Math.min (HEATER_RADIUS_CAP, (attached +1 ) /2 );// cap 4 }public static int getHeaterFuelDrain (Level level, BlockPos heaterPos) {int attached =countLatchedToHeater (level, heaterPos);if (attached <=0 )return 0 ;return Math.min (HEATER_FUEL_DRAIN_CAP, attached);// cap 10 }
A Thermal heater has a seven block radius. Seven mites take it to three. They have not attacked you, they have not been seen, and the room you were standing in safely thirty seconds ago now ends before it reaches you.
The Frostmite is the only one that never needs to touch you to beat you. Everything it does happens to the building.
The Hollow cannot hurt you. Not a little, not eventually, not at all. It has no attack. That is the design.
The Hollow has an ATTACK_DAMAGE attribute of zero. That is not a placeholder I forgot to fill in. It is the design.
It has no goals either. registerGoals() is an empty method. Minecraft's whole AI system, the thing that makes a zombie want you, is switched off, because the constructor sets noPhysics and turns gravity off and none of the pathfinding works any more once you do that.
It does not hunt. It drifts. It picks a point within eight blocks, floats towards it very slowly, and picks a new one every five to ten seconds.
It does not hunt you. It is in the room, and eventually the room is small enough.
It does not attack. It climbs on. It calls startRiding on you. From that moment you are wearing it, and four things start happening at once.
Minecraft counts you as fully frozen after seven seconds, and starts dealing freeze damage there. The Hollow takes you to fifteen. It has no attack of its own because it does not need one. It holds the door open for the weather.
// Offsets around the player for ice entombment BlockPos[] offsets = { playerPos.north (), playerPos.south (), playerPos.east (), playerPos.west (), playerPos.above (), playerPos.above().above () };for (BlockPos pos : offsets) {if (iceBlocksPlaced >=6 )break ;if (level().getBlockState(pos).isAir ()) { level().setBlock (pos, Blocks.PACKED_ICE.defaultBlockState(),3 ); iceBlocksPlaced++;return ;// one per call } }
Six blocks: north, south, east, west, your head, and the space above your head. It is building you a coffin one wall at a time, and it is polite enough to only use air.
Swing at it. Any swing at all breaks the grab, and the same swing deals two damage. Unless you are holding Acheronite, in which case it deals six, which is nearly a third of the thing in one hit. That was deliberate. Acheronite is the late game metal, and I wanted one moment where a player who had gone and got it felt the difference immediately rather than reading it on a tooltip.
It ignores arrows. It shrugs off half of a normal sword. It takes fire at face value, and it burns from eight blocks out rather than four, which means the Hollow is the only creature in the game that dies to your heater before it can see it properly.
It is watching for exactly one thing: a Frost Ward Torch, sixteen blocks out. It scans every ten ticks, stepping two blocks at a time. If it finds one it turns and sprints directly away, more than three times faster than it drifts, and keeps going for two seconds without steering at all.
Scaring one off grants an advancement called later_casper. The fact that a joke I typed at midnight is now a permanent string in the mod's data pack is roughly how the whole creature ecology got built.
The Mimic spends its first twenty to thirty seconds doing nothing at all. That is the entire point of it.
It has five phases, and it starts in the first one, watching, for twenty to thirty seconds. It stands completely still and turns to face you from as far as forty eight blocks away. It does not approach. It has no health bar and no name floating above it. It is drawn the same way the sanity system draws a hallucination, a flat silhouette that always turns to face the camera, so wherever you walk to look at it from a better angle, it is already looking back.
Exactly 400 + random(201) ticks. During them it zeroes its own horizontal motion and stops its navigation outright.
Stands still. Faces you. Plays a stare cue if it catches you looking directly at it, with a cooldown of five to fifteen seconds so it never becomes rhythmic.
Triggered the moment you come within sixteen blocks. It locks on to you, then copies your movement and every angle of your head and body, every tick, for five seconds.
Forty health, ten damage, and it is now wearing your skin. Red eyes are the tell. Fifteen seconds without sight of you and it goes back to watching.
Under half health it retreats for ten seconds. And if it waits out its whole timer and you never came, it digs into the ground and is gone.
Not a walk cycle. Not an approximation. It reads what you are actually doing, every tick, and does exactly that. It reads the real player object every tick and writes the values onto itself.
// Real-time player movement mirroring Vec3 playerVel = targetPlayer.getDeltaMovement ();setDeltaMovement (playerVel.x, getDeltaMovement().y, playerVel.z);setYRot (targetPlayer.getYRot ());setYHeadRot (targetPlayer.getYHeadRot ());setXRot (targetPlayer.getXRot ());
Your exact velocity on X and Z, your body rotation, your head rotation, and your pitch. If you strafe left, it strafes left on the same tick. If you look up, it looks up. There is no smoothing and no delay, because a delay would read as a bad animation and an exact copy reads as something wrong with the game.
Over those five seconds it crossfades. For the first half the shadow fades out, and for the second half your own skin fades in, pulled live from the connection by your UUID. Smoke covers the seam. The eyes go from dull red to pure red across the same window, because once the change is done the eyes are the only thing left that tells you it is not another player.
The only thing the Mimic actually looks like is a blank shadow. Everything else it ever looks like, it takes from you.
There is no mimic.png in the mod. The only texture the Mimic owns is a blank shadow. Everything else it ever looks like, it takes from you.
The eyes blink on their own clock, every three to five seconds, and every Mimic in a group is on a slightly different one so they never blink together. It is quick: half closed, shut, half open again.
The eyes are a separate render pass on a seven tick cycle, once every sixty to a hundred ticks depending on the entity's own id so a group never blinks in unison. Two ticks half closed, three ticks fully shut, two ticks half open again. Minecraft's glowing eye render type ignores alpha entirely, so a closed eye cannot be faded out. It has to simply not be drawn.
That is why the stare works. For a fraction of a secondthree ticks there is nothing there at all.
One more detail, and it is my favourite thing in the file. When the Mimic catches you looking at it and plays its stare cue, it does not play the sound at its own position. It plays it at yours.
Killing one grants not_a_shadow, to the killer and to every player within thirty two blocks, because the point of that advancement is that somebody else watched it happen.
Everything else in this chapter reacts to your heater. The Returned is the only thing that goes looking for it.
Fifty health, eight damage, eight armour, five texture variants so a group does not look like a clone army, and it opens doors. It also takes the same three damage per second inside four blocks that everything else does. It walks in anyway.
Most of the ten commits on this thing were not the entity file. They were goals, and each one is a slightly different answer to the same question: what does a thing do when it remembers that the light used to be somewhere?
The extinguish goal is the one that took the most tries. It extends Minecraft's own MoveToBlockGoal with a search range of sixteen and an accepted distance of two, but a block search alone was not enough, because the first version would happily beeline toward a heater on the other side of a wall and stand there grinding against the stone forever.
// Only target heaters the mob can actually see Vec3 eyes = mob.getEyePosition (); Vec3 target = Vec3.atCenterOf (pos); BlockHitResult hit = level.clip (new ClipContext( eyes, target, ClipContext.Block.COLLIDER , ClipContext.Fluid.NONE , mob));return hit.getType() == HitResult.Type.MISS || hit.getBlockPos().equals (pos);
It can only go after a heater it can actually see. Put a wall between it and your fire and it does not know the fire is there. Walling in your hearth is a real defence.
A raycast from its eyes to the heater. If the ray reaches open air or lands on the heater itself, the heater is a valid target. If it hits anything else, the Returned does not know that heater exists. Walling in your hearth is a real defence, and it is a real defence because of eleven lines that exist only to stop a pathfinding bug from looking stupid.
When it arrives it puts the fire out with a call to heater.extinguish(), plays the fire-out sound, and puffs ten smoke particles. Then every player within thirty two blocks is granted an advancement called they_remember.
The advancement does not fire when you kill one. It fires when one wins.
Twenty four commits across thirteen days, and the distribution is the honest record of what was actually hard.
Commit counts are every commit whose diff touched that entity or its goals, first appearance to 31 March 2026.
The Frostbitten took one commit and the Returned took ten, and they were started on consecutive days. That gap is the whole chapter. One of them is a monster. The other one had to be taught what it wanted.
Which is the difference in one line: the Frostbitten is a monster, and the Returned had to be taught what it wanted.