From eed5851583d38e0ff8d1484a7a5db2c2dc34557a Mon Sep 17 00:00:00 2001 From: Stan Soldatov <118521851+iwatkot@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:57:39 +0100 Subject: [PATCH] Files for procedural generation * Procedural layers. * README update. --- README.md | 1 + data/fs25-map-template.zip | Bin 2197113 -> 2200477 bytes data/fs25-texture-schema.json | 21 ++++++++----- maps4fs/generator/texture.py | 55 +++++++++++++++++++++++++++++++++- 4 files changed, 69 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 337d968..9b006e7 100644 --- a/README.md +++ b/README.md @@ -397,6 +397,7 @@ Let's have a closer look at the fields: - `background` - set it to True for the textures, which should have impact on the Background Terrain, by default it's used to subtract the water depth from the DEM and background terrain. - `info_layer` - if the layer is saving some data in JSON format, this section will describe it's name in the JSON file. Used to find the needed JSON data, for example for fields it will be `fields` and as a value - list of polygon coordinates. - `invisible` - set it to True for the textures, which should not be drawn in the files, but only to save the data in the JSON file (related to the previous field). +- `procedural` - is a list of corresponding files, that will be used for a procedural generation. For example: `"procedural": ["PG_meadow", "PG_acres"]` - means that the texture will be used for two procedural generation files: `masks/PG_meadow.png` and `masks/PG_acres.png`. Note, that the one procuderal name can be applied to multiple textures, in this case they will be merged into one mask. ## Background terrain The tool now supports the generation of the background terrain. If you don't know what it is, here's a brief explanation. The background terrain is the world around the map. It's important to create it because if you don't, the map will look like it's floating in the void. The background terrain is a simple plane that can (and should) be textured to look fine.
diff --git a/data/fs25-map-template.zip b/data/fs25-map-template.zip index 98b509f741dc723e73d058ad4a3ce74052b7e78c..677c21aa69c94f3252a1da943c8037b4d1e6a18f 100644 GIT binary patch delta 18815 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
    s)U+MsJ_hpDI?4vsTHYCHi0o*Mg z+t3{hg`qGrJLpmu;CnCM&pB(z5PI#RE~aZ;5qd8l&!>9_5r}l}{xzAX@dmmm_N}34 zKOmh)ts&rPzbe>37=BjaX@G>u5}$K%;!(0k*H8!z<}9o9Wr3&$8r4Jpg3-VTlcoHE zwv_C}Ul2TRx#0_{h4#Dn0A9<;yekwCSRUx$xy&eoC0~7Bf^w_s<*NSre-D#$M!sBScwn~@tb>t{SpyZgAtmnh&` zk5Mh};7E;jBj@IqX27|l97g)!!Y${My3N;(L9A8H#!Ova*i+ReN?pF6OU0&1eQIx8 zy4F*l5Bor@7TbUi{@`bAc@!QzkFsGh9uH127fk!*vSVyLs@qPjG0_p(`Izx=-=xHH z;c(QDC4FBNpPSA;ZJ@6Axkk$~WP65@L`XgQ$^u%zWLEhIJ)j5+=1oS_jc(9)?}(~S znhGL=Q#w{xlIi%IE9_h-EVpM$!DLAhj`R2LJQHPNc<$P3ox0K(h^!4)`V};Zem{Gz zWSi6cpTm#oH0*mbIjHFq=;_B6+bfxeVH5VOKc3i~2aDKnT)d-Ojp~ouAH|JJ$-`vR zuckwPpbj36y93Y^oI;II556wta*8$8Y=xxD51r>{E!iK301w>U6a3?(~u7iciE zctSvV|BsuZ9~pQr-W&(pmq_C6RFJ{JoC~sCExdpI?8bUea;Kb>5$q5hBhsB5yhBje z(b8>~`%#5~zEXS*3Gi29*#QOlO3vGR|0MuYKj?ojAM8IE0R9bojQ^OhNWu-{eZ-NB zn#DBy+sBO}P3M|*>Z#_4vl)^IN9bOYs7ocLBOSzS_gch+cnLd47N4qp#-3 z7oKM2iTZJEKp_juerU3(5JqPM%f4`8s`I>MEaFP=_OQ(K7fk@y(Dj5HTEG$U<9B1=QRDsBWS zM}x5{Y_#{4HU*6OhIO^uc~Iw2lB-9TT$S#FPRR# zRgss94AUD@%$DYgMdJmEW!Zl$sn@09%dVHEQTyz)WVkAD$lL0i(CgFAdLB{&c5F(1-Ki*B zwJm7_Hah9+-EqyKyjc>|&Ox)bjr0%;EvL4@h#sOSWf3PSN@_4gEe9VmDN1^pzl78- z80PI5W#w|!?U!ZqO8}}4z|bFVC@WWDeS*u}`2ATWrm=q4v%?0ppZGhseL3d+wVH^yz?e*L`cR`P_%E7I6>grR)A$a6s_J z*+_oya%h#o>krp`Lq8sy0XK0xPZwOCgz2g;ad*LEGJW_haCuCY@g?wnY3w85)}kv7 z<8J^)5Xc%xl*I8fKM=4Rn3(TUi3tXkh)#m|Sq?~~bO5V z#y54|=XE>eHXzrvRMzCCxpi{4HOuaEq;%4Tffip5S%42&Oh9EoL`?^LLpy+H56dPS z6p=w(NE~xZ$@35JR5Q%>NxfyqZ6&er%R1Hivzj8W4|{}Lm#Shqe>ynNt~OXZZI(a^ zow5)JY%eqi-Xax|pQr&+R|Ez%QI}{6s$PT|^;ZuslHT8>FA=mHn2unb7}G;c38gO< z{w=Iv8N|xJ1x5lu?{9sKU*#q@IT7euk3mKN9BrQa$tWwhB;MMHL55#JROLq-8DXh0 zE~U(E^n5M+LD7l$>9R-|t7P6eF}toq6gN9{!X$SkuQ*=%HW42V{m(A}#NdNnCHf^s zhF=Wh>Z&GSo|t8lbI>1;<{O77DtNcWgPXx)T^zIohJh=Aj_@U_eIHe zuHBP9fKLwHRJB*`$CoV^Bdxu&^(jFAs9CmczZvwZr+37Ve)7YYI8PfY)f5K5Sclf% zo2(f0U%dltxtK4z{Iq@Pv41(6{qrSy?YY^k|K_m!>~L(PHd;+j^10rcVsv#>i{qy0 zG*9Zfs8S4JmOF3hEX4PspRQA>-y1q&mf-3S6iEHO*`>#&63d0*Vois=ZMIbTbnCS$0>>a%Y&qN5!WJ-Mra+}k2Q&U5m)Jxc-DmhcJ4Aq9}TnNC!K)VR@}-4 zd#_}dOFr!thTz{gxNZd$)byrZj^s-dB>b{cHj=Dvq(MXOHWD^h3@UTrb@9 z+QlA;LppM|o>lernS=4_#Ge3?&)viJ$E{4=PDJxJr*nV2m<@=_@fA%stsHWUE?E}2 zmyErvE7l=ytUa~|4C}1cMgk0iyb6ojqpK$O=CF9K?i-%a*OBQEBId0Nv+BgOXdY}< z;G^ae8+`LYSq)yCY?iO?_Y6&n0I{QW;x1bFqoU$7+;l5}xt{r?QGg`Gq@A@VZ?xTn zJgZ>l-^MJPZMRx;m%g9jgQU7*$=*{4Bw2e{SkH#N(Nz;@w|C~t_-}mgww4&jG&3j4-{Z(!s9>F@*1u?E}#lm4&m#M#++h#ao2<(OUp0vu-EQg zo9(tM>he&LW1l!@_lHA`N05yXH^=~)kUG&6m2@3~b&hVzyuLSjhDSU}+y#y<%};L( zy1d4AC#~O}+s{^xtkiW5u@r{L#jr$By9xdyvqG0I86Ht9V#GBtvktNkBYMJJ#^5F^*F%Ymov&b8EQ69WMgWIjn;J$ zX62-R7hlZ`_4peKrgUu1GH)$3d2cT4_ZTsW9e=1?WrX+}FvG@|yezBobMLHb`|EFr zd8SpA#k=9nP^Ts9P4%Cv$j$d7W@aD01k`sw)$TjCl>h|X#^vXJdG>fp{_4|a4dj3k zSY_;ZKPly;bi6y-sh~`?_3_63a7Cq4lXur_G0eR30B6%AcZ^Mb^zLfCS}^^MYNi7& zsi_&puB7J;GVD-n!UaT z=|zuMMIBHVg-P*dP^UocjBWaiVi8}qDv|)36cqz?MzG7<75?nk;qBuxWuI*!9GO=k zE%5J{m=q^yMG{4QNk2j4OjZrwAPqg5ilHwl`nn=4zYw>Wf7%jVrf7HBL-LvQa9hU? z66bf;E|PgQid;M?hSUy+EwbqW!$4$zt}o&e#{!`93G=Um4~`JA>hZzfL4@CT(zQ^g zWWZvg`_E^)FAZvm;+gmM1Mh@r)Hwd?uvL-ilL<3^`KzrAqCL`MKQfhH4~*^_4KUQ_&B>+$z?5 zb8n;UEBIg&2x5qcf+-b0xa6ixZo)%%i$DaNl{2Ja-S|^^ht}P@bsn`));-y&iY$ny zAs$?)Co!DG9q~){`*S>o<9naejkHM1zm9YtKu(4a2Ho!GTs%Vps+e7mNxC|v#^ z(>jsRGGy;R!LHr9RK1%N!F#Iyp#^Dulo@lD2}Mhx6P#h(7(YD5D($St{{ypIRMRWH z3Lk&4@G#r%w_BG~+zX54CI4hrnXL*SiM9S_+`IhaIJqQ@Xe!;jZ@l{-dOYKyhsA(C zwqAEs2Qt@7USv)=l1P+45>ca#11=FUuV9!T*k<8fTkAWI|Z`iu)kV!&5njllX5~$sExNE97#mfeEdF&bd6I(VnydT2s0G zG)HPh)pU&oa=S(H%S`sQOFQqJ8?88%MoAT06xH+s&GZ8IRU0x(ZL_J_LE7-JW7bIn z@VJsV(lS!XdeYHtQb~gxlide^7%5UUJwU*SWDBXFOrnfBt}LuzBCH@lnG~A#CqJt? z5tS-3GkWe)goA@t0en!CImvWVw4Ys(7#H}kD}GXEab!q^#bL9`q9<(Ov%hc^wdxw^s>fGbD2>ShqHQ5LtbAp= zV3quOER)T#MXsIeJkzLh6KE3i>SU+oDEH}Pr`?ev7pbcPXDac1B`MWd|b{rYx>?wq1i6#uIw4Yh2SpEArS8812(s`%OWq0W<6bD2OGmt9D(uZj- zT&|LEEAemybqqBCRLNAZOon9PgRDrV6i2Et^EBwVY?V+AqJ5poSCwRuLrQtY*c1}A zd;n(t6u8k#urf=m(mtV<8)z}0^qxBGP;r(}JsPB{CcH$fN?2BxXl^}`OFc)O;CKPj z>z>UE&*}vx^{{%ib+f2mz;3R=LZLz)SQBEz3aveJnAitEh6_~37<~X!K#x*QX<+(- z(|V}kX8=mL3TLdI6-(TmBB3kJ)WIISj$$r-cxpDck zZft?HT&LJQ%%<1_iY_a;nd=;IrO*=xoRszFAc^=LxW*+@m{O?@tWCs$6Ka}l_84Vn zreE6_v*$0-!dN3%$Tu{O61S-!~I&twKRxUd7KVJo~8of7RAW~;2?UR z;wsK7Fx-#bK!>XTa3O>-IR!~=6D+C{D;nC%@)Bp|#8Q+MboEovB~(!-QQ4za-l}PX z3@Jh>CoeI|QG=TgW3ytDW4=c?112sjxlYa;Ve8Lkg76;{tkED@=8y1U4uGXrZL#F< zyqQVx97+U$(x8bLh{ z_DZD8uwH1F4a$?i>`?j0#fn8sUY2 zlrj^lLKKX#D&gsQ!KB0aGZRyvX}1&82GpN1`>K&F?wFQ+c}w_aKo$UAf{pkJmBoq| z|Kik^O&C?w8x*SX!4-B~rg1uPj;g(c=1s6v%<}|`_+v^DO-`*%tTH-JVP}LbUHTl! z6f*h2X|WAT6^k7=%P44l@>e|IB|%gn1QUT3Omh?q9lOdHNF&J)OzHB8;#en&9F51V z1c7BB46IB_Ny|28@Js>7r?Q6gjQgY4;4;}E>SE>eXhRaJJ}5E8#Dwyqte(`n+dqln z5yI|@&Y4>+2&KPo9bPzf+D4-Ngwld}QV(~IcuF_-k0jwLbx;-vVb)(m@6N&5*Sy!#FFq2 zZ4n>oJWpi`%UvVEIH0(O)PixDVX+@c1+yJT?NYZ{!9Tw~s##UAcAm7>ig~tL4HrAe zPVTpXV=g{DEDD}R#iWVDwdEkg zSU?mw+b*b_fL}*oCAUxn)a%2ZjZwFYQNxVdRjK$UyDq;ic@Jiv@H8Xprc@4{!&805mfOh1oS$<}YLkz;*b9XVxPS z*&|lwZ)9)@reB+ka+2nu;U}uebM9}XdT-I4j$AfBWWi*RHW}e17JDUc>#hvScXuRV z;8!3f%5h#<&BI*z5b1%p1kA{28+^)HUbtfvc-=PHrTfz07g?-E0r{tquo_q>7QtoE zKp%L(&Nk`}eBX(4e4vj)-*ZmjEgM-zb%AS#UjIEvBO4S1RNK~GP2d?w3s_Gf5dB=w zJ%4Yd6W{e4krh%E;;2)OwRHsyM&D)7 z5Fhy6TsE-}nh;fVqr{IZHooVe4?fTS~|rX=q(|i)F6iDH2dB$cPN6r$c3| zh|gaKL-a@u;XhIj!25zh5gBG978ZjW;(;0BGjCP7#4@q4ZR`d>DHcG8l|8qbuK|CW zw*vlv!J$WB0i6T)bV2-^4r`BwZYgE{sjD#Cnp5D+MwZFb5I4EcwPO4_=L)O~a;zi> zNVYsis0w)vaS2a6PMP|3LAE12pJPPe08#j3F~P~hqA=sCk(|Br9f!7=Ntnx6VbKtd z(R!@yQ&2r#*pQya=2lX5+oue(S$*Y!=3f&dpbQ&8`!_wb;B1#^EGLhtq|Z@9IkWQq(yh-nnxB#;J~fJIy> zrS4KbsEaxL22r-qY~r3dNZy}7MQK1Xkcq}0oFbn(gSX=jwPQe;(9b1)!con2Xr_&Ya?dl!63It-I7 zO1|y)V7Gf-&R0l8c)FRHnNE_6SqZL(!|7{DU3S&-r*+2GscY9~LtV%}V_yT%UIKy! zq~l#F%P+!u*r;YjNdbKGzaF}96066p9T1XF&OHA;CLK9B^YT4^Ed8n1oO)qbdsz11 zIa+#qeM}a}p#EqneYo&0W~%-yU*R= ztFCN2ZOo~o^%j74yE|M=le?tBMcJnD$@RO->(5rb^70$zMo&Quj*Zvb@UyeE$2kJ_ zNvO#-_RZzm?iN)*hXdwRgLgpK^((EBg^LF@V+`FKlRPO3SgNDlT#^w)ilTPBif ze4Sgn=(6++y+~dDsI<7~+0qx?OT87t%f>8ghpd-wMfHpz`!H=aetFK_6oc0EgBKbqrzh#a+U zBn@)37+x0#=yG9-mEV7r4PHM!l!OzpQLX=~O0?-Z=NQ`XE~D4o)CGe#wMXz!Rne-7 z3-gIC56D`boX4!}X<*P?llzq%I(L77P@5Qt5diyCbW&XnwoD62YgiNC(23}7RB=_2 z9R-HsWXjMATz>OMO7*!kxbD>LkM3&PRRBQsy`{Lz<~6W&*2s8VeOn9h{T{eyFo5^oG&)X$KEz#$HtjC4{XD6eHCdT{ z(N(O*W|rm;^M3n&l5EcURbP7vwM=048z;}@$EalYnPI+GkG&j@18UVvzUWTeUC z1Y-~+#v#F={Td>AVvse)p(4IG)VdPdR~yX#E1-P`xbN`8zX1@@!wzPN?S}_7%M8+v zRA36`7eS~ch6MKWD~v$pnSv30cjkTv!|$;3|DONwe|Cits4`P9(QgzKk)tK10P;0l z0p>eEd@_&*sCVW1@jVEmqmaRjQ!6pZA1eExSZ{tkQJ;Xl*=@PE=_1ggpu zO#B-KM{H|}IegFL@I8~m_e>7oGyTu=Km2VEgvU0t#x^AR`igx+Un2u$zgHw(C?*M+ z9S}fBM`H6mYWaH|40*o!#WzAQ3CuSQ4EVM}3V*l#zMMb4XX5-`JO|D%`_A&WeNXTU zN5OuPmKfx!uLooPUrrsk@AmhCJ5YT)nZIX0__kYrSE~a3#`Iu-ueGme5?9fZGZ-2> zYB||=d*2@&e67tIf7u}p+iljn5x?)HwdJ>B2QczTcdE2o7TO!gJfH8u{ zZN#MZul)L1ERYy5$&r=dSBIOm;|LlQ{eyD(7Wd*HOa>_eedA)yy7Gt1#}Q$K5(nzW zXMbY#%`>rv34UU)W5p6qhBct;ku%+XwCPV(m|! zB(iTCCW}lxEa`JKuC9N;L(~=;+l_51gy?0|2EjYtEGlRBmmS5X{MNI!S5bd@R4s9J zsMx+c(+&WD$`ki-ZX&a5QlD0UW;p4Z{?(ajWS+jdiBiT*Lle=})6u)!aXRpw94zjraP<+hi>Hm3^W0VIcy5WrwJuG2Dt#i)~e?onn<~n4vbD z5MRbFSp-(VIf{w;`f2)XYFV+RbZf(-+_7q{y~5OvEqgtk_bN)g>^|a3S9c+DNK#H= z6BCW}?{hx6IyyHm4v&*RciiIGHZf^fHWxyj6l})@)Kdl!6xFsvkGR+B)WY1FWz8N1 zCDmPkr!i^@8=VUbCXik77+jFiF2Od2mvmrX(9Nde45BZVB>D-HiZMT%YH|oA&#q{6j7RDAD#_`o_S|R{Og#2M18cp zT!)1wi4ayYZfy$0I?RKu_qxBHM}&-~AVv2L8UC6X3#Qy>$MS!t3wNpSq}0e*ps6VZ zCUby{hz+PZMDL(_=fN_v|Hf@>QYZkxSdgzvs3nrY?1+he#lslcqMq*s{8I{Xm8o%N zhyX$K*G2tTi3zz2?W;QumeDB-RyzXL9;U<)Nw^$hJNmL2J{9Oor2 zgQSaWX0Gy|PzZaT);{Fv#jdsePO}Q~Qix5tMAACOZR9eBC!HV5t`^3VGlLCav<-RV zP%%x6&~BYMPa9?M5%G*n1Q+>IZB`Ud9DGMCA^n%*It2Uf+E{q}wEoWq#04wOUmGdbXEQSUja=3R|{GC|%Df0(=bih4UDb92*l`7^oR_e5)%TF8JYT z9v$_bzfE)+`BqjwY%U;S1v;urb9jiBVw+3Y%z4tM-hzOTx=@uemhKe*0n27cI)j`% zOoO0vb*=4d$P79vT0HHyZxaXY(am(du6WMNnrI9n-UoCdvP`FRy@>v8Q0wXg?zuY3 zvS&geY9o0gQppqz&0yQmXEb>es8#4F(h%;PhL6CYulFtr$98kNbo`2VHFMtT@_Ryp z$*@&f(LsTB96EeNonk})m;1YRYYbs^`IaAZ2W45dTwNrKURmh>COJ<=lfY)AO2$=F zfTjHItNfJNM{(EprvmJZ7-R|r#!vlcmhQ_BDzrj8lDz7Q#k#!e z63fhfHvLqp`ugiqx>FzdBA6p@W9n)&W?{O0tg$Rsn$!MG=u1u%pj*qN2{W3l9er#3 zQ{C@T#V^5_Zy-TCHttVoQbT1~3TBvliQc#ZgI%6$hKhq5Iz@IJdVT(c=iS9G4m7zkZo7>?;Jh?l_8G-AsSabbJ2AtvcEgI9;jc2HtTM9sW!Z2e*l%_I(Zo-? zt4nGo2NUBHY35%F%7r3g>#!(PL>SIQ_Qq++{gfRTx#tX4k4}b?2a+{5#}@I(RfqMe z32H1mNxa80xg9MUp1zeLVq;BYBsRQ_Ka|2bl48w5MkMM(0dTx&D1RAM38XjXsa@Qy z84$WWLKZ_yij~RHWMc6+Ns7MuRoH zQFb0i+bw9(=4I#poc{!)LFOPiRA6r`Io)D*X_8i4AY*L|5w^r&`dggPatS8Qj|$1b zJHXcu;l-HA3^;F-2|H+nAz5(zdt2aRDZ6ie&)Jrn*%A13xCa@+__OMKKxKBK(I$?I z(=bF9xhyD677yL`+3p-2gJy z06f}YZ8d^eu0}ld#FWtVdjcb5QbV~x#^#@w5kFQ@Vha>$nfL0_VG~>{y?`^hGuj6= zbkbd%^DUK?1I`O0ISodgc4bcMVm0;I=EGpS1qt>#c4+Gv-PbbM(#}~Igv_b3xY-Bc z?E#^w&6WBk<9wIzNt)piom*Q=#PiQD(mstS_E%)(<`{3g}@6z z7jN*O+CX21lO2&bK4oE zYyT}tA4txm-QT8PS!I2 zrfFHZ$xsM6uiU%Q_TeG;f;%_v8R1edEtz4hOnkpQ(Fzj!!HnSEo`K=-0&2vNvH(DN zhF{hCnGcR|?<6@qR*=O5xEAO2S_Sj0Na4BeDQ|x4VrJesQ3?U}8u=z8JuOmzj?tFywW$N1WW8o%4>V2QM<&oWMSyu|+ka z0f{kpJy}~-00+KotTy*%M#@E%i%Eqa=ds}CxH>!E!tjR+E6!0!W&HRN|p?c2-O~6FDd4zW1P4{y4uN~8xx0C`D>qLM(Txo2l ziShxxL5#OfJR-KUZV1*Pc&R1TisB|Ee7wB%jWhyUvs!=ufECO#r=eCQ$P5l4Kda!V zRA41oT`)>X3|#461Zunxe?%yck&Kng&qaeav^-!%Bpg1=7mDhl+-d22rmojD<~ z87G>7x7^6I5QG9VQK$YJ$2Neq>~CrBC%=Z6G>l&^bgs{nJ$6m8aP6r)4e984h8+Ei z$3HDk%setC;TpHok{r2jD6SS$GvwkY543ZEefEOmfHc) zKi`#nOsb&pn@f_%pIyqe6I<(`KJix-%YeFLf9Btac3AAO)>!dor*yHLjO_> zbJ=E0C<%@bPjhHz9P5AnK^TF*o|ukiq2@?n?H6z%-$2@u@#A9!zhUxvVnw~C0MJiz z^Z4>emH1XQHB37W&C=@@6v4v(o%A6cSM<1euH@iBLnL(&_GVGqi^zc|n?QN_d=S1p88T@o4diW^>)BzQV8QQ(gm3R{n^lhSx$*W zV1jNf4THENU14%Tf-F|8-tG?{KH` zfuDBFFUzl@j0I1!=OU!6I~HXqpvv4$ds55;$MbvKKqm@V*QRyj&aL$KC^UL5|?8yK^ zCnQ6dE!aQfxW7oz*RKXud{sE+MhwKvF2j6%+pjzdUOKx`P2L^h7obH%PN*_vNHVYH zNg$}_$k%x;eR!DWeNeZ|HGg>66I)=__;sITe^ZobTQmlUI47y$z|f<X-x1zHJG#ATEc(dJ|bvzWzYoKntl zW^@I=VTP#0u}Qj_&~;uoIp#(o!wz^bs+=DBfQu`WI4l5&hb*CZxML+gg=0l;H$a&= z^_OK?RGb2!>ilr8Zf&J+(a!wLbxd7U{6ai-eFATdGtpl2`S8Vsou(_W(E{(XDaxv{{ps@M|GK#Ic%~me4&WhHj#3oG%p{_)iZYYq>)R+-lq3|na$n6c zGDEt;{Rk&eZDF;^Hf$M^I5_xFB0p8vf5d;k4@yxy$n+Oj%X zv&ON}w5G9mHejpw?Ru0#$R+~w^;b!J*=>tY-^YGDF;>Zed<(*?$%~8`Nmh$|m@D^^ zPShU{>R73M`b{v+_8CcqK(D;;O0amb&Pwu-#sx*6M?4l+WPqjhR3Ke^<4nQCOXUX= zCmeIrGvE%>ou!Yf0LTgNTtZ5>@mfK7t?zdD;DX$ustl0y=6ndfuioQt*@Y{9RW@4< z%pNf_)O~u0d0S!{^YM%DFFUBKA=ON}9-oKtP{(LR6#|FbS+*EOvwn!=yq}Ux5lBXN zI(O&mDhD;YHn+9r^&1}_Uj}fYtNg;9N@uEUPF572bq|QlPg==)Z7)Umhpg>Q&AHr74Orqjn#_5PvmziR9sfT>#o zI_EUvH|9g}cqzQT>`1Hg)b{o+cN3yXslNR%lGwcMSFmsWriYTMXHFU)d&^a~&QjEt zR|#F0ZlcxC7Z^gSeR~`KDy&;voPjHgmrh;*=#Ih*vtm%H?wZ>xrl_>WF>)EbzV`A; z+Q$#pG5>m>*GjIX`=q$)$ZLdRWQyuOXs5EGg*eb6{jj+mj2iml{A-J}`o%G`Yo@xG29zcXC6m?uh@X@BOo&wFeq#||;@T0%V~LZd^QDYVdAgDF5U z>WO%0_P_JyU*+sV`%cZ2r%jGbmQt!vE7V;?2&q~7#W!l9i5hF^v6ns9wW*dIr6!nQHCt3?k zCTG#6c-ff>NS2&08`>J~%#(Q00-*C9p^GGkm=@&j($rJ@b+cvP0pfI9DR&|$!){mg zau>&bgU7mGj+P6GY|lh8O#Qpf)&aA{!Oonb?@@4 zwKNz+O$IM55AMIb#G|U9F60_JuM`*s92!gRp|5Q&Q^*?r>M0g?t11De+5?Qu>PZ)= z7i?%-p|a_1^DE1eFbqQ5#EsGX$CSstFE(zkl{L>?!oG=KFIpFI3V!+4_I}tEPaTt= zR%d5j^o#($hDNXHn?085r6pvfV*})jJ6o`2(nl|>QM#>n3OMoDrM4oi7}8n=_)qswi@>Zo+ePBK<1=}vYuF+LkUOhYc$ubXIAOT=!!M=F zM8YGYYBg22nxl&dqFGVMmP2j&d#=x!jOW#qC^?&1jJZVZ z_F{AgEgZMi^0P4G)>MAjr{BAOg<)jJjTH!Goh;YE9sP-1xhBa~OZY>G+P3@+Uvy}(af+g|j?(xn}i zo8>*pvs>S9QM3ecY+EGfMjm%c0s*k=u8Dr`Er|o{UG~0c#7gH_nt5XeqPfK5&)c-$eW3?TN<7wuEd9#*jd_ER@FacbV2#`rhCR4C43@|HjqrbH^aD<4)Ea6C0z+Ii{DSZT2<3 zj%QXAB_UQh<%Ifjb;otF!)S*N+FoitU?68!%XQgJ?3LhqWCOK#9F?>dzUWowZQi`j zx%g-0JM8>Bw0O~i+YwrfDpIZXES2BWQ>!mPJ?~>NW>@lDB7l8)rmFeEL0}PK8cYKYg{MU?Hre;#yV@-%#X@cCrrNTJoS~r9;O3htw9Mo?||N z97Ct{0|f14&cwXeRuZ+z=hwOM_JarQ)?>o3N{V}^?>^`H$dpkfPxg^)%xTmldSIGE z5=0r*u0w8_3LF$Z@V^lv#|SpY3pVnB_(1}ogCIeW5C{S~1Ud{728n<~L1LgIprash z&@s?)kOW8)bOLk|Bn6TNodTT($$(@*P>>u5RwvjfKh*z!f06La82EXi0||kD_&VWN zBjM8c^RaM6erPY=Di;2T-+2UI6AQQJ7i8d%$HATW^?mVA;@}VYwfyj-abO-DfWPz{ MZYboI00&q64=aF0^Z)<= delta 15423 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 Z9GuKj1rtaxQtcB-sGx+rNkBkA{tqkA dict[str, str | list[str] | bool]: # type: ignore """Returns dictionary with layer data. @@ -99,6 +102,7 @@ def to_json(self) -> dict[str, str | list[str] | bool]: # type: ignore "usage": self.usage, "background": self.background, "invisible": self.invisible, + "procedural": self.procedural, } data = {k: v for k, v in data.items() if v is not None} @@ -212,6 +216,10 @@ def preprocess(self) -> None: self._weights_dir = self.game.weights_dir_path(self.map_directory) self.logger.debug("Weights directory: %s.", self._weights_dir) + self.procedural_dir = os.path.join(self._weights_dir, "masks") + os.makedirs(self.procedural_dir, exist_ok=True) + self.logger.debug("Procedural directory: %s.", self.procedural_dir) + self.info_save_path = os.path.join(self.map_directory, "generation_info.json") self.logger.debug("Generation info save path: %s.", self.info_save_path) @@ -251,11 +259,56 @@ def get_layer_by_usage(self, usage: str) -> Layer | None: return layer return None - def process(self): + def process(self) -> None: + """Processes the data to generate textures.""" self._prepare_weights() self._read_parameters() self.draw() self.rotate_textures() + self.copy_procedural() + + def copy_procedural(self) -> None: + """Copies some of the textures to use them as mask for procedural generation. + Creates an empty blockmask if it does not exist.""" + blockmask_path = os.path.join(self.procedural_dir, "BLOCKMASK.png") + if not os.path.isfile(blockmask_path): + self.logger.debug("BLOCKMASK.png not found, creating an empty file.") + img = np.zeros((self.map_size, self.map_size), dtype=np.uint8) + cv2.imwrite(blockmask_path, img) # pylint: disable=no-member + + pg_layers_by_type = defaultdict(list) + for layer in self.layers: + if layer.procedural: + # Get path to the original file. + texture_path = layer.get_preview_or_path(self._weights_dir) + for procedural_layer_name in layer.procedural: + pg_layers_by_type[procedural_layer_name].append(texture_path) + + if not pg_layers_by_type: + self.logger.debug("No procedural layers found.") + return + + for procedural_layer_name, texture_paths in pg_layers_by_type.items(): + procedural_save_path = os.path.join(self.procedural_dir, f"{procedural_layer_name}.png") + if len(texture_paths) > 1: + # If there are more than one texture, merge them. + merged_texture = np.zeros((self.map_size, self.map_size), dtype=np.uint8) + for texture_path in texture_paths: + # pylint: disable=E1101 + texture = cv2.imread(texture_path, cv2.IMREAD_UNCHANGED) + merged_texture[texture == 255] = 255 + cv2.imwrite(procedural_save_path, merged_texture) # pylint: disable=no-member + self.logger.debug( + "Procedural file %s merged from %s textures.", + procedural_save_path, + len(texture_paths), + ) + elif len(texture_paths) == 1: + # Otherwise, copy the texture. + shutil.copyfile(texture_paths[0], procedural_save_path) + self.logger.debug( + "Procedural file %s copied from %s.", procedural_save_path, texture_paths[0] + ) def rotate_textures(self) -> None: """Rotates textures of the layers which have tags."""