Gameplay / villagers
Villagers & transfer papers
Two people who trade in horses, and the item that lets a horse be sold without either of them touching it. The cowboy lives in a barn on the edge of a plains village, never gets off their horse, and sells their herd as transfer papers; the horseman is an ordinary villager profession selling tack and gene goods from a workstation. This page is the source of truth for all three. The items themselves are listed on Items & recipes; the genetics of the horses the cowboy breeds are ordinary breed founders.
Everything on this page compiles, registers, and boots a dedicated server clean. None of it has been seen in a world. The checklist is verification §0-AC.
Transfer papers
A horse changes hands by paper, not by proximity. There are two items and three moments.
A signed paper is drawn as the horse it names — the mod's HD
horse mesh in that horse's own coat, shrunk into an item slot
(client/TransferDeedRenderer), in the merchant window and everywhere
else the item appears. That is what makes a bearer instrument usable: the paper is
a claim you have to walk out and collect, and six papers that differ only by a name
in a tooltip are six papers you cannot tell apart from the animals they name. The
deed carries the horse's genetic and epigenome codes for it, so the picture needs
neither the horse loaded nor the server asked, and survives the horse being sold on
or shot.
| Moment | What happens | Where |
|---|---|---|
| Crafted | Eight paper around one horse hair makes one blank transfer paper, and the bench stamps the crafter's name and UUID onto it. | TransferPaperHandler.onCrafted |
| Signed | The bound player right-clicks a horse they currently own; the blank becomes a signed paper naming that horse. | TransferPaperHandler.sign |
| Redeemed | Whoever is holding the signed paper right-clicks the horse it names. The horse becomes theirs; the paper is spent. | TransferPaperHandler.redeem |
Why redemption is a walk, not a click
A signed paper is a bearer instrument. It carries no binding at all — the binding is on the blank, so that only someone with the standing to write a paper can write one — and redeeming it does not require being the person who signed it, or the person who bought it. Buying one from the cowboy moves nothing: the horse is still standing in their paddock, and you have to go out and find it.
That is the whole reason the item exists in this shape rather than as “pay the cowboy, receive a horse”. A claim the bearer has not collected yet is an object worth trading — it can be handed to another player, sold on at a markup, or lost in a creeper hole with the horse still standing there waiting for whoever picks it up.
What a transfer never changes
bredBy is untouched by every path in the system. A
horse bred by Jesse Calloway is still bred by Jesse Calloway after four
owners, and HorseRecord.attribution() — which prefers the
breeder over the tamer — keeps saying so in the
family tree. The signed paper carries a snapshot of
the breeder purely so a buyer can read whose line the animal comes from; it is
never written back.
tamedBy is only ever filled in when it is blank. It
records who first got a rope on the animal, which also does not change when the
animal is sold. In practice the only horses it gets written to are the cowboy's,
because their stock has never been tamed by anyone.
The genome, the names, the pedigree, the generation and the breed label are not touched either. Ownership is the only thing that moves.
The cowboy
A horse breeder who is generated with a barn on the outskirts of a plains
village, and who is always on a horse. Their name is drawn from
frontier given and family name tables
(PersonNameGenerator.cowboys()), and that name is what the game says
when it says who bred one of their horses.
Why they are not a villager profession
They are a custom AbstractVillager, not a
VillagerProfession. A profession is acquired from a job site by a
villager whose brain runs vanilla's daily schedule, and that schedule would
dismount them every morning to go and stand at a workstation. Everything that makes
this character themselves — always mounted, home is a barn and not a bed, stock
is a live herd and not a trade table — is a fight with that brain. Extending
AbstractVillager keeps the parts that are worth keeping (the merchant
screen, the villager silhouette, the trading goals) and none of the schedule.
The horseman is a real profession, for the opposite reason: a shopkeeper who walks to a workstation, restocks, gossips and goes to bed is exactly what that brain is for.
Where they set up
The structure places them bare in the middle of the barn and
CowboyHandler builds them on their first server tick. Their
home is that spot — the block their routine rides back to and
the centre of the box the door code works on — but they do not
found there. The barn's interior is eleven blocks by five with walls on
every side and a horse is nearly a block and a half wide, so a string of them made
around the barn's centre came out with half its members standing in the walls.
So they walk out first, to a paddock 12–24 blocks off, and the herd is made around them there. The bearing is taken from the village bell to the barn and sampled in a half-plane around it, so “out of town” is literal: they set up on the grass past the last house rather than in somebody's turnip field. If that half-plane has no room in it the search widens to the whole circle rather than fall back to the barn.
A candidate has to be ground, and the surface heightmap is not enough to know that: in a village the highest solid block in a column is very often a roof, which is where the first cowboy to walk out ended up standing — on a house that was not even theirs. So a paddock must also sit within 3 blocks of the barn's own height and have 3 blocks of solid ground beneath it. Either test alone is fooled: the height test passes a low porch or a wall top, and the depth test passes the flat top of a hill fifteen blocks up. Together they mean “ground, at about the height the barn is at”, which is what a paddock is.
Every placement — their and every horse's, at founding and at every restock — now asks the level whether a horse-sized box fits, rather than whether a one-block column is clear. A clear column next to a wall still puts a horse's shoulders through it, which is exactly how the barn filled up with embedded horses.
Their herd
- Four to ten horses, plus the one they ride. All are made on
their first server tick, in the barn. That roll is also their
stockTarget— the number they are restocked back up to for the rest of the world's life, so one cowboy is a four-horse outfit and the next is a ten-horse one, for good. - Every one is a foundation horse of a real breed — no
parents, generation 0, and never
feral_mixed. - Half their string is one breed — the one they are known for.
A
preferredBreedis settled at founding (drawn from the biome's pool, weighted the way a wild herd is weighted) and the horse they ride is one of them. Every horse they breed after that is their breed until half the target is their breed, and drawn from the biome pool after that — so a breeder's yard reads as a yard with a speciality rather than as a random sample of the county.CowboyHandler.nextBreedForcounts rather than flips a coin, because a coin flip on a string of six lands on six-out-of-six often enough to be seen, and it self-corrects: sell three of their Fjords and the next three they breed are Fjords. - Every one carries
bredBy = their name. - The horse they ride is the herd lead. It is herd slot 0, and
every other member carries its UUID as their
HorseCareAttachment.herd— so the browser and the info panel see an ordinary herd with an ordinary lead horse, and the man on top is a detail. It is never for sale. - They are branded, not owned. A
CowboyBrandattachment holds the cowboy's id. Vanilla lets a player tame any untamed horse by climbing on it until it stops bucking, and their whole herd standing there untamed would otherwise be a free stable rather than a shop — so a branded horse refuses every interaction except a transfer paper. Kill the cowboy and the brand is cleared: their horses go feral and can be tamed the hard way, while keeping their name as their breeder.
What they sell
One offer per herd horse. A horse costs one to three emeralds
— HorsePrices.DEFAULT_PRICE, and what almost every horse in the
game costs. They are the early-game purchase this mod is built
around: you buy a horse before you have a farm, not after you have a trading hall.
Which breeds they can deal in at all is the breed's own
source checklist: they draw from the breeds of the
country round the barn that allow cowboy, and falls back to every breed
that allows it when the local list is empty. So “no dealer has ever had one”
is a thing a breed file can actually say, and it is a different claim from “none
run wild here”.
A breed that should be dear names its own range in its file
("price": [min, max]); anything that does not gets the
default. A range rather than a number, because two horses of a
breed are not worth the same and a stall listing six papers at exactly two
emeralds each reads as a vending machine — the roll inside the range is
taken from the horse's own UUID, so it is stable across every look at the merchant
screen. The default and the roll live in server/HorsePrices,
deliberately on the Minecraft side and off common/, for the same
reason RarityItems is: how much a horse costs in emeralds is a
gameplay-economy decision. What a breed gets to say is only
“mine are dear”.
This replaced a table priced off the breed's Commonness tier that ran
from ten emeralds to forty, which made the cowboy a shop you walked past for a
week. No breed sets a range yet, so every horse they sell is currently 1–3.
The offer list is rebuilt every time someone looks at them, because the herd is a live thing — a horse can be killed by a wolf between one customer and the next. A horse leaves the list for good the moment its paper is bought, whether or not that paper is ever redeemed. They are not a levelling villager: no XP, no tiers, no vanilla restock timer — what they do instead is breed replacements.
Restocking and rotation
CowboyHandler.restock looks over their string about once a minute
(jittered, so two cowboys loaded on the same tick do not stay in lockstep) and
does two slow things.
- Tops up to
stockTarget, one horse per look. Horses leave — bought, tamed, eaten by a wolf — and without this a cowboy you have traded with once is a man standing next to an empty field. - Rotates a full string: roughly one look in seven, one horse retires and the top-up replaces it next time round. Without it a player who did not like the six horses on offer never has a reason to come back, because they would be the same six horses forever.
A horse is never retired with a player within 48 blocks of it — the rotation is meant to be something you notice by coming back to a different string, not something you watch happen; a horse vanishing in front of you reads as a bug however well it is documented. And “their string” here is exactly the set the merchant screen offers (alive, loaded, untamed, not their mount, not already papered), because “how many have they got?” and “how many can you buy?” have to be the same number or they restock to fill a shelf nobody can see. Tamed horses are dropped from the herd list entirely, so it cannot grow without bound over a long world.
Their day
They did, for about a day, and it cost more than every other part of this character put together. A mob rider cannot steer, so the itinerary had to live on the horse; the horse's own goals all exist for the “someone is on my back” case and fought it; a villager has no seated pose, so they had to be sunk into the saddle to stop looking like they were standing on it; and getting a mounted man and eleven horses through a barn door at dusk was never made to work at all. Five rounds of fixes, each exposing the next.
The herd follows the man now. They are an ordinary villager who
walks, and CowboyHerdGoal points their horses at them instead of at a
lead horse. That deleted CowboyMountGoal,
CowboyRemountGoal, CowboyRoutine,
CowboyDoors, HerdCollision, the saddle sink, the
patrol, the shelter and the flee — roughly a thousand lines for a
character nobody could tell had them. They keep ten times a villager's health
(Cowboy.HEALTH), which is what the night cost in the end.
So there is no routine to document. They float, trades, panics, strolls and looks at players — the goals every villager has, plus one of their own below. Their horses trail them at 14 blocks and settle at 7 by day, tightening to 4 after dark so the string gathers on them rather than strung out across a field.
They can work a door, in daylight, with both hands
CowboyDoorGoal. Until it existed they could not open a door at all —
not for want of trying, but because a mob needs two unrelated things to use
one and they had neither. The goal is what swings it; the navigator's
canOpenDoors is what makes the pathfinder score a shut wooden door as a
way through rather than as wall. On its own, either is useless: no goal and they plan a
route they cannot take, no flag and they never plan the route at all.
- Both leaves. Vanilla's
OpenDoorGoalopens the one door block the path runs through, and every opening in the barn is a pair. One leaf is a one-block gap, and the ground pathfinder rounds a mob up tofloor(width + 1)blocks across — so a one-block gap is not a gap at all to a horse, and the whole point of the man walking to the barn is the string walking in behind them. The partner leaf is the neighbour along the wall with the same facing and the opposite hinge. - Daylight only, on
Level.isBrightOutside()— the same test the gene effects use for theirdaytrigger, so the mod has one definition of daytime. It reads sky darkening rather than the clock, so a thunderstorm counts as night. - They never close anything.
OpenDoorGoal's close-behind would be wrong here twice over: the herd is following them and would be shut out, and the barn doors standing open is what the doorway headroom inbake-barn.pywas cleared for.
None of it is a routine — they open a door they have walked into, which is vanilla's own cheap trigger, and nothing sends them at one on purpose. What it buys is that the barn is now a building the outfit can actually get inside. Gap 63 is the part that is designed rather than measured.
They do not go indoors, and does not need to
They cannot. Walking into a house and getting into a bed lives in
vanilla's villager brain, and a Cowboy is an
AbstractVillager — the same base as a wandering trader, chosen
precisely so that no schedule drags them away from their horses. A wandering trader does
not go indoors either. Giving them somewhere to sleep is what the entire barn-shelter
subsystem was, and it is written up in
gap 55 as the thing that could not be made to
work.
So the night is survived rather than avoided, on two numbers and no behaviour:
- Ten times a villager's health (
Cowboy.HEALTH). - Nothing hunts them.
CowboySafetyHandlercancelsLivingChangeTargetEventwhenever anEnemyis about to pick them, and that event fires fromMob.setTarget— the one door every way of acquiring a target goes through, whether that is a nearest-attackable goal, a raid's orders or retaliation for being hit. They are never anybody's target, so nothing paths to them and nothing swings at them.
Enemy rather than Monster on purpose: it is the interface
that means “this thing is hostile”, and it catches the few hostiles that
are not Monster subclasses. Players are not covered and can still hit
them. Their horses are not covered either — they are ordinary
animals, a wolf getting one is a thing that happens, and that is what the
restocking is for.
The barn, and how it lands on the outskirts
cowboy_barn.nbt is the whole homestead in one piece: a hand-built stable
— hay-bedded floor, water cauldrons, two double doors at each end, the cowboy
generated at its centre — with the house behind it
along the street, and a walk running down the front of both.
Worth knowing before editing the bake, because it is the one thing about the piece's geometry that is not obvious from looking at it. Layer 0 of a building is not the ground — it is the course that rests on the ground. The street's road block is the layer below it, outside the piece entirely, which is why a plains house sits one block proud of the road with a step up into the doorway.
So a path laid in layer 0 is a block-high curb you walk over, which is what the lane between the two buildings was. The piece now carries a ground course beneath the foundation: everything lifts by one and the jigsaw lifts with it, so nothing about where the homestead lands changes, and the new bottom layer falls in the road's own course. The walk runs down it.
It has a column of its own, west of both buildings, because it has
to be in front of the steps and there is nowhere else for it to go. One
column further west is the street's own connector block; a piece whose box reaches
over that overlaps the street piece and is thrown out by the placer, so the
homestead would simply never generate. And it cannot run under the steps
either: DirtPathBlock will not survive a solid block overhead and
ticks back to plain dirt, so a walk beneath the stair skirt would be a walk made of
dirt. In front of the steps, nothing is covered and nothing converts.
Terminators are the edge of the village
The barn is appended to minecraft:village/plains/terminators. A
terminator is what the village generator places when a street connector has
nowhere left to go: both village/plains/streets and
village/plains/houses name it as their fallback. So the
terminator slots are, by construction, the ends of the village —
the last piece on a road that ran out of room. Putting the barn there is the
closest the jigsaw system comes to expressing “on the outskirts”
without hand-placing the building and owning terrain fitting ourselves.
The barn's own connector is a minecraft:street jigsaw on its west
face, in the step in front of the north pair of doors. The generator rotates the
whole piece so that connector faces back at whatever it attached to.
It sits at y=0 — the barn's own foundation
course — and getting that wrong is what sank the building. A jigsaw pair
lands its two blocks at the same world height, and the street connector
it meets is at the street piece's y=1, one above the road
block. So whichever local layer carries this jigsaw is the layer that ends up
resting on the ground. It was y=1 at first, on the reasoning that
vanilla terminators put theirs one above their ground block — which is true
of terminators and the wrong piece to copy. The result was the foundation landing
in the road's own layer: the stair skirt round both doorways was buried
flush with the ground instead of stepping up onto it, and the barn read as
half-dug-in.
Vanilla houses are the shape to copy. A plains house puts its
building_entrance jigsaw in its own foundation layer, and so sits one
block proud of the road with a step up into the doorway. At y=0 the
barn does the same, and its steps are steps again.
The jigsaw block replaces one of those step blocks, so the bake reads whatever
was drawn there out of the source and writes it back as the jigsaw's
final_state — no hand-copied block state to go stale, and
re-exporting the barn with something else in that spot just works.
It goes in at weight 3 against the four vanilla terminators of weight 1 each, so roughly three terminator slots in seven. That is not how often it appears. A village has a handful of terminator slots, and the piece is 15×15 where a terminator is 2×3 — so most of the draws that pick it then fail the bounding-box check and fall through to a small terminator instead. The weight is set high to compensate for exactly that: it was 1 while the piece was 15×7 and carried the barn alone, and taking the house in doubled the depth, and so doubled the ground it has to find. The effect aimed at is “most plains villages, where there was room”.
Why the pool is edited in code
A datapack can only replace terminators.json, never
add to it. Replacing it would freeze today's four vanilla terminators into this
mod and silently delete any other mod's additions to the same pool.
BarnPoolInjector appends instead, on
ServerAboutToStartEvent, which needs the live pool object's element
lists — and that is what this repo's first
access transformer is for.
The cowboy comes with the building
They are carried in the structure template's entities list, which is the
same mechanism vanilla uses to put villagers in
village/plains/villagers/*.nbt. A template can only place an entity,
not roll one, so they arrive bare — nothing but their id
— and CowboyHandler builds them on their first server tick: name,
home, herd.
That founding runs on EntityTickEvent.Post and not on the
join event, for exactly the reason
HorseFoundingTickHandler documents at length:
founding spawns horses, spawning a horse ends in an Attributes.SCALE
write, and a scale write runs a collision scan that can force-load a chunk. Doing
that from the join event or a server.execute task re-enters the chunk
system's ticket pass and crashes it.
One cowboy per village
The jigsaw generator has no way to say “at most one of this element per structure”, so a village that rolls two barns gets two barns. The second one is just a barn: of the cowboys within 128 blocks of each other exactly one founds, and the rest discard themselves before spawning anything. The tie-break is the lowest UUID — the same rule HerdManager uses to elect a wild herd's lead, and for the same reason: every candidate has to reach the same answer without talking to the others.
Re-baking the piece
Two sources, one output.
tools/barn/cowboy_barn.source.nbt is the raw structure-block save of the
stable; tools/barn/cowboy_house.source.nbt is a byte copy of vanilla's
village/plains/houses/plains_small_house_1. Both are kept only so the
buildings can be edited in game and re-exported; the mod never reads either. After a
re-export, run:
python neoforge-26.1.2/tools/barn/bake-barn.py
which adds everything a structure-block save cannot carry — the ground course,
the jigsaw connector, the headroom over the doorways, the reshaped house, the walk
along the front, the work posts and the villagers — and writes
data/horsegenetics/structure/cowboy_barn.nbt. Commit all three.
The horseman
The roadmap's “Horse Master”: an ordinary villager profession that sells horse tack and horse-genetics goods from a Horse Trader's Post. Five tiers on vanilla's ladder — Novice, Apprentice, Journeyman, Expert, Master — not the design document's, which invented an “Adept” rung that does not exist.
Two posts, one texture
Cowboy Hitch and Horseman’s Table: the same block twice, on the same three-face texture set, with different names and different jobs. The hitch is 2 hair cloth + 3 braided rope + 2 fence; the table is 3 hair cloth + 2 leather + 2 fence. Both shapeless. Neither does anything yet beyond marking a spot — turning them into real workstations, a hitch you tie a horse to and a table you work leather at, is open work.
| Block | Hands out | How |
|---|---|---|
| Horseman’s Table | the horseman | An ordinary job site. It backs the
horsegenetics:horsemans_table POI, which is added to vanilla’s
acquirable_job_site and village tags — tags
merge across datapacks, so adding to vanilla’s is safe where
overriding a worldgen file would not be. One villager per table. |
| Cowboy Hitch | the cowboy | Not a job site at all. A cowboy is an entity, not a
profession — they have a herd, a stock target and a merchant screen that sells
papers rather than goods, none of which fits on a Villager —
so there is nothing for a profession to point at and no POI to claim.
server/CowboyHitchHandler looks for the block instead:
every two seconds, an unemployed villager within 6 blocks of a hitch that has no
cowboy within 32 is taken on. |
One block tried to do both, handing out a cowboy first and a horseman second by
alternating. It could not. Converting the villager meant either
discarding them — which silently holds their job-site ticket
for ever, because Villager.releaseAllPois is private and runs on
death, so the post produced one cowboy and then nothing while the rest of the
village stood unemployed — or demoting them and trusting vanilla to
re-assign them, which is two more moving parts than a second block.
A post each is far less clever and simply works. The hitch makes cowboys, the table makes horsemen, and neither has to know the other exists. Discarding the villager is safe at the hitch for exactly the reason it was not safe at the shared post: they never claimed the hitch, because the hitch is not a job site.
One cowboy per hitch, guarded by looking rather than remembering: a hitch with a cowboy already within 32 blocks is spoken for. That is self-correcting — kill them and the next villager past the hitch takes over — where a “used” flag on the block would need saving and would go stale the moment they died.
Both of them stand at the house
They flank the house's front step, one either side of it, with a villager on the walk in front of each. A villager takes the post they are standing on — one becomes the horseman, the other the cowboy.
They were on the barn, and moving them is what fixed the house. Not a question of where they look right: the house has to exist before either post does, and while the house was built at runtime by the cowboy, the posts had to be somewhere the cowboy already was. That ordering is what finally sank the runtime house — the posts are what make a cowboy, so a cowboy cannot be what builds the thing the posts stand on. With both buildings in one baked piece there is no order left to get wrong, and the posts can go where they belong: on the doorstep of the house whose family works them.
Baked into the structure rather than placed at runtime, because a job-site POI is indexed off the block — putting the block in the world is the whole mechanism — and because a shop front is architecture. Neither villager is given a profession: letting them take the jobs the ordinary way is the only test there is of the part that has ever been in doubt, which is whether the POI registered and whether the tag merged. Two nitwits standing there for ever is a real answer to a real question.
One family per village
Whoever is hired first names the family, and everyone after joins it.
Both handlers ask the same question —
HorsemanHandler.familySurname — which looks round the village for
a cowboy or a horseman who already has a surname and takes their; finding nobody, it
coins a new one. So a village reads as one outfit in the horse trade: Wade Hargreave
at the hitch, Frank Hargreave behind the table.
Order-independent on purpose. The hitch and the table hand out their jobs entirely separately, and which villager gets round to which first is down to where they happen to be standing — so neither role can be the one that owns the name. An earlier version had the cowboy coin it and the horseman inherit, which is fine right up until the horseman is hired first and there is nobody to inherit from.
The nearest namesake wins, which only matters in a village with two outfits in it: a second hitch across town founds the Adamses, and a table put up beside it joins the Adamses rather than the Hargreaves at the far end. It counts the two roles this mod names and nothing else — a player who renames their own farmer “Bob” has not founded a horse family.
The horseman keeps vanilla's brain, and gets a house
Nothing in this mod touches how the horseman behaves. They are a completely ordinary villager with a profession, so going indoors at night, panicking in a raid, hiding from a zombie, restocking and gossiping are all free — that is the whole reason they are a profession where the cowboy is not.
What that brain needs is a bed POI to claim, and a barn on the outskirts can easily be out of range of the nearest house's. Beds went into the barn first and came straight back out: the barn is a building made of doors. Four double doors and a two-block gap at either end, and a villager only ever shuts the one they walked through — so a bed in there is a bed in a corridor with three doors standing open.
So they get a house, and it is part of the same structure piece as the
barn. It is a copy of vanilla's plains_small_house_1, copied
rather than referenced because it needs changing and because a vanilla template is not
ours to rely on keeping its shape. tools/barn/bake-barn.py reshapes it:
- The two jigsaw blocks come out. They are placement machinery and nothing resolves them for a template read straight out of the data pack, so left in they would stand in the finished building as jigsaw blocks. The one in the doorway becomes air, the one in the floor becomes floor.
- The interior is widened to four blocks, by duplicating a column of the plan — walls, floor, roof and all, so nothing has to be redrawn. Vanilla's three across is a bedroom; four is a bunkhouse with room to walk past the beds.
- Two beds, pushed together against the back wall. One is all the horseman needs; the second is for the look of the place.
- A chest either side of them, drawing on
horsegenetics:chests/cowboy_house: feed by the armful, a lead or a saddle now and then, and one roll in four or so at a piece of this mod's own kit, so a chest can teach you an item exists. Nothing in it should make a player feel they can skip the horseman — the saddle is the only real prize. - The stair beside the beds comes out. It is a chair in the vanilla house and it reads as a headboard once there are two beds against that wall.
- A step outside the front door, with the two work posts either side of it. The house sits a block proud of the ground the way every vanilla plains house does, so without the step the threshold is a ledge you jump at.
- Bark back on the corner posts. They are stripped oak in vanilla; nothing else about a homestead beside a stable is planed.
It is set down beside the barn with a lane of dirt_path between them, the
same block the village's own streets are made of, running along the front of both and
up to each door. Two buildings on the edge of a village with nothing between them read
as two things that happen to be near each other.
It used to be built at runtime and it never once appeared.
CowboyHouseBuilder hunted the far side of the barn for a patch that was
flat, clear and untouched — every column of the footprint agreeing on its
surface height — on the reasoning that no house is a great deal better than a
house dropped through somebody's roof. In a real village that test never passed once.
Baking the house into the piece answers the same worry better than the test did: the
jigsaw generator's own bounding-box check is a far more careful version of “is
there room here”, and it runs before anything is placed at all. The price is a
piece twice as deep, paid for in pool weight.
The cowboy will not use a bed — an AbstractVillager has no schedule
at all — which is why they get ten times the health and hostile mobs that ignore
them instead.
The trade table
| Tier | Buys | Sells |
|---|---|---|
| 1 Novice | 16 horse hair | Hair bundle, saddle, leads |
| 2 Apprentice | 8 hair bundles | Basic whistle, blank tickets, iron horse armour |
| 3 Journeyman | 4 braided rope | The four general breeding carrots, a common breed spawn egg (22 em) |
| 4 Expert | 2 hair cloth | A random common gene carrot, a random uncommon one, a random common/uncommon research paper, an uncommon breed egg (38 em) |
| 5 Master | 1 stallion seed jar | A random rare gene carrot, a random epic one, a random rare/epic paper, diamond horse armour, a rare breed egg (58 em, one use) |
Each tier draws three of its pool, so two horsemen in different villages are not the same shop. Hair buying is the early-game emerald tap and therefore the number most likely to want retuning; it is one JSON file per trade.
A random carrot, without a custom listing
Villager trades are datapack registries in 26.1.2
(minecraft:villager_trade and minecraft:trade_set), and a
trade's given_item_modifiers are loot functions that run when the
offer is generated. That is exactly the semantics the roadmap argued for:
“a random rare carrot” is rolled once per restock and then sits in the
window at a fixed price, rather than re-rolling under the player's cursor. So the
whole “custom listing that rolls when the offer is generated”
requirement is met by a stock vanilla mechanism plus one loot function:
{ "function": "horsegenetics:set_random_gene",
"target": "carrot", // or "paper"
"min_rarity": "uncommon",
"max_rarity": "uncommon" }
The pool is computed, not listed: a gene is a candidate if it is registered, has a
gene carrot, and its GeneRarity falls inside the window. A
third-party gene therefore joins automatically, and legendary and mythic
are never sold because no window reaches them — a comparison rather
than a blacklist that can go stale. Within a window, draws are weighted by
GeneRarity.lootWeight(), the same weighting the chest-loot papers
use, so the price ladder and the find-it-in-the-wild ladder agree.
An empty window returns an empty stack, which VillagerTrade.getOffer
reads as “no offer” and drops — so a rarity tier with no genes
in it costs a trade slot rather than putting a blank item on sale.
Breed spawn eggs are the same trick with a second
function, horsegenetics:set_random_breed, which takes a commonness window
instead of a rarity one:
{ "function": "horsegenetics:set_random_breed",
"commonest": "rare",
"rarest": "very_rare" }
The membership test is the breed's own source
checklist — a breed is a candidate if it allows spawn_egg —
so a breed a player drops into .minecraft/phc/breeds/ joins the
horseman's stock by being registered, and one that opts out disappears from it, with
nothing edited either way. Within a window, draws are weighted by the breed's own
spawnWeight. Two functions rather than one parameterised thing, for the
reason there are two loot modifiers: a paper is knowledge and an egg is an animal, and
a datapack ought to be able to retune one without the other.
What the roadmap asked for and this does not do
- No random genotype vials, and no buying player-made ones back.
Both need the assisted-reproduction /
collectedFromwork that is still unbuilt. Tier 5's buy row is a stallion seed jar instead, which is a real player-made item today. - No custom gossip type.
HORSE_TRADERwas flagged as unverified; the horseman uses vanilla gossip, which costs nothing and works.