From f0a7cf815d4215fa9e50b2ca47126d745ced84e8 Mon Sep 17 00:00:00 2001 From: Daniar Mannanov Date: Wed, 26 Aug 2026 02:06:00 +0300 Subject: [PATCH] world: prove undecorated base terrain bit-exact against vanilla MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TestVanillaBaseTerrainParity compares our noise+surface+carver+aquifer+ vein pipeline against a vanilla capture whose biomes carry no features and no structure sets: all 393,216 cells match. The plain-state fixture mismatches the base-terrain diagnostic used to attribute to carver or aquifer defects are therefore feature outputs wearing plain states — monster-room cave_air, geode voids, lava-lake lava — and its doc comment now says so. --- .../world/base_terrain_diagnostic_test.go | 26 +-- .../world/testdata/vanilla_base_12345.bin | Bin 0 -> 786480 bytes internal/world/vanilla_base_test.go | 177 ++++++++++++++++++ 3 files changed, 190 insertions(+), 13 deletions(-) create mode 100644 internal/world/testdata/vanilla_base_12345.bin create mode 100644 internal/world/vanilla_base_test.go diff --git a/internal/world/base_terrain_diagnostic_test.go b/internal/world/base_terrain_diagnostic_test.go index 5859ecc..af8695d 100644 --- a/internal/world/base_terrain_diagnostic_test.go +++ b/internal/world/base_terrain_diagnostic_test.go @@ -10,20 +10,20 @@ import ( ) // base_terrain_diagnostic_test.go splits the vanilla fixture's block -// mismatches into classes that name the responsible subsystem, instead of -// leaving one undifferentiated pile. The ore-replay diagnostics measure how -// feature placement drifts; this one answers why: which cells already differ -// before any feature runs. +// mismatches into classes by what could have written each side. The ore-replay +// diagnostics measure how feature placement drifts; this one attributes it. // -// Every fixture cell is compared against the undecorated base chunk. A cell -// where both sides are plain states (air family, fluids, bedrock, stone, -// deepslate) cannot be a feature write on either side — it is a direct -// base-terrain defect (aquifer edge, carver boundary, surface rule) and comes -// with sample coordinates for targeted fixes. Cells where exactly one side is -// a recognizably feature-placed state count as a flip toward that side; the -// remaining ambiguous pairs (disk outputs such as clay or gravel look like -// natural terrain) are bucketed separately so they cannot pollute the plain -// signal. +// Every fixture cell is compared against the undecorated base chunk. Plain- +// versus-plain pairs (air family, fluids, bedrock, stone, deepslate) used to +// be read as direct base-terrain defects, but TestVanillaBaseTerrainParity +// settled that question: against a vanilla capture whose biomes carry no +// features, our undecorated pipeline matches exactly. Plain pairs here are +// therefore feature outputs wearing plain states — monster-room cave_air, +// geode voids, lava-lake lava — and the sample coordinates point at the +// feature, not at the noise stack. Cells where exactly one side is a +// recognizably feature-placed state count as a flip toward that side; the +// remaining ambiguous pairs (disk outputs such as clay look like natural +// terrain) are bucketed separately. // // Run with REGIONIO_BASE_TERRAIN_DIAGNOSTIC=1. diff --git a/internal/world/testdata/vanilla_base_12345.bin b/internal/world/testdata/vanilla_base_12345.bin new file mode 100644 index 0000000000000000000000000000000000000000..4b68fe768ba46a0837b79292e3b017b62d9251e9 GIT binary patch literal 786480 zcmeIbyK-bn5^aZ8NA3?HMT(@^6)4e+v}vXF(OSA{i=*%#`d`WPvva3=JWm3dK;f|p zRv8h#{T0hkCQwy9Hvjkk`G5T%|NH;*KmOO3tD~@6(@^ueUl*x%{e}nZMsvzt}5lU2RF5W7KV)6z{%j z2)zkIUCa-+Wod~#I=Cp^E%vG5=T57~7 z&h}Vsai+Seo-MV8ZEdwY*;mx$kLqW;{8CXL&Y=48?O)|1|K88}+CI{n z{%Om6wUYGoa%6AWMY~7kt&z5v);de8C`Wy*nY52rdE{Dc>E&H|d)F&9Q|}X+Z1Gz6 zs%lGW&X$TSI#;XvV1)n#AOHafKmY>Yhrr8!;%jvuscVmW^?Ck#qgVai8$YieR%KZ0 zzh2SbMy~tt-&W2&tiHVbTK(5nf9vh%UBA}4pP(nS%4&UnhrN1vzHh(g`ET+&KOghz z+235hx4U_CW}mY=*H?Lad-U1c^6XorrS7b*GTf`zoOSQ`YO8zc)za?I^q|;AeB>#* z+toYk{!Djn`K@YMo$INd>8{qUj&H4blAdRF&nMs+oK0}9=O@j)GiRTxSbseMPv~sE zd;QnngAU$KAfAD@M-vHwO5o+c^)&AP{AaXP%cFYDHQS%%pT&Hv?d;un_I}l8`g`?! z#_w0_XZJqq?=1fP^?T;O^U?fw9*^AN(f9YG@sG~$(fCK$-4}Z{xwH4T=YN*xzHWN2 zGk(8X@B8h~XZ@W$pMAcMKgWD`RXulwdC^|SuY@;@5?X#Q3G{nXB8wAZDs zo{GJ?>UU*7<8!93@;+{ld+xG`!@9q{ZgmweeN|uTy1%`?S3mY|VOIBF-MqEOO7Lcn?)SRXRsOvib>y+SpW|2GAMT58?~^BIPfNR#-rDl?Sajz3>-W{|?eph9XCC&P zuhHpT3F|X%xypaW=)UUf`z!y7&Y%D6^}Tx5oAfo;(0A&`X>reWHBor0uIP3Cd$O-< zpE2HNfBA3d`|OtrCx3Uci~lOx8HGpmdl-KePCvEJ{rrC_748iI2z*xpXW#c%KUIpy zg=oqgPEKi{*Pum4Qq$j93rn}RAeYCp! z>+|M0D&*;HJ9n9D&6C#Ly++p^YQ(sY%%jy7)%9sy-!uB2?#GV4l0|geSNGpqeOjwl zwAx>5tHo($A3d?WAAvfhwn|mTS-nnOXKodpGWSe9e{v#z9+~;~`cC~Rnx+u6XE)9n z&Gbi9&o^?+DyKeIt*=z+Yc=$piY5Y@@rs6@fSGP>#o78SHf;OK%y-2NI|LvA0SG_< z0^gUw>gTHOd*jb_vorqj^XsnT$Ms$IudnIn|24zs=xa`o&u86xR6WnX?oIJ~{VS-R z;fz#j-nBQfwXW5p+H;>CviUrEgvDyC_OPwjdyh7H%rNTC;0oia9!9$@XS)49&${ba znqT{#ZO^s!kX<(WRF9s2^{;;3&vIDPdY0k+=X>5k+c75yKmY;|_wY&e_mNV2P^wLC)Te+K>sCh&Odfz_tr;6mRZco7yIWU;Q7|Ic3JJSSzE6$?7t2H z&#zy7gWldh166lSU8PqG`>#YG=3Qsp&vVq<+tt`s(W%cj^TGCW3G|;gKbORN-TdW` z-Pe0nCGY1Tu$%q4cKP10d3toinMb{QuUC!zdlTsCKli+QK6JBry}Wg=r_#sw3g>$W z^n5?^9R028x%ZiFZH%vq_KF|vSSp_x<@dKm2kR>9{&IFNzqRqHcxOG%FTdHE>&qXx zU+u=YOWjMZwD-F_*PL@}pJ(oMuT`D7>OLw|^Z7OFuD&v$ba;;ujw()UFHpxZv zKS&%;hm_P6S1YE)`Mk<2b2-YEnzhE%y>8HY){42;?Onrh&K2wB>-u!3RsPB!`mg=E zbiM3AH=XOctq61;xA*1sj<@`W_c7y)zU=-8zk^jXe_NCHjoH;d^O}k z%wx}3^?R(|c^~t2&RF$z&2+iDdU9u~>D(Q;8>x@8Upm=TJ#IhM^FBlTjog**E&g`v z;&GuBdP6OVwNvoPgq2U$`g(MIeMZ99b?u+NX^~%?{nbXLr+j?>cCGP8p5tzLAIILb z8=HaRr%(=(i%t$LXbrkp-CnDHn}sRg;;(ZGd-9UkticHyhv&Ya%%^xEG?_FG)#^Xc}NJ1%-Mfr)*{zjlU^obJMR8j;wlA8ozG* zu3GOkKeyI6rDfcuo|+?6zuNT#sMFeAdRFh7N9FVR_U-)I{zSgD=~QRZ>fmq|3! zzI+F5&PRqDy)j>{UDR2YHt)`3rpY!_B5&GbH};$Q#oG*4Yusa{>AUAzeNScGSCa4R zr=nfzy^{J|`EJ%EQFp#&wYB@?)Y^Rt-TUXR>&)(YtelE=*-@{gK3A;o)UTx_i`?Z6 z(pGn&*Yij2*R|JOr=nf<+bgNh73(|ot7%EYyLtoL>Y94B=3aW9pSg?N^L(qW((YZx z+tRL~x0d#_SEIky|MQ=c$n5T|+TX5Mt3GO(f3BVBX4yyEuC=PI5~sateT=iE-q5zX zKC0JTAGO~zsp@#UR_*m(t@@~iCGR}ysd-NFsdnuhJ1RADtJS@2&4|zMpSAosY!t?iSi!-&g)F>W)F&@gDtb zO7F+&tnymd^w;|P_58UqpAq=3^FRN|`TW^`WRhpxAIbg9*v~!xvzzWI-*dOK3M>7w z%B!p&Z`bGKy6&02j{FGau_^4H58Zp6|B=`rv(Eex+_J{me9!dE^ci<&l;5uJ=6~P! zp3lf@?1}l0OzyGlpO4S;{y)15^WPC#e}0JD-^)MWt|NE#Qd?zK-oIZ~dS+mEPT*`x zYhCl->$@raaWcV`?z$`8cjoypiQT%MpQ6^f=dj9tkG_6B6g``v^TxWW9rnHY+wksIIaQyrgx)b^hMdv$z1=AF#D|322UTkmvDV#UI9n(J2Q z`BNSBs_kYRe&f@V-Slc-X&0MWzWT1eb$_3ou1WL}K6_3+x2x58{!~Z3YO!zg`texkCTkDrcJ{C<9^&f{}>b3LoSRsY#j&)cu~ozLGh$Xs=o6RuY8Q=Qj8)6brd zGu?f#&iR{5%)$F{)s#lNES}*^x3wnhSPqXd$tmacEydvfq&U9<5{Cj;r z-&Wnf^h=)%#qW_k3pj zlbI%w=XU2gwN{_3&g!QYJ4bkJ)mHDdS-kVG27#7e&t%U}wEGyJJqw@P)#|K%YO!nM z{HM)HMH`iy_l(XX%Z{ZvQ2YO#05@smNGsei}aWAE?J`T5^YvYp!a9=AR! z`}yl%hj#qV|NZFv-}Iu%A6YQDGN<_WpfT-`&se(s_S5g?sh-q-V75 zZ`RfBy(s!Lt~GD=l74BcJ5PVb|4cWXReW|`tG4_7^A)~l&&Ol>u6|BLJ-1J?BE?vJ zhMtqCx|Fckr>e5%w8mZQJ?hFZBP-w9m%VDv?AofhyHZ+n7ddx&&5%)bml>)x_hJ<_ z(x#o1*sF)yzqEL*dRp6E@@egH^6fmeIHy;t?fmRf^?qM-_uAXfzOg#!^MqAIX1Z*Z zZjG0kl;hm%iuG&j;rMpV46WU#wJs(6?BkfUv{SL)_g*WJ*-h`!E5Sa8Dfjj`Thlu8 zzy<*bKmY;|fB*y_009U<00Izz00bZa0SG_<0uX?}YY4pX3jz>;00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_a1i+Ic>VVaUq76{U%&Uyz-W2-ciM8NxW9gvrM|WqL#bYC&o<8a&#cNf z^SaOG-t6ssUTxPpT4jk>YhLr-tJut)F_|aT8t;CyqGEk+Gu2bgXM0_>x25)Bn`>t# zTQb(Z_K9B~&)m2s}8jP_S_-aqZ~Qg-*k20%IzebF+ zIIBCT=k#+GXQh->X#ATRiD_;yltzx zZLX&-oVA|pnXB^nTw_*yN7NYEYDBeEPj^%4_j=7Ur_g%nRI_LwuUV(}s{XTlY0LSi zEqBLsug^zX*+BpT5P$##AOHafd~E_RFJHTVx_>(X{Vn-A{=M~eWt8_Ppy{sO|5oRE zsx!T+XZrk}$}rckK8Jv(G|Of!)={tOsJH5wzRNypVR8PsiuE}JM0uXe6Nq*6sOqTi z)tv4;ch$$rvZ%sJ#s1y|a>8S!)W#TR4(_o{t&8K>Q!|HM~s z^;z0lfBA1{EB)m~+4s6~xME!+{?dQ*e6)I=%qT5&XZ6wfX3jc=%--+h-&^y1pWe^# zJU;szW2@%*teyeSe?CFYH|9Unk1j9I$6Qrkp{?d0@$LL;=dlkxpN?J)z1kvQJ=c9` z@vGYEUTUxVY*ptxSs!O$AJy<_T;0Q{$TE+2l-D-e)>t(iz2+R!U$YbCB%QirQj46e zuIyPg&h|L=$7e|D+P(ZYd}98yXY1;7nb%s?^U>#huXE1Y6{3Id^#u47ihi{govg)b z-A_=S`(2x_SK~bM@O(8Rc{H!r_pj!VbF+`0jGTh)UX?%fqmN^iHQpEG8g+qI{i5yBzb^4D^m{W%KupS~d7fu^x4+kDovH6RUi$UPt|^ zYOm>De5Ox_vgnx}W3eOw@mtSd3^k=Xx7+^8U!VV%Jl!u(Gw0trWGDSjei5(gy&mU_ z&*J&Wy6S8e9k%RivORdbHj z+Q+W^uzv)BobRq0GuzQYg8&2|009Vm4Fc!i_1mB5+S7Q)GkyGtam<0`;|PrN?|;Ix zNAy(p*<)C%+GfZY?^e3dHxU|!*Q8CLm!jeRu{cVjL-_p9}Fo^y}LxsF#wXX)$v ze6PNGhdMs>usD0Ht%pzPVT+=CNB+UW6^p3ynI)qK(;JIwfq@@cMHUFDzYndxiqc6UonyY{BN8t3Y<*Jo;tzh94< z_RjjYD5p-qcd_y6tZ?EYfB;`F)+ zjJ(q_uj9H_eO`AuQ$C9={;T4BFOUA$muK;3`o6pORW;*P4L<>M-Rk`LNOh*~)vR~? zm%%6V+t2s%zZW=(e{?=)@n`k(w!daKn~yuuoP6q6PqDY_Y;~SL)w%AR>;LXPJ-nN* zUwuCFTYZ!@=CrEi8P0X9tN1g0o)zmy6IjhpeZ&-39eKiY-Re4i9*6bo5YUWQ{rU-5 z>Da$Iftc|64$Obe<|ioor{gCO;EoW000bZa0SL?p@H4`U3N{Ep00Izz00bZa0SG|g zvk}<+-FN@rReiSJKeC^fKR&Wr)_VCPzVh7f_G<6_n)9w|-#vGQso&(v1$V{2#g+8IBK z&G?lnkDa>Gu1tQrbnx3`e|$>6T+~*d_gmr>cY8NpGaS~84S!`;ch~q^?B#q^&fZ&( zjJ03YGs?TFj&syud_Q(iM>SVOWAAH@UnFhSy)Pu9Wi{C*NCiYSH=i{#Oc7`>-B4rAM{cMclR4vA^a~UiEPElmE5; z;h|V}G5$&)SG*|A`^DbH^P1~c`}*YQe0e=?6It|i^Rr!RQO)J>zo@Epi)*^AIm5$! zd!M;vk^lVFcS<#DhGu)_c6M7@pE$La$lxle%E#x+8bq!W_p18xNe|~Qv8s454XeH! zXFttEdV0CL%X;mg=GXq_eSN;_ZECOCuWBiyDyXO9_2@ITqTHq&s{6iGKh*iDRBpVS zV_M_tso2&-RjOi3__ceT((X)Qx8}W9D?ZClugWCF7O&3jYVx{fJD8v_%iaX0gkZB(k= zs@GaKtEB3kSNq3Vw$&}HXI96ymiejFJ3e9NUKguoR_ImFOO~5n?PY(_Z#R(dI>P$! zJYDmxBNY+)Di-@&3GA8fnYRV1n?in33|7TGAx;dEt*PY!nI%odR zp!jujJY)X5+pm7E*u|iI9D!%de>dZu_HnnQ(u%hp@y z=UP}pU#rKzUvBkXEZXA)a=!C9r9Q9q`26Q}=hd)2n?TNYK8Mujm95X!@^4j(cX`CG zVzIwJ0ncwWht%i2+^5fD!@8>L2%Zj;c%L=rHz$3+KJQQQb1kgr`Z^Zn83gtd-m9Kp zc+Gop{9JYXO6BumP3C!uXEdMTBdX_n_I#}GvW`^Dyyta3l##%G!a2h+GA#S(y_(VU z+|pN?s_#^^`v`bSD{tw0b^cCt=DC{l-|MT&5x>?#In(#iKSlMFR`=cO_o;tRC*|1H zoTSfVHQ!aF?()aWI#%&}eXp)~eKotMu)3}F)xD(e)%l#9c{L~NyUtcx^b_%`zV6d^ z(ceWg(AwGc_x(rlk0l>iBu?u&(-Y#Oia)`ns|`KF4a#e@~z2y=scVVs_seJ?d8H z(R(#3&!bbHcV<1*v9p*=)L*Nquco-_%l^CE;j`*1u)}b&iJ`%eWl)~ucK?nl~lF&_Xxke zKGv(b$LLl))BD={=)G!w>9x<^t8M&v?^fSOk7|vc<&FqLjzL zw0c+7mSA|aYOnWdf0tf&O|8A!M)&Gj?eMSp$9P%nv(n#U-{-WdHS)JyTiqx3;qz{_ zuX6XE_p2?z$Wvp-?7iB@_j=n|ueQ;9b?mH-p6QV>I~eoJVvkmDS+u7d*sQ1xr{HRuarlvkt?)}?N`w91I%VAV&z1L5$W*>9c-e$S)k4`?dN+nb6 z+E;aqZ`If8eRLZ?s#Tw<=enb29IeIQLXI5jgh%yxGnnPh>~l4Ho9lVAnV!*=pFOKO z>a9BJSy?-0)!M6V{HRvFuiWRKMcX!;Z@$asYR+J;XFu&7eR@u9XX{sI@9jF@+gs(E znVdV;w0c+7QE$~=@6}e%uG7y|V@+%BQcqjEi@&)}uXY!nYgPTcRrhV$ig{9(d2V<2 zMYsHF1~aI(+&lX`-m$S}jCWNX^;YfmUVWWDM%Vb6x|?p?XZLK}qwn(v<+G>9RL4~_ z8tt-pf^XGLYZmX^;WO%v)Y|K<+Q-+-v-m!`jUUyj&(x~-oj&8dp02X*^`NoqVz298 zfd2>Bkj(R)8Ue8GFUZ?lbEuT@X`b@2Q-^ph<@1KwOeA;)p*Wdo>7Ln`c zr#=CFe^rZ#^m;#~R{!ngUzeErRrRp{tMf?RYU`0YyVnv}KR>(YqkRJUnsv6ZZ}q>s z>9%@gZl_yytF1?ypVKo5tey`&9eVBS?dSi;cK-1vfOfid{_$xUYU|P0=lp94)MsP% z{QT?q&XZnkx0-OO{r5l5KRw!bPM@8?zq;=TeZMi`-j-+2KP~Ja009U<00Izz00bZa z0SG_<0uX=z1Rwx`?@Qo?Ul4!*1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZafg6F}UjEJ3Pbcu# z?kO?rQ9;roFw^ifx5BMTX4S#z=R6^3^FLe0F4J>wWq@)|E3?-+|9wRZW>{ zWoK~jRkO|ggs=T`RZicoucz4d)v@-CSk#F-DchF#gWoxC-s?GymNnwv6pXj>yYkxlsSEjfuQl^l zHLTX#eloA~ID_Nc4l79rb8 zb)8_4(eh49D)yiCfDHl=fB*y_009U<;QJD|{axV8{Elb(*nDJ*7=J82kt^Z_2 zeAfibf8}wnem1?xGpphJEB*dYn0fxF=^C^8vaPGHV}6dZCL0VycTMArzV%g=)aM>& zx;qTNd6)NRn8)8kVIBDslofg1-TYT1?$uXS93Shf#+m-iCur5fYii8y@V#woYPz>4 zxT0{cK7T&yY~~)$uXWZ%>k+5c>r8KZP<)@G&B&<|7>QTabX!|Jc|O%v_tsZ4N!_~| z9edlo_WI~y&sEKg7;~j1vgC=~+XxX}ygfD||NJMu9?L=WdlT4CNHbjdc)niSUL#7s=X&eS=@9}i z|6R=}vi|wc%YWC|BXSk5`G-2@51aDJtFNFKKLNeUxe^%ZR#g*R`TY6M|NMVv^T`aF z?&=xP^yV3)&7UC0g}RDX4=X)8{Mx&-`<>})f|cKT{&V_@jj8K>I*SimsPVghKBOtP zeA+1~D!jC7)q0vmSN;9>v%A--JA&aS7B!;o&*pos>j|hi+x;$swABsO`C4_fJ|k+? zRMg#=BRnEP^Br|%bDo-e+^?eT8Cm)#)LN{2-JRBmx|hE0A(VBF^XPSKcCoI$;;-1q zy~;29Dzog4pXHFYuOCm2{qi<-cczE$`25uj(Sd%q);yhekiO&YtV2~_bBy?Pf9`D+ zAN|;8>@C%KeD>b!?#a1(U9}uPSLgja-x^))vidG_pNQW54Up8ehvVmehosuO=>794 z!t3WF?qr|!{la6WDssVJO2=yd=0Kc4UUPKuw;SCd&+5aHeYa|ZJcbg$Lz z96i&e>G_!F{tnhPd);n7y`Zztu-AjJp0GJf&u6ZNb?=cg95Xo5KIu`F?>+ys>7Kp& z&*v|XWZUk7ba=GZJb4mnsXN6fN40Ba$~;rU*O|4>qTSi(p`6aY>%YzW`A(0{UnExd z@_g2MlI(q~#Hu{i!)n+@-Kr;8BfSrw{IXSR+H=O$!+O|eHByh==YBro38;5_-ac-= zy1Th}9jjW2RhiO9Hru_XuAS_2HLUfkjkV(G?&{CxoAHq$zWV%emc7?n&+mHj-PgBI zkC{)X`kFss5u-Te896$Brdyj&&(`YI=1;}Gt*(vg7wt!CXuXoQXTJ`p7-_u*qahFxB|8zB<(X(QtlpZ@M(7C%OOKg;~y`uEKBY^=Q%})r^$T15-D;WJyI$8> zYP?pR{rca}#j3tmTJg+?>3aU2nmtGQnuc>}&aUF`-0}Gx8I;9OYO3C;8_(C)agF?8 zb)ETorq823v(;qA9%t|W^wJc^*=g?jbkL_n#suNeV`lk$_#A$kiz4I`{|%U@Yu(f9 zr{C-07ae8>M~?q$N)x!k_*M3wMx^>%Kd z#(!rTx_nywaymYZ96zWx!_n_?awXOvpee6e1UIv9y*v|5Su;wHn7LvP^4I+()8&`E zGtIEz|LF?PZqlV-n#3o zN73;e$9PA^Dk_;ZIL234#z^@o#_z})8!=Yr(P8!PHd3dv+R8f5UAvp*4x6UxDx;Tp zuJt}*$RjZufN6n+4z5 z`%gZiA5*L`x%bnts&*b9@7`VZ$dL8gowBz!POl}P`R^$EJv`4Gk?ZKt&Sp5zE9)-v zE)MNA1a=d;C(r5~d`~Ps5P$##AOHafKmY;|fB*y_009U<00Pe<@bcTsZ+)(`XqV^S zb9J6&4d0q6eCk2_R_}Yym8L#cQOZ))x=(eqw)L%R^{Mr#Cwq*Ps+acm z)!pNimg-%t+Glp3M}J3o?LDeJ@;PU8T(278h=zv&x{y%w#4dvo29qcYBi$0ad=hra%!lBD*gI;s2883j~aQU z)=eutL~E?)K0{Y8*GdPSsC4V#I%`E79h8`x*R`|D`Pysozux6)DR)U9^KkUB9=*t? zi;Wz&4nwoBxNqNNd`E;|s+ZlB zlKVT(&5RcBiGTF`#XAUqLsJwep9U|`_04p^}eog?ZE2o*$ca>AKhJb+f?J$ z|1DZkx0=WOE?KM}OdRFA9r?m~~(MN_7EycBu(@nj4AH92j$!PuP*fpZ=8=X~4|F`U_c+1;TJD6lt)^a~}%^bGclB;+2&>B`NUQ>~_uI&hAk)Ld`xK^9N zQMHaebG>G`Jy|Ww+l-2yv2)e^T{7QhFzumJ!^b@z>s9xyuALrF!o{~l+au#!y}MIn zxJ4`LG=nQ`R`(md>ua=F@jCOE+3erk>Qd!3zN;L2dsfI@Mx5_n7q#=wx$N%UX7K4) zZ_ll*P4|a7Rc`Za{INm+0uX=z1Rwwb2z)OB@$=yACq{nq`-BAI&u#l>?lJv5|Gqlv z`w}>t&olJ1C+K}|NcJ6p{d_~+PwyUmpW*yF#993AexG04-EPNU+KPWimXV`1 zEm|MMt?nPyYp&0?U*FCX8GE)eBl{lO`O`S|n3h?WsVa9p_xm*=c|NN5^}fP6 z?mWM@l)093oZT^>oVEHoMc$9ke{~z@pLLbCee{ZB#uJ@my-80`E!+YX)93%cQeHYF1v8SW==WYV`%=gjwU5~%|`PlXL9W>2%J;9Hd z|GN4!zJKhp^Z9V!{MQVB`t$MCKLhTa|KE%6(vCmVSDYNb*H_u^`~J0#R{UPyslUDK z)zz&&kKO!N@9<~oD^AY;n7)ek^KquH=Mnv_)${KkyV%d5ng8mRAE(b}bZ`B6wCBIN zo%L0;^xd5PIQaxvXWnJ~IPG4(D}v99pOeh|bCUP!^Jve1bvx;+*qBn(-%V?;?jk=< z6T^AEJ*kv_atZPl(J7xByZT0H9ZSGW~Z=W7tYyUNy zdY|_YerI}mm~+jpy>hhFs+aYw6}#$@Rnn)`(<67`n+!8&=14vL+IOGqF~hc=XB)b1 z*6Q`tKR;Fb9Q$N5_G4P3BFmZXd4#v$3oT7$sOqerjJ1E;QTE|onNVSt8DQzPrOy z*4Syft*Qz&@M+J3hm@&%Lj`kKJ{r$oA&xFS}pU?wysl#J90=%B00+{pUe}Mv6Iy6 zE~eW~e-`T+S|h%-JoB{Ay|1mC&AZvZCsLi&uf#^ZReQZxU#rJ$+8nd{RS!k9URBS1 zKY7JSZ{zDJ^m=~oexG|^d*8X#Req~8y*?eIo{_Wqz1qj0>HYNk_@LkB80XRIc^W-y zwz;ZmEA4Un?0%Uwde2k8)6IIT&%U?M?P_(NKh;rhpN?Lyk=oa~quR!w>HX}(|15vz zte&}-KL2b8uf9e`K4Z78dtO_eue$KP=epIFpM6uE=~eCZ{^@A-Hc}_ooXs{otj}Wa z(KF7O+EsdMtEc|Y166zPeb8Lj5bKrhd(U;N^ZcpK^s0_}tG4?1bX0w&rao7#_f^O9 z>YXOfIi;|=!rJ3Km3{T-eO2AO=6dp(>5iS}uj*JoGi%r8@6|SbRI5Hyt+zeRJlj6< z6uzrxBfMN8BR+DsuO7XxyAg%Cp1kII5}fI&j`cJ1tbVVy@uOPxnVR}sb*JkI@27wE zH#jpo&$Q+JW?AFTGrMdv{^@NpX{kG_^Zb={jnY12W7q4g+UvdA>b0&tGyhDL*LwQD z`u&~V&v(1dBckQg<`9q8mZy|#)ijh^f5Xz>>2LW zw)*Eg^?ce6M}Db`{yKiIC+W$f3NrI+4QsLuesYly+LDjFOzy7 zJ*Pa&ufK=Y6ENyh*Zu8vtLyl&;`g=eo)3{)-~GGm>zkuM00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY=tlfVnVAOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=FE9V! z_1DY4`TEHO{`$S%-lxBQkDXqt9(()9-kz$jGweNT#A=@zoHIPf?!uD3^2wa3DNBEo zJhwSycTDE=2-Q+T3jP-xwC)GA9)nMMj>qXjd(%k6!AbzGh^2 z$H^I;NA?=y8>FW@lb7sa^G-SZ>Qx@9X`4HUv*Xp1m9VCF=CHr~6yNsa40Ux4XN@fL zobqt?nxoq6XjZq$1?5SF=(67$cW^o;>NpWNBg^_SuhRRxuI#Mg zm9|yRl}}sC727pqtGD*m(nrNPbpO`b5nk=(HSM_@wXpC7fy>kNAAPM@+^4Uioqwf2 zBl{|M*kAs$Q_(!1HK%7x=zX*Arns)Wi~330ee+#&RQ#IQUcayUKKokb{l8;l?Xel$ z7yVw(4-@tj-@f|qM^_o1qpz}GCV2c>>3dbttJtu=yzEpoG1^m>x+eLI=(lEP!q0ey zKl_B&PsjNuz%%%K{~W*iJskB{ly_RhtRq($vG)Y_^Vhp<$N91Nd!qY}IX{=c`Md1> z=6}!gwY%-Evt1loC2&S@uRr$uoP8fZ%UaW-tW3gwzC_G)J&1hBv&5y#jm10y|%~5sfa)SaeZ5A zSAYG!(zD(?{(1WR2ATg+{aO9jj_Tg|tF7*zqt}e>exE<*+eZ16di#9btLJp)@sVfW z;iI~2Dpo2Mq-Fs^Ho{en#Sl9dWAHDy59@jH{jKK050{c1b)cC%zuC!M(j`=2wU$NWG zP~RC>UG0A^*sH6Y*gu-Uqw`Y+OH?@$o%&|AD*ed{_b>ePT;ZU<2*keUz@=G`S{v*qk9NI z00Izz00bZa0SG|gwFLMR!fT0rFaNXopXuL=#?QOW?%xoC2J`>k&&2us_fNoHy`SB) z^4wn$&mi#l{P&YP`*$Yk^>sFvvn;ci?_k@reZ~!g>@LqU^j!r_w!XIARArZ^jruI7 zeaCyYy7~Gh``qieRyoUZuJ1k0Z_!S;&$d_f`Bi<|+f}_+-ut}2xqDu9vDeRYuk!Zx zp7-nZeTIFfbw2YO+nQ_JVcK(7J<{6l?9*E7NgmbG?$302pVhHm*IK9AwNG`_%yXtV zy4Cj6i+rtre~NB;TRp4WYH9a*8}H8aww|N<)meIbp5>9}e)p)}=bN29ubFnA&G&4( zZLK~jqfd@#&;6;T-K*+cd^gW?s4o@be5o872-&ve<= z@t;G#Xa4KkeUwsJ&-T07h5xx8H<@LYZGO-6pX-_P*Xif;6`ys7pFv5|Z`-+CA zw+u$lR<9@dR!h5oZ=Ly%(;6-JJRh3d7#o&$rg3WhM%@?r=}dQD8PV^Qp||GwOlSU{!EP1LwTF4HJgj@|{cImsd5(5l z9@Rg?{QdKp?=-GGujikm<~pl8T6sucsqOcNnV0joYkIc!dXi7IwEHvt{pTMYB-^&T zIGyPktGmo!ooTJ^^0=#cwCA@{rLR@TuX}WTuYE4t$5o!A-Ig=m{O$ji)%WvSbGUxq zsH(BQME#L!>{<_7TA%i$h}Kq5_vqEX-|wEC@IBX~gFb7X)t_I}?wyr(wb~P_Uh=7y zejgsat)BO~^J^V_FS-A?eCb_&+1bw(q#tqNch#-l;tqpj$5sBL-Ig7D`@H8G{q6Fr z|Fu`@+V#15JZ$r1TE45xbj?sxKTe10r@;5So-avlaiq>MIZdx6r;{n9m!qvai#@&8 zY}GgR{;gc8st;v!p4L07rI)ffR@pM=HGXmbTU0_n<`q$y>9W7jOPAQyPC{S)65ngY z;1z1jt)0%z?NaqN^Xnup=W_S!% zSI zdiVV6y?tlh&@}ClR`0Cb?sQDOp5*D9g@49+=e26BXP)faukOTlo!e9T$ev7lzdYO1 zv9Vf>HTAT5=N{x&8C;ahlw{A$P26?1)z0dgjdiON6zHut|$PTn?@*K}*^$2zE zk>2Sy+u1KQTh{BD@2Jl#y{$iI{k0+rqu$No#&71iA$iPbjLFWf6JF(SCw}uP@z}mH zf$MvCIZx03E8mgc-%jA{`FML~A|U_)2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00h1&fwO-@I@7=Ey?;*M`w8yVprrq%^yl#6rVxMt1R(I!37mcBJJWwUzpsA(v!9I~ z)xSEQ@818T^F53I?)<*`{m$n1sQ%UYeE0qzo$p!vcjx!j?{_x8NA<7H=ezg+=zP!O zzdOHQcfTP2_@BD}{uoKN@MSbOh`&@bT9&zq-jXu3c+siCRL^zLjV~%PWyQu2>@73$NPTpni zV|{gx)aM>&deW5Vtc#i>_M=bl@t!_)>a#jycfZy$Czd_kqwnu2`kArco$2`u^pQR* z!>-fxSoiuYA9uxS0&C{>czoSWU)j$+>U($H(LH(A(I^mr00bZa0SG_<0-uM#-;+N( zexB~$r<1>5)?cc4rvJ9gkR8u+q(0B_(fS|VO=|sFhpir`_MW5Odd&3d@jiN1i2U_W zz5QPGduyJh|GmuN{#PE>qod54yN}c79J2nr!>WsF_8z-dk5hZkQExroqSu?u;%kM_ z+m72)=xxWNzRRHc>kRI1k*bNlX8#fV z{&n*HJJ-)V_V+`D00bZa0SG_<0uX=z1Rwwb2tWV=5ct{zZvT(MY#;yu2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< U00Izz00bZa0SG|gClmPp0p4H2&j0`b literal 0 HcmV?d00001 diff --git a/internal/world/vanilla_base_test.go b/internal/world/vanilla_base_test.go new file mode 100644 index 0000000..fadb434 --- /dev/null +++ b/internal/world/vanilla_base_test.go @@ -0,0 +1,177 @@ +package world + +import ( + "encoding/binary" + "fmt" + "io" + "os" + "sort" + "strings" + "testing" + + "regionio/internal/worldgen" +) + +// vanillaBaseFixture holds vanilla overworld terrain captured with every biome +// feature stage and structure set emptied out (cmd/vanillacapture +// -featureless -blocks-only). It is ground truth for exactly what our +// undecorated pipeline reproduces: density terrain, surface rules, carvers, +// aquifers, and noise-router veins — with none of the feature drift that makes +// the full fixture's mismatches hard to attribute. +const vanillaBaseFixture = "testdata/vanilla_base_12345.bin" + +func TestVanillaBaseTerrainParity(t *testing.T) { + f, err := os.Open(vanillaBaseFixture) + if err != nil { + if os.Getenv("REGIONIO_REQUIRE_BASE_PARITY") == "1" { + t.Fatalf("required base-terrain fixture: %v", err) + } + t.Skip("base-terrain fixture not installed; run cmd/vanillacapture -featureless -blocks-only") + } + defer f.Close() + + var header [16]byte + if _, err := io.ReadFull(f, header[:]); err != nil { + t.Fatal(err) + } + if string(header[:8]) != "RIOBASE1" { + t.Fatalf("bad base fixture magic %q", header[:8]) + } + seed := int64(binary.BigEndian.Uint64(header[8:16])) + if seed != 12345 { + t.Fatalf("base fixture seed=%d", seed) + } + + type baseChunk struct { + x, z int32 + blocks []uint16 + } + var chunks []baseChunk + for { + var coords [8]byte + if _, err := io.ReadFull(f, coords[:]); err != nil { + if err == io.EOF { + break + } + t.Fatal(err) + } + chunk := baseChunk{ + x: int32(binary.BigEndian.Uint32(coords[:4])), + z: int32(binary.BigEndian.Uint32(coords[4:])), + blocks: make([]uint16, 16*16*WorldHeight), + } + var state [2]byte + for index := range chunk.blocks { + if _, err := io.ReadFull(f, state[:]); err != nil { + t.Fatal(err) + } + chunk.blocks[index] = binary.BigEndian.Uint16(state[:]) + } + chunks = append(chunks, chunk) + } + if len(chunks) == 0 { + t.Fatal("empty base fixture") + } + + // The capture must actually be featureless: any state that only a feature + // places means the derived datapack did not load and this test would + // compare against decorated terrain without saying so. Copper and + // deepslate iron ores are exempt — the noise-router OreVeinifier owns + // those, and the veins belong to base terrain. + veinOres := map[string]bool{ + "minecraft:copper_ore": true, + "minecraft:deepslate_copper_ore": true, + "minecraft:iron_ore": true, + "minecraft:deepslate_iron_ore": true, + } + for _, chunk := range chunks { + for _, state := range chunk.blocks { + name := stateLabel(state) + featureOnly := strings.HasSuffix(name, "_log") || + strings.HasSuffix(name, "_leaves") || strings.HasSuffix(name, "_planks") || + name == "minecraft:moss_block" || name == "minecraft:magma_block" || + name == "minecraft:calcite" || name == "minecraft:smooth_basalt" || + name == "minecraft:amethyst_block" || name == "minecraft:budding_amethyst" || + (strings.HasSuffix(name, "_ore") && !veinOres[name]) + if featureOnly { + t.Fatalf("capture at (%d,%d) contains %s; the featureless datapack did not load", + chunk.x, chunk.z, name) + } + } + } + + od, err := worldgen.LoadOverworldFinalDensity(seed) + if err != nil { + t.Fatal(err) + } + fluidPicker := worldgen.OverworldFluidPicker(od.SeaLevel) + veins := worldgen.NewOreVeinifier(od) + carver, err := worldgen.NewCarver(od, seed) + if err != nil { + t.Fatal(err) + } + initCarverReplaceable(carver.ReplaceableBlocks()) + + var total, exact int + pairs := make(map[[2]uint16]int) + samples := make(map[[2]uint16][]string) + yRange := make(map[[2]uint16][2]int) + for _, chunk := range chunks { + got := generateVanillaWithoutDecoration(od, fluidPicker, veins, carver, seed, chunk.x, chunk.z) + index := 0 + for y := MinY; y < MinY+WorldHeight; y++ { + for z := 0; z < 16; z++ { + for x := 0; x < 16; x++ { + ours := got.GetBlock(x, y, z) + want := chunk.blocks[index] + index++ + total++ + if ours == want { + exact++ + continue + } + key := [2]uint16{ours, want} + pairs[key]++ + rng := yRange[key] + if rng[0] == 0 || y < rng[0] { + rng[0] = y + } + if y > rng[1] { + rng[1] = y + } + yRange[key] = rng + if len(samples[key]) < 10 { + absX, absZ := int(chunk.x)*16+x, int(chunk.z)*16+z + samples[key] = append(samples[key], fmt.Sprintf("(%d,%d,%d)", absX, y, absZ)) + } + } + } + } + } + + keys := make([][2]uint16, 0, len(pairs)) + for key := range pairs { + keys = append(keys, key) + } + sort.Slice(keys, func(i, j int) bool { + if pairs[keys[i]] != pairs[keys[j]] { + return pairs[keys[i]] > pairs[keys[j]] + } + return stateLabel(keys[i][0])+stateLabel(keys[i][1]) < stateLabel(keys[j][0])+stateLabel(keys[j][1]) + }) + t.Logf("undecorated base parity: exact %d/%d (%.3f%%), mismatched pairs %d", + exact, total, percent(exact, total), len(pairs)) + const maxPairs = 25 + for i, key := range keys { + if i >= maxPairs { + t.Logf("... %d more pairs", len(keys)-maxPairs) + break + } + rng := yRange[key] + t.Logf("base %s -> %s: %d, y=%d..%d, samples %v", + stateLabel(key[0]), stateLabel(key[1]), pairs[key], rng[0], rng[1], samples[key]) + } + if os.Getenv("REGIONIO_REQUIRE_BASE_PARITY") == "1" && exact != total { + t.Fatalf("base-terrain parity failed: %d mismatches", total-exact) + } +}