Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
1437 commits
Select commit Hold shift + click to select a range
4809173
fix(mace smash): unlimited fall bonus + tier1/2/3 + density on full fall
jiangmuran Apr 30, 2026
5207589
fix(amethyst): Fortune drops use ore-formula, not linear bump (wiki)
jiangmuran Apr 30, 2026
6091a5d
fix(ender dragon): heal rate is 0.5 HP/tick, not 0.01 × crystal count
jiangmuran Apr 30, 2026
f4a8273
fix(arrow): Power enchant bonus rounds UP per wiki, not nearest
jiangmuran May 1, 2026
0d83980
fix(bee): anger duration randomly 20–39s per wiki, not flat 20s
jiangmuran May 1, 2026
916f8f2
fix(bee): pollination valid-plant list matches wiki, not 10 stub flowers
jiangmuran May 1, 2026
a3ae1de
fix(bee): pollen fertilize chance is ~5%/tick per wiki, not 1/30
jiangmuran May 1, 2026
58eace2
fix(dolphin): feed accepts all 4 raw fishes per wiki (cod/salmon/trop…
jiangmuran May 1, 2026
8383d3d
fix(frog): froglight mapping is warm→pearlescent / temperate→ochre pe…
jiangmuran May 1, 2026
e5426bd
fix(panda): genetics use wiki 1/32 mutation + 5/1/1/1/1/5/2 gene weights
jiangmuran May 1, 2026
ca83831
fix(goat): screaming ram interval 5–15s + correct snaps_goat_horn lis…
jiangmuran May 1, 2026
a39dff7
fix(breeze): wind-charge cooldown 32t/1.6s, sight range 16 blocks (wiki)
jiangmuran May 1, 2026
2bbc429
fix(enderman): pickup 1/20, place 1/2000 per tick (wiki, place was 10…
jiangmuran May 1, 2026
45b72b2
fix(wolf): tamed max health is 40, not 20 (wiki)
jiangmuran May 1, 2026
53b2ef0
fix(turtle): egg-laying has no time-of-day restriction (wiki)
jiangmuran May 1, 2026
bd99c0c
fix(slime): swamp spawn uses wiki rand-vs-brightness, not fixed 0.5 t…
jiangmuran May 1, 2026
9cfb9eb
fix(pillager): patrols spawn after 5.5 days, not 1 day (wiki)
jiangmuran May 1, 2026
f4ffd43
fix(pillager): align patrol delay to wiki Patrol page (5 days, not 5.5)
jiangmuran May 1, 2026
3ad21f2
fix(rabbit): non-snowy color mix is 50/40/10 (wiki), not 50/25/12.5/12.5
jiangmuran May 1, 2026
df2e9b1
fix(zombie): drown timer is 30s wait + 15s shake = 45s total (wiki)
jiangmuran May 1, 2026
4c81bf9
fix(fire): age-15 extinguish chance is 1/4 per tick, not 1/25 (wiki)
jiangmuran May 1, 2026
a35d077
fix(thorns): reflected damage range is 1–5, not 1–4 (wiki)
jiangmuran May 1, 2026
6219acd
fix(biome): altitude temp falloff is 0.00125/block above Y=81 (wiki)
jiangmuran May 1, 2026
bdcb400
fix(splash potion): drop ≤1s applied duration to 0 (wiki)
jiangmuran May 1, 2026
3bf5cbd
fix(dragon egg): teleport volume is 31×15×31, not 31³ (wiki)
jiangmuran May 1, 2026
1c98e7c
fix(bow): full-charge base damage is 6, not 10 (wiki)
jiangmuran May 1, 2026
b4e1765
fix(trident riptide): launch magnitude is 6L+3 blocks/sec (wiki)
jiangmuran May 1, 2026
4d62aac
fix(armadillo): scare distance is 7 blocks, not 3 (wiki)
jiangmuran May 1, 2026
778175b
fix(bell): glow trigger 32 / apply 48 — two distinct radii (wiki)
jiangmuran May 1, 2026
733de84
fix(cocoa): mature pod drops exactly 3 beans, no Fortune effect (wiki)
jiangmuran May 1, 2026
f5d2043
fix(xp orb): magnet attraction radius is 7.25 blocks (wiki)
jiangmuran May 1, 2026
3136147
fix(xp orb pickup): align gravitate radius to 7.25 blocks (wiki)
jiangmuran May 1, 2026
715805e
fix(netherite upgrade): preserve damage points lost, not percentage (…
jiangmuran May 1, 2026
d4afa4f
fix(explosion): damage formula matches wiki (3.5·r·(f²+f) + 1)
jiangmuran May 1, 2026
b5e3ff4
fix(suspicious stew): durations match wiki 24w45a Bedrock-aligned values
jiangmuran May 1, 2026
58489f2
fix(suspicious stew): hunger 6 + 24w45a durations (wiki)
jiangmuran May 1, 2026
135ae6b
fix(suspicious stew effect): align durations to wiki 24w45a (3rd module)
jiangmuran May 1, 2026
e03ea1a
fix(brewing): water + (12 ingredients) → mundane per wiki, not undefined
jiangmuran May 1, 2026
cc8add9
fix(crop): beetroot bone meal is 75% chance +1, not 50/50 (wiki)
jiangmuran May 1, 2026
913c369
fix(frog tongue): froglight mapping warm→pearlescent (4th sibling, wiki)
jiangmuran May 1, 2026
c575af2
fix(frog variant): froglight mapping warm→pearlescent (5th sibling, w…
jiangmuran May 1, 2026
451bc4e
fix(copper): aging chance is wiki 64/1125 (0.057), not 1/7500 (~100× …
jiangmuran May 1, 2026
67cecf5
fix(cat morning gift): weighted loot table per wiki, not uniform 1/7
jiangmuran May 1, 2026
d6f6d8c
fix(fishing): treasure pool is 6 wiki items; lily_pad is junk, not tr…
jiangmuran May 1, 2026
ccec3c6
fix(lightning rod): divert range is 128-block sphere, not 32 cylinder…
jiangmuran May 1, 2026
1b2202d
fix(smithing): template copy MATCH includes Trail Ruins + Ancient Cit…
jiangmuran May 1, 2026
31367e9
fix(lightning): copper strike resets ALL oxidation, not 1 stage (wiki)
jiangmuran May 1, 2026
1d62009
feat(evoker): add fangCirclesAround() — wiki's 5-inner + 8-outer fangs
jiangmuran May 1, 2026
26d132a
fix(deep dark): no natural mob spawns; warden only via sculk shrieker…
jiangmuran May 1, 2026
dea45d0
fix(fossil): Y range is two wiki bands (0..320 + -63..-8), not -24..0
jiangmuran May 1, 2026
8240c5c
fix(ocelot): TRUST_FOOD uses webmc:cod/salmon, not legacy raw_ prefix
jiangmuran May 1, 2026
65f301c
fix(smoker/campfire): fish recipes use webmc:cod/salmon, not raw_ prefix
jiangmuran May 1, 2026
d05a9b9
fix(campfire): accept canonical webmc:raw_* meat IDs (registry-aligned)
jiangmuran May 1, 2026
f9f69cd
fix(food): spider eye Poison duration is 5 seconds, not 4 (wiki)
jiangmuran May 1, 2026
645d2ff
fix(armadillo): uncurl delay is 3 seconds, not 2 (wiki)
jiangmuran May 1, 2026
8358293
fix(wolf pup growth): feed reduces 10% of REMAINING time, not total (…
jiangmuran May 1, 2026
0e81666
fix(fishing rod): reel velocity is 1/10 distance per tick (wiki)
jiangmuran May 1, 2026
2f2f443
fix(arrow critical): Power bonus rounds UP per wiki, not floor
jiangmuran May 1, 2026
d3b8e99
fix(arrow): Power bonus rounds UP in arrow_crit_damage + arrow_flame too
jiangmuran May 1, 2026
7a27eec
fix(enchanting): bookshelves only count on 5x5 perimeter (wiki)
jiangmuran May 1, 2026
5050a14
chore(bell): drop deprecated BELL_RAIDER_RADIUS alias
jiangmuran May 1, 2026
0527a2a
fix(bamboo): plantable on bamboo + sapling per wiki, drop deprecated …
jiangmuran May 1, 2026
8bb0c0c
fix(bed): rename badOmen → raidInProgress; clarify bed power 5 comment
jiangmuran May 1, 2026
0aed04e
fix(cake): cake can be eaten at full hunger (wiki carve-out)
jiangmuran May 1, 2026
625c744
fix(sculk shrieker): warning level decay 200s → 600s per wiki (10 min…
jiangmuran May 1, 2026
4126899
fix(sculk catalyst): sensor 9% / shrieker 1% per wiki, was 2%/0.5%
jiangmuran May 1, 2026
39dd7b3
fix(cave vines): bone meal grows berries, does NOT extend vine (wiki)
jiangmuran May 1, 2026
b6621b4
fix(chorus fruit): teleport range ±8 inclusive on each axis (wiki)
jiangmuran May 1, 2026
e1d7ec7
fix(composter): full canonical item table per wiki, was missing ~43 i…
jiangmuran May 1, 2026
dd8fd41
fix(composter): MAX_LEVEL 7→8 (wiki block-state); bamboo NOT compostable
jiangmuran May 1, 2026
1f27fb3
fix(conduit): range = floor(blocks/7) * 16 per wiki, was 16 + tier*16
jiangmuran May 1, 2026
2270897
fix(conduit_structure): align range formula with wiki canonical break…
jiangmuran May 1, 2026
c129d16
fix(conduit): rename dolphinsGraceProvided → conduitPowerProvided (wiki)
jiangmuran May 1, 2026
0ff4803
fix(coral): coral fans drop nothing without silk touch (wiki)
jiangmuran May 1, 2026
0482863
fix(daylight sensor): inverted = 15 - regular (wiki strict complement)
jiangmuran May 1, 2026
48c7a22
fix(dragon egg): teleport range ±15 inclusive + 1000 attempts (wiki)
jiangmuran May 1, 2026
4e1c717
fix(decorated pot): add 4 missing canonical sherds (wiki)
jiangmuran May 1, 2026
0fe40ad
fix(dispenser): default behavior is drop_item, not place_block (wiki)
jiangmuran May 1, 2026
259bb48
fix(dispenser): equips mob heads + carved pumpkin in helmet slot (wiki)
jiangmuran May 1, 2026
fe3766f
fix(end stone, end portal): stonecutter end stone → all variants; por…
jiangmuran May 1, 2026
4009cb6
fix(farmland): trample is deterministic at fall > 0.5, no mass factor…
jiangmuran May 1, 2026
9da2c76
fix(flammability): bookshelf key was 'book_shelf' (typo), should be '…
jiangmuran May 1, 2026
c32e591
fix(glass): tinted glass drops itself without silk touch (wiki)
jiangmuran May 1, 2026
2db2ce4
fix(farmland): jumpTrample threshold 3 → 0.5 blocks per wiki
jiangmuran May 1, 2026
a0d9b85
fix(flower pot): add torchflower, pale oak, eyeblossoms (wiki)
jiangmuran May 1, 2026
61628db
fix(shroomlight): drops with any tool, no silk touch needed (wiki)
jiangmuran May 1, 2026
b0964b0
fix(mob head): wither_skull → wither_skeleton_skull; add piglin head
jiangmuran May 1, 2026
681608b
fix(lectern): comparator signal uses *14 not *15 (wiki off-by-one)
jiangmuran May 1, 2026
35b58ac
fix(tnt): chain-prime fuse is RANDOM 10..30 ticks per wiki, was alway…
jiangmuran May 1, 2026
397f064
fix(smelting): add raw_mutton, raw_rabbit, nether_gold_ore outputs (w…
jiangmuran May 1, 2026
5541526
fix(note block): octave bumps at B→C, not just at semitone 12 (wiki)
jiangmuran May 1, 2026
bdf79d5
fix(jukebox): add 6 modern music discs (creator, precipice, lava chic…
jiangmuran May 1, 2026
5b5f81f
chore(bee): drop deprecated ANGER_AFTER_ATTACK alias
jiangmuran May 1, 2026
4e64425
fix(wither rose): full canonical placement surface set (wiki)
jiangmuran May 1, 2026
8529130
fix(axe): unwax + scrape all cut copper / chiseled copper variants (w…
jiangmuran May 1, 2026
f60b4fb
chore(inventory): use optional chain for slot-merge guard
jiangmuran May 1, 2026
048ccf3
chore(main): use \`import type\` for DebugFrame, eliminate last lint …
jiangmuran May 1, 2026
5737944
fix(squid): ink sacs ARE affected by Looting (wiki, was 'unaffected')
jiangmuran May 1, 2026
ab26d7d
fix(mooshroom): empty bucket gives milk too (wiki carve-out)
jiangmuran May 1, 2026
47a9843
fix(chest boat): add pale_oak to wood-species union (1.21.4 wiki)
jiangmuran May 1, 2026
d8883e9
fix(vex): vex outlives summoner death (wiki, was expiring on evoker d…
jiangmuran May 1, 2026
0221a0e
fix(magma cube): attack damage = size + 2 (wiki, was off by 1 for small)
jiangmuran May 1, 2026
ed3d67b
fix(guardian): laser range 16 → 15 blocks per wiki
jiangmuran May 1, 2026
345cf68
fix(pillager): crossbow charge time 20 → 25 ticks per wiki
jiangmuran May 1, 2026
accca29
chore(axolotl): drop deprecated resistanceAmplifier alias
jiangmuran May 1, 2026
f9b714e
fix(enderman): teleport range ±32 inclusive on each axis (wiki)
jiangmuran May 1, 2026
7858d96
fix(bow): Power enchant uses wiki formula, was 17% of canon at Power V
jiangmuran May 1, 2026
33f0bf5
fix(brush): dusting takes 96 ticks (4.8 s), not 60 ticks per wiki
jiangmuran May 1, 2026
c647809
fix(brush): TICKS_TO_REVEAL 4 → 96 (wiki: 4.8 s)
jiangmuran May 1, 2026
b7f7941
fix(trident riptide): launch speed (6 × level) + 3 per wiki, was 47% …
jiangmuran May 1, 2026
97c97c2
fix(smithing): add bolt_trim + flow_trim to SmithingTemplate (1.21 wiki)
jiangmuran May 1, 2026
fb4f1f5
fix(shulker box): comparator output uses item-weight not filled-slot …
jiangmuran May 1, 2026
c59424c
fix(fishing): junk reduction per Luck of the Sea level is 2.1%, not 2.5%
jiangmuran May 1, 2026
372ed18
fix(brewing): add 1.21 Trial Chambers potions (wind charged, weaving,…
jiangmuran May 1, 2026
9ed0eab
fix(brewing): also extend brewing_stand_recipe.ts with 1.21 potions
jiangmuran May 1, 2026
0ddecc9
fix(power bow): bonusDamage rounds up to nearest half-heart per wiki
jiangmuran May 1, 2026
832a704
fix(quick charge): level V → 0 ticks (instant), was floored at 5
jiangmuran May 1, 2026
6222fc0
fix(brewing): potion_transform.ts also gets 1.21 Trial Chambers potions
jiangmuran May 1, 2026
4ca1182
fix(banner): add flow + guster patterns (1.21 Trial Chambers wiki)
jiangmuran May 1, 2026
370fb29
fix(enchant): Breach conflicts with damage enchants + Density (wiki)
jiangmuran May 1, 2026
ee39a8c
fix(amethyst): cluster Fortune uses standard discrete-ore formula (wiki)
jiangmuran May 1, 2026
b0003b6
fix(piglin barter): full canonical 469-weight table per wiki
jiangmuran May 1, 2026
3c5f829
fix(enchant compat): Density only conflicts with Breach (wiki canon)
jiangmuran May 1, 2026
f2fb951
fix(enchant): add 1.21 Mace incompatibilities to incompatibility list
jiangmuran May 1, 2026
73e8d4e
fix(warden): emergence animation 5s → 11.25s (225 ticks) per wiki
jiangmuran May 1, 2026
c657c7d
fix(wolf armor): scute repairs 8 durability not 16 per wiki
jiangmuran May 1, 2026
60f3802
fix(shulker): remove undye() — wiki says shulker boxes can't be undyed
jiangmuran May 1, 2026
b095af5
fix(painting): expand canvas list 10 → 47 per wiki
jiangmuran May 1, 2026
5ddbe0f
fix(target block): split arrow vs throwable pulse duration
jiangmuran May 1, 2026
e595197
fix(tnt): explosion-chained fuse spans 10..30 inclusive + injectable rng
jiangmuran May 1, 2026
092cd78
fix(vault loot): swap bolt/flow armor trim ominous-only flag
jiangmuran May 1, 2026
56965be
fix(wither): T-shape stem at bottom (was inverted, skulls floated)
jiangmuran May 1, 2026
c531ab7
fix(wall): single-connection wall keeps post column
jiangmuran May 1, 2026
9d8916f
fix(waterlog): add 14 missing waterloggable shape tags
jiangmuran May 1, 2026
2b28807
fix(bastion): rename 'stables' → 'bridge' (wiki: 4 variants are bridge,
jiangmuran May 1, 2026
7561bcb
fix(buried treasure): Java armor names + add iron_sword
jiangmuran May 1, 2026
023eff2
fix(dripstone): cap stalactite fall damage at 40 per wiki
jiangmuran May 1, 2026
5816ee9
fix(spawner): add piglin + enderman to nether_wastes mob list
jiangmuran May 1, 2026
17fbcd1
fix(blast protection): knockback uses 15% per level, not 8%
jiangmuran May 1, 2026
8b559dc
fix(bundle): use 64/stack-size weight per item, not full-stack rounding
jiangmuran May 1, 2026
2d8edd4
fix(smithing trim): template IS consumed; expand templates + add resin
jiangmuran May 1, 2026
9de83f7
fix(armor trim): add resin material (1.21.4 pale-garden)
jiangmuran May 1, 2026
13cf0f9
fix(compass): regular compass spins in non-overworld dimensions
jiangmuran May 1, 2026
c1fa724
fix(sheep breeding): non-mixable parents pick a parent at random, not…
jiangmuran May 1, 2026
d50d3a6
fix(firework rocket): boost duration 0.5+0.5×flight per wiki
jiangmuran May 1, 2026
191ae63
fix(thorns): per-piece independent rolls + 1-5 damage range per wiki
jiangmuran May 1, 2026
6c10318
fix(honey bottle): drinkable at full hunger to cure poison
jiangmuran May 1, 2026
7388f82
fix(grindstone): single-item disenchant preserves durability per wiki
jiangmuran May 1, 2026
5ce7e11
fix(loyalty trident): return speed ≈ 0.83/1.67/2.5 b/t per wiki
jiangmuran May 1, 2026
a42d439
fix(loom): add 1.21 flow + guster banner patterns
jiangmuran May 1, 2026
5c0b9cf
fix(respawn anchor): chargeable in any dimension per wiki
jiangmuran May 1, 2026
d442d27
fix(potion color): instant_health is red-pink, not orange (wiki)
jiangmuran May 1, 2026
bf43798
fix(shovel): rooted-dirt action carries dirt-replacement block per wiki
jiangmuran May 1, 2026
093c479
fix(smelting): nether_gold_ore smelts to gold_ingot, not gold_nugget
jiangmuran May 1, 2026
1577e9c
fix(template duplication): add 1.21 flow + bolt trim recipes
jiangmuran May 1, 2026
f1569b0
fix(bogged): bow cooldown 70 ticks (3.5s) per wiki, not 30
jiangmuran May 1, 2026
733d85c
fix(breeze): wind-charge cooldown 1.6s (32 ticks) per wiki, not 1.5s
jiangmuran May 1, 2026
e09427b
fix(breeding): cat + ocelot breed with cod/salmon, not legacy raw_fish
jiangmuran May 1, 2026
7da0b55
fix(dragon egg): horizontal teleport range reaches +MAX (wiki, was +M…
jiangmuran May 1, 2026
b8a8c73
fix(glow item frame): emits 0 block light per wiki (was 14)
jiangmuran May 1, 2026
f014de2
fix(hero of village): 40-min duration + 6.25%-per-level discount per …
jiangmuran May 1, 2026
642b0b5
fix(furnace minecart): fuel lasts 3 minutes per coal per wiki, not 4
jiangmuran May 1, 2026
c887145
fix(painting entity): expand canvas list 28 → 47 per wiki
jiangmuran May 1, 2026
7b4b611
fix(silverfish): swarm radius 21×11×21 box per wiki, not 3-block sphere
jiangmuran May 1, 2026
badae0d
fix(villager levels): Java tier offers 2/4/6/8/10 per wiki, not 2/3/4…
jiangmuran May 1, 2026
60a1ab7
fix(ocean ruin loot): Java armor names per wiki
jiangmuran May 1, 2026
f459ec1
fix(shipwreck loot): leather_helmet not Bedrock leather_cap
jiangmuran May 1, 2026
a823859
fix(trail ruins): brush yields trail-ruin trims, not trial-chamber trims
jiangmuran May 1, 2026
5b0373d
fix(trial chamber): SEPARATION 12 chunks per wiki, was 10
jiangmuran May 1, 2026
6e0251d
fix(note block pitch): note 0/12/24 = F#3/F#4/F#5 per wiki
jiangmuran May 1, 2026
bb7e228
fix(block sound type): wool detection works with webmc's wool_<color>…
jiangmuran May 1, 2026
5eb2b21
fix(footstep block sound): wool detection works with wool_<color> ids
jiangmuran May 1, 2026
1d3cf63
fix(portal cooldown): player gets 200-tick post-teleport cooldown per…
jiangmuran May 1, 2026
b98065d
fix(bastion weights): uniform 25/25/25/25 distribution per wiki
jiangmuran May 1, 2026
1ca824c
fix(village): full 13-profession job-block map per wiki
jiangmuran May 1, 2026
d7f7fdc
fix(piglin barter): align with wiki canonical 19-entry / 469-weight t…
jiangmuran May 1, 2026
4c6f141
fix(dirt path): rooted_dirt is a separate shovel action, not path-con…
jiangmuran May 1, 2026
50fff98
fix(note block): wiki-canonical instrument family per minecraft.wiki/…
jiangmuran May 1, 2026
f0be5b1
fix(sponge): align siblings to wiki 6/118 (was 7/65)
jiangmuran May 1, 2026
f6d758e
fix(falling block): dragon_egg + concrete-powder side contact per wiki
jiangmuran May 1, 2026
feca2b4
fix(helmet): turtle_shell (webmc registry) resolves head slot per wiki
jiangmuran May 1, 2026
8ece39d
fix(riptide): submerged formula = 4L+3 per wiki (was TODO)
jiangmuran May 1, 2026
b2cdca4
fix(fishing): wait floor 0 ticks per wiki (Lure III can bite immediat…
jiangmuran May 1, 2026
89c7661
fix(drowned trident): cap drop chance at 11.5% (Looting III) per wiki
jiangmuran May 1, 2026
b552e6f
fix(axolotl): play-dead duration is flat 10s per wiki (was 10..15s)
jiangmuran May 1, 2026
0d5f413
fix(conduit): damage range fixed at 8 blocks regardless of frame size
jiangmuran May 1, 2026
c8c6310
fix(bogged): difficulty-aware draw cooldown per wiki
jiangmuran May 1, 2026
3a83a93
fix(end crystal): heal rate 1 HP/sec per wiki, was 20× too high
jiangmuran May 1, 2026
dcac968
fix(end crystal): correct heal rate to 1 HP per half-second per wiki
jiangmuran May 1, 2026
ecddec1
fix(warden sonic): ovoid 14h × 20v range + 3s cooldown per wiki
jiangmuran May 1, 2026
92167e2
fix(warden sonic): align two sibling cooldowns to wiki 3s total cycle
jiangmuran May 1, 2026
68ed20c
fix(dragon death): subsequent-kill XP is 500, not 12000 (wiki)
jiangmuran May 1, 2026
3147a6e
fix(evoker fangs): per-fang charge is 1.25s (25 ticks) per wiki
jiangmuran May 1, 2026
501f348
fix(pillager): 3-second shot cycle per wiki (was 2.25s)
jiangmuran May 1, 2026
35f586f
fix(guardian): post-laser cooldown is 3s = 60 ticks per wiki
jiangmuran May 1, 2026
8e0250f
fix(sniffer egg): moss-block speedup, drop fabricated warm-biome bonus
jiangmuran May 1, 2026
2fd2955
fix(sniffer): mycelium is NOT sniffable per wiki (MC-260259 WAI)
jiangmuran May 1, 2026
ba63bc3
fix(breeding): expand wiki food lists for chicken, wolf, bee
jiangmuran May 1, 2026
a7fcfb4
fix(horse breeding): inherit-stat random ranges per wiki
jiangmuran May 1, 2026
07829de
fix(horse breeding): triangular R term offset by wiki minimum
jiangmuran May 1, 2026
0315a49
fix(horse breeding): wiki (p1+p2+R)/3 formula, drop average+jitter
jiangmuran May 1, 2026
66f0a3a
fix(goat horn): rammable matches full #minecraft:logs tag per wiki
jiangmuran May 1, 2026
ece3e6c
fix(plains spawns): add chicken + donkey per wiki
jiangmuran May 1, 2026
105d1f7
fix(ore vein y range): coal extends to 256, gold to -64 per wiki
jiangmuran May 1, 2026
1e57aad
fix(buried treasure loot): align sibling pool to wiki canonical table
jiangmuran May 1, 2026
8dcc40d
fix(mineshaft loot): canonical lapis_lazuli id + wiki counts
jiangmuran May 1, 2026
6cebfd5
fix(shipwreck loot): canonical lapis_lazuli id (was bare lapis)
jiangmuran May 1, 2026
ce724be
fix(enchant compat): asymmetric breach/density/impaling graph per wiki
jiangmuran May 1, 2026
f602fdb
fix(enchant table): mark treasure enchants, default selector excludes…
jiangmuran May 1, 2026
9be2fe9
fix(villager workstation): add nitwit profession per wiki
jiangmuran May 1, 2026
9e4be3f
fix(villager profession): traded villager never abandons (wiki)
jiangmuran May 1, 2026
9742b07
fix(suspicious stew): add torchflower + eyeblossom flower mappings
jiangmuran May 1, 2026
ec92723
fix(food nutrition): align sibling table to wiki canonical entries
jiangmuran May 1, 2026
68e950b
fix(food stats): raw pufferfish triple-debuff per wiki
jiangmuran May 1, 2026
abf8f38
fix(food): always-edible flag covers chorus_fruit/sus_stew/honey_bottle
jiangmuran May 1, 2026
42586ab
fix(furnace fuel): every wood + wool family burns per wiki, scaffoldi…
jiangmuran May 1, 2026
2a87b6d
fix(smelting): accept Java canonical raw-meat IDs (no raw_ prefix)
jiangmuran May 1, 2026
c275598
fix(arrow flame): skeleton_horse not fire-immune; add ender_dragon
jiangmuran May 1, 2026
0912221
fix(firework rocket flight): align sibling damage formula to wiki
jiangmuran May 1, 2026
d348414
fix(campfire cooking): Java canonical raw-meat IDs + drop fake raw_cod
jiangmuran May 1, 2026
1a0852d
fix(lectern): 1-page book outputs comparator 15 per wiki (was 1)
jiangmuran May 1, 2026
2526262
fix(beetroot bone meal): 75% chance of +1 stage per wiki (was 1-3)
jiangmuran May 1, 2026
8dbc9d3
fix(sugar cane): mycelium is a valid ground block per wiki
jiangmuran May 1, 2026
2218c0a
fix(lava+water): cobblestone is the default; stone only for from-above
jiangmuran May 1, 2026
50d8381
fix(fire spread): all 9 wood types + bamboo/vines/grass flammable
jiangmuran May 1, 2026
888cf9d
fix(powered rail): unpowered rail halves velocity per wiki (was 10% d…
jiangmuran May 1, 2026
8407b81
fix(lava flow): cobblestone is default; stone only for from-above (wiki)
jiangmuran May 1, 2026
1d03502
fix(mace): smash bonus is piecewise 4/2/1 per block tier per wiki
jiangmuran May 1, 2026
d29094a
fix(blaze): single trio per attack, 5s cooldown, 0.3s inter-shot per …
jiangmuran May 1, 2026
1ae0429
fix(ghast): shoot interval is exactly 3s per wiki, not 2-3s random
jiangmuran May 1, 2026
7b84c7f
fix(ghast): Java target range is 64 horizontal × 4 vertical per wiki
jiangmuran May 1, 2026
c3f9527
fix(phantom): JE spawn chance is 1 - 3/D (wiki x-72000/x), no cap
jiangmuran May 1, 2026
7ed13ac
fix(phantom): drop Bedrock-only light gate from JE spawn check
jiangmuran May 1, 2026
5c46b83
fix(silverfish): cascade radius is 21×11×21 (XZ=10, Y=5) per wiki
jiangmuran May 1, 2026
71afc98
fix(creeper): fuse sustains in 3-7 block band, only cancels past 7
jiangmuran May 1, 2026
cad3a2d
fix(slime): swamp altitude range is 51..69 inclusive per wiki
jiangmuran May 1, 2026
a975d56
fix(iron golem): difficulty-aware damage range per wiki
jiangmuran May 1, 2026
3911329
fix(skeleton horse trap): chance is 0.75% × regional difficulty per wiki
jiangmuran May 1, 2026
b9530f9
fix(husk): conversion to zombie is 30s + 15s = 45s per wiki
jiangmuran May 1, 2026
461ba7d
fix(witch): potion-throw interval is 3 s (60 ticks) per wiki
jiangmuran May 1, 2026
bb27b52
fix(illager patrol): size is 1-5 random per wiki, not constant 5
jiangmuran May 1, 2026
30b8946
fix(chicken egg): rare hatch is 4 chicks @ 1/256, not 3 @ 1/32
jiangmuran May 1, 2026
4fc6a1e
fix(sheep breeding): mixable parents → dye mix, else random parent pe…
jiangmuran May 1, 2026
70c26d0
fix(food): honey_bottle + suspicious_stew are alwaysConsumable per wiki
jiangmuran May 1, 2026
26599db
fix(water source): require solid block below per wiki
jiangmuran May 1, 2026
f9ea202
fix(fishing): Luck of the Sea adds 2% treasure, drops 2.1% junk per wiki
jiangmuran May 1, 2026
72e03a9
fix(furnace XP): copper_ingot smelting XP is 0.7 per wiki
jiangmuran May 1, 2026
377aa95
fix(turtle egg): day hatch chance is 1/500 per wiki, not 0.02
jiangmuran May 1, 2026
c17a405
fix(axolotl): play-dead cooldown is 5 min per wiki, not 2 min
jiangmuran May 1, 2026
8be70fe
fix(copper): oxidation chance is 64/1125·0.75 isolated per wiki
jiangmuran May 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .github/workflows/auto-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@ jobs:
gh pr edit "$EXISTING" --body "$(printf 'Daily roll-up of dev → main (auto-generated)\n\n%s commits ahead.\n\nMost recent commits:\n%s' "$AHEAD" "$(git log --oneline origin/main..origin/dev | head -20)")"
else
BODY=$(printf 'Daily roll-up of dev → main (auto-generated)\n\n%s commits ahead.\n\nMost recent commits:\n%s' "$AHEAD" "$(git log --oneline origin/main..origin/dev | head -20)")
gh pr create --base main --head dev --title "Daily merge: dev → main ($AHEAD commits)" --body "$BODY" --label "auto-pr"
gh pr create --base main --head dev --title "Daily merge: dev → main ($AHEAD commits)" --body "$BODY"
fi
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: ci

on:
push:
branches: [main]
branches: [main, dev]
pull_request:
branches: [main]

Expand Down
9 changes: 9 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ export default [
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-misused-promises': 'off',
// We deliberately use indexed for-loops in hot paths — for-of on
// arrays + typed arrays allocates an iterator on each call. Don't
// let the linter rewrite our perf-tuned loops.
'@typescript-eslint/prefer-for-of': 'off',
// Type-vs-interface stylistic; we use both interchangeably.
'@typescript-eslint/consistent-type-definitions': 'off',
// Generic-on-constructor stylistic — auto-fix often breaks code
// that depends on the variable's declared type.
'@typescript-eslint/consistent-generic-constructors': 'off',
},
},
{
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"wiki:crawl": "tsx scripts/wiki-crawl.ts",
"signaling": "tsx signaling/server.ts",
"bench:mesh": "tsx tests/perf/mesh-bench.ts",
"bench:nbt": "tsx tests/perf/nbt-bench.ts",
"ci": "npm run typecheck && npm run lint && npm run format:check && npm run test",
"verify:m0": "npm run ci && npm run test:e2e",
"verify:m1": "npm run ci && npm run bench:mesh && npm run test:e2e",
Expand Down
16 changes: 15 additions & 1 deletion src/blocks/amethyst.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@ export function dropsFor(state: AmethystState, hasSilkTouch: boolean): string[]
];
}

// Wiki (minecraft.wiki/w/Amethyst_Cluster#Light): "Small, medium,
// and large amethyst buds give off a light level of 1, 2 and 4
// respectively, while amethyst clusters give off a light level of 5."
// Old code returned 1 for every bud stage, dropping the per-stage
// glow gradient (the visible cue that a bud is maturing).
export function lightEmission(state: AmethystState): number {
return state.stage === 'cluster' ? 5 : 1;
switch (state.stage) {
case 'small_bud':
return 1;
case 'medium_bud':
return 2;
case 'large_bud':
return 4;
case 'cluster':
return 5;
}
}
19 changes: 19 additions & 0 deletions src/blocks/amethyst_crystal_growth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,23 @@ describe('amethyst crystal growth', () => {
it('cluster drops at least 4', () => {
expect(harvestYield('cluster', 0, false)).toBeGreaterThanOrEqual(4);
});

it('Fortune III ore-formula avg ≈ 8.8 (wiki)', () => {
let total = 0;
const N = 5000;
for (let i = 0; i < N; i++) {
total += harvestYield('cluster', 3, false, Math.random);
}
const avg = total / N;
// Wiki: average is 4 × 2.2 = 8.8 shards. Allow ±5% tolerance.
expect(avg).toBeGreaterThan(8.0);
expect(avg).toBeLessThan(9.6);
});

it('Fortune III deterministic boundaries', () => {
// rand=0 → roll=-1 → multiplier=1 → 4 shards
expect(harvestYield('cluster', 3, false, () => 0)).toBe(4);
// rand close to 1 → roll=3 → multiplier=4 → 16 shards
expect(harvestYield('cluster', 3, false, () => 0.999)).toBe(16);
});
});
21 changes: 19 additions & 2 deletions src/blocks/amethyst_crystal_growth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,31 @@ export function randomTick(stage: AmethystStage, rand: () => number): AmethystSt
return stage;
}

// Wiki (minecraft.wiki/w/Amethyst_Cluster): "Amethyst clusters drop
// 4 amethyst shards when mined with an iron pickaxe or higher (less
// or none with lower-tier pickaxes / Silk Touch returns the block).
// Fortune uses the standard discrete-ore formula:
// probability of no bonus: 2 / (level + 2)
// otherwise: equal chance for any multiplier from 2 to (level + 1)
// Fortune III gives an average of 8.8 shards per cluster (~2.2× base 4)."
//
// Old `base + floor(rand × (1 + fortuneLevel))` yielded 4-7 at
// Fortune III, averaging ~5.5 — vs wiki ~8.8 (~37% under canon).
// Now uses the wiki formula via a multiplier roll.
export function harvestYield(
stage: AmethystStage,
fortuneLevel: number,
silkTouch: boolean,
rand: () => number = Math.random,
): number {
if (stage !== 'cluster') return 0;
if (silkTouch) return 1; // block form
const base = 4;
// Fortune up to +3 extra.
return base + Math.floor(Math.random() * (1 + fortuneLevel));
if (fortuneLevel <= 0) return base;
// Standard ore Fortune formula: rolls = floor(rand × (level + 2)) − 1,
// multiplier = max(1, rolls + 1). For Fortune III, multipliers
// are uniformly 1, 1, 2, 3, 4 (avg ≈ 2.2).
const roll = Math.floor(rand() * (fortuneLevel + 2)) - 1;
const multiplier = Math.max(1, roll + 1);
return base * multiplier;
}
31 changes: 31 additions & 0 deletions src/blocks/anvil_enchant_combine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ export interface Enchantment {

export type EnchantMaxes = Record<string, number>;

// Wiki (minecraft.wiki/w/Enchanting): canonical max levels per
// enchantment. Old table only listed sword/bow/tool/armor enchants;
// crossbow (piercing/multishot/quick_charge), trident
// (loyalty/riptide/channeling/impaling), mace
// (density/breach/wind_burst), boot (depth_strider/frost_walker/
// soul_speed/swift_sneak), helmet (aqua_affinity/respiration),
// armor (thorns), fishing rod (luck_of_the_sea/lure), and the two
// curses were missing — anvil-combining a Multishot II book on a
// crossbow silently produced level II (the book's value) instead of
// capping at I per wiki. Aligned with enchant_max_level_table.ts.
export const ENCHANT_MAX: EnchantMaxes = {
sharpness: 5,
smite: 5,
Expand All @@ -31,6 +41,27 @@ export const ENCHANT_MAX: EnchantMaxes = {
punch: 2,
flame: 1,
infinity: 1,
multishot: 1,
piercing: 4,
quick_charge: 3,
loyalty: 3,
riptide: 3,
channeling: 1,
impaling: 5,
density: 5,
breach: 4,
wind_burst: 3,
thorns: 3,
respiration: 3,
aqua_affinity: 1,
depth_strider: 3,
frost_walker: 2,
soul_speed: 3,
swift_sneak: 3,
curse_of_binding: 1,
curse_of_vanishing: 1,
luck_of_the_sea: 3,
lure: 3,
};

export interface CombineQuery {
Expand Down
33 changes: 25 additions & 8 deletions src/blocks/anvil_fall.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,43 @@ describe('anvil fall', () => {
expect(anvilFallDamage(10)).toBe(18);
});

it('cap at 20 for extreme falls', () => {
expect(anvilFallDamage(1000)).toBe(20);
it('cap at 40 for extreme falls (wiki)', () => {
expect(anvilFallDamage(1000)).toBe(40);
});

it('tier progresses intact → chipped → damaged → broken', () => {
const a = makeAnvil();
// Force the rng to always trigger degrade.
maybeDegrade(a, () => 0.01);
// 10-block fall → 50% chance, rng 0.01 always triggers.
maybeDegrade(a, 10, () => 0.01);
expect(a.tier).toBe('chipped');
maybeDegrade(a, () => 0.01);
maybeDegrade(a, 10, () => 0.01);
expect(a.tier).toBe('damaged');
maybeDegrade(a, () => 0.01);
maybeDegrade(a, 10, () => 0.01);
expect(a.tier).toBe('broken');
maybeDegrade(a, () => 0.01);
maybeDegrade(a, 10, () => 0.01);
expect(a.tier).toBe('broken');
});

it('rng above chance leaves tier', () => {
const a = makeAnvil();
maybeDegrade(a, () => 0.9);
// 10-block fall → 50% chance, rng 0.9 stays.
maybeDegrade(a, 10, () => 0.9);
expect(a.tier).toBe('intact');
});

it('1-block fall cannot degrade (wiki: only falls > 1 block)', () => {
const a = makeAnvil();
maybeDegrade(a, 1, () => 0); // rng 0 would always degrade if chance > 0
expect(a.tier).toBe('intact');
});

it('degrade chance scales 5% × blocks fallen', () => {
const a = makeAnvil();
// 4-block fall → 20% chance, rng 0.21 just above → no degrade.
maybeDegrade(a, 4, () => 0.21);
expect(a.tier).toBe('intact');
// rng 0.19 just below → degrade.
maybeDegrade(a, 4, () => 0.19);
expect(a.tier).toBe('chipped');
});
});
36 changes: 28 additions & 8 deletions src/blocks/anvil_fall.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Falling anvil damage + durability decay. Damage scales with fall
// distance (capped at 20 HP). Anvil damage state cycles through three
// tiers (intact / chipped / damaged) and breaks at tier 3.
// distance (capped at 40 HP per wiki). Anvil damage state cycles
// through three tiers (intact / chipped / damaged) and breaks at
// tier 3.

export type AnvilTier = 'intact' | 'chipped' | 'damaged' | 'broken';

Expand All @@ -12,23 +13,42 @@ export function makeAnvil(): AnvilState {
return { tier: 'intact' };
}

// MC formula: anvil damage to entity = max(fallBlocks * 2 - 2, 0), capped 20.
// Wiki (minecraft.wiki/w/Anvil#Falling_anvils): "The damage amount
// depends on fall distance: 2 hp per block fallen after the first
// (e.g., an anvil that falls 4 blocks deals 6 hp damage). The damage
// is capped at 40 hp, no matter how far the anvil falls." Old cap
// was 20 — half the wiki value, letting late-game players walk
// under a 30-block-falling anvil and survive on full diamond armor.
// Sibling anvil_fall_damage.ts already capped at 40.
export const ANVIL_DAMAGE_CAP = 40;
export function anvilFallDamage(fallBlocks: number): number {
return Math.min(20, Math.max(0, fallBlocks * 2 - 2));
return Math.min(ANVIL_DAMAGE_CAP, Math.max(0, fallBlocks * 2 - 2));
}

// Per MC, anvil has ~12% chance to degrade per use at a non-zero cost.
const DEGRADE_CHANCE = 0.12;
// Wiki (minecraft.wiki/w/Anvil#Falling_anvils): "If it falls from a
// height greater than one block, the chance of degrading by one stage
// is 5% × the number of blocks fallen." 12% is the per-USE chance
// (anvil_damage_chain.ts), not the fall-context chance — old code
// used 12% regardless of distance, so a 1-block fall could degrade
// (wiki: cannot) and a 20-block fall had the same odds as a 2-block
// one (wiki: 100% vs 10%).
export const FALL_DEGRADE_PER_BLOCK = 0.05;
const NEXT_TIER: Record<AnvilTier, AnvilTier> = {
intact: 'chipped',
chipped: 'damaged',
damaged: 'broken',
broken: 'broken',
};

export function maybeDegrade(state: AnvilState, rng: () => number = Math.random): boolean {
export function maybeDegrade(
state: AnvilState,
fallBlocks: number,
rng: () => number = Math.random,
): boolean {
if (state.tier === 'broken') return false;
if (rng() < DEGRADE_CHANCE) {
if (fallBlocks <= 1) return false;
const chance = Math.min(1, FALL_DEGRADE_PER_BLOCK * fallBlocks);
if (rng() < chance) {
state.tier = NEXT_TIER[state.tier];
return true;
}
Expand Down
26 changes: 19 additions & 7 deletions src/blocks/anvil_fall_damage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
tryDegrade,
DAMAGE_PER_BLOCK,
MAX_DAMAGE,
DEGRADE_CHANCE,
FALL_DEGRADE_PER_BLOCK,
} from './anvil_fall_damage';

describe('anvil fall', () => {
Expand All @@ -17,15 +17,27 @@ describe('anvil fall', () => {
expect(anvilPassThroughDamage(1000)).toBe(MAX_DAMAGE);
});

it('degrades on roll', () => {
expect(tryDegrade('webmc:anvil', () => 0)).toBe('webmc:chipped_anvil');
it('degrades on roll (10-block fall = 50% chance)', () => {
expect(tryDegrade('webmc:anvil', 10, () => 0)).toBe('webmc:chipped_anvil');
});

it('no degrade on high roll', () => {
expect(tryDegrade('webmc:anvil', () => DEGRADE_CHANCE + 0.01)).toBeNull();
it('no degrade on high roll (10-block fall = 50% chance, rng 0.51)', () => {
expect(tryDegrade('webmc:anvil', 10, () => 0.51)).toBeNull();
});

it('damaged anvil destroys', () => {
expect(tryDegrade('webmc:damaged_anvil', () => 0)).toBe('destroyed');
it('damaged anvil destroys (10-block fall = 50% chance, rng 0)', () => {
expect(tryDegrade('webmc:damaged_anvil', 10, () => 0)).toBe('destroyed');
});

it('1-block fall cannot degrade (wiki: only > 1 block)', () => {
expect(tryDegrade('webmc:anvil', 1, () => 0)).toBeNull();
});

it('chance scales 5% × blocks fallen', () => {
// 4-block fall → 20% chance, rng 0.21 just above → no degrade.
expect(tryDegrade('webmc:anvil', 4, () => 0.21)).toBeNull();
// rng 0.19 just below → degrade.
expect(tryDegrade('webmc:anvil', 4, () => 0.19)).toBe('webmc:chipped_anvil');
expect(FALL_DEGRADE_PER_BLOCK).toBe(0.05);
});
});
19 changes: 15 additions & 4 deletions src/blocks/anvil_fall_damage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ export function anvilPassThroughDamage(fallDistanceBlocks: number): number {
return Math.min(MAX_DAMAGE, Math.max(0, d));
}

// On landing, anvil has 12% chance to degrade. Damaged ≤ chipped ≤ normal.
// Wiki (minecraft.wiki/w/Anvil#Falling_anvils): "If it falls from a
// height greater than one block, the chance of degrading by one stage
// is 5% × the number of blocks fallen." 12% is the per-USE chance
// (anvil_damage_chain.ts); applying it to fall context makes a
// 1-block drop able to degrade (wiki: cannot) and a 20-block drop
// no scarier than a 2-block drop (wiki: 100% vs 10%).
export type AnvilKind = 'webmc:anvil' | 'webmc:chipped_anvil' | 'webmc:damaged_anvil';

const DEGRADE: Record<AnvilKind, AnvilKind | null> = {
Expand All @@ -19,10 +24,16 @@ const DEGRADE: Record<AnvilKind, AnvilKind | null> = {
'webmc:damaged_anvil': null,
};

export const DEGRADE_CHANCE = 0.12;
export const FALL_DEGRADE_PER_BLOCK = 0.05;

export function tryDegrade(kind: AnvilKind, rand: () => number): AnvilKind | 'destroyed' | null {
if (rand() >= DEGRADE_CHANCE) return null;
export function tryDegrade(
kind: AnvilKind,
fallBlocks: number,
rand: () => number,
): AnvilKind | 'destroyed' | null {
if (fallBlocks <= 1) return null;
const chance = Math.min(1, FALL_DEGRADE_PER_BLOCK * fallBlocks);
if (rand() >= chance) return null;
const next = DEGRADE[kind];
return next ?? 'destroyed';
}
19 changes: 15 additions & 4 deletions src/blocks/anvil_stage_damage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,24 @@ describe('anvil stage damage', () => {
expect(damageOnUse('anvil', () => 0.99)).toBe('anvil');
});

it('fall compounds damage', () => {
expect(damageOnFall('anvil', 2)).toBe('damaged_anvil');
expect(damageOnFall('anvil', 3)).toBe('destroyed');
it('fall advances at most one stage on a lucky roll (wiki)', () => {
// Wiki: 5% × blocks chance of single-stage degrade. 10-block drop
// → 50% chance. With rng()=0 (always passes) we get exactly one
// stage, NOT three.
expect(damageOnFall('anvil', 10, () => 0)).toBe('chipped_anvil');
expect(damageOnFall('anvil', 3, () => 0)).toBe('chipped_anvil');
});

it('fall ≤1 block never damages', () => {
expect(damageOnFall('anvil', 1, () => 0)).toBe('anvil');
});

it('high roll spares the anvil', () => {
expect(damageOnFall('anvil', 5, () => 0.99)).toBe('anvil');
});

it('destroyed stays destroyed', () => {
expect(damageOnUse('destroyed', () => 0)).toBe('destroyed');
expect(damageOnFall('destroyed', 10)).toBe('destroyed');
expect(damageOnFall('destroyed', 10, () => 0)).toBe('destroyed');
});
});
Loading
Loading