From a04e3ec9871fb62a9e7effa1343613236da5f246 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 22 Jun 2023 19:49:21 +0200 Subject: [PATCH 01/17] Write about nodes --- .../yarn_files/functions.md | 16 ++++++ .../yarn_files/graph.png | Bin 0 -> 56337 bytes .../yarn_files/nodes.md | 48 +++++++++++++++++- .../yarn_files/options.md | 17 ++++++- 4 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 docs/src/working_with_yarn_slinger/yarn_files/graph.png diff --git a/docs/src/working_with_yarn_slinger/yarn_files/functions.md b/docs/src/working_with_yarn_slinger/yarn_files/functions.md index 311194b7..986759d7 100644 --- a/docs/src/working_with_yarn_slinger/yarn_files/functions.md +++ b/docs/src/working_with_yarn_slinger/yarn_files/functions.md @@ -14,6 +14,22 @@ Which will result in something like this: The curly braces (`{}`) are not part of the function call, but are used to interpolate the result of the function into the text, as seen previously in the chapter [Variables](variables.md). +Speaking about variables, you can also use them as parameters: +```text +title: Start +--- +<> +How many sides does your die have? +-> One + <> +-> Six + <> +-> Six thousand + <> +Rolling a die with {$sides} sides and got a {dice($sides)}! +=== +``` + There are a number of built-in functions available, such as the `dice` function used above. Defining your own functions is specific to the game engine used. For Bevy, see the chapter [Custom Functions](../bevy_plugin/custom_functions.md). diff --git a/docs/src/working_with_yarn_slinger/yarn_files/graph.png b/docs/src/working_with_yarn_slinger/yarn_files/graph.png new file mode 100644 index 0000000000000000000000000000000000000000..85c8d24b9ab2e7101b77b43dee6d31f6e6990759 GIT binary patch literal 56337 zcmY(qcRZV4{65@a#7>OZBcf;n~uJ?6a?<6Y=V-8j!))OaAa9lPqyn5oq zDWel7PBwvYzNy1%`04Cx7>wuhpxOQ*eHH`jU0B5Y?75@E3HJ%r`!t?J^7#3^YS#dc# z0W1iaQ~>T_`WBULJ(I@MS(_NH2x7OZ=pa@6=!PVfzO_eOH3I7uA&zL$Wkz( zY|?rTF$-K~>#2p|RU0!%DNXVvFu;iZRyRMcTLx$GPMQK^@_xGmjH%vNChNN~n2+pN z8Uc+)VS}HxMG;*tlTARQkwIn%RcA_1RVk#xI_=H#7=KUv!a7)OXoA6dM)1*Ys<4`G z+u=NO$==+x3sE#BT@l@d2;1G?;|s}aLN`Nn?)GMk$ZS1*6uK~2G%!Rz|S)3>Rt5K0H3-o`CetbhS3beV*1H2%A$RepdWc zpz^)?R_kzd#+C<5z)Yi8cA@6m-7NpJq1lYo58l%kn!_mM3NONzpwj)B_rdEAiu?8( zZg=B2dbV#%ebO3h^e0I+-&=Y`-sj4l9Z3)9xrdza`O!B0IA!N>y8h0@IknKuwt|nR zgU{6Hm72VgPN&W~RlU&)*+9G=u^pdK`6R0D-}&eFZ)u-Ilda`X_A@^xUT3SWF3vvD z2u$%=Z;*exRI=x>zp3MUOgnJ*xtlw`|8s(|Ibfl;g0xM)#wp7+{w(s9i>nJr&V4wrOv&bEe* z{Mj2e6N09FetUN^(x{i?>Wo0QtF`i|NAIJvMZO>1gapc|8x=9eQKYDeS8-Z_%Ny{C zRQlOGhpNW$*`>jeaG24P!CAM{e$BkezrKf3fA{P+#L=F?wIlYPtZ!`GtE5-V+=6b4 z7wbij%GrG>QQqp!D4B2ap8m-xuKTkCSk5@*&tRSXnH-mHAVMYJ^y?wqK= zRr#LMvT600+NcRlF0Ylp8V!DPv&JF3to=3z#=Jzg`@=S&+vT*nnwJ*Vq$2WK2^dc~ zs*gbL5%qx@*Q)VSC6Q*=5f#sM-uDouWRqVfFp{rk81gumsxPc}Sj4sGH}9HBaX z9m*SBNqXavR(ZC)IIe9ceJ9i7$5NK`n8ADU`dd_yWN~*AJnH!d5(PeY&}eW_NWXUN zrH^@RP7d|{*UZqf33p8#!ykLx`uN&%q(K|~<86c>zI;vl=r=Qv z3lx24)D=?SzkmNA{+hYK(r61S%&@w#=T&1VcC^t;$ssf}qeS>Bw=oKjcxn+Gy8joW z_w$>TO?k^OD~yO9-GP?hDSIK6+G{Gnk_F;1`cgOc@gfTxX1FlkL;#KJzV-q#lZnAQ zVa6dZgooYYNS9?D;M z)A9G`>rL@vlK9Nd(%=J;g>)nQC`#~&dO(@p0{((Ye)_E2B^`nZ6jeo)dwTS7YyXE$$c-G98kzP_6)h2_bWL|lp94~<@_zTE6P zyW<=B>&LHlN}69w$KTf-_oDwkkN&9(jBp=9+y&M-c#eL&KP&9lMk>)qKOpmz_($)m zMK2_bI?;NZS{^$^O(*h)s-jYPKPuapesH%ZE-rtaSCuc{5DBryO>-LWrP2mvGRD< z6MPc{>y2xA;(GlxvP`K<)6J%oP8*>IMIStlUW)>PWR{H|%LA3zq|Y)6%mScu;G-aG=_aP;_lYv>z#nx3W3pGQFK79RpH-+s<| zz)q?@Zb!xaBkw*i&#w;-2A%c{S|8c}?7Z2&!xy^xxm4=B+&aXlz!ivpUN=P{lt4fl zCpMkY6fD~RT<^$hKZ8!qhzj%mT4n3l`I$r`i6561s``AJXH}^(?KmjxSZhD{2_y$1`)aAzi`@vfo^S=E=IKPZ?(UXasCbDFPes!AJ^~ zcd1$oBb5SdA?r-!E6G&vo#0Zd?d%(CCbcvPZ;N8>H91`%LGI^@VIfdB;u7dAZt{4^ z>A2_Uc#Gc7ujMiPgp%D-Cy+q!9C&z!+elJSI=R-rw``S|#ItF6yl6>7`m)}Im;k$` z0K!s!j)1pFQ1g<$p+roOy?_b&`Q_~X9Q|m{aXt_EcUO-d*x`~^s<_NscPH(}9r_l3 zRF`>?=7fD7j>l+!Yc7=j+mgPx3@sVADiGl4PALXvPc8v`q_XH7eBV0p4%POo@=Z}RaS%$0MbZXYh)bPSj~+6?`W>5?Id zh2%a1ra=!jeJn4^YZPR~?laGo{VqdHr(na}u~GHWS)#hT8uU_MhIptRjl?y(Ioq0@ zvUMMu^h^)G-R|NJS%x*&WtVm@x!s>x0rq)g?uUc zh>*Y*CCjnTg7g@7@rN+Yqg-8s@`ccL_kfu?}aBib+PrT$FQGf7J}m-EZF zioKHGR7$+r0WaS&wzTxikFQz-;7H)gaNxD)A-S`I+}x@jdm?HN{-$=Nic}-Zx>*E& zjj~{sg!H_Rt;KdTjWl_u*x7SxN;g#`(J5$_g9UN=)SG0t2{;ecR^#1+zVsQnOGa`8 z(EHZst+oxfA5W}Qb!n#arR~YKKR(l_GGx5*t0=!szeKhAdvi7APZewnNZ;$-ruot| z>AAmuZ|BSo3Vl4e1bZCiHJp8Pm36xiNi88q*cudnI-A>CQ{&~nUyoI`hF+aKLzADV zy!snHy^f!6siIFNf2p z6!*!*)=B)f(}#oQ!YBnf8&tgr{qLXksQ9tEnVnK7Mj3$czUyCoHjj^(-T!EqzMw1J z{@s!hP2&MDD&ytvr2sf>1&*=5?`}l`sG9LWz4l(EpZ&Fv&Ba?Db*E{c6LmMf*4S!I zH9d>j@uyK)LYF@Bm9$f%Z2kdS-D66IR_f`qTDQioYw`p>ri;yuupU45`QCI`do|aO zX7r-%I4gtqu;I+*Zb|b;2@5h7QgWe>-rjg^!@oXe9C_=fL~LDo)xe+&(bl~|sa}9m z=st4ujpH9-&3huCT@_UT8+l%S>GqD)40*4l?i_OT_fPvm+EK0g)Gj8nWyD^Vq5)t6 zJ&#|#X~K?D(+zb_;J-Zd8m!L9=fTd-7{8fc`Jd@mj)}+iV%H;@9v)sf?)4=^zWVJn zb+mndLv4*U!;OU`wi~?RDB!2-x*vevvpp*|Q7q0u)rvlj?BGu8P7h~GziE-qSP`L) zdDPM48D#-2pB|XI=d}eSb&WGAqmd;|RL9&*>7AMhgwdncuMGk@KOZg&aKKaLo!U1- z8*kHLIH{@y_i5cjh+_2V^I#6W$(z-7OE%CsG8+1cWjSxzzi-+r0oA2Yy4-#c%g4&b z4L#c+2@%^Qs6#fFKNTJYND<>jo9kA+=h|lzeJEWDSpK!{_t?w@t&u==Ip0^d`Ku=3 zIMJ*mg)%nC?ILZL*voAq;e=vSOyA&xkeyz_?M)5ON!7ZF1!>FLi&?rgl*@mU#78nS zTGXO{=}B-@WZbPt3(72B8hp%U_sQms}lr6yo!`IDX|I+P;IqWWwuif5E3GqSIAc{Z=^B4 z1u~FhZ?FcV>jY;dVMhS~)HdeVBIOuAwq_|o!=EqxRRO^@X`7qAb6J)J$^&!HPZJ+v z(czo#Rw6x25{W7Z4g3jBBTW<45F**oIK}Bnk&#E6YaeIm=8Og%A&eSZ`@VCB##PPs zb=0-&dG@pHzMt3#TG?)&f~K=-z9Dk7RH-5^vr|-5=~U^%iLx(A!4VB-0xpTbz*LL( z;K<3ETf4{HdIVGzx}C(t#&eL+3HJrck{uLFtcmtE58XdL45n8blb;D20gGe$ECd!6 za#eRq+N3yJG@_5&_>Hlq1rRF$>HPVsya^{vRX_2czA-}}>q+P)a*6M`(n~wx?IB!j zqAu}trn@jYKV1%k3->&*JeH81R>Fr##(^2|wjUYy@u%s5tasB{#;AYM)~}Hl$nVc% z!LG5n>yr|xV78$2NMni5`s4agR>nEZIK&n6)V1t%#lmgb_~HEFg7k-5==-aPfOtAu z9eg=xn0h(Pq0bI$lC;2pKf&XKKUsyqrhrfgh&U%xrP8vds5a^&mbDv^qv_70M@;lj zIv+|JiJ4NIq<0SZa|kzdmYEbx**{*LH34!AU+yBKHdq+euL0(aY?^nrc(UAzE1XvR7jwBE>R@s(a|zA-%EmZ9@Uv zrkr0uiu)*m+yQfx?r%wa3#J=g=&PCrPCl=9?f*ba&kH7uA+ws#H)RFKuyoEMxE7cL zeQ`B%E%RL>$fYHDn7>xazht<0t`u3;U`YIIeG1Bpjd_=*C8T++ffXz+?L2;R90Ipn zeUijO#)Zx2ZUZaw8(;W2&;q zVoi(Zb3Kya2MH$dXvp;mEMyMCqivweEi-21AmBic!-7ZVxeodpN^4<=D!WH)JkdmElILcCfn9AerGzrqN7sLCoq>GV z0|0AT6M+edRDtAri=uSiyPP&BG()Ob(F%DHga?M8I2f;yst6w|oN&=|p1+7G4oec7 zxl!PXoeTO6Vy+qYf(xv=$rYn9wO1srAlMCgzCtdV&Fi6vRo9mFCfA6c;<{DHu248J zHVH}|^1r6de(5im8N`M?wGTW}qGy*}RA5GA=l$-_5^GE0RlcD7DHlUWutGzd#M4@l zEHT2OSoigcS%xweI6<0II?POfgrl)`pPC^#0f_P#<_k(uUVzpmUSu2RK-Yo2(bcuS zirB=bx7BmnB&&(>VGk{icUy+u3jGg~BX|m63}uF6>oCUsI?G8@$tt>^Bnewq0;A#M zUIj>0Pqb%h}rG4$cLS@Z_-6gd6Aor`A>Ody$MhrFpGNpS_UCp<9AJ zJ#?;9rSmx~Jfl*P6bAAwBbaRURF7*%ECH!w7jJz(>tE1WenPYAtUA0M`xOx7- zTF#-k?*T3KR`G#NRI^{#= zwxfu`q3B=NNdvlzp1;%CHmc)l^qKt`gP8)A4BBlIWaEnjN=k{}jsDlb_alG;z)1gJ z*nHV=KEqNi9b`r0)cOVRMs=yk#Fs@3Co&zeu;9|x1^dB} zwn8DbB(!)Eo~qpUZ-@4~T#rXyFufRA4Q10mqqbKyD}2s7LN%n@Pg6_!@IrF}tf6JM z0g383H=8lu=O^v)Jqx<$O>LlbdI*HHv71P=KhZZ72g;uN2{%8421UO)+tJ+g5IE$j;Cld}q8$qiZJ>5Ug?@iWS+ceM%gDQ3@ zX=mK%BcAZvqV}=Mt8y(WH9g(d?z7w$@vUpBjeN2)9R$|%p^JZy$$XGCRSr@_8M|pY zE~pLup)gNP2u6D=8It>pO}riO>XOC4QBQgO+C-0#x=ms3us!xWAZrhP{YZmhZBU_OLlA@Sux&KqS zeo_Q#<5i;1qze!KlWBKhF-Z_u*uhv^BAvjqa^N;1ru9oy4~&d77JzBz31iQ&oVP-rhy+;E>?k74b(A{>FW#B9Keeq*{G6thdE@#kjq;PBNe~+7Jv?oZ*%hHhBmo z^R2uS5L|?Z(|d*eTDGFLA~w0&|H$okiywbJS~b?Y=S1&Sn^8-S+;5!={*NpQZQm7D z$ZWxNat=Ct{qnzp_maRU2B{XGE}BIUL`!S0&O_>5!8{=4VTtZLhG=Sc`f!MLk{m>)9VAHWK7}pWsCM;8 zf;p(KaO{KlX)-=okCAUmAlv(BJU85eun+_5ASwu6g)Bvqc?Oe;MlSVXTlA&oxkh-T^ZHq3G#B_c zAqtUw9JxXWIS_1_7b1hu2FcHW`EkF&hU|X%mrlf@67er2Ye0fy8TQyL4zGNqWF(If zR$u1s$|G1A_>#z52y3~&JcOs2C8fm{O&w^1(YJK#}%asXRFcxmb!sbvpZ;IK!7_kOU+D zsX+Dw*!Asfj9Sz}aXNQak4_a6UY6$^I?%sciI{{0s}u8o!z#dGR6i(OD>_v@8#EUFlS+MIvA5 zb+ls`G@xsj{SwRw#1&l!nlkj%a%K0om*tI|q5AN=T0^eMn$slits>1cDI$^?bL@ji z5u6@gkti5|so^GPw#=t{koiK{-{#v(A3l_y7i0j)`#mB7MEOhNik_k~qq6`GZK3_| z#2eKr6Q#t8zeYSpHVO;xpTxBh>VEf3 zHb{>&<@oQ^ZY<@5X5ReKb9D7wm2S`Ewa<5!U{$7~5qlfvLb6dKg=%xN?}NYp(}@bQ zu)zmAfxbt7IpSG{>;y*E|42g zqE3cSOb_IWs?8+F##Xq*?bLc~>4whuoqgEkR3>62c6(^`vYnX8c+UBoN6%XSV<_l@ z|CBxS+1>Ou$&uA@egryC88H?FP!r9e3a|6WbF^rV?}MhDZ~a7nct2n3N#tyZGkc=Z zF!JmBewAO|Rp`azr$t(!2Ns>jRfq(LZ*6_;cjcmw{$+88h`{INE?ysO)6hR0SvwZf zKg4+ppP)6zyPpqsaBv;ai(szPiP4D{57H$H3M$rf1$m1A5<1e*606n&c`1e1CUE!Q>l+tagBlv7ANLVkSYGl1y01q#SQ}w>K|9p(!BYz$RTdop!1&O^s7<9KP$}OV=RobWr zmP|=!jn>%a>6pI$(30V*Y)#p*H!skHlr6{Ghwc!}Wp{q6~w@ zS4cIJWh$TqWW?2;yvi3>!#@?+VIhAW&YhJz55tz!!_-X1u`Jb-P0No%*BG!_p+A;J zC%KJ^z3xoxJiXxsFqT(c9SI0s5ExeqmH~-NH})1n#}4Mx%TWRr26+FebH;a^ueytY z%CP2K)0c$lK59PKFB~f+scw2QF)?Xl`;1bk2Iv-d9%GtE6wCf9g9c}ut2)>ae?}Ec zTovP-=R=ex5%s(PAl}LI-rdN)w%~zB`momN1(kwtDR%B-vot9K0pD z!KH^)&ml2_{Lx=DE-k4U{bDf_D{}LZeY| z3v@liRx;~fT{GddVXPYvb75uU@PC%iQ3{L6dz99%*dchz07*gk=1Z6-a`!UBdNB3u z85Ge{tZ< zG4ffnD?(7=WkHB)919!wruUAjjR=v|z==H&Gt07q-7aGJhL`EQdPyKi6Qr>B>fM9G zre+2bG`bE7YuV;eR1V*9i_SPO(H8H!g|Eu|kLE6Ly`G4y?-j!+K8fIwrZk}MfiHrj zsw{>yE_6_p>u&gzRoOlss!mY!7#2~8s+I0>`G~zKyEs%b6%DH|6T?&hwhf@pfR<|} zjC$&))_RMdx3FpD;t7?;x%wopXtF5U{4W%u!3Mv`j`=Wv;uSmAq#uXhA0W$Nwb&RBsVTAMjD5`>;}Ju{U?hm_j!UaM25S2GA??O z&Sgs3mFM48Ga9DK?PjQ9s~Bf^{K&)rG4HYdT89tE?2OrjyBgcM1Ei+x(8v+zGBq?U zPegY{sr+QL$ESiNdO5YYzvO>O7l33ErR0?OApyNStZRseEbrurhHMS&99=LHy5qtb|WmO-$ zl}NFv4YTRm{=tR05;S}PQ@}m zAqRoAD^a*+cca?AxlLVivlN_!;W~r3i0y(hd8;Nx6SG#fvm0h&TDI8_FXUTE(!q)q zMTd2aX|d>x|-B| zkMb_1kw?S&$vsycG7`X&3R0;*Y&IgyIFz@t#J6AuASFP(tau%r+DWB@p3?{Ne#jq#IEcCh% z3A`C`DpEvCQmW~xGfQ2(CjCp2Je-_*FOfI^Ey3uYf2y zxC14*G5;oKB=kJMiit{5P@oG{Ms{HAqRMf>3B#&~3X6gUkMWInD9{58w0vpsCa0Kw zH{HlqU*OttSm{%Chqkb_EdTeLT)MrQVf5n%(cZ&s3T^XZx{+Pc9f2$9{5y{ri_1B8 zPQ|EjzrGf#CV3ceORbBynGFT9=3pro!a`0F_e9HfFJYZ85ys+kPL;;aBU2!`6#$bL z)5?6(}Kb zzO{{*lLjwFUyfn8Ey;cKxG-|~PFgMa@{9~;K$v8-Y^Z7xi|{zqckK0)*KDY2K`n-F9U8GEry4$68l|# zi5p6Rr8&q%4G9yRh^${DfrqW#@JOiVU^HB1}hxv!u=nLWU9%TQM-)$W0vM0HTb=;^b4QN$7A z{8z-)x;aW9)KTQkww;J-htDRb0h$7Stm8D$@%hd6eHzVbt|FR88nlDQErDY;$fRphn3sal7k17VV;*4pVD5M@eFYrtr8w=t(}Q_q(@& z`!cFg=08C`gvr#b%?@D+R%iEc2}r)Vmeea_iMgKE_b2KhS0PLpk#_!O&5l7EASvxa z&+uG9=jNS=+L#LPt24Y#$}oHg*kQ2Nr!a zA$@@!?5`M(F2xnkPX%wIqGl7=_>VrS;bvkELjKKzzrgho;O7xv9(H?xvz7aN;EYLH z*%crrHZO(seD@sP&Us;|LwJ#^VRRPsol(~o*7xd4Q?K(?y{}S9Qm}6+>DuR1(lXKx zp5y!p%INX=MSq6GeRVJyD z($uIE#FJ7;4He;U?R)O?-g88d6iE7j{1l?c*=lE(_+Cbc?f5xRGIVH&NdcY#i6^C1 z*DzYKDoL6>j;;e;e0Z&UnSUv~eq3i=IIfeU0=h1;?KBFUHGM1=}1ell2YPB_IRZpNUr!Do4g}#*VYh zfcq@_c(1#G4te+K4S(IInh+W!{tyTH8?!*DHd?$wwkUSVs*WpC||L?7Lk z;z2(f4VXEdRifSxl~g@VL$|vm_}M321Kg@6YJ_dTR^hl^*=S-V#wn_~@%_;wn^Paf zA}}8S*WZ9v=vWY72G-Lqys)*ptID^|jj7xim*G2-9&wDMoQeK{`B>Yp@bT1xE8p4* zS8rC>-TK*o*IUoMi!G^JFb#>4Le9l}VpyA5Yw>x02O$H%I7c%i|4GGIP-*$?Zi8bJ z?8$xqzEA`*h}zPvgTiegO#8+R&@`hH7!8zwB7~PN`#VySbx6pSB4w8QwZT?W6pTtv zlVagn2dBLi6&nPf;QL}IENpdek?9n^TouGK8n3QDBrzr+BxUv^6(X(N4-ztkuQfD+ z#mTW9GY0Bew+Y6P5M7EyF)<&N(TQ0w%3b_EgWxH{OIJA%nL7^Vz-7e8ZO-K;WD$C( z%f`z~K$CNA4!05XqdU1}C%#<2uAPyGn)*zF8wuE4$igtc>@_gM zLy8xkAPt|0_Qd*kzbEX{dg~MNB-%kj#of{0NkXqV{o1t?{UsxDtKiGaIFHLb`-1fg zf`rC2iFdvjZjUh>k}SBao}ZIQVy5-!P@JO$5#~*%>Tzk?{RX+#@TXy%(I+YR&!~P# z2UU;P)${>Db`Ga-zUtOVGYY#}UAUBjW=NB;0>6kQA$@jPbqfnQWl6OBYEc=1r<3T>nJ@h#Fa+cHom(%Pk*( z0i~=Q7|sAX8e}e9mDi|3G$rekC0VmOxFWv=^4Lm%#3XQTK`kmz@8B_%9@?Eh} z?0kdkB?0cPXoM@eI_!Lgmb>DfavAapir5!>G*juQC&ix#p^z~ZZ{AdAvUCfQr_0?)*I>}3E~RCj3B61 z>yY8esQez#c~S- zyL*+Q0xfBPkiOMIk5gYOXU7HA6PZWEiT-rA=p7dn6OuP=(2A z2wVn<>*K)&5{g)yJ=r-f+haSvRAYzFv~WqEHkVZQTnzJQGBZjn?;<&S;G@}grNwk< zbKAzo_x+7|2N@PAm=GIBC7_EDn0{zFRcV2Q1I3eNH1BJkD0IalUGiAZa~5fzV#>3O z%_+B%71d6eayA)W=2V)CCqmP`jD zRG%b(>Pjz|%1qYkLOf<%HQ>X$q*Q;FyI7IKHxOejwiC2JB&2`bs!XJt5rK z0gML$WMzQlh(HLD1Cy``Nl`t}8D<_u18jy}m&2U*PPB~a};fk-h1ngdI?$pC@9^sI=+|j}bsmQN1l~DZYDjjx}>9)_Y)W{+m76QW;9S`Aa^Py+P9Y zvF%Y@@WJNn7$?vGGIzFJ04dTjq`+sPVQmjm)D}gvl2fV;zY;uUS8D~K-2@)H9HUbs zE}|~|a*heo|9JT8=`2zVpC6v7Bn9J2ox(`5PQN=ps}PbVe7Q|fsT=^tDMiLzf#zj# z+k0a@rGG+`6wGumJYX35*8wQ z(!iM#TvNB9-R{Uic1Pj2%=&M;?0GJj(x$8)CQX$8F~wg2EFXzWEUzcfZ$lP(U1N#w zyxI8Wg@ziawlKpGKxZi;$nu_>0E(hiZ)5L6?te&3X%260zw6@2erG#ysV`2; zrlszB5uaax_RyQ{_dROt%wR)roz8O#4JccYa|dw44<-U>?1RF4S}wsaiUx6Kl5$>( zR7=H58EOKHz=?4qGhtlGun^Zx^aH}x2x*)8_o?qtfP1p;_Db|g)A8w3F=w{wz;%Ix z==|QU7Kd_-p$J7}aL#AkK*F5rZtRPW^ociW;;CKQ1Ht!fU~!|6>H%Z3tvA0hCw=Hpm;JIV-ZKJJ(uue+pf^BT^8_g_rq zURb#lCrE4tEFG8nAqmgi?H+=b!$5S8xy5G+I>`~y(H&f;qla`Nz&8ekVK{*9lUg?p z?pGMLxBqY-=z;PcV{JUSA^qmS80D6N1*9W)* z%iM)+A+>OlEgb|exK6N1ruqNMJH?RiL&LASzC>aks?ySTjqrAv$d6)o`_%8a(T`7O zEQ^1bm$}pM(i<@ADn`5OaJwk~k2=_*c$eL!*N_d$Yc?ek9t$E#9aw$F5plONKKk28}SlKl`j14@O-irLW`pd5j{B*(vPDe5{OmzY`LYHOz+$kQi*(1x(Lp zd)ZWhbKP>J1)0gqY?R(=(fh&{!_YD)u$uweS3EZqP*nJxa26cJ-A2Nl$HvRjQ5Hb@ z5V|6a5{NZ_s46fZscm>n7~(5t#b~B3eesL z4kWB^yAne$gDwUD8%$K8eBhB&|!Qs*j|S)X4_$WMM-w zs5ArLW}REWp3uq@;KWIS=bjO^;B`?4CRh*bz@5xn^=t`!yBPwG<;4y6&9fU4UWl`l zW3bjUpW&W)-SM(XjMl51ie0gFptDi%SG5~c`n7mo+)J<~NE)~1onX7lPa#SMZ_n%d z4d@e*QXVdBiV2|ZGVCAb^Uyv#xXCsuk1Iish?#hG!*OvNK}hs?XF>I5i(yRJ#`ARh z;?EEWJ6JlEr_cId=2saeI#Cexlc zx!t$CNAz`#_FfV$DZMdJ%yzUK6*)VTIFg9LVbD*gpPu)qu;0X!{+aes)nQ0!?f)urIh+04^Qyh^qpp`Fu4@JdxF|^O zDUszq=N>eCOnZ!#{ zb3nzA^R=fpcNon~KzBsq%Cv6GFV2?U5SEbCWF7G+ySDR3mXbP)!PP*MQTcCRnflU; z;=jUwUh`Tx77G1T(~|}^w_x_zCh{wJe7vsqw&6AH{wWhnPe$Qtqzjh>w)dK)&QfS= zlZ8kMqm7gykEn840%!gaZfYp2S#giS#rW$Wd|`-cHR14SHhdN`1?D)%8NOnl{=Z1KMv@!iONei z#0c-d1pNIiIA_(9UVp0N@bGbqWz^4WJr>@3nS6eY;IDVzeAo=x`mrGFT;mStZ{m2q zz279EH0^Hnpr#ETf^CM zLRLVUEfMdZ@fLrS>hBs*QQn*;%EDELa_|wC9J@^OVyL?g)2{uptu3s+HCZ`Mk z)zGW!g*TRE@4mPW;ItwAKjwRhXRp4ie(C{Bt-a@bmZbF+hENS622s5u@!+SsOMqc!hT$$=PVE+`wXq^n=_oYHT^3fucq(?N9$7YXas*jh|FB*2~70dU+I zGD360cb7SQ$2^Twx7jH@TttB~$=_NG(Pqw>s=)c08c@OFWz>>sfiS|0k0o?e@TjTM zjCJRqb99}gpqvX-lGPJQ3ku;G^JFbiISNVW;L`g8r`iol$LIcCarn@7VIz+&-Tq0l zBnLoRCkY%M$vyFrD--5DY6R@1( zYz(_@U_P`x_!Rrv=e5&C%91^*R>~=$a()UIN&@Gzo1Y7xdhr zRL0PK*T7_Qn{-VGsK#~;pYo0*Na%Fw2|i}t;RvNE5EI&vClhWAVdd7E=q#q(Ud@r| zkE3doG0L;mo=_iB~Z|=g}L!Vzt-0!HfY|6T4>L4_guhWo6TXpRf^sJH;(& z^K%`=Dy~_fb~&o4$TC-t)qd&C0s(y!iM-lkXB(nqmkxq20fn)eK|aE<0N!vLULp%- zdsdozJYalnfpZj6awlUhL>-Zx`3^Uc_)Z%HZQoTjj?52@zi5D;XNI0@Z~@Bi^v`fz zJYz8|{q`-CL{E{3gx%09L)vy97UIItQQP~uQ}WAphBCw$3kkTW-4o7%S1L65R4Zho zs(G!|G7m3NtcEcZ%2&Tb&t`$oU_R8V?-n*@%i~DkTJ88wj&AVu)z`?KG)GR3k{6tG z#`9m&MKm;9?)>VEjX##te3NeTpQ{!Gn6Wd0nJL_M3N6NosS^5&+m{nlK0h@ulA1zV z0|swGC!qAOs!?OlB$6a>i6G{H7%k0cLv!!ZdBH+9tnAZqcK|K63m}-J3IZ=Iz?nX#o z0cAwu=@D5RXE0yjm@iV>(MUsrHXmnA?|sA8E;i?n;Zi7NA-fu<(+f!=Ce;!qJqz;^xvzG?`n{7yOOUAQe-+$$*qF*l`_T z!4(Vd`hS>u%dn`v@Bdpx0i}lS7#itDQW|McDFviErG}L5ln@Y*7U`}51csLGmM-b; zd-M7JuK#sE@X1`q!>PUYs`qP|<=(fql`SIttrC_EVb+&l@CVv>`2*Uy9R#RJ<=0C1 z!ea?#@wZF639T43i--=`6+>w9FgSV|PsDoMX?1{`2n~qk-8-y4pdh!~4BD5xjk+!B zh$ix&_b!QBJQH%V8#Ll=jq|JSW|7kR1>q_0=tgZXBGCAjC%}5RA9GNDp_gm6!ojRt zx^DMR#u)4JLt%$p+t2d9Vunz(!bD=7MvwE7*-Eogql)6738})-)>$V{kbNrVur&GO zj+d8aRgo3K62oC>d*SmOq0j#Y6UjfgdW|6hFFM!8V&4U(3SQTCdhA3)U8eMH3&Z26?SgYT2~XaU~|lwd1Ez- z&cgKSY7feuzSq$iu)C2!1sT7^!{D`J)Nl6M!pos$ZLg%}+C}a@)Va*FsLrtiSCx{k z1ec(&%RZX!xq}qkLB;*g{z2^;dEtzr)FE6ubJ-~tGxZ*C5x4*GeQJQ3RjW_e-f!!l zVFJr_$Tj529OCVkS_eVlS3dLd9L#EeSp#DulB)W0X?5>A#eT>D0Ha=+g?9`LLkpB0!anETnsQvS1^6Qpnlp!cQ7Cz61^n1 z-R@?15{W^1soe1Iw-y4;_A>IKY`zX#>!ajPNQriINN`{TsZI`9tpVN8Td*O%w#Lru*K8A8mL}`2l*lx$u7Iyn94=`~ku9#=%k$9RsEp>l zA*z0P15?j|dtg@C3CL(KOWr>GxYFdXFvh+DJKHIXH6YHPMtOw35hy9QxYK z_811iFvS)xJ0K$$ZbS0*rOYHP89hwx2sMMShLA|1WC#!Xm>h>l7zBK2PkYWdNBt{N z^aW5S8ay_{eC$se9<5z>i=B0jiw(FX!gbP^`?Dvog-y9o;{^+$MGBu ziztJLJd%Mn#fNXEoXZrjF6X^I!?BNYMAf2ai#GEO{rk=V0?SiSWmu8`PJbBCT|y&@ z95!%=zx)8rCk9Vk6p`D$T$@70@u*%xFi;r+Fef1x0g;bhfB%adE52dZhI$?#D^S;^ zpDsK1SC-Dy_cTu3Cw3XEZzTdW>oqdkwSPUb~nmv zHPHa7ag8Wgd)M3(Ks84fCG{5Qt^bo~Z{S)5YxA^u@Z7jWC51khiVmgnrlI()kviSW z`_xaD-I;#=j-(CM;J1iWRPjyN3Nn2+(S0@2_h=q-KougmwW=?)i%yu-o=_iD8iXxZvbUpXvwFML421k7k&9%~@B zpHU9T>mDGrU_Z-TGs*d8!i3gx@CKVf?R@i>e>_D5645$wA z@*$)Gp@~nWvln^k?{r;h6ySU59;hms_ z6u2!k8^L&u6f@9vDJA$4T+uDKA}r%qIQ=03u>dvl2DA}Ufj<*jlWO!%kRY2j!n~-l z!4!1$#eUHuN=V$H3G00jLsjzu2os+#UZlJ%#j~$LSWp~&72l@FnSDot6StnbI*0E_ z^x#jtc)+7jvW^FkCws6r~2ch^d;n|7dbzR0N3SqauuHAdvDH`kf)x(F! z+Ft=+<~;=}O({=gjqsSf9*i(CIEwW{4Lt^4%LWjmKlCLnLex!Z4amj3+lqCn-OCIC zv&FoQE+U|t0$1ku1TG!83dVktEMMP*y{YmQp!l{DXx|yh?fb7E*d>Gq5R8Vvvf;I0 zkfvb!Sl10Yp%;`uV~mTKf&lLB$riWXRD?_wVmYL8yv^UNUL^x@X;pAd2bAvyAnr9e zuMFTx6NdF>AiYX~lVaY0I?H>`qOWg`qwd3mfn*wBEj8GF?&Q^btT-5aRR>^toe68aSP7mRDSTrwa(=XmC4J$86h7 z&f*YM{r9(al{#V|U1Wpw7^u!;G*PqP<|{|*5c!5acmr+@Rj&IBt$Z^9!wXH&eiQ0;W(brIWxav6@kHjJsQv$CTtDY~BE>M$!v(w&OW zj64S(;LZ2!vXvF?+#fuQDDlA;?k}vD#63lHLut5tFR@1R z2U+-*DGxB}A=E;7DjQ`61CPhTcn)cu+(`MX?FYr~;SVkuGv37N$m18BWUMVOF@8O# zc}c%`eYM^|%q<{QEz2WN(KH8~dfZp)R4=vu=gtFzNu_z9@jE8jt zTI4UsX$p-p8DHYc;BOb1V_n?CUYRKqEN=oKy6x783689xq6M14(}WJSE!K&kaSHB* zXc0}b@7=^fCg0#bS0_xaC!1>b8C=nHE)43plYtDGdjZZ{<+(pAs^!|`RFSo6d;lJV zJxZ&*=2NSLzJ_6~#Hx5IS~i1b!J+9jZKf8E(epG%yM0C1^*_X}0BLfcsJ$K1Hy?Jx zWV3K#d>a}(NE;@_%Sc*;;{gQXZ~^eOWR>oN>tZnve z_|^HA(8oxvd~puJs4LNH+8)$S;Vb4T=XYTs39m~p_=?*u-lPZO%?FN*erJnmzm5;9 z3xm|l8FeD@In^!%2At@FBGG)EL;F5;pK3~g+6wk$wmiaFErh7ICtbv2?)G}H5$qop zxhdTVH6ZsLS~pA(`Mllq_V%_pw(6BkwF|=VU+7L6L{dCCGm7$+BZ89D@zQZCLTK9) zTx5~Ohj2B;xtQ?IEZT^~3!0|_m2cX9z6#k%hEz-3rUQ*cIQ2TI0n<8MD1kYa1gMt& zyCfp{mDSA=%LH712FLJD>JnLr2;`u_L>BF3e(#(;vFm@8cMZKMa-jhK@xoeS{h^N# zGzJ$1sfF+vv<19*AhX;l^3ofRVwyL{%DtH#*uN zr%K5qTcD5PW>c~HgYDt6cPLFPx^{%rTMmm6+FI9rQT7Ozy*WByUrAfT)l^hU8=bb| z2xYCOhv!9f6OCe@KBpPR8+t?`=+s@RIt_<~FAxNpbN@Wn3bUPK?B|~WVU9*YD6Je( zXr8ah6;BATAHeKqVPr1Y&D9ML@;7*0M|~(ad~M^~P1eteqx5(!-k&bnv)+2zkvB-9 z3YvQ<^L8G<4w_ECW%341f!#x!Ivm`zfMVR&+E>(HxJSnzFNV{pqViNSmL9Bi2R3z2 zNtbOP(Q_P`tfkD>o!zvp65Ymaem7&3kGy^oRqR?3F!ALOs-o^fO+sU7f@IJbPC`K< z9EDWxaURtOK0lui@!%4hGIgh_EGjcx-F9bq`K>0bwd17e&7)$?-OL}MAR~JsnRoeu zy=r)22-(TS|=J1|b${X)x#fm$p| zQ76#u^NTsEIMG#AWg!w-D4eZ1o%b{`co+zaGUty6g2n{60un59@e8X(X2W2UVHUsg zg(HGE_631O$N>DlewmL*NX$(QD&z#ri5vxa=)q#49Et4uu{T&NAZyX4Zf6>_7*4?I z@*rYKp>H$5f8J+pRjqOKr_~=twyK_HE$RSl6_?T?Iu*tiGjQfMXiA|*vAkZ=my4L|+3%<~9LPBc1qA@3ZN_SFy~MlEK|(tumLwmo-zybttB`5`#+9KgTit zeP}t_N4N4ar3Jjj1#+-Z?S#9|!TzRr^u#*dkanTBOz96-G~ikXUl zfXdvXyS6Whee$DOD5XtL{pXFF7!uOfPFur&CiEcLmr~}kKUL0cF}uAJC&ssBFw*P? zm!NvP_w72F3rMSghU~$ac+*F2f`Jq;o*Ol0Nxb<(b)#U>@{7GX9}cnsL<30MU~A-& z3KVOZ3vjfgZJLUmf)H2&%2A|S=VWE)wmLW8-cD{ zFldx~d{tD|Tge8rZLox3;p-Flwz?LDp!&QLTRnR{X@vwT(wF$5QrE8=e``>LP$P!H0u8Drd9L=Hb&?PRBXS-n zGAWDYgtR6(QXpAPuTc-FJM3qG@wypmM8y6i1olbN-`-4}PQd{!kk@iG0P?=vAnEq{ z+@o+9zzZF-}CH~W=LmO-Y&Y=uc-hCX6} z)^aKUQvDkZPtyDW-6d&>Uc8knKNiLUjw%m|#J5P%rv(+Y)R4%I~7F+X6h z<>apk`;Re5t_gea*uViSQV}6!V%~EfBB#J&=j*^ON^oI zqAHx($o|V!Nb0eq4U+y04)KE+O3E&rd^5}GR7B;(amy66|NFyELHWBta^EmnR())T z91qzN2Z^k&d2%zvFlWlQ9KDBoF~r~XG>a|>XoYylc#QwK^mEK)N(R$~1wgX1oT6s* z?083p;6#|<>8TEBIZ%+KRwlSKvTg2y^6pEBjF(sCjcK{1Cc^%~5;B?>X%y@1l9nEC z4DJkRL8a)2YOLoQ#_jGMfD2$l#Qf{QRulcvK}?%}gA*%{g4aonX0HEWs{v;2UkA2q zV7Ddh%ZE3BOi}>2OdeL)xOBkrW(H!NZuFUN&N~wx1_(~c`T0>3UK|s!jRa-#Y`JG- zI5mM?ER-55l}F`AB+&@`5tlK-_rqi~!w@RJGRQm})(-k7yVy$;fL6)4pLN+QH5-ld&ww`A~@C9t?dLrp}q z{08xwviuh6m(}l9lkz;Cp!-faT`R>g*;9!KMm{GiP@h}CJ;;-wKSv;f2nN zcvqVI_s1m(BgV7-b4?zT0M$7Uu&vC=0x5#kg}FzV@=G}?qgwHeQDbImOXqEY;d2k> zkpXTpz15*Q#I*X)wztNZDcXD(z zwTjIE*5rK~G+X~!bL8mDVk$7N18I#95HGml=axx*pZQWZ#bnobU(n!F2Xp|}71%(( z+Itd)kJQ0+CqFU}178jdyc7WYc3e_$dvNqcTEW{1?HP6bB+(;m*R2t{#YDT=8j&}o z3Y6m4HD1?etFT(wu_=gFj^B(Js8Rs^!Bvg(;c~|V8jFzaqmyhD*_#vq$MW@kT>AE> z0y)?+m1pF%{Htu|8&JcfD_@ZS9g+v7pQ??O5O`<_aA zUUPG^;X?6g%k=zJc{Ss;KRJ_Y!LwIjZ^12k?5?|}~3SvMnl=PLG50}#gS$2}tgSkJiD=zA*P6(;r zsUiF3y}O47eC0xl)KJ7VftDWq{_w81URov{mPCEW2}^2(_e!Q)^kxGB1Nf3?23=5@ zpOT6K8f~lHMaYFhYzAyCt+&1V`7v8<&!j|v>QH;Vw65+JE0qK)_VFKX+*`;y3#{t5 zZ-VKhKgaZ~T0tcs(lD*?0EnT0{O&NBk0_18`GaCOJWzs%4J^Dl@uxroG_JB9Uk&W> z#Lyi_YZ71RGZY+|-N=C0ZhVp-B_+15U<0fm0DRCVGgKOVBlP9+k)hM>+E)6&IF<}O zDz|JSp`sW4^%zGYg04!uNDhQ0BWNGCSw*FcfSIP|m!HV8*!wsAdBL~|V1IcxDqed~5KKyO|1bI}U|__3zZB{!pZQe9xS3o4j z!pRGLIRrni7ZJ*rlMY`2YuWuQXn3MjUtcFn-;+kcOE>}?rBIiT{jhQLSdMvj8`8!d zyNx*aNHu|uab7-fL2FaxMmkg@oxtp^4wbQJS0J!5%V&8T^{j}LP=`Z?^c?K@&GO41 zv&sf^H_Yoj9H#h_|$U`+4fa@5_gQ+61*7vL~S4}VlB35DJQsI>1E z&w+I_uBwv?>~@?wNhy1=j1cT7{%fE*>hR`}?X+nXU=TZqh=}0G+5o1k+>6NPvpYs{ z>tmJ}+2ECu&lCe#G@Ma_j8(Tm(MFRL@Vlv*SVmhsFDo9xv=2c2MM4M#A&A4WvFmDg zY^%w2%9A0{hbuBD6#Ax*;JRH{Nam77gQob&_njH>XYqnp(DTXT7Gwu*I7pa<%P2Yk z2{#LyY1dC=l6{t)++9RPBb!gWO^z1n?a4w@uB6fByKL$Ja{>zXS+SMbGLR*-eEB-{ z2e=aAcvi(BMZJ&JmenNq;3~vZtIY-}*dx-tTw3(@W`J`q$Q*xuaX7fj)e>NT#0U=% z*E&4K18ocFUM8Sj;XOIoGn|yn zB|L+hHzBp8JCWxO(p zauA6I|{FO-4f6By^hV< z8kla_7cDfcipXb~3li_K0s=$iy#76nBscgj<|Aq$u!^5>wmoju(fj7HVyf%)Ipx7J zV>r(e3QAXn;yqx2Hov77$=y-7tp*9FwUQQ}HzQoiupbn|4mqA5Xi6d7JVTPa>)Kxy zAJC&f@-dhr{0^x_6HpPiM)UjjOx_f*IbXw5MH=r0iYXYeSdJH(y<{B?0#q|2HlPva z`|A4}{)>Q2ZV%uAiaKTtN-vwrMr$xn+iYzPz~h#MXAB2C$Av#q5RvVf%v}x#i^~jm zL-!4lZi7=#zk)C{4RlSo{Oius|Ap**ex9^FGFBjM5YMHCOq^WdiwgCH<%DuD9)NEt z#&!IqZK83q>!2|A@B@84y5C3}ZGTOh;;6S#9VVyg5Gj1j)_25#2LgcA_Yc2%_DPDu zk~CpIdG|vGm)di0BlzqVxU%X%cJruL$b78&geoyk5e%e3M zE6tD})a6uDy1&P9=xp=5KET#B98jStKt(C^>A0c`?{U+=YCe#X`aD$`avTUmm|8XU z*$_|;3!&1;({0qyNe+@55zd}?@U_<;tZIf$yOi|6Zs}gSt{(Xoa3|f0rbTOsG)(zyVzH7-RY4D;Fr94fcR1b z47K_P-=Hl55fM-PL>n;Qf5eG^P8i*0hmRZuSSN3{)|Gfyy$fJ;Sq;WO?q11w0JqJ& z@PX5PnMwZOiY)fY1^3kONgKTLRtp(^NZLFAWfgn_%`cDe_ZFHqfET>cyB9toE@?si z`0M;qd+@^(XGLl=Uw~hFzn=lSpf2EtXh-Vcfmai-(iQDtPz9wRxKS9hq=01LRpzGe@AL3A=O%_K6jY#PZ3H*5&HK4`$ zH<9&&9zLH$BkVX)f1$VD;_x;Gh$xeD0wEX}Ht#?Ric+Q#MCqwwKE45J;b4c}_Ukk_ z`}gYZ&krHjJp$4YA^dvhof?K_ineV`m(D~+@NEcIy(OdQLs(&c)de{5#WgV(h7?MS z+|Y(4R*T7!dA%uwVZH|BJ-_Xo6Yz3JKO{l2mcSQ>v%B08{(u#BRY+tRzUd*L;}2KU zOQQ_r$3lB*u$qtuZ(~}UKQO?iq^H0%<0T0L`xihbq${P@jNOsK5`@gFdDieTt8^B` z^(?5r3y+NbgvovvkUP7%Jbu8#daGpX1P&uYFLMgU*mJQ^HP|+r!X$C0Q-9#HWB@ETl+A zxIL^Ic0BSS`~ijzn!XZr2XT(VJtbKt;#{+R9ls>7g8YNKyfc$c3aY<5ss3P!x^7Am zoGn&=RTrdocvNdFK0GAd7ls$0=<0br+c-9Ap6piJ#R`bX8&TlWh!Gfn`cdO=46{A6 z2JYtiJf7V!brInA$CyFiak8MB&}+0R@uxsix03zc-VRM4S8V z>E!L>JSHqQaw<;0I3mi{;|l1;=ngcI9+e09k+8jG_CJNr|SK zgcEw5P3bk-bbB`2L#q99KVS5;&=v?S-}DI-?mYl+u##3i9wr(b16+B-p!Zp2&$(*r zK1dl&lMB0*4NWt`SY zxHSJ!*)Q1vGCKe9hTz#OPR`@$t~BK&fP*DlAjIGgPZg}L{O3MVWe8&&&zgL`* zGXKCdn*+uqJQ<0X)qPnlxpiEkuA9XYCsXp?@0vmRJJDQrBp-_lZbJwA)A!!D>Sk=t z1?mgA)ByK9kvq3eG@jL6NmXi3Ra!>E`#n}G5~2qC!^*X-G-}?>T=ZZ5r*OQ@7v9#( zOa^}7Agk=I7)J$ZiY)XJ{d&g^cCvc=CBtd2mDQfNwxBuPzbj}pf#QGvm4&5P9yhzK zNJcSF=3O}0980`ip?S6s-`Jn;bh8#)L)Z{r}D|RG|+At^ie177fKGdTw@Le7d zgfc-(W$x?BK?id|7^EhwmWC-4hQ=#3hX2Gj%W{r-6AJYnb!4GJlswM&jw7XSK;D13 zflf+@o1`$dNV-`3Z9iuisnf7PS-d02V>UZ{qEJI^3(4d=YXY4(*2{tnQbH0f0yzIW zxGVkzA!#I-8xx6w@mPaqA(4p7C^yBI!?2VjG;19SM#)s+f;ZTsGbYG$0tU>KV;Wq@ z@DON4*4WOk2V%Ede#zZDTHCl;PoIm>#U;*UpyRLSIdzzw&hK&@>q&v&j;&4^QTTAuG5 zVYrud)gpo;kRmdQ%(Gi0*Kl4p!8TL63MfH?5; z(W)~4=XJ7STCf`}o}MM@6GlqwFV1Dfq+NDXTP@4AG4eWiXohyN2OF|1wFr1#lo86Z zFmhfrx$Fww8)n`Ya)#`v(k(X-jjBpoB#=DCmG;bky#Md}dK}fm3yXJq0dcXz)CvP?KBtlV`FJXAR<% z$+j!VYLLWqV@EzRfDWfRiZlTGvxfY#9GJ*KdGi+~4d^XA@c1~Yd1$lvmV;i|!dH+* z)88_6Vy-KLlFILW%>WKT@0+^Cr(Ef!44r=Jx&>9dJ#q-O_CK7z#q-bAcBk!ablP8JAFzgXrtE-|84ns6 z@DwV7LSaFdvnIOATyuxbTm&(0tVP;9HicAj?S-mnb!s z2zuorT_P|QV*fMv=h0W9xqQ3t)8eYI0a?V&A_wx&xLYkEr2r@iM2*zpnm`9}sl3up z7TQ(#tnZ#-SZ-6y(o=MEmXF25JeVPPythM5OFy;K5DeIm*hEK1uLJ!FW2Thaza~;}a#9lj z9knCd1ZT1JmYEx4^< zoR4PQRc)Rt?$^YvF*chHVy&^c_%DJP56+bL7hUt9LcrWv7$>&0Kc&+AbsaP^oxZ*- zpp6j5?H%+9+u1XJvt~zkgx=K_Hd`ZZ^0Wa}3x}BJ znOI)kw-;SvY@NlE;R#yih?d>Up05lZ=UQoPVvo=Fz0VuH=0XcGwy>kYRHw#!Fx=xa zhyssoUtZeXAq+uNQr{o zn(a&Avd=~C@b~VSJU?8&X$EDV+zUf4c8gS55fPs|KOy^1_t`ahVL)VaObi@yoWmRr zlKTKUVLX|S`XIg0=yUH&>Av%cJ*bGZ5pp8~c^Jb&S*6KZRCjm~>vJ-p1BR)*y_nk& z-MIUUb@$tAjalE}0TA2tx?K4Q6c}jE^M?Tu55sbpOxwK93sk&%|KpQ#oBpwX$i8G; zAQ+H?$03yHJzjUm8LogLbWA=Fipy|&{4lEHw$k(#8iD0=(GFq+k90dQg=Mc#|E>Zo zuOEcGfZlL6cmsxrR7Nj?nLBF10v?xZNljlWVakZ}hv_rG&;IVQU64Nq%4Ktn zg_@-er9QVidfm4p?6+~0Y@XMj1CRrJEU9}2J z8nn*b&o&;L%|=z&{yoQ1?R$K?7Wfp(IogyAJ^rm!flL4V4dM$r`_~r+FO#1+ekiBCd;fOCLN+ z_2yN?=9?Na_TAmJ(9f*-cJwT_x2hWU_nuu{@lJkh92ZNk-d$)|8pRm+0Y)1vS0`l$ zBqimG>{`sf;=h|T`tT;AVlNXrJ1FQhn^vZ?<{9VA9p(;&>EySbBd|I{$8# zCR&*5e$TZ<=sq7z54wC1m)pJ=AU%2*q4USC1yGkn+W_v=)AVjLJKBYI9Xv~ijYx?I z(F0$sKlcvp!TDm5GrDG~G+k@Erw}R+i za;~m5FT&a>&$e9+U0?#Nm?-$q9)mXGNl|5lt0?wuz46>YE8D;FFRK&&cLE8CGNoEfgcmKF5dJn z{#iUuKmS8{{H^OxY29*|?JahkKM_ zm`ICJ_@_fi6PWjteveSOLEM0mLT5K(cPnD+VC0b%17)&N_rucrOKTWVc1Qx1fxiI{ z^!`=L`GQBIXTq8!<&|naAv=KxdezY_fY8m3!dGs==QO)HxwFt)DCiEp;!qxZe#EfcPcIE<%KSPJPb|U`1wwu%sBr156 zPKM|rNl&$FhTW~P`_$8jYqQ1HW74R8iqT^V0 z&m}aWEN2i|xsJY&!^FZSCQu8%ei#=ue?ppN^y^P*!#(oXKDI{dJ7D8~q#9oLWZd-F zrXX=jd~!^UYnTUC8bGN2sB~SSjbOt?i80dDv9WR=Q3N;;(8KkQ;0)jlVel80fzR>MOqwMPC86Jza;6hHtumgw-#=# zZ6DZn8bF&>9@Lg>_cnTOh$mWwO+kYcz{{Wa^`Fd&(&Ko2R$InZq{xqH4 zAkQiZMi3ODc1%=^;$<}Z62WM5VbyYGl{Pu+_;~dGs>#8!ckA;?+}72@em>uqb=VR9 zJxSGyRP6q8&{YAcXmGV&Zyjc3KE+-nA2DLa??(isTS&PF)16FglhSxaYUdmkWKG@F zAy~-mBvd=>5Olk7V;bU#9b-)r!{y!UuNgP*WWVVhr%XCIfIfw7+cYdJjJCLfvT5rH zC5tzW=$sYEJvvmNf8=sovtf#ht% z-A>Eh&Ytv8y!V?Z#NhGJhRE5!Rqu?h0=S(gCjoKS=7tvT3U(=<1Y+eb(#|tGb?@Af zzF63*KE2$UgQ>Lgk3sTAl|ki?{(ReW?nI)k5Q1cPe=g^kzzIRpwofU~hdJ=qie*sF z@=hy~nuH`wrW#|!S@0ntvEy(Bp+ny#6QFTYOM237 zY^nITZ?sAb6cOWeEyd-ntiH+Py4k_n5zF zOX-*rY>B${Go-VoMhxmXl<>RLQvIGO9z!11tIise(Ae@n;qjb)t{((f&?F2L57al- z*xu&N%qx(w*F=&m$J2HY88+Mk=R>b{8j%+>^16OMu+J-1i4A_xcImNrya+~gy|Ey zC`Blr^U5GcP5(Q))VFOKrV>Jzf?*MtQ=q_xp|N-+=C4^;jQMm;7eo>M8*A*~1HSVu z=Kq2IQm{Bks*3AU8gerdVb{zsBI zn;3R(?eaOOU`2c|s-i%Twh_XmSqb9o2#;|VJw%6LLTGpJ^>4Q|U9F-J(jgT&zx#05 zYmY~l$(NPRsk<9(3w-t2^$$-DP+uuO#g_b{n0bi$;Hij&5^4Y2@92M*N~pTS3QO4R z?6aw5FBS3H+RA-LY+9+!u;E(U$;_T$44baf!+E8%R&OI90vhMx)2{<&th?Tgwie=K zN9q{G`(p(QjxW#ob&w`JenfmokFTvQr{{N}X_T?Rf#tqyhmu zE_*x&dk}o88}~^&v&q-cQ^igKvkK^&#jACUR+=2d z>9WR3+VQPCR7i4p*Dlz{tKqW2U$WHAPivB((dLEb_>H{a=&sZQf~$5nMGG zxY;MukyJ7TUj(f;^%kOV^cE>!kjjfCnlct)vWF^pl{T}rZ*g`YjoX*~NP|%j^NmvS zGI6ENoGY>+S&(q1U>X_CDkHklGW>OkqZNgy81ii9mQathHx_6S6K`%a>@w7NLnLd^UH{uWVgOt9Oxi zKoaXCgA4pCrNGDSvn{obqty#H#7!~OZwVU@@t#EzDTSAp+e8rg*2wBWAURJQ%JjO% z#&-118}{Da#XwVq-98Ib!Ym|&CFF}q* zqLUNS)m?2idwc?XuX2xcEIdxZ`AH&P9&0WMmp>h;>l~*B3^C6x7Anr=!{TJYw__DC z;Sa8t!7$**!P8{R3N2za@u-`J;g)W-33tI_H^EWpO*^{#+Y|Uuszb)3PPy=(Q%$Co z&yh@YV>Xa`42#^XVhGYHGnjgjaXNb|&%xZr%{K^CY#fx!BP*D1wFF$Iq-Qzw$dlSm zd6$8Cqi5RKkLS>PCe))HgWpN7wBZILpFe^XDxGJqppGyKK_?xRSl>DE==g;&&z>Oi zRsN`Htv|K(NN|55mt|KEW9`?}{!OAZ!RYx`o_A%LcWL*SC3!O@krX`em`E$Sl|$QT zHPVB9)Qs-`_Q?OfAGvF4K|Zr7FPD?e;ekFQugopZg&$zb8CF99`y#A@q8l0aTq*L^ zPK0a^wM{y?qhcg1N^$g6)arvHEX0m&Wby(%lk=IZ*dRs4>8_p6h5)BT`l|1{YOMk^@EkCFCLe*D^ z4~12Dy-WUY`(=Xj#~#_Y2WaQiX|{6)i0YobXdoFwCpc|Nqbe3WFnxuOgwhn5osfYP4h{PY~R=T+x8K<7Tj{Xm+4~Sfa)?GrBS<>Mj{7h>K0PLm_gR)8^iRp zho`7AR&gBqCIV#50=h+ny4`4FX{9!=7w-#|#Ym<8Ib{b|%jC7jkOiPG^$;l%VBxdl zWPih;M*oYisW%-fe0~#$vRt}jlDjn4_HCK?b(nBC9n%pyR2ow*Jr1vxSSi9uK&HLs zz044=KydqBIQ)H=ziM*=t?hFBWax%w16NcnyX+&{79Kx=wGWOo-zK{DW0t$1g_{O<4P44@8@SsiIEVx?^stf@_s+9VV+I(u_xYe%Sq0yu@L* zQR~%~$>aKkg8cZhCu_XQ_u6Im=Z3I~b86BhgOYwd9D5qWY0>N4`4W}VGW)%Fa{(ly zzPz(N(|v|uT65C*X5McAEbL&gP>2nm&dkPtT@hEz6*QkHp|}+`ZaX$Ts6Pp?_v0EyW#FNq-*{uGuT$gJu|ue@HBF-eiAy|KPc#C2irCdYbSnxo)Jn zQtX>8ZxOhaw5M{vbw4gbQ3Y}!a@ z(sXF1M7N!`h^$BVQ3| zA^6Sg)J&Bk5G!XIm?nLP$jdSP&U;8XMqLykg;D=3%f~fte`?;xB2h`E(uq!2P8W@q zirzh{3awc9JSdVj8Ok8*Rj88IU5IzLwL*^SG#}ZPo?ZA@6Oq4+{Cp5)trL57Cn%_pb{laJYaI2&PLSf`tQvf} zXu^ld<=}S>#JF=D{NSis_)X;1(#uSt9uN}C+;mC@#c+y>l8eQ^TdT^_UkkxJd5eh^ zX>ZXjWxx802ZMn;hq!TftXkA<7TYlxS zm5=S~e#NJ4<};Juwz)Owm>eOS-m%nL2}HSrwjhC^)uerl${`2mN4FA|5ymEw6_D)u zWXU1r55)^6>zuvqUV|A3V3X*DDZY)RqfAF}jKK}!U3mJIxf_E!r+3Qhf!*&9y$~-P9Si{=REa32#VL z2aKw8JHmB!Hqh@cl`1-CJt}I`_UW6EVcCzTUml^#mOn2afCb3CEMr?>N;bRAuu2(3xa8hWsoSw}|FU{Znj=R5Sefb5OupncZ*jM9Thz` zV8o7sWIM8=)996Q#RRlfi$qYVX-@aSD!sL`EIll(C7{fwN_cW|F>@HV$N$!p41T*^9Yvs*?xm63K zD=LYZL^3PV7n2%R-eFH4;I+HRbKDil6 zM8sgoh#*2ZqxliMh8;Vt9=|W9`(uqB1suy?4t}D3Jz^#jhtl!x1y|sA6MLi89bTD3 zIVvRWcsaWqlvl3>Bv3a=MwZ0(YL1Kuk-B_y7;cXOwNuAV-~K? zbL_D+C%L*S)50h&Nw33RZr7XMuldpxM*}Iz|0?2wd5~4sB-s!8T)C{3n7*>sR^0h+m$4IwLZ;KwoLnIMQZ%>yE2VX4*l*o%piL% z^xi@W%j9Ju)Xjtq>1hRGWOU~Q7uSrg;p5odzLTEH*O(#|NNTWZ?j~aF!FbQH#s;;) znMyl`1#zU?{}+YH=}Xnvw1DYSX8|xKL*Zj#1yU@@bpE4TcX~pYNOSmxPiL_7Y{qOX zmE%V<5nY$}FTUEX25ibE-W%7s*lkLG@ywCaK8b`Av8C4s68>b9>^1!}yaE4yQv5ca zfjGG&*4scxd92`iSd+}8r0=U>oc=b;R^O5QS9eA4Hf~couM@m=AK~@tyOQx*LYDi; z_c6kKoV1k~CiC%vv>%0SwgMYGIWwLd@oQXZl_8l|s&!WCbj_=<%q$ZQC>lN`$+NxS z`eP?(GY#uQc{y3H8SFdo{o=G*csZ6)NQyXrf_XDsv$Oy2yI_Xhn5gQa=Iesg&0WGn zj*xL@we1uSZyNUVAmhmjocz)O#}?%e>x=pN$#x}uS0oMklaT@@DOY+0lE$prv*Ji; zr2mUtxe(p)wl1mEC&In(WYn)_k>c*teR|$=%oKKzB1n zVvd*TFxZRjJ70_5?MX`pcMdO^>zS{vrsUhtIMMLL4dAX2T}eaT=1D)JX)Y035*fh6K* zF{cg|*aA#Ku>E_fQfo{Oh^P!An(t9#uCEHOp-9Oi8?U7O6n6x@+wjQt(JBHM4~dRF zP3OswY{F6w^G8AbBQFJ3np@5DMQvTAIto|ZD54{mrs91xDd(9SrXOBhz9+nTwJsyA zMK07SBV*sPXHV7;VNgtrQT8Q!7}>H7vZT7-eLmN9{qFDYasNLL zkD23~^Lo9W+hHXt8%zk1!Tp*t5!?!>cjMQ0bB85#xsq-;mln4g36hhVgYo9&wDqU; z2~|BGo5|h4XF3jPw<~!Q$OJYB@@A=KV`HXVF(WfcNsM0M?RhQ)h3_1r!$tC! z#NZ5IU|l=D29@4Oz6SIOa%e}K8d!T~S*VHdszbkGtB)HDwGwH!*eo`?@%o&Hf?j|q|1K~rdaN1p4G zdCL4`&WI0dr-K;XUNDrFw0n{F22PM%%J}RGV=a7aWjB~cjS_SbPifyDO%)jlV>9PQ z@R3}&1dDGiaO#^dL!JAgS?bfH41CQL50kHhv|^6SAj#~9UV~;_d}^30MUnTDM7i6U zWc@G*KE7!^?u~m{>v2zByB+d+uDoHQ%t}_OufREJ$F1!Vl7)CyUd1wTskE#M(VzGl zg_clhA3RRVk~m0e;k>RY?d9`{kR_8}tBNIht$~`?(kL!XWmO0*f*V@G7aiZT>$!@2alR72Lg%lIMZvKYNfo!Z zwg6ogElpn-{>FTIZeg_E3X5_LyQ`_&5{$4Sryi}?qqvKO4-s_BYQd<^5p)lT$~m?< z@(fg*d$o5IPng7GT;jH6LwJl;z0;Bf>DNuSljOONOs6Ky?>l2^r6y@7pZaY*Za+^2j^FByW&uO>L@%{hM2m!8V)a_bfk z`az_>_Fj3?4ZDWb8`5N-i#zI-1VtExVwl>K=m+0E3G9!fGYvnyW62r^jrWCZL%7Me z>6?zp?>7?+=OA&^d2WFuoa{PNQoS9oi!ZNI0m<0Ebu@>rzKSX(plpp4@h~~F6*(|= zTUOSnNdSqlAV5lT3EL5jieJ{bQ!u+uj)_u431zCo@_{5_ck~06;tm^ELz!4GP1{~i zPOHr-Fnj+#8%m>4kIf@b(ZZg;A^6R{{GI7J_Pfnok#~FL^9+S`M=VNhh-O(}yT3s% z6_H|Cp&4Hyw#;8OQQBiP-)Gm`XT>x5h)YcFTiC&?mC3;4yMkzr%FXr+jw$C~ldX~> zRDRU?VIIeSpTx@!+x98g^bbE4NdF+`Zc;u+GcpG3M7of=?>X{^%X1DlTWFgfmcDOdAYrlVS~PO-Fb%B_lkHgj68Qa zQ)a~v3Z_4e(GK)lXQE&Xal?{nxR8itl_kC_2g*ZfcIaf~#U2=c(F9YhP%r2YS|0@7 zTZ^pYXE1RHyd{TT1m0%gb{=KLXb(uyE(2EOctm}6f+12(7H$k+jRn#~Bhd8}~YA46sdxrRgC* z8W+;bzRr7pN^hH>Q4p7_qzeDAYxZ@K*tGjt&5y_H{+fcGES(8zV0qYegX<#9Xo&>s z_4TjET|y_hG)&>clNCsV<4pF z`w2!#)MY$OlVkdJjg;)8MlLJaCrTG+_dQMC+WH;0+4+`Ht_pWHBI-r-zKvB2DRs|f za(H?4{gvItSbN{ED;^tnvlSiE&X;(8eRz-iALx)eGV^Gphi2azyaOtO;|$F0bjx?X z8GVprT-H04B0y(Ob+b+uGBw3XA%@3E`NOc8i1 zlQO&TL*e4ZvC`W#e-#|x{)%hlnGcSX&KA!Y|LiihxgGECgm?n{TWG^i>6Jd(^8`fDw<@&CJNWGj&CdQTyPrrbe6Tx91U6$e(pv6T+7eWPM2s1*o_79y za3zsVGw>v~IDajl<<(Y~ay_UxI77XISZv_yyX~%yZ271eh*u#Km=mn|^uN`v7v}$J zrcM^&7sg|_EyQnd7hTUCAd^D)OgSJ{A@hyVsf#Vcp^OS=PgaFgWm>kG=5p(Q(;+8jq914ii3EzBmQMB0;}Rl@3j3oUni>#T6#iB&vq}(JwBT_>1Ui z^K$bh_eit^l?wv46s|%CVnISpEeXnWa)wlDHla7tngwa+?>J~<;m(m4)6iL}d^yS9 zwjY6}aHJ*iDV7Pk?(_U{!s9_%769C~pZFpEbSb4GR|~?JL>}FOC8G5-E%DIITLiib z{0q4S;k!;c#tQqkeZ2!I5C{HtKT#srAp0}5XrY$1e$;B(6e@45vh|MQp_p|?7Om%6 zOshsTI->FCU+Ktp%fSaEtq-uV83Qif4N@W#pmUbRmOWr#G-3sA2{>Ns&sq-ALU1i5 zYLZNBO^;ykBkx-+->AjyH71utTxxp%f+tPv|_`7+ETBX~#(4Ryrwim}zEZbhxA+#hK(W0;X&hNT$%;?>+R zdg0AyDr-Ec;8!Ga0DRuyVhT608aHwcLn>BWcip(f4ZY|omE(7k1Z~HqS#Tw*HSH$h zg{XdyvR{X(26qCKbU@sJ4RosW(5iF%ZFg(zKb-5o>_Uj310wEIHE6)A>-S=AMsu(=)@nCm)ety!a z>;7r6K(>qmyN_KfzH_eDc;KD#MbNeN{oPG*3}`1-nr{!~2hIVp!O1FjJRvyf$=C0F z>Fvi!uT|7fN#V1R)Ul&SD(24OpuGu#nC1^?z{)K#t~m#?oTr>{OpIP=Y;lzqo1?a1 zJ<)~*>nb!TR+|VXb=PCC-j$VW)*0G!e`oi&E+#R?&N>se71bZaa82->-W%u1m-RzF zuWUFBxc(trzpBqwcl2oS^fBNY25nJ3BVnV>8+isji5|_9891!ZdIUS;`ckK&h&4`x zL;RNWPeeHHRs#Rad@E_g8tn9*fuW zOCgsfkd|$;%)7S>>9OVyt^lgsx!+q0zqd{RMQ!-W&e_1ur_LX5YyEzVfzwxn-(vk7 z_Nv4T{{j-xU=EIja`1r9^G#EBpHuzS-(Lu-3($;2lYl03gS(b`YLE-g_ zS4AXE$F-;oX^TkNidBgPvx}s9WXZT(e&lcvU)?N@U(>ZaHF3ee zd)*#YodbS*8~L9yOAP2}6z+Pz+xr4~VS@D=v<|E2m?-nkbE{A&jPx|-qfeLBvnpO= zEoMWOu0>mIEQr~S<|9oZjNY~eePsarP3B7Ay(0`}h<;d`^JHkjQZpa2$0WMKLWZ0_HI4Vr(q z^Ifl2-PR`_gLe+}kr);D#9pgRi>;l+tzE3RYL6O;3IfWH@M!CZZ~KUQzuS&pdc4@2M4GfH=_|Q}7W{e>1#8={JHKpaN4oNoO8?~m2%FpZOuOAFo&tF~Y zJd@}Y3!~6OV~Wp6rPerBQc1$5+}0@9VqX^#wM%ln&yvw9sg)@hUC?Jlwb50>FwZAw z&2cZ7l?14nzVF#ZB&`rPLbkBL-O)r=}fUHg6;9zWsi$Em<96XQVRa`St%UF zThaFy3n0rrfr@K`SA=b5t`!^5IyBO_VSPEdqKw6rwmuU%(wiY3HhC1<#4N>YTD@b& zA{WN8a4IO_dhl?Vr>$I2(>9>DSr&W%$hIl!}aIE#nKd2M6kBi2Db{f;K2nQulXcpTRkbm*hAWvD9EXIFZNX z*&V(ZBA>Ml2c3kA=Mxjpjo~zgx$)``ck@pI8$Sq=Zn>)~@}<8$zcE&15Lm&39x;~* zxdxMC-x!prNH~2DcKvf#n~9F8xT)tKD$}12X%w^C8vJ26`gf24mbQm4#K=y^+A%h? zw4lwrgD`$_+$nx@)pyxwf_=PIg%I_wC)VV_!Oi7W#rC;=KdxGXRJK~n2PaC73<@Tc zMn5c@A?);Rz3T>8sYmg~nB-`}OtjtheY|pvDuc*5$1x@WA2OZ7vn3_R>V4=%IUa{p zE{>D@tdsTJx_G*^$G@S}m9%uRwIg=wjhA?jM3_#O&}_o`-Vaq7IZ z7(;Dwy+RB$FPvb-q|itHif&M&R0#fE$#Ob6O7Z9kFWUzbp4mPO-PHW8(&7g1R}?*F z!L2Q|3~7e85Ir(xlRNpctMI~ET3(KIDEj_Nq3GD9ykD#Od<{&+TShJ$q11;tKkC7J z|J;)Qmij!S&ZldJSObj85@GOOx&+~o>}@PbZIw*YNysWU4m8{q%nZ$EQq==q{+(0;-?hD!6fcz9<;>P$A}d25X*TrbsZCs1Ae*KgIFQye0jY%z<<1j z!RwP8g|h$$#FRBK&`6)=wc1J%TXP#ZrCd?%@z@*q>&mJi)w;2$W1Q*rH~TzHYOD=S z=h3PgRh=n`a>!eKX-W!fr4i$%&*?Y2LH|{nRRh)p{R{F0)-PQB(Sawo6B?9yo=iR- zSq0R|9#X47=tI1fqf_AX4}$}jF5<6b1reUQ7U?nWE$#Y?f29jy<$$Ju4Vusb$Esq~J9fL|yQ=gxGC;fbY$rV3|MnNKom?{G88BqABS@+Jtx;Ir)EncTePPbi5ns>YUVkb6&q<0)7_04@n-p2p z#tb4HBQ5wB`PZYn*1vIk>ecM$RD7(rx z_kevTuTCc$@(i>~+MVB3%~GBAOw=mykYBfs7y!DV{byT^tXgROaSP27E;J@rFy*$U z-&yo86)1Al;qhZP{44v>`v`m5FVT>L>VmurZGd^8uIC|3-9pLQokFIU5it;lu?aw} z?&$b;edtH+?>hJf#}9|n`(Am~t%IfKZi680tNe~z-}f8$Gn&rF?_~;XCiHauT5#vS zeM%I+Y9j4-Z2N}8GZkK&{U8;lj+HC^wO?jdejRDrx7BU1Jk)BG;rh=vDYTdSN7T;9 zr5NmFRc5qjc8Y zy`?YA1)km?C78uhh{WyM5t$6HM<=lb!~ydP=uB;%y%sI=Q07jO9yx9FQ3zh}S(!}kYN4kQaZ*qc4yK+N`6Fjm#=uN_ETks z9Z{se{PUKGNWY9aDiUh!iSD;*Ev6|MY$t40Ht5IHPvEI-e@;*O(QY1gR$!79Lnmzl z26+P47XKk>fN0UZGoaHSI@_qM;pU9VIB$WOJz2FIiZ|^dW-1<*7F@I1Y_075yG5^+ zMf}y(@qh9-JW?bR&d#dY%GEM$0;if1I&F`K3dF+gBu>kuq)-6j(<5TF>3-6*V#`_b zaIfhnen7Y@2=DlzAKFp9jnPL)-j{EALR(~7;dDYrP4QiNvFQcyW-)`xr=yrNqUk(& zB~RG{udNsYXLoEHeT+8bCVEu1R{wO8OW`e$P{F3~$S$cXW|80i6fTfws;NOWq$PV$ zXLbuGgXD&dxhg8hs!vULHg47v%mr-UXDh#JYBR9DnBWo}ytR1a>G#M~s`j^;-o*Zl zU^Gp?@kJq)EMj-R^Z91-YY7))i1psN3Kp-;)r)H?(OfJWw-1-NmyoyG|Ki(FB4nMy9!F^b`J>v-Cu}70rYp4A^=ag-0TE0yu42>O`g?p{% z2Zg%2(V;$0Gz9txn$MMd53R*{dwsL8kv{w~@z=TJE8eso0H9-?h)L9Q#o*~$n1c~l zG+_vaqI)fap>@Pk%fybhC^S*Si+->AuI6UM-+z}WCb2ro$)N1}xnW7MTPQb}#0L!Q z<_sxmg584>Dq^dLypj!5OPr8M2z=iLmVYaH>b5FxqBYdwevrKE0FA16(lu{XMWiE+ zaA7c2jfaUx?&slCUfC|6jL3+0-|6~Y5Tw$x&}3FQYI6p-_YW5GH|*tlAG15$s(#8% z$0tiay4+A(dlV2Ro`Qqi5D zMzZxoDnWE*ZIUXtvZlZgU}$RGcFK7Ug7!@50u2S1;t$AjHj&lw+j8#V%~=njvmtm1o&gQyiUvanlO!26LVo+?XspejW-pnt z!sJKpxtau`OJu_Ig)CG56P@zqNbBUnfh4Du!A84ZIQMI;kw0durP|&GO|;8IUUZ`v zWQ0H0`dQ2HL1Cz71V>Ika(_E2+!lC=-_$B=Vxp;eVSppx=Y&s4H>-AM5%dm@aNX-B z%|{gt%y0x_hkK>LJUndEif8S**5CEawFERYL@yU;)22iqg5%^F&|!h?BV?YDxK+D{ z_|9o2a&L`@zr#w@hWlbJseST+DlpQrQwFK4hmvr=wmf&}sMUn4_>lJ^AGGB#8eV=_;$YBAH4VSI6VB{O(&4?LWgJLY9DZHDCk>}zkJ zb~WKlgUas$Nurg=tK^OuyP4^>?xw1y*?J7FIVK~&BG|TFK7&uRa>$vc?m1XcF^4B& zn#pC5q-)oDy!$3_Bq9Iqpcu-Pdb{(_XPdm!5_-hJklKC>Pv|k2^-t8guxHTBOcMbg zVS{ibe5M6vm(A*C_rp|S`Pxwx0iD~h%hA*(zs#opp7Y=L?*huzf{QeOc+f2om`N5u z#ef~_qeMD$A``{?N@#BK1I}N3Fao{!D=ZQRC#z?m#8~N{3`iw1IglHaem3+fF+Edn z;mINkW`3&5OfGjjmEflH)y5K(4RG!I3GZBBUI=6eo^VAQr$c|T(b(h)$zQs5V;ynpGqkPffO)RS>vf?5Lp2EHX+o`{ zU%zOx|JEti1<_!2FJz~EaO>sHY`{WgtN(HQ0xD!R{Bp8tZjwMq^lIP!BKyFt`Uv$D zpf%G^O6uqE#I2*U>G1!aVKd+iFLS72QRZ~7<7^~d0+56E^AdYb>Ce|2V9tMXSVbj* z?fB2FtDwLZ6q4QUkDeC}Wb^-7>BHOYQ@8inyn=M$iDs9dv2aydV`ju>PT(L4HfrCK(F!jvu8&qR5NtTfL28( zPs(9zNL*pyp~J-`2m|5W7F zWI`*ydaNSmS*v)wV6MlKP?#_CcBtal=b)DIU|-XoQ)u(=N=7`^Q z91N8URwj0|FkCP>+NU#^{em+hi~xq4cAGycBJis*H_$XHlH0ibsX5=f6F0L$q2&VJ zw_%%V)e8nd13A}ODm}MwP$nHP8Tx1EPl(s*-Qqad->D|r^^My<2+9RYnUXF~YQx`x zi0DaAZPka}Hg`(+8 zwQ<1Ia0am$R+tPyACy-27wp1oO?V=sVi>eZ>kgdBoQFiKo|(J-+#?lqESXr+-Db3? zqiG>71iyACn7M>sSN7X-f_(mTyZA2HGUtv#yK{Al#zI*M8rA;f-df1Pn&_O*GsJmM zmM`v_O|Gh)A&y^ZY6tug+g>hyrjfiOdyX}``g5W1I>~{l`}S zGBXj;Ag+0=^MQVF$*T@Qh1$!t$dDbq^CrciN$UAcxgs?l;Eq5l%kD=2x?qaNW@yN= z9%D{a7Ai zc}@tJaX0NeH5WX6QJ>vxXR6x(8(d{u{og%V7YcOx@E?H4n91x=4*QYkvQlc&>EdEV zyH1F0W%P=dQLHgN+U2=O;Jr$xYhzn6VVGtO+8^M&55DHcRxj-c~dM8>-IDVNAL+ z^ky9!&>c%Xj!Ot|6c?4;P7S(Qs3OYH?9I1jR${!?q=`5CM+6>FX9;%b^Q+~xUZ()G3-6|{2dS0KOvDn38J|6HkMaGzdR9W3G4G{G%j`OVdJUW;D#MBJUeeycU5 zz$YE`Z0)`|M?2>^i|sqm(YJ>zTBbOsrsDpX+~7_<>ljh;O~5tL;!c*;B%FwsU3}!3 zw0bAu3OMIKKlk7%OT4Kseo z1|B?Q>v2SC+7pDkpS{Pd+9sF~Vgi4OZQ3gIY0kN22B$RzdyL(k&SqHoC2@&3iy0;Z zS5SCGlQix_GkrnxA$D5XYe^;?>;AW{=}|e(uDn^r3y&k5YiSxw?Z2y-BWf^&yi8~)1!pa`JG^K2rB&L0 za|hWf0KufnP=nyAir!A2DcaXkgi0hO+e=jv@Qy?4>lZzow6B$f4|Ih*h!?%58k-}4<^|!M zHvG(tJmzK~GDzjdb-!Y6O_R|@dgWlJUf&y49{A=9;FuR}O4r2c0DhoRU2bBgVR^1= zelZej)(wU&aRq)2r)s;cfygxsCExAsZRmLO&uzR8&`GCJjv>L&2{6ow`n)4h;K@ef zN!T#OmJif?LUfN5#Xbyu<8W9K&p`0fNjQXa?nb^7$YfJR*s>ur*>pJ3{f5`-*FN(? zDakpXAM_f&OjtbZr)Bn5W_{KZp<n1>B_wgTLTP_PZ&F`^r=->@ z+<=JheSbyk^*$^R;ze9zf$Z7t)!dNZxeQlfbN&=SEKxJ^)+)iJ>&sb{j5q)BEny@- zO4>H4N*4;8oRbV!i3Lc5S!FC~Pts=lXS>jJJ$4L~pkD>w+V=zs(Xrj2H z@kAosjJY_N$^c=H3nm*sa59!b6YW@_Cn@Xs-n`xiwVOes0Nj$@`-MQD$FHl|CbYzy5f7{y9^$il}n3Uu)Lmo5>4a>_hT?jY6-#O0|ZKD<3MZ@ zU(a+v3rY|rMeL?thVjMd*%L1CF&R!6;Hhbr=Zv{qZzv@iE8f{OzvitcOwK3exSi-} z*%XjzVMRgfFcV}XRSOdvlSK7(dJAIW!&kz7n4wo{7xmeh*jDZ;+FoxRVS%Y`tKM1> z^T0W8)DJqQt&7#K7gqaG&I|bQCrI7?{NRyzVlyVQYmkZJ9|B)hhs!{m)^Kk;n(batSmSy1&4Nu-8*QxGgFfQWk%H4}V5i@q~mw z*DI5wlag=j{GvJtl8IQ{Q->&RLm4a_@iWgrPVr33@kZ1xpV-}3hVKn?SQP6{fMa`K zv;lb|ZfaZH%;CPgNIIow;e;fWRlUk#i+6J8NPR~mC`|%Ex<}`P+~4b%el`5Lrp~(?oAC6`WOG6DrEH5WivHn)nnTmbNS`i+&T!45Y!1bX-eSS!-fY9UxShu-qz1dOJ(D zEg0}aiMBBatN82lrIZacXBhWr&;975A?{knz-^}#olj1epwAFi2(L2oBTt(OH#=?@ z<}vMm0t4);Oc?(Q$A0+IbQz{oFb4*%3?tQ;ul7q2ta*ii20iV63|#+Ublo+v#y_?S z9szJIAYjiAH+8+S(w-Winrm9IoOZA5tS-|(MXK$Wzp&#~5!3t#3=rP&@ymZeD8MB6 zSI;xYTka(0CjPOqJkU(Tm9*lnpvzSriL8H*vfwhje1`D0Q}iqO7cZU^GDt5nm!-tlunO-gRM>)OKrD}M+2b@Nr@m`SgVcYgO4{0e3x zXS|h=)*F(TI}E0cR#n!ZnolbZXnX%}7MwOsra}!FN@+U=ua=K&7(X6Wa!$b03mhx< zWnR5>km;lkfA#(UmL#Bm&H$$`4;8K=Rx{h4 zwmR0*I?ar1^pCLF1+Ra7DGB@tH7pp)A0c?-Dql?<9?;_vb8VcOQ{M`n*qV==r^u}S z&RZk8Aj_r&-ccTqe-05eL=EUZPxf^Wl7kCypHM41om>}|uR14GU)?T%bVLhFw5!P3 zlW)?$trsv@-!o>cSV${O+YBZ0Tc75h&P@WWh?uJhn}5@kw_z>3BS;H0l8xJXqMLI$ zHPJV;PcX-JIF{~Dl(1S?FRua4XZX$jiz_Y$ee(0XC#O8Wiep-LX`S0ReIE-V6L%=7 zH6>@gdQF>?i~r_T;Ya2N~IqfgGYt8-H}bw_X6mW9Li)NV_}?6Ge&9z<`P( z=PV&^g@8i=D}rTm#Sc=oZz zZav172^#XNhr=^_A!x^^dCp33t$oc!Z0b?wB3q-MatM%0G{;pTnGpZq!U1H-xbXyr zexSAeqF>HcAN_Ls%O(;$_2oXW|A6T~684Br5&Dr@0z<8?ILS1UVp^uZ44_7P!$6ih z&-@yeGupzEGRgkI0a%Ap!IoS7In#9x6@t)bEPOeCKZ3L5g=gfj7oZ}HW_7)fU^ke* z5o3^&Zd$bhsS-e5%eLO5JJ^;OSmI?NI!R|xTx;j*ry}P`MQY~V$oWIaaaE{a&t&Od zSI;=rM1q6-UMGw*T97p<$LwVD%Jj6tyIIoBZTQ>_I$5a-RV>q_w}h zHJy!C4~!_`q~d|~R}7pJ6{2IZ7DVyJ43WS`&_fkNZ~SVDN%O`tTVf*rt_Yf8EF#eC z2vaQStNJu*RR6TSMt6qsfC;)4I$;s_$9aKsv%4+ocTMf&qABl6MfW8AvU!e<+e4YR z_cFkxo)0*uF*dH32W8;jaSB>A5%{NY2MChxdUxjFQxddz8|GAo!fQN630g}KmY_^p z%4P0J*N^sB0$*@a!^;nnCC{m(a4*at6?g+}7$`^4FEo zvXFcZKW&c=m(@Gl2;uzr;D!Y274`h8iV?+WJ;Y&gbz|%kCu0SO&xxXS-i``D=MvAs zZ^Nd2|69Le?qZB(o80j=l2L4li>iR?2khXvJ-@_W85|OV0mHC0b1VfgRzV&sjfa3W z^_=%?CZqSFk_`xo%;NMyUjsp10n&YLU4*CHasMLVegILq_9@>}tt01~mTQ74ycs!t!bxct(`L9s$bEDl!^nToMsUNAB8-B9>%t#n_k@W``I5Tq8JjgAAq z=Zf-6Qr@B7wh#wA3Y>0g4}zoMvDQ#)geZZY znJ@47Hxx2uU;c@#-nf=`DmG(ifsdt%%RdZ+x<~2>gt8X*Cvv*3b*V*ZrIdO!4B1&# z(0Y&SCO8`T%N;7zQqljL+w;H4QKvw`iMLjsT=D+P*EcM%3&?b)LI0x>VNk8MD`sv` zVclD7amwE=I->5)nNG2lU7Y5hw8Amtd!m&FcEscWVx!*tTW*M+a~|C~OrZIeX)K{; zWgPx!Dk+d#$Fy9`Pygp|UsxplVnzA&{^LUlW(DuZ$~F%={aT`Z<~EgChgM z|DX8j8lWV3!2q}jmQ7uA>V&Hc?FH9(b5xxs;sGEi_?#>Lp&<}l@b9Mp=H5?G@h+GH zaSe7YrlJU9NND9vM2biO0{h~6Pbr5+x&K!uek0_^Pzy(W&zfFTbn}bpuCGFU$r_te zv1SWyGVR0v1|t0L@8$qq|E1kW_pGg$BMWzx@3Gt33c7EJ_C1>)F*WV^yj|6Sx=r+T z&b6LIXUg4R`Es%{n}^>@H7^r#&NyUg*X1(t^mkcVu2DnNMKRjHa?eO^(3_JI`Tvp@ zIK&TAqOe!yw;?lM-7Nxi4r6s>%V(a8&1OmZ$@M74d4G@!oTRI%UTms>a;=z;<_)I; zl=AyHxBe#g10YU*&CNVLXrQexmU#OEL=3I9{GH3*Uw+EAh7)mnU{`4LbmtS->gt!* z9-Hrq&w=PpM#4h}9x}6y<+y*__z4gR;~>h`hLe@)|vmw>;DJu z=wmsP2&kEqt^0~pobaWABClHsK0chFd!cv6LiRYnWR50t5mz5`BWKWx0|R}%4?fyQ za%E`MG`N#RZ;?JU_u*+_PsA4XigH>L&S#o46!U9xAKc$v(Kn}})G25PO7Ymc`c>Lr zZs@4mGsI2va(eHHBH8aZBReLQf-0GMl60aGi4VY(91qMIdy+7TF9_WhS_l({X7xtU z>tLe^1v#h~HS05^Ao^8t_E7pz0!d5F91ZnY`YG}}h*-oh<~;rB*H})VUr*AXjmI}? zqrHHRgV-^J8Q%E+*oA;_@9D1i5WrJggnoPGa;fD>r{qMOjyzBYfNZR9sUQO@Bp4Nw z+a<#3s(g-_joo1=ncW@}`GiV@Tq7fz#il*4rGegnn>>5E(!lHMr_5WFVw#p`G8eF& zAc+$q_i2wIWXNR^h-4}!st-m;FA$?^S}dF1+z2hI5yVvz?QxxWJWJy>CzxlLHtwrW5O^ zP!dVmWC?bhI#%2<+fY$_Nqa}Bmcrpa5wqx$+rNWO?(+%10%0bc%fi7SAVSOmj$`DN zxw93 zVYT@KO~oqF%k1jvYegamLtr0DCRgS<^_lV<`J50maP}xi&;7OMylCLK-*_D-KoR~;4*Xv$1H?g!QXcxq*FU`{{+)2y zF!rZb$~wQ>BT#mS5F32?5?|aR@)_6-jt0U<;Lg$aAxs@gJ@Qu__zgzlbn_ce>Ri`P zc7+-7m;{^!j;E}VpsaU_Np`y^xLL6lDr%RFxmIyF zQ)!A(bndV|q7~BYXLDO5CJ$pgCCve|p$kue zDF=<|?uP1Rv7Z*+mg`EoWXrd=W?ZJhxt3{zN>)*Fojpq850e`S*L=nAC{&IEG|d|a zssjY?#Nd|{7G+&$ngqO>-e!GCD4{On=4N*h3%k?xsv3&Zq49d6KyWKKlHvhNK0+~l2?@T`c z70>a_vv0a*d)bJM3GNum#!o!i{f{#9-+~qo-a20@U1HyER9o%ADD{61`6PbL*V0k) zDr}ne&e@Rfpluyn%O+poW{OX%V^-jrTV;FWVrbF7X1M>Lv;ZC5P@dJh_T2rF($%{6 zme(tN{^I&*Lr;rAOOMzuA2+t3E}^ zGgXl&=OMcPCUGkh?VTIN*$D*mvYQjPM{CERe|~OHqJON|^;Z8`&9+@h=#gu`bT-g? zS#}^K?nD&G@O;Jj)}#Ew!4Q?3gYORum%*^m%|Cz_`d2$c!G)eQA)*nKqV~^!H!uKD ziNJ357OG8J`)ri}5dtxcJXs6=GgUKPHVb0QzO=fXA|&q>+j zdCnSK?$dU*7CFm%A9C3_aFWa-Hc!1md>g@(T8k?&4s8__TRaeG@bqeQTj|$cB&t%` zia2R2`mrm|Puf=2h;d-mYRJRpzbag2esJXrVLg;tf9bTZzeM;F_Aacre(O3VvZ&Xb z@(M4Y`_HFumw!LmtwnfqDo;OW#6RQ2?aa;3p_Ghhtul-xk#A$pZ_kUWtzu6nf z3vpr{CCfrMWQ^_UNG4ZUL)HZ+yMVdFeZZCSYmQewZ4&5mQ+u@*+06v`Cv`!!;~49Vj+9dR_4HHSUnSTImp|!Bhc6YQbW?ZM{-3U{JRZvJ z|KCztY)Keo5Lrs5kbOxqxMgd&h#@o~A_zzi0UMeffURU+0f=&U2nK=X~Zl=e!rOsf;^_SaBHKKsS0O7EPUTHRk2(1k}X9 zqa31~q-t_;Rn?9%@0FgGsg>o1rP*TQC2i3Sd`kR`2(2rovH~O+(|?FcZC0*v^?3M> zT>M`{yKLiuL+;?klOGPuQ)XiF1!Et~E1pW^0JjGulodB)B2-mO?=(Mqa`Lr~-#94+ z8pMi9d8Xs@UB#fqg(YzEoLJA(=a=8G%WfH%uBKZ~imS8B!=Fn)%Qcp}AS5Rhr^f>K zD-E(ECGrXiGy){AuQh%zM};(DKYjK+Q>?KfdBPGLBq}zU1|1BS_qnZd?s`7WLTRdq zc;qR2BVE!+Am$cT5&%=^e|lQ*YjCm7`wfixI*B_g&03&I{N^yBE?Cvn2mj?bWXSA} zyAFR~*TqJIEa|G0#d^i1R~e{)^GR+p(FoUuYkLtfYocrhz-TD)faoboBOcO}==z>_!( zivAi#%h&W?MGjuKZtC=PU~F-1iAfK>-3G$}$cN6D)}xWzQRbW9Kh5#MBuwV(o8EC44J56A z#MD-7^J-wbh=DwAlg#p~HM5sWigd+CKXCVCI$!97uH6zodxW`nyy(u<0Q}G1v3F6t z3_y`Kibku)zYr(_iL<7U>B&ba3=i~h_Ed@_9}<_An~(;xppO1vw~qy}=!Y3RA3YU? z=YvH5gWdwUS+h>1)m7(62qbvh)9^{C3-=CTTI=sdU3Aqgz0JDynty|*j$kOb5*7c} zZlc=|p1$Ii;TkD#JY%HZ4{jS*rj~pwPQSDOC|B3aW+@^_GB(FkHToP3ZvRAk=fkH& z_!cnDRkFXvw^D<13wi-9;axc>LG#N~>G zXP~~UO>>8U<$(Gtj%#d@jmJS4&=^RX_fUdIf33uDj=5lmyixry$~ZvAJ`<$1OZF{p zg$PNNJ@7OW&=>S>;?|}m=52^L2(*tf(y+#sF(~O8^-!u!i`0jbVsbz|z3p5z`^{>3 z2#qkpx5AA%Wx4WU;$4SOo42$6tL4g__Ob%4_Mn?;4hZXBKV-m~M4cq2;ItGEwyB=H zR-=?&;SVTU?`{9$EaJ>)^G_t9?7d};g-VK3A9v5w#@XQ;c^8*B@-CLRSyO8;0f^yR zfLCcu40VmEC)0K1$(tX)A;#C95{aP>xcjyNsb3kcRPq;U_l+6DB8~`_0z`3!J)y*!vj)X_|>l?sJx9S6)0ege1 ze6WwbLb+O+Tqm3NzN4A?`g{FNwutMFy9(75-ZIbe1cZ>;@Kr_dvEUu~3A8vfUEKziD|hBg-5OmWh5OeH zd)f*t+Ub9Bik|FcK2i}R1s!67_mvW`;2}Qr=O$X~{@qtIkGL0eF<5E;=~xa@F$M#g zoP$Dh``0>*uWuTGvyd-5;=oG+A6ro%xVK?!cN|qumqou}^*>JoPFIe3C3d&67{qo5 z?hVmnp2pc{smGEoWhz{Lq$rz=@!C6pas^cV)E>cHO}Rv;eDB1jL?|gL7ID>v^E;ZG zVEb6~NzOukP|ady{3+GGT>Hx(VD3?9ts&~`<)YB9c_@Gx{q<-qr+oqa=~m#(R?n6m zi9zYCD~(*%8>Un&+IKN3m-rQIw^8d6spIyKzCN|t2)*g%wGjSu5SIk@382sM+ z$nruW&y+3RHf{F?T544bgWZ&BS6>RKskEHa+bz@NQ~PJ36i>ck1G%^U(V{K<`l$R) zoZp%djB7rynalmpC7JNH~UIl_{yK*WFeI~t)Wtdx&4v(J=CYM3zM-#7q8=4 z*U?{iN&hY$uI=YUSn2BOaxn7e_4(~SZ{D{R*CV%dz1V}nmlwvRXng|2u%+D+BC_yi z9XnPbT-Q` zoXvWqi?U*0<>25@7h~jw1ivvf({v#)${hmN5}l_&)0NDMRKR#efD#>>QX3>n1RZsn zER-||m3WQ8I5@L&zY6*SOl;3tq4u`-`=B~N7>w48E9(RsI3A&Xsb<%C;NoJ%fy{nG zx7EC>IL{e6@q*_0dt&(wM1cAxM!Hn|fA)jY3y;kP-E{?ubIob>D_befgF`1QRSf`# za|<7G^&Iw$prD{1mww6*y>Cuw$TVFiy8-)+?@s2<)v^z!=%$>@p`Kr14t1-8B_ZoP zbc=jOo3r-&B>BEjm*dFr%#-wVV%Rin+JfjdC}t;Kbr@2!W;o=>B^T2kTrc>~6L<&G zs^Pv)op_(ee%dn zoLfdV45-KZgjS5&NTnfq=j5FE`^L!8WwIR}gJGUs)_Z5!*fc-~}XQqk2Y@0?>3q zIs^NTUcf8^N?Sj-0q)TJG!L0hK0MGF)SpF(0S6Th9kv>^=O^@yHRw+>{WWGR;YbT& zDKZnOLn8T)hWY?@>xjQQ0pNjJc#HZ-w?I;Dj4yn-dVAV)XL@_K+a^f>z2Mb<$W7O7 zIfB0f@TyV%)~QCGci$i$T?n5_H+cz&i_oX_lWeQkE8o%w7#pM7;T=9{k~jbx93JV4?=lSFxh z7d7L0Mm{pY5BL47V7zjg;I$qRl!F5{G)X+AL85~vX21=G#2NJQrJd|5ygpc&a_TIJSs!9%w?WaM^%#?)-FVPl1#nt$-wyFbut zxl;a6-DB-O-lvmV+jr%Y-M13H2+29(IG4;xs0YIV6N$pyHj;}TIu&0n?B6WC6PimH zGXOFrZ0L_d9-lEWk1gCy*$K}NRZAE;U0xP~l~gTOIyuBs3i}hAUiC?RE5S{_d{ zgUk5W$1C4yAxClpUqd?U5h(ay8vaA{>mqGC=IbA7y}BS(js2@vJu=yUJm5N(mLm=d9X@A%Wr@)^Zd>l*W%x=2f|HdD^Qt2%?6EIWtA^hbWWVJ{!; zP$M@=@#f#q_=EZJUQ%fjpqO7$6#ybH%amp#E&q8v&oV@BX$6VjpsJWA>C!7UD>2NJ zeU{3dI~99dSC?gZm>BA8ecOBj@B;F5aRHPz2$5^@N0^Z=kid9gef!9FCqh?O*Q1lB zT>U`I?8Pp|gfjmlF_^J4Sa7wFpkRM|WoP1^T~%~6OH|M`pqU@SbG0932L*vhx}Tg} zzz6bs)tMa`1H^ZLP`Q^>qAQx2%`(#%2*8EyXaA=R^S^vQC1Ktjs5^Zif3OTQnE&pA z+kv`)2l5BY9O&A??yLBAsLpt>Wga#O8CM;u&wmUAtXr!;I_3KuVAnE~-Y>4dy+u#q zdgw@6aL$-3l_|CFYzQNg!qQ!}SDzRaRWW2?!b(Ti$$`@3#jZr<5k=Shd-fqK=PBw- zA?w@qY><~4CC(ZX8598Gf4?Wh9Ib)g`evWGHf9>lCinT#9x;!pmDnSn5(+R#0C4}7 zOe*Tvvx~)I9_Bj+FG+?e&ortr`As5ssP@k n)c2dAfqWV~uxZ#v-Y!=zYQW~>6O_jvKr+-bzEOPrZp8lqQEqY1 literal 0 HcmV?d00001 diff --git a/docs/src/working_with_yarn_slinger/yarn_files/nodes.md b/docs/src/working_with_yarn_slinger/yarn_files/nodes.md index 5d766914..76c658f3 100644 --- a/docs/src/working_with_yarn_slinger/yarn_files/nodes.md +++ b/docs/src/working_with_yarn_slinger/yarn_files/nodes.md @@ -1,3 +1,49 @@ # Nodes -TODO +In the last chapters, we have so far only used a single node named "Start". +We will now use multiple nodes and `jump` between them to compose a more complex dialogue: + +```text +title: Start +--- +Ferris: Say, do you want to go on an adventure? +-> Aye aye! + Ferris: Great, let's go! + <> +-> No thanks. + Ferris: Okay, that's fine. + <> +=== + +title: Adventure +--- +Narrator: And so, the two friends went on an adventure. +Dictionary: timeskip (pl. timeskips)(fandom slang): An instance of fast-forwarding a substantial amount of time, such as years or decades, as a narrative device in a story, quickly aging characters and developing events. +Ferris: Wow, that was a great adventure! +<> +=== + +title: GoodBye +--- +Narrator: And everyone lived happily ever after. +=== +``` + +Here we've got three nodes: "Start", "Adventure", and "GoodBye". We jump between them using the `jump` command. +You can see that we always arrive at the node "GoodBye", but optionally go through the node "Adventure" first. +If you're editing your Yarn file using Visual Studio Code and have the Yarn Spinner extension installed, +you can display this flow in a graph by clicking the "Show Graph" button in the upper right corner, which will show you something like this: +![graph.png](graph.png) + +It is allowed to jump to your current node: +```text +title: Start +--- +Ferris: Say, do you want to go on an adventure? +-> Aye aye! + Ferris: Great, let's go! +-> No thanks. + Ferris: Pretty please? + <> +=== +``` diff --git a/docs/src/working_with_yarn_slinger/yarn_files/options.md b/docs/src/working_with_yarn_slinger/yarn_files/options.md index 6e36c408..ce191ac2 100644 --- a/docs/src/working_with_yarn_slinger/yarn_files/options.md +++ b/docs/src/working_with_yarn_slinger/yarn_files/options.md @@ -25,7 +25,22 @@ Ferris: So, how's life these days? === ``` In this example, the character "Ferris" will only answer with "That's great to hear!" if the player chooses the first option. -You can also next options inside of each other: +This can also be used to conditionally set variables: + +```text +title: Start +--- +Ferris: So, how's life these days? +<> +-> Pretty good, actually. + <> +-> Could be better. + <> +Ferris: I see. So you're feeling {$mood}? +=== +``` + +You can also nest options within options: ```text title: Start --- From 90b11ba671135a0151d888d21c07b4d81545bcd8 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 22 Jun 2023 23:35:26 +0200 Subject: [PATCH 02/17] Finish writing about yarn files --- docs/src/SUMMARY.md | 1 + .../bevy_plugin/dialog_views.md | 3 +++ .../yarn_files/apples.png | Bin 0 -> 54327 bytes .../yarn_files/commands.md | 24 +++++++++++++++++- .../yarn_files/options.md | 6 ++++- .../yarn_files/variables.md | 23 +++++++++++++++++ 6 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 docs/src/working_with_yarn_slinger/bevy_plugin/dialog_views.md create mode 100644 docs/src/working_with_yarn_slinger/yarn_files/apples.png diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 8b405d97..d00b8f7b 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -13,5 +13,6 @@ - [Bevy Plugin](./working_with_yarn_slinger/bevy_plugin.md) - [Custom Functions](./working_with_yarn_slinger/bevy_plugin/custom_functions.md) - [Custom Commands](./working_with_yarn_slinger/bevy_plugin/custom_commands.md) + - [Dialog Views](./working_with_yarn_slinger/bevy_plugin/dialog_views.md) - [Differences to Yarn Spinner for Unity](./differences_to_yarn_spinner_for_unity.md) - [Porting Yarn Slinger](./porting_yarn_slinger.md) diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/dialog_views.md b/docs/src/working_with_yarn_slinger/bevy_plugin/dialog_views.md new file mode 100644 index 00000000..262383ec --- /dev/null +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/dialog_views.md @@ -0,0 +1,3 @@ +# Dialog Views + +TODO diff --git a/docs/src/working_with_yarn_slinger/yarn_files/apples.png b/docs/src/working_with_yarn_slinger/yarn_files/apples.png new file mode 100644 index 0000000000000000000000000000000000000000..7dca3343cbe2f731bc9af3c9a28351e23370a85c GIT binary patch literal 54327 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 b9nzjr^%L37aehn#{@qpAy>` syntax a couple of times now. +Everything that happens between the double angle brackets (`<<` & `>>`) is called a *command*. + +Commands serve either fundamental operations such as declaring new [variables](variables.md) or instructing the game engine to +manipulate the world somehow. A command takes up an entire line. +In contrast to [functions](functions.md), commands return no value and can thus not be used within lines via interpolation. + +Defining your own commands is specific to the game engine used. +For Bevy, see the chapter [Custom Commands](../bevy_plugin/custom_commands.md). + +The following commands are available by default in all game engines: + +## Variables +- `<>`: Creates a new variable and initializes it with a value. +- `<>`: Assigns a new value to an existing variable. + +## Flow control +- `<>` / `<>` / `<>` / `<>`: Executes lines conditionally. In [options](options.md), place `<>` at the end of the line. +- `<>`: Immediately ends the dialog as if it ran out of lines. + +## Engine communication +- `<>`: Waits for `$seconds` seconds before continuing the dialog, e.g. `wait 3.5` will wait for 3.5 seconds. +This will not block the game engine, so the rest of the game can continue running in the meantime, presumably without the player gaining control. diff --git a/docs/src/working_with_yarn_slinger/yarn_files/options.md b/docs/src/working_with_yarn_slinger/yarn_files/options.md index ce191ac2..714d9b2d 100644 --- a/docs/src/working_with_yarn_slinger/yarn_files/options.md +++ b/docs/src/working_with_yarn_slinger/yarn_files/options.md @@ -70,7 +70,7 @@ Shopkeeper: Here you go! === ``` -Finally, boolean variables can be used to determine whether an option should be available or not: +Finally, boolean [variables](variables.md) can be used to determine whether an option should be available or not: ```text title: Start --- @@ -85,3 +85,7 @@ Shopkeeper: Welcome to my shop! What can I do for you? The above file will result in the following dialogue window: ![cond_options.png](cond_options.png) + +Keeping the disabled options hidden is the behavior of the [dialogue view](../bevy_plugin/dialog_views.md) used here, +but these options are delivered to the view, which means you could still show them to the user +in e.g. a greyed-out state. diff --git a/docs/src/working_with_yarn_slinger/yarn_files/variables.md b/docs/src/working_with_yarn_slinger/yarn_files/variables.md index cc123100..ec1305dc 100644 --- a/docs/src/working_with_yarn_slinger/yarn_files/variables.md +++ b/docs/src/working_with_yarn_slinger/yarn_files/variables.md @@ -37,9 +37,32 @@ Ferris: Hello, {name}! Wow, you're {$age} years old now! Time sure flies, eh? === ``` +## Types + Variables can have the following types: - `string`: A string of characters, like `"Hello World!"`. - `number`: A number, like `42`, `0`, `-99999`, `3.1415`, or `6.0`. - `boolean`: Either `true` or `false`. All variable names must start with a `$` and can only contain letters, numbers, and underscores (`_`). + +## Conditional lines + +Boolean variables or conditions can be used to only show lines according to a condition: + +```text +title: Start +--- +<> +< 2>> +Apple Aficionado: Woah, that's a lot of apples! +< 1>> +Apple Aficionado: Congrats, that's an appropriate amount of apples. +<> +Apple Aficionado: You should get more apples. +<> +=== +``` + +This Yarn file will result in dialog that only prints the first line: +![apples.png](apples.png) From 1f9fab014813e41878d48174b769998c9fea93f7 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Sun, 20 Aug 2023 14:49:28 +0200 Subject: [PATCH 03/17] Write about setup --- docs/src/SUMMARY.md | 3 + .../working_with_yarn_slinger/bevy_plugin.md | 10 ++ .../bevy_plugin/dialog_runner.md | 0 .../bevy_plugin/setup.md | 150 ++++++++++++++++++ .../bevy_plugin/yarn_project.md | 0 .../yarn_files/running_examples.md | 2 +- 6 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 docs/src/working_with_yarn_slinger/bevy_plugin/dialog_runner.md create mode 100644 docs/src/working_with_yarn_slinger/bevy_plugin/setup.md create mode 100644 docs/src/working_with_yarn_slinger/bevy_plugin/yarn_project.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index d00b8f7b..27c281c1 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -11,6 +11,9 @@ - [Functions](./working_with_yarn_slinger/yarn_files/functions.md) - [Commands](./working_with_yarn_slinger/yarn_files/commands.md) - [Bevy Plugin](./working_with_yarn_slinger/bevy_plugin.md) + - [Setup](./working_with_yarn_slinger/bevy_plugin/setup.md) + - [Dialog Runner](./working_with_yarn_slinger/bevy_plugin/dialog_runner.md) + - [Yarn Project](./working_with_yarn_slinger/bevy_plugin/yarn_project.md) - [Custom Functions](./working_with_yarn_slinger/bevy_plugin/custom_functions.md) - [Custom Commands](./working_with_yarn_slinger/bevy_plugin/custom_commands.md) - [Dialog Views](./working_with_yarn_slinger/bevy_plugin/dialog_views.md) diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin.md b/docs/src/working_with_yarn_slinger/bevy_plugin.md index e69de29b..068544fa 100644 --- a/docs/src/working_with_yarn_slinger/bevy_plugin.md +++ b/docs/src/working_with_yarn_slinger/bevy_plugin.md @@ -0,0 +1,10 @@ +# Bevy Plugin + +While Yarn Slinger is built to be engine-agnostic, the intended way to use it +is through an engine-specific wrapper. The currently only supported engine is [Bevy](https://bevyengine.org/). +It is a data-oriented game engine using an ECS, which broadly means that you don't look at your game world +through the traditional lens of objects mutating the world and each other, but instead see the game as a collection +of data attached to various entities that can be queried and manipulated through systems. + +This chapter will assume that you are familiar with the basics of Bevy. If you're not there not, +try to come back after you've gone through the [Bevy Book](https://bevyengine.org/learn/book/introduction/). diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/dialog_runner.md b/docs/src/working_with_yarn_slinger/bevy_plugin/dialog_runner.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/setup.md b/docs/src/working_with_yarn_slinger/bevy_plugin/setup.md new file mode 100644 index 00000000..b7729338 --- /dev/null +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/setup.md @@ -0,0 +1,150 @@ +# Setup + +We will now go through the steps to setup a new Bevy project running Yarn Slinger dialogs. +This is the same setup as in the chapter [Running Examples](../yarn_files/running_examples.md), but with explanations this time. +If you've followed along in the linked chapter already, you can just read this part without executing anything. + +## Setting up the crate + +Run the following in your terminal to create a new crate with the required dependencies: + +```bash +cargo new yarn_slinger_playground +cd yarn_slinger_playground +cargo add bevy --features filesystem_watcher +cargo add bevy_yarn_slinger bevy_yarn_slinger_example_dialogue_view +``` + +The line `cargo add bevy --features filesystem_watcher` ensures that we can use *hot reloading* in our project, which means that we can edit the Yarn files +while the game is running and it will reload them automatically on change. + +The dependency `bevy_yarn_slinger` is for the Yarn Slinger Bevy plugin proper, while `bevy_yarn_slinger_example_dialogue_view` +gives us a nice default [dialog view](./dialog_views.md), so we can actually see the text we've written and have options to click on. + +## Adding the Yarn Files + +We'll use a single Yarn file for this example. Inside the folder `assets/dialog`, add a file named `example.yarn` with the following content: +```text +# assets/dialogue/example.yarn +title: Start +--- +Hello World! +=== +``` + +## The main code + +Add the following code to your `src/main.rs`. + +```rust +// src/main.rs +use bevy::prelude::*; +use bevy_yarn_slinger::prelude::*; +use bevy_yarn_slinger_example_dialogue_view::prelude::*; + +fn main() { + let mut app = App::new(); + app.add_plugins(DefaultPlugins.set(AssetPlugin { + // Activate hot reloading + watch_for_changes: true, + ..default() + })) + // Add the Yarn Slinger plugin. + // As soon as this plugin is built, a Yarn project will be compiled + // from all Yarn files found under assets/dialog/*.yarn + .add_plugin(YarnSlingerPlugin::new()) + // Add the example dialogue view plugin + .add_plugin(ExampleYarnSlingerDialogueViewPlugin::new()) + .add_systems(( + // Setup a 2D camera so we can see the text + setup_camera.on_startup(), + // Spawn the dialog as soon as the Yarn project finished compiling + spawn_dialogue_runner.run_if(resource_added::()), + )) + .run(); +} + +fn setup_camera(mut commands: Commands) { + commands.spawn(Camera2dBundle::default()); +} + +fn spawn_dialogue_runner(mut commands: Commands, project: Res) { + let mut dialogue_runner = project.create_dialogue_runner(); + // Start the dialog at the node with the title "Start" + dialogue_runner.start_node("Start"); + commands.spawn(dialogue_runner); +} +``` + +Reiterating the comments in the code, let's take a look at some snippets. + +```rust +app.add_plugins(DefaultPlugins.set(AssetPlugin { + // Activate hot reloading + watch_for_changes: true, + ..default() +})) +``` + +This setting for the `AssetPlugin` enables you to edit the Yarn files on the fly while your game is running and +see the effects instantaneously. We recommend using this workflow on all platforms which support it, which is to say all except Wasm and Android. + + +```rust +app +// ... +.add_plugin(YarnSlingerPlugin::new()) +``` + +This self-explanatory line initializes the plugin. When using the standard constructor with no options, Yarn files will be searched for in the directory `/assets/dialog/`, where all +files ending in `.yarn` will be compiled as soon as the game starts. + +The plugin makes sure all components of Yarn Slinger work except for any actual graphics. You need to +instantiate a [dialog view](./dialog_views.md) for that: + +```rust +app +// ... +.add_plugin(ExampleYarnSlingerDialogueViewPlugin::new()) +``` + +Here we initialize the dialogue view shipped by the `bevy_yarn_slinger_example_dialogue_view` crate. It +offers some sensible defaults which you can see in the screenshots used throughout this guide. You can of course skip this +and use your own dialogue view instead. + +```rust +app +// ... +.add_systems(( + // ... + // Spawn the dialog as soon as the Yarn project finished compiling + spawn_dialogue_runner.run_if(resource_added::()), +)) +``` +The line `.run_if(resource_added::()` is our way of saying "run this system once as soon as our Yarn files are done compiling". +Let's look at what will actually be run in that moment: + +```rust +fn spawn_dialogue_runner(mut commands: Commands, project: Res) { + let mut dialogue_runner = project.create_dialogue_runner(); + // Start the dialog at the node with the title "Start" + dialogue_runner.start_node("Start"); + commands.spawn(dialogue_runner); +} +``` + +The main way of interacting with Yarn files during runtime and managing the flow of a dialog is through a +[`DialogRunner`](./dialog_runner.md). To do this, we use the [`YarnProject`](./yarn_project.md) resource we referenced in the `run_if` section above. +It represents our compiled Yarn files, which we use to create a new dialog runner. +We then point it to the [node](../yarn_files/nodes.md) named "Start" of our Yarn file. +We use `start_node` for this, which will "move" the dialog runner to the provided node and start executing the dialog in the next frame, +using the registered dialog view to actually present it on the screen. +Finally, we spawn the dialog runner on an own entity into the Bevy world. + +In the end, your file structure should look like this: + +![file_system.png](../yarn_files/file_system.png) + +Run your game with `cargo run` and you should see the following: + +![hello_world.png](../yarn_files/hello_world.png) diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/yarn_project.md b/docs/src/working_with_yarn_slinger/bevy_plugin/yarn_project.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/src/working_with_yarn_slinger/yarn_files/running_examples.md b/docs/src/working_with_yarn_slinger/yarn_files/running_examples.md index b9229a65..d551168a 100644 --- a/docs/src/working_with_yarn_slinger/yarn_files/running_examples.md +++ b/docs/src/working_with_yarn_slinger/yarn_files/running_examples.md @@ -50,7 +50,7 @@ fn spawn_dialogue_runner(mut commands: Commands, project: Res) { commands.spawn(dialogue_runner); } ``` -Don't worry, we will look at what this code does in detail later. For now, just treat it as something +Don't worry, we will look at what this code does in detail later, in the chapter [Bevy Plugin / Setup](../bevy_plugin/setup.md). For now, just treat it as something that runs your Yarn files. Finally, add your Yarn files to the assets. Inside the folder `assets/dialogue`, add a file named `example.yarn` with the content From 179b057f01cd6cd63e13eb7f965894dd174c6eea Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Sun, 20 Aug 2023 18:44:00 +0200 Subject: [PATCH 04/17] Write something about yarn project --- docs/src/SUMMARY.md | 5 +- .../bevy_plugin/compiling_yarn_files.md | 54 +++++++++++++++++++ .../bevy_plugin/dialog_runner.md | 0 .../bevy_plugin/localization.md | 3 ++ .../bevy_plugin/running_dialogs.md | 3 ++ .../bevy_plugin/setup.md | 2 +- .../bevy_plugin/yarn_project.md | 0 7 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 docs/src/working_with_yarn_slinger/bevy_plugin/compiling_yarn_files.md delete mode 100644 docs/src/working_with_yarn_slinger/bevy_plugin/dialog_runner.md create mode 100644 docs/src/working_with_yarn_slinger/bevy_plugin/localization.md create mode 100644 docs/src/working_with_yarn_slinger/bevy_plugin/running_dialogs.md delete mode 100644 docs/src/working_with_yarn_slinger/bevy_plugin/yarn_project.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 27c281c1..ead9a1b4 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -12,8 +12,9 @@ - [Commands](./working_with_yarn_slinger/yarn_files/commands.md) - [Bevy Plugin](./working_with_yarn_slinger/bevy_plugin.md) - [Setup](./working_with_yarn_slinger/bevy_plugin/setup.md) - - [Dialog Runner](./working_with_yarn_slinger/bevy_plugin/dialog_runner.md) - - [Yarn Project](./working_with_yarn_slinger/bevy_plugin/yarn_project.md) + - [Running Dialogs](./working_with_yarn_slinger/bevy_plugin/running_dialogs.md) + - [Compiling Yarn Files](./working_with_yarn_slinger/bevy_plugin/compiling_yarn_files.md) + - [Localization](./working_with_yarn_slinger/bevy_plugin/localization.md) - [Custom Functions](./working_with_yarn_slinger/bevy_plugin/custom_functions.md) - [Custom Commands](./working_with_yarn_slinger/bevy_plugin/custom_commands.md) - [Dialog Views](./working_with_yarn_slinger/bevy_plugin/dialog_views.md) diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/compiling_yarn_files.md b/docs/src/working_with_yarn_slinger/bevy_plugin/compiling_yarn_files.md new file mode 100644 index 00000000..96fda8b0 --- /dev/null +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/compiling_yarn_files.md @@ -0,0 +1,54 @@ +# Compiling Yarn Files + +The `YarnProject` resource represents the set of all compiled Yarn files of +your game. You cannot construct it yourself. Instead, it is inserted into the Bevy world for +you when the compilation is finished. You can however steer how and when this is done. + +## Starting the Compilation Process + +Generally, you'll want your game to compile the Yarn files as soon as possible. This +is why the [`YarnSpinnerPlugin`](./setup.md) will start doing so by default when it is added to the app. + +If for some reason you do not wish to start compilation right away, you can *defer* this process. To do this, +construct the `YarnSpinnerPlugin` with `YarnSpinnerPlugin::deferred()` when adding it. Then, whenever you are ready +to start the compilation, you can send a `LoadYarnProjectEvent`. Its construction methods are identical to the `YarnSpinnerPlugin`. + +## Settings + +If you look through the documentation of the [`YarnSpinnerPlugin`], you'll notice a few methods to modify +its settings. The first few deal with where our Yarn files are coming from. + +### Yarn File Sources + +By default, Yarn Slinger will look +in `/assets/dialog`. Yarn Slinger can only read files from the `assets` directory +— or its equivalent, if you have changed this default in the `AssetPlugin` on platforms which support it— +but you can change how the `assets` will be looked through. + +The way to specify this is via `YarnFileSource`s. This enum tells Yarn Slinger where one or more Yarn files +come from and can be added to an `AssetPlugin` with `AssetPlugin::add_yarn_source()`. +The enum variants should be self explanatory, but the two most common use-cases come with their own convenience constructors: +- `YarnFileSource::file()`: looks for a Yarn file at a path inside under the `assets` directory. +- `YarnFileSource::folder()`: recursively looks through a given subdirectory for Yarn files. + +Since the Wasm and Android builds of Bevy have restrictions on their filesystem access, +they cannot use `YarnFileSource::folder()` and must have all their Yarn files listed explicitly with `YarnFileSource::file()`. +As such, the default behavior provided by `YarnSlingerPlugin::new()` is not suitable for these platforms. +To avoid it, use the `AssetPlugin::with_yarn_source()` constructor instead. + +As you might have guessed by now, `YarnSlingerPlugin::new()` is simply a shorthand for `AssetPlugin::with_yarn_source(YarnFileSource::folder("dialog"))`. + +## Development File Generation + +TODO + +### Localization + +The settings accessed by `YarnSlingerPlugin::with_localizatons` are important enough to warrant their own chapter. See [Localization](./localization.md). + + +## After the Compilation + +TODO + + diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/dialog_runner.md b/docs/src/working_with_yarn_slinger/bevy_plugin/dialog_runner.md deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md b/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md new file mode 100644 index 00000000..e06b957a --- /dev/null +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md @@ -0,0 +1,3 @@ +# Localization + +TODO diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/running_dialogs.md b/docs/src/working_with_yarn_slinger/bevy_plugin/running_dialogs.md new file mode 100644 index 00000000..290d28be --- /dev/null +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/running_dialogs.md @@ -0,0 +1,3 @@ +# Running Dialogs + +TODO diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/setup.md b/docs/src/working_with_yarn_slinger/bevy_plugin/setup.md index b7729338..fc30847f 100644 --- a/docs/src/working_with_yarn_slinger/bevy_plugin/setup.md +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/setup.md @@ -134,7 +134,7 @@ fn spawn_dialogue_runner(mut commands: Commands, project: Res) { ``` The main way of interacting with Yarn files during runtime and managing the flow of a dialog is through a -[`DialogRunner`](./dialog_runner.md). To do this, we use the [`YarnProject`](./yarn_project.md) resource we referenced in the `run_if` section above. +[`DialogRunner`](./running_dialogs.md). To do this, we use the [`YarnProject`](./compiling_yarn_files.md) resource we referenced in the `run_if` section above. It represents our compiled Yarn files, which we use to create a new dialog runner. We then point it to the [node](../yarn_files/nodes.md) named "Start" of our Yarn file. We use `start_node` for this, which will "move" the dialog runner to the provided node and start executing the dialog in the next frame, diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/yarn_project.md b/docs/src/working_with_yarn_slinger/bevy_plugin/yarn_project.md deleted file mode 100644 index e69de29b..00000000 From 8e1f23fec01553600b434011e907422ef03ce27f Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Mon, 21 Aug 2023 13:18:01 +0200 Subject: [PATCH 05/17] Write about dialog runner --- docs/src/SUMMARY.md | 4 +- .../bevy_plugin/assets.md | 3 + .../bevy_plugin/compiling_yarn_files.md | 17 +++-- .../bevy_plugin/dialog_runner.md | 65 +++++++++++++++++++ .../bevy_plugin/running_dialogs.md | 3 - .../bevy_plugin/setup.md | 2 +- .../bevy_plugin/variable_storage.md | 1 + 7 files changed, 86 insertions(+), 9 deletions(-) create mode 100644 docs/src/working_with_yarn_slinger/bevy_plugin/assets.md create mode 100644 docs/src/working_with_yarn_slinger/bevy_plugin/dialog_runner.md delete mode 100644 docs/src/working_with_yarn_slinger/bevy_plugin/running_dialogs.md create mode 100644 docs/src/working_with_yarn_slinger/bevy_plugin/variable_storage.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index ead9a1b4..7f152ed0 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -12,9 +12,11 @@ - [Commands](./working_with_yarn_slinger/yarn_files/commands.md) - [Bevy Plugin](./working_with_yarn_slinger/bevy_plugin.md) - [Setup](./working_with_yarn_slinger/bevy_plugin/setup.md) - - [Running Dialogs](./working_with_yarn_slinger/bevy_plugin/running_dialogs.md) - [Compiling Yarn Files](./working_with_yarn_slinger/bevy_plugin/compiling_yarn_files.md) + - [`DialogRunner` and a High Level Overview](./working_with_yarn_slinger/bevy_plugin/dialog_runner.md) - [Localization](./working_with_yarn_slinger/bevy_plugin/localization.md) + - [Assets](./working_with_yarn_slinger/bevy_plugin/assets.md) + - [Variable Storage](./working_with_yarn_slinger/bevy_plugin/variable_storage.md) - [Custom Functions](./working_with_yarn_slinger/bevy_plugin/custom_functions.md) - [Custom Commands](./working_with_yarn_slinger/bevy_plugin/custom_commands.md) - [Dialog Views](./working_with_yarn_slinger/bevy_plugin/dialog_views.md) diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/assets.md b/docs/src/working_with_yarn_slinger/bevy_plugin/assets.md new file mode 100644 index 00000000..2d10c044 --- /dev/null +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/assets.md @@ -0,0 +1,3 @@ +# Assets + +TODO diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/compiling_yarn_files.md b/docs/src/working_with_yarn_slinger/bevy_plugin/compiling_yarn_files.md index 96fda8b0..630c930e 100644 --- a/docs/src/working_with_yarn_slinger/bevy_plugin/compiling_yarn_files.md +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/compiling_yarn_files.md @@ -12,6 +12,7 @@ is why the [`YarnSpinnerPlugin`](./setup.md) will start doing so by default when If for some reason you do not wish to start compilation right away, you can *defer* this process. To do this, construct the `YarnSpinnerPlugin` with `YarnSpinnerPlugin::deferred()` when adding it. Then, whenever you are ready to start the compilation, you can send a `LoadYarnProjectEvent`. Its construction methods are identical to the `YarnSpinnerPlugin`. +In fact, when not running in deferred mode, the `YarnSpinnerPlugin` simply relays its setting to a `LoadYarnProjectEvent` and sends it. ## Settings @@ -38,17 +39,25 @@ To avoid it, use the `AssetPlugin::with_yarn_source()` constructor instead. As you might have guessed by now, `YarnSlingerPlugin::new()` is simply a shorthand for `AssetPlugin::with_yarn_source(YarnFileSource::folder("dialog"))`. -## Development File Generation +### Development File Generation -TODO +`YarnSlingerPlugin::with_development_file_generation()` accepts a `DevelopmentFileGeneration`, which tells Yarn Slinger how aggressively to generate useful files on runtime. +"Useful" refers to the developer and not the user. The default is `DevelopmentFileGeneration::TRY_FULL`, which will be `DevelopmentFileGeneration::Full` on platforms which support filesystem access, +i.e. all except Wasm and Android. See the documentation for the full list of effects. Suffice it to say +that this is not very important when developing without localization, but becomes vital otherwise. See the [Localization](./localization.md) chapter for more. + +Since these settings are intended for development, you can use `YarnSlingerPlugin::with_development_file_generation(DevelopmentFileGeneration::None)` when shipping your game to optimize the runtime costs and +avoid generating files that are useless to the player. ### Localization The settings accessed by `YarnSlingerPlugin::with_localizatons` are important enough to warrant their own chapter. See [Localization](./localization.md). - ## After the Compilation -TODO +Whether you used `YarnSlingerPlugin` or `LoadYarnProjectEvent`, as soon as the compilation finished, a `YarnProject` resource will be inserted into the Bevy world. +You can react to its creation by guarding your systems with `.run_if(resource_added::())`, as seen in the [setup](./setup.md). + +Once you have the `YarnProject`, you can use it to spawn a `DialogRunner` which in turn can, well, [run dialogs](./dialog_runner.md) diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/dialog_runner.md b/docs/src/working_with_yarn_slinger/bevy_plugin/dialog_runner.md new file mode 100644 index 00000000..4c149b8c --- /dev/null +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/dialog_runner.md @@ -0,0 +1,65 @@ +# `DialogRunner` and a High Level Overview + +The main way to actually manipulate the state of your dialog is through a `DialogRunner`. +You create it from a `YarnProject` (see [Compiling Yarn Files](./compiling_yarn_files.md)) with either +`YarnProject::create_dialog_runner()` or `YarnProject::build_dialog_runner()`. +The first uses default configurations which should be alright for many use-cases, +while the latter allows you to add or change functionality. + +## Dialog Flow + +The actual navigation through a dialog is handled by a [dialog view](./dialog_views.md), +which is responsible for back-and-forth interaction with the player. +As such, most of the methods provided by a `DialogRunner` are to be called by such a view. +The one you will want to call yourself, as seen in the [setup](./setup.md), is `DialogRunner::start_node`, +which will tell the `DialogRunner` to start running from the provided [node](../yarn_files/nodes.md). + +## Variable Storage + +[Variables](../yarn_files/variables.md) need to be stored in some place. By default, they are kept in memory through the `InMemoryVariableStorage`. +This means that when you quit and reopen the game, all variables used in Yarn files will be empty again. Of course, this is suboptimal when you want to allow +the player saving and loading their game state. To accomplish this, you can go one of two routes: + +- Manipulate the variables in the variable store. Read then when saving and write them when loading. +You can access the variable storage through `DialogRunner::variable_storage()`. +- Directory use a variable storage that stores its variables in a persistent way, such as a database or a file. +You can change the underlying variable storage through the builder API discussed later in this chapter. + +For information on how to create your own variable storage, see the chapter [Variable Storage](./variable_storage) + +## Functions and Commands + +Yarn files can contain user-defined functions and commands. These can be accessed with +`DialogRunner::library()` and `DialogRunner::commands()`. For more information, see the chapters [Custom Functions](./custom_functions.md) +and [Custom Commands](./custom_commands.md). + +## Text and Assets + +We make a distinction between *text*, which are the written words organized into *lines* contained in Yarn files or in +[localization files](./localization.md), and *assets*, which are supplemental data associated with a line. +Assets are referenced over a Bevy `Handle` and can be used for things such as voiceover sound files or images that might need translation. + +Of note is that using assets **requires** using [localization](./localization.md), or at least thinking about it. +As a consequence, language settings are split between text and assets. After all, a player might want to hear lines delivered in the original recorded language but read the text translated into their own language. + +You can read more about how current language can be set for a `DialogRunner` in the [localization](./localization.md) chapter. + +Text is provided by a `TextProvider`. While it can be overwritten, the default `StringsFileTextProvider` will be a good choice for +nearly all users. The only reason you might have to create an own `TextProvider` is if you want a very custom localization strategy, such as +translating text automatically through AI. + +Assets are provided by `AssetProvider`s. In contrast to the `TextProvider`, you might very well create your own `AssetProvider`. +For your convenience, Yarn Slinger already ships with an `AudioAssetProvider` that you can use for voice lines and a `FileExtensionAssetProvider` +that can load any asset based on naming conventions and file extensions. See the chapter [Assets](./assets.md). + +Text and asset providers can be set through the builder API and accessed later with `DialogRunner::text_provider()` and `DialogRunner::asset_providers()`. If you know the exact type `T` of `AssetProvider` you +want, you can call `DialogRunner::asset_provider::()` instead. + +## Builder API + +As mentioned in the beginning of this chapter, a `DialogRunner` can be modified or extended on creation +by using `YarnProject::build_dialog_runner()`. In fact, `YarnProject::create_dialog_runner()` is nothing but a shorthand for `YarnProject::build_dialog_runner().build()`. + +You can use the builder API to inject your own implementations of traits used for the features presented in this chapter. +`DialogueRunnerBuilder::with_variable_storage` changes the underlying `VariableStorage` and `DialogueRunnerBuilder::with_text_provider` the `TextProvider`. +`DialogueRunnerBuilder::add_asset_provider` adds an `AssetProvider` to the set of asset providers called for each line presented to the player. diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/running_dialogs.md b/docs/src/working_with_yarn_slinger/bevy_plugin/running_dialogs.md deleted file mode 100644 index 290d28be..00000000 --- a/docs/src/working_with_yarn_slinger/bevy_plugin/running_dialogs.md +++ /dev/null @@ -1,3 +0,0 @@ -# Running Dialogs - -TODO diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/setup.md b/docs/src/working_with_yarn_slinger/bevy_plugin/setup.md index fc30847f..374dc10f 100644 --- a/docs/src/working_with_yarn_slinger/bevy_plugin/setup.md +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/setup.md @@ -134,7 +134,7 @@ fn spawn_dialogue_runner(mut commands: Commands, project: Res) { ``` The main way of interacting with Yarn files during runtime and managing the flow of a dialog is through a -[`DialogRunner`](./running_dialogs.md). To do this, we use the [`YarnProject`](./compiling_yarn_files.md) resource we referenced in the `run_if` section above. +[`DialogRunner`](./dialog_runner.md). To do this, we use the [`YarnProject`](./compiling_yarn_files.md) resource we referenced in the `run_if` section above. It represents our compiled Yarn files, which we use to create a new dialog runner. We then point it to the [node](../yarn_files/nodes.md) named "Start" of our Yarn file. We use `start_node` for this, which will "move" the dialog runner to the provided node and start executing the dialog in the next frame, diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/variable_storage.md b/docs/src/working_with_yarn_slinger/bevy_plugin/variable_storage.md new file mode 100644 index 00000000..33e4cc42 --- /dev/null +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/variable_storage.md @@ -0,0 +1 @@ +# Variable Storage From 7bd2c259294e970877a2ba5f106a6da0d83dbd81 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Mon, 21 Aug 2023 13:25:18 +0200 Subject: [PATCH 06/17] Rename VariableStore -> VariableStorage --- crates/bevy_plugin/src/dialogue_runner/builder.rs | 6 +++--- crates/bevy_plugin/src/lib.rs | 2 +- crates/runtime/src/dialogue.rs | 4 ++-- crates/runtime/src/variable_storage.rs | 10 +++++----- crates/yarn_slinger/tests/dialogue_tests.rs | 2 +- crates/yarn_slinger/tests/test_base/mod.rs | 8 ++++---- crates/yarn_slinger/tests/type_tests.rs | 2 +- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/crates/bevy_plugin/src/dialogue_runner/builder.rs b/crates/bevy_plugin/src/dialogue_runner/builder.rs index 2b5963f4..cb69b6e3 100644 --- a/crates/bevy_plugin/src/dialogue_runner/builder.rs +++ b/crates/bevy_plugin/src/dialogue_runner/builder.rs @@ -1,4 +1,4 @@ -use crate::default_impl::{MemoryVariableStore, StringsFileTextProvider}; +use crate::default_impl::{MemoryVariableStorage, StringsFileTextProvider}; use crate::line_provider::SharedTextProvider; use crate::prelude::*; use bevy::prelude::*; @@ -41,7 +41,7 @@ impl DialogueRunnerBuilder { #[must_use] pub(crate) fn from_yarn_project(yarn_project: &YarnProject) -> Self { Self { - variable_storage: Box::new(MemoryVariableStore::new()), + variable_storage: Box::new(MemoryVariableStorage::new()), text_provider: SharedTextProvider::new(StringsFileTextProvider::from_yarn_project( yarn_project, )), @@ -54,7 +54,7 @@ impl DialogueRunnerBuilder { } } - /// Replaces the [`VariableStorage`] used by the [`DialogueRunner`]. By default, this is a [`MemoryVariableStore`]. + /// Replaces the [`VariableStorage`] used by the [`DialogueRunner`]. By default, this is a [`MemoryVariableStorage`]. #[must_use] pub fn with_variable_storage(mut self, storage: Box) -> Self { self.variable_storage = storage; diff --git a/crates/bevy_plugin/src/lib.rs b/crates/bevy_plugin/src/lib.rs index d6f57445..64fdb39b 100644 --- a/crates/bevy_plugin/src/lib.rs +++ b/crates/bevy_plugin/src/lib.rs @@ -113,7 +113,7 @@ pub mod default_impl { pub use crate::line_provider::{ file_extensions, FileExtensionAssetProvider, StringsFileTextProvider, }; - pub use yarn_slinger::runtime::{MemoryVariableStore, StringTableTextProvider}; + pub use yarn_slinger::runtime::{MemoryVariableStorage, StringTableTextProvider}; } pub mod events { diff --git a/crates/runtime/src/dialogue.rs b/crates/runtime/src/dialogue.rs index cc8353f5..feb463c3 100644 --- a/crates/runtime/src/dialogue.rs +++ b/crates/runtime/src/dialogue.rs @@ -52,7 +52,7 @@ impl Dialogue { /// - The [`TextProvider`] is used to retrieve the text of lines and options. /// - The [`VariableStorage`] is used to store and retrieve variables. /// - /// If you don't need any fancy behavior, you can use [`StringTableTextProvider`] and [`MemoryVariableStore`]. + /// If you don't need any fancy behavior, you can use [`StringTableTextProvider`] and [`MemoryVariableStorage`]. #[must_use] pub fn new( variable_storage: Box, @@ -391,7 +391,7 @@ mod tests { #[test] fn is_send_sync() { - let variable_storage = Box::new(MemoryVariableStore::new()); + let variable_storage = Box::new(MemoryVariableStorage::new()); let text_provider = Box::new(StringTableTextProvider::new()); let dialogue = Dialogue::new(variable_storage, text_provider); accept_send_sync(dialogue); diff --git a/crates/runtime/src/variable_storage.rs b/crates/runtime/src/variable_storage.rs index 160f4bef..e735dfcb 100644 --- a/crates/runtime/src/variable_storage.rs +++ b/crates/runtime/src/variable_storage.rs @@ -68,16 +68,16 @@ impl Clone for Box { /// A simple concrete implementation of [`VariableStorage`] that keeps all variables in memory. #[derive(Debug, Clone, Default)] -pub struct MemoryVariableStore(Arc>>); +pub struct MemoryVariableStorage(Arc>>); -impl MemoryVariableStore { - /// Creates a new empty `MemoryVariableStore`. +impl MemoryVariableStorage { + /// Creates a new empty `MemoryVariableStorage`. pub fn new() -> Self { Self::default() } } -impl VariableStorage for MemoryVariableStore { +impl VariableStorage for MemoryVariableStorage { fn clone_shallow(&self) -> Box { Box::new(self.clone()) } @@ -114,7 +114,7 @@ impl VariableStorage for MemoryVariableStore { } } -impl MemoryVariableStore { +impl MemoryVariableStorage { fn validate_name(name: impl AsRef) -> Result<()> { let name = name.as_ref(); if name.starts_with('$') { diff --git a/crates/yarn_slinger/tests/dialogue_tests.rs b/crates/yarn_slinger/tests/dialogue_tests.rs index 2408c9be..9b041e04 100644 --- a/crates/yarn_slinger/tests/dialogue_tests.rs +++ b/crates/yarn_slinger/tests/dialogue_tests.rs @@ -228,7 +228,7 @@ fn test_function_argument_type_inference() { let storage = test_base .with_compilation(result) .run_standard_testcase() - .variable_store + .variable_storage .clone_shallow(); // The values should be of the right type and value diff --git a/crates/yarn_slinger/tests/test_base/mod.rs b/crates/yarn_slinger/tests/test_base/mod.rs index 4d6e64b3..0a898f2a 100644 --- a/crates/yarn_slinger/tests/test_base/mod.rs +++ b/crates/yarn_slinger/tests/test_base/mod.rs @@ -47,7 +47,7 @@ pub struct TestBase { pub dialogue: Dialogue, pub test_plan: Option, pub string_table: SharedTextProvider, - pub variable_store: MemoryVariableStore, + pub variable_storage: MemoryVariableStorage, runtime_errors_cause_failure: Arc, } @@ -57,11 +57,11 @@ impl Default for TestBase { if let Err(_e) = init_logger(runtime_errors_cause_failure.clone()) { // We've set the logger twice, that's alright for the tests. } - let variable_store = MemoryVariableStore::new(); + let variable_storage = MemoryVariableStorage::new(); let string_table = SharedTextProvider::new(StringTableTextProvider::new()); let mut dialogue = Dialogue::new( - Box::new(variable_store.clone()), + Box::new(variable_storage.clone()), Box::new(string_table.clone()), ); dialogue @@ -75,7 +75,7 @@ impl Default for TestBase { Self { dialogue, runtime_errors_cause_failure, - variable_store, + variable_storage, string_table, test_plan: Default::default(), } diff --git a/crates/yarn_slinger/tests/type_tests.rs b/crates/yarn_slinger/tests/type_tests.rs index de5abfe3..93cbc027 100644 --- a/crates/yarn_slinger/tests/type_tests.rs +++ b/crates/yarn_slinger/tests/type_tests.rs @@ -417,7 +417,7 @@ fn test_initial_values() -> anyhow::Result<()> { .declare_variable(Declaration::new("$external_bool", Type::Number).with_default_value(42)) .compile()?; - let mut variable_storage = test_base.variable_store.clone_shallow(); + let mut variable_storage = test_base.variable_storage.clone_shallow(); variable_storage.set("$external_str".to_string(), "Hello".into())?; variable_storage.set("$external_int".to_string(), 42.into())?; variable_storage.set("$external_bool".to_string(), true.into())?; From b9f6cfc6a2ea828be5790b68c738e1b239c8c9cb Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Mon, 21 Aug 2023 13:32:11 +0200 Subject: [PATCH 07/17] Improve signature of DialogueRunner::asset_provider --- crates/bevy_plugin/src/dialogue_runner.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/bevy_plugin/src/dialogue_runner.rs b/crates/bevy_plugin/src/dialogue_runner.rs index 36a686b7..c170c69b 100644 --- a/crates/bevy_plugin/src/dialogue_runner.rs +++ b/crates/bevy_plugin/src/dialogue_runner.rs @@ -320,12 +320,13 @@ impl DialogueRunner { self.text_provider.as_ref() } - /// Returns the registered [`AssetProvider`] for the given type. + /// Returns the registered [`AssetProvider`] of the given type if it was previously registered with [`DialogueRunnerBuilder::add_asset_provider`]. #[must_use] - pub fn asset_provider(&self) -> Option<&dyn AssetProvider> { + pub fn asset_provider(&self) -> Option<&T> { self.asset_providers - .get(&TypeId::of::()) - .map(|p| p.as_ref()) + .values() + .filter_map(|p| p.as_any().downcast_ref()) + .next() } /// Iterates over all registered [`AssetProvider`]s. From 30531267bcaf836486e54720477d9e022a41466e Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Mon, 21 Aug 2023 15:08:17 +0200 Subject: [PATCH 08/17] Write about localizations --- .../bevy_plugin/compiling_yarn_files.md | 2 -- .../bevy_plugin/localization.md | 28 +++++++++++++++++++ .../bevy_plugin/variable_storage.md | 2 ++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/compiling_yarn_files.md b/docs/src/working_with_yarn_slinger/bevy_plugin/compiling_yarn_files.md index 630c930e..e683ec61 100644 --- a/docs/src/working_with_yarn_slinger/bevy_plugin/compiling_yarn_files.md +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/compiling_yarn_files.md @@ -59,5 +59,3 @@ Whether you used `YarnSlingerPlugin` or `LoadYarnProjectEvent`, as soon as the c You can react to its creation by guarding your systems with `.run_if(resource_added::())`, as seen in the [setup](./setup.md). Once you have the `YarnProject`, you can use it to spawn a `DialogRunner` which in turn can, well, [run dialogs](./dialog_runner.md) - - diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md b/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md index e06b957a..e02c66f0 100644 --- a/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md @@ -1,3 +1,31 @@ # Localization +If you only want to support a single language, you can safely ignore localization features. +As soon as you want to support [assets](./assets.md) or multiple languages however, you will need to use localization. +Fortunately Yarn Slinger makes this quite easy! + +Let's first look at how to use localization and then explain what's going on under the hood. + +## Using Localization the Easy Way + +We specify our supported localizations when adding the [`YarnSlingerPlugin` (or using deferred compilation)](./compiling_yarn_files.md): + +```rust +app +// ... +.add_plugin(YarnSlingerPlugin::new() + .with_localizations(Localizations { + base_localization: "en-US".into(), + translations: vec!["de-CH".into()], + }) +) +``` + +The *base localization* is the language in which your Yarn files are already written. +The *translations* are all languages you want to support. + +TODO + +## Customizing + TODO diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/variable_storage.md b/docs/src/working_with_yarn_slinger/bevy_plugin/variable_storage.md index 33e4cc42..d9e545c4 100644 --- a/docs/src/working_with_yarn_slinger/bevy_plugin/variable_storage.md +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/variable_storage.md @@ -1 +1,3 @@ # Variable Storage + +TODO From 6f58b1e80575e33fe60861c78c6d6264c0bba3fe Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Mon, 21 Aug 2023 16:33:08 +0200 Subject: [PATCH 09/17] Update docs to new Bevy version --- crates/bevy_plugin/src/lib.rs | 40 ++++++------ crates/bevy_plugin/src/project/compilation.rs | 5 +- .../bevy_plugin/localization.md | 14 ++--- .../bevy_plugin/setup.md | 61 ++++++++----------- .../yarn_files/running_examples.md | 26 ++++---- 5 files changed, 74 insertions(+), 72 deletions(-) diff --git a/crates/bevy_plugin/src/lib.rs b/crates/bevy_plugin/src/lib.rs index 73496382..ef4eabdf 100644 --- a/crates/bevy_plugin/src/lib.rs +++ b/crates/bevy_plugin/src/lib.rs @@ -53,29 +53,34 @@ //! //! ```no_run //! // src/main.rs -//! use bevy::prelude::*; +//! use bevy::{prelude::*, asset::ChangeWatcher, utils::Duration}; //! use bevy_yarn_slinger::prelude::*; //! // Use the example dialogue view to see the dialogue in action. Requires the `bevy_yarn_slinger_example_dialogue_view` crate. //! // use bevy_yarn_slinger_example_dialogue_view::prelude::*; //! //! fn main() { //! let mut app = App::new(); -//! app.add_plugins(DefaultPlugins) -//! // Register the Yarn Slinger plugin using its default settings, which will look for Yarn files in the "dialogue" folder -//! // If this app should support Wasm or Android, we cannot load files without specifying them, so use the following instead. -//! // .add_plugins(YarnSlingerPlugin::with_yarn_source(YarnFileSource::file("dialogue/hello_world.yarn"))) -//! .add_plugins(YarnSlingerPlugin::new()) +//! app.add_plugins(( +//! DefaultPlugins.set(AssetPlugin { +//! // Activate hot reloading +//! watch_for_changes: ChangeWatcher::with_delay(Duration::from_millis(200)), +//! ..default() +//! }), +//! // Add the Yarn Slinger plugin. +//! // As soon as this plugin is built, a Yarn project will be compiled +//! // from all Yarn files found under assets/dialog/*.yarn +//! YarnSlingerPlugin::new(), //! // Initialize the bundled example UI. Requires the `bevy_yarn_slinger_example_dialogue_view` crate. -//! // .add_plugins(ExampleYarnSlingerDialogueViewPlugin::new()) -//! .add_systems( -//! Update, -//! ( -//! setup_camera.on_startup(), -//! // Spawn dialogue runner once the Yarn project has finished compiling -//! spawn_dialogue_runner.run_if(resource_added::()), -//! ) -//! ) -//! .run(); +//! // ExampleYarnSlingerDialogueViewPlugin::new(), +//! )) +//! // Setup a 2D camera so we can see the text +//! .add_systems(Startup, setup_camera) +//! // Spawn the dialog as soon as the Yarn project finished compiling +//! .add_systems( +//! Update, +//! spawn_dialogue_runner.run_if(resource_added::()), +//! ) +//! .run(); //! } //! //! fn setup_camera(mut commands: Commands) { @@ -83,9 +88,8 @@ //! } //! //! fn spawn_dialogue_runner(mut commands: Commands, project: Res) { -//! // Create a dialogue runner from the project //! let mut dialogue_runner = project.create_dialogue_runner(); -//! // Immediately show the dialogue to the player by starting at the "Start" node +//! // Start the dialog at the node with the title "Start" //! dialogue_runner.start_node("Start"); //! commands.spawn(dialogue_runner); //! } diff --git a/crates/bevy_plugin/src/project/compilation.rs b/crates/bevy_plugin/src/project/compilation.rs index c5b6aedc..78a5f0c7 100644 --- a/crates/bevy_plugin/src/project/compilation.rs +++ b/crates/bevy_plugin/src/project/compilation.rs @@ -65,8 +65,9 @@ fn load_project( && !is_watching_for_changes.0 { warn!("Development file generation mode is set to `Full`, but hot reloading is not turned on. \ - For an optimal development experience, we recommend turning on hot reloading by setting the `watch_for_changes` field of the `AssetPlugin` to `true`. \ - You can see an example of how to do this in at "); + For an optimal development experience, we recommend turning on hot reloading by setting the `watch_for_changes` field of the `AssetPlugin` to `Some`, \ + e.g. via `watch_for_changes: ChangeWatcher::with_delay(Duration::from_millis(200))`. \ + You can see an example of how to do this in at "); } commands.insert_resource(YarnProjectConfigToLoad { diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md b/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md index e02c66f0..e8fdd80d 100644 --- a/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md @@ -13,18 +13,18 @@ We specify our supported localizations when adding the [`YarnSlingerPlugin` (or ```rust app // ... -.add_plugin(YarnSlingerPlugin::new() - .with_localizations(Localizations { - base_localization: "en-US".into(), - translations: vec!["de-CH".into()], - }) -) +.add_plugin(YarnSlingerPlugin::new().with_localizations(Localizations { + base_localization: "en-US".into(), + translations: vec!["de-CH".into()], +})) ``` The *base localization* is the language in which your Yarn files are already written. The *translations* are all languages you want to support. -TODO +Put the code shown above into the example used in the [setup](./setup.md) and run the game. +You should see that some files were generated for you: + ## Customizing diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/setup.md b/docs/src/working_with_yarn_slinger/bevy_plugin/setup.md index 374dc10f..3d999569 100644 --- a/docs/src/working_with_yarn_slinger/bevy_plugin/setup.md +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/setup.md @@ -38,29 +38,32 @@ Add the following code to your `src/main.rs`. ```rust // src/main.rs -use bevy::prelude::*; +use bevy::{prelude::*, asset::ChangeWatcher, utils::Duration}; use bevy_yarn_slinger::prelude::*; use bevy_yarn_slinger_example_dialogue_view::prelude::*; fn main() { let mut app = App::new(); - app.add_plugins(DefaultPlugins.set(AssetPlugin { - // Activate hot reloading - watch_for_changes: true, - ..default() - })) - // Add the Yarn Slinger plugin. - // As soon as this plugin is built, a Yarn project will be compiled - // from all Yarn files found under assets/dialog/*.yarn - .add_plugin(YarnSlingerPlugin::new()) - // Add the example dialogue view plugin - .add_plugin(ExampleYarnSlingerDialogueViewPlugin::new()) - .add_systems(( - // Setup a 2D camera so we can see the text - setup_camera.on_startup(), - // Spawn the dialog as soon as the Yarn project finished compiling - spawn_dialogue_runner.run_if(resource_added::()), + app.add_plugins(( + DefaultPlugins.set(AssetPlugin { + // Activate hot reloading + watch_for_changes: ChangeWatcher::with_delay(Duration::from_millis(200)), + ..default() + }), + // Add the Yarn Slinger plugin. + // As soon as this plugin is built, a Yarn project will be compiled + // from all Yarn files found under assets/dialog/*.yarn + YarnSlingerPlugin::new(), + // Add the example dialogue view plugin + ExampleYarnSlingerDialogueViewPlugin::new(), )) + // Setup a 2D camera so we can see the text + .add_systems(Startup, setup_camera) + // Spawn the dialog as soon as the Yarn project finished compiling + .add_systems( + Update, + spawn_dialogue_runner.run_if(resource_added::()), + ) .run(); } @@ -79,11 +82,11 @@ fn spawn_dialogue_runner(mut commands: Commands, project: Res) { Reiterating the comments in the code, let's take a look at some snippets. ```rust -app.add_plugins(DefaultPlugins.set(AssetPlugin { +DefaultPlugins.set(AssetPlugin { // Activate hot reloading - watch_for_changes: true, + watch_for_changes: ChangeWatcher::with_delay(Duration::from_millis(200)), ..default() -})) +}), ``` This setting for the `AssetPlugin` enables you to edit the Yarn files on the fly while your game is running and @@ -91,9 +94,7 @@ see the effects instantaneously. We recommend using this workflow on all platfor ```rust -app -// ... -.add_plugin(YarnSlingerPlugin::new()) +YarnSlingerPlugin::new(), ``` This self-explanatory line initializes the plugin. When using the standard constructor with no options, Yarn files will be searched for in the directory `/assets/dialog/`, where all @@ -103,9 +104,7 @@ The plugin makes sure all components of Yarn Slinger work except for any actual instantiate a [dialog view](./dialog_views.md) for that: ```rust -app -// ... -.add_plugin(ExampleYarnSlingerDialogueViewPlugin::new()) +ExampleYarnSlingerDialogueViewPlugin::new(), ``` Here we initialize the dialogue view shipped by the `bevy_yarn_slinger_example_dialogue_view` crate. It @@ -113,15 +112,9 @@ offers some sensible defaults which you can see in the screenshots used througho and use your own dialogue view instead. ```rust -app -// ... -.add_systems(( - // ... - // Spawn the dialog as soon as the Yarn project finished compiling - spawn_dialogue_runner.run_if(resource_added::()), -)) +spawn_dialogue_runner.run_if(resource_added::()), ``` -The line `.run_if(resource_added::()` is our way of saying "run this system once as soon as our Yarn files are done compiling". +The method `.run_if(resource_added::()` is our way of saying "run this system once as soon as our Yarn files are done compiling". Let's look at what will actually be run in that moment: ```rust diff --git a/docs/src/working_with_yarn_slinger/yarn_files/running_examples.md b/docs/src/working_with_yarn_slinger/yarn_files/running_examples.md index 47dfebfb..98c09450 100644 --- a/docs/src/working_with_yarn_slinger/yarn_files/running_examples.md +++ b/docs/src/working_with_yarn_slinger/yarn_files/running_examples.md @@ -21,23 +21,27 @@ Then, in your `src/main.rs`, add the following code: ```rust // src/main.rs -use bevy::prelude::*; +use bevy::{prelude::*, asset::ChangeWatcher, utils::Duration}; use bevy_yarn_slinger::prelude::*; use bevy_yarn_slinger_example_dialogue_view::prelude::*; fn main() { let mut app = App::new(); - app.add_plugins(DefaultPlugins.set(AssetPlugin { - watch_for_changes: true, + + app.add_plugins(( + DefaultPlugins.set(AssetPlugin { + watch_for_changes: ChangeWatcher::with_delay(Duration::from_millis(200)), ..default() - })) - .add_plugins(YarnSlingerPlugin::new()) - .add_plugins(ExampleYarnSlingerDialogueViewPlugin::new()) - .add_systems(Update, ( - setup_camera.on_startup(), - spawn_dialogue_runner.run_if(resource_added::()), - )) - .run(); + }), + YarnSlingerPlugin::new(), + ExampleYarnSlingerDialogueViewPlugin::new(), + )) + .add_systems(Startup, setup_camera) + .add_systems( + Update, + spawn_dialogue_runner.run_if(resource_added::()), + ) + .run(); } fn setup_camera(mut commands: Commands) { From 5ff6cd92810cd8e4a4d01d3fcc08154718ecf33c Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Mon, 21 Aug 2023 16:58:50 +0200 Subject: [PATCH 10/17] Capitalize Yarn --- .../src/development_file_generation.rs | 4 ++-- crates/bevy_plugin/src/lib.rs | 2 +- .../src/localization/strings_file/asset.rs | 4 ++-- .../src/localization/strings_file/updating.rs | 8 ++++---- crates/bevy_plugin/src/plugin.rs | 16 ++++++++-------- .../bevy_plugin/src/plugin/yarn_file_source.rs | 4 ++-- crates/bevy_plugin/src/project.rs | 2 +- crates/bevy_plugin/src/project/compilation.rs | 6 +++--- crates/runtime/src/command.rs | 2 +- crates/yarn_slinger/tests/test_base/mod.rs | 2 +- .../bevy_plugin/localization.md | 17 +++++++++++------ .../bevy_plugin/strings_file_generated.png | Bin 0 -> 8767 bytes 12 files changed, 36 insertions(+), 31 deletions(-) create mode 100644 docs/src/working_with_yarn_slinger/bevy_plugin/strings_file_generated.png diff --git a/crates/bevy_plugin/src/development_file_generation.rs b/crates/bevy_plugin/src/development_file_generation.rs index d900fe62..21315af3 100644 --- a/crates/bevy_plugin/src/development_file_generation.rs +++ b/crates/bevy_plugin/src/development_file_generation.rs @@ -5,14 +5,14 @@ pub(crate) fn development_file_generation_plugin(app: &mut App) { app.register_type::(); } -/// The kind of development experience you wish when creating yarn files and dealing with missing localizations. +/// The kind of development experience you wish when creating Yarn files and dealing with missing localizations. /// Defaults to [`DevelopmentFileGeneration::TRY_FULL`] in debug builds, [`DevelopmentFileGeneration::None`] otherwise. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)] #[reflect(Debug, Default, PartialEq, Hash, Serialize, Deserialize)] #[non_exhaustive] pub enum DevelopmentFileGeneration { /// The recommended setting for a development environment: - /// - Generates line IDs for all lines in loaded yarn files and writes them back to disk. + /// - Generates line IDs for all lines in loaded Yarn files and writes them back to disk. /// - Generates new strings files for all languages that are missing them, filling them with the lines found in the Yarn files. /// - Adds new lines to strings files when they have been added to a loaded Yarn file. /// - Marks lines in strings files that have been changed since they were translated by appending "NEEDS UPDATE" to the respective line texts. diff --git a/crates/bevy_plugin/src/lib.rs b/crates/bevy_plugin/src/lib.rs index ef4eabdf..f21273ab 100644 --- a/crates/bevy_plugin/src/lib.rs +++ b/crates/bevy_plugin/src/lib.rs @@ -168,7 +168,7 @@ pub use yarn_slinger::prelude::{ }; pub mod deferred_loading { - //! Contains types needed for the deferred loading functionality, which is used when the list of yarn files is not immediately available at startup. + //! Contains types needed for the deferred loading functionality, which is used when the list of Yarn files is not immediately available at startup. pub use crate::plugin::DeferredYarnSlingerPlugin; pub use crate::project::LoadYarnProjectEvent; } diff --git a/crates/bevy_plugin/src/localization/strings_file/asset.rs b/crates/bevy_plugin/src/localization/strings_file/asset.rs index 4d21a19a..98a374a4 100644 --- a/crates/bevy_plugin/src/localization/strings_file/asset.rs +++ b/crates/bevy_plugin/src/localization/strings_file/asset.rs @@ -248,11 +248,11 @@ pub(crate) struct StringsFileRecord { /// the line's text as it appeared in the base localization CSV file. /// /// When a new StringTableEntry is created in a localized CSV file for a - /// .yarn file, the Lock value is copied over from the base CSV file, + /// .Yarn file, the Lock value is copied over from the base CSV file, /// and used for the translated entry. /// /// Because the base localization CSV is regenerated every time the - /// .yarn file is imported, the base localization Lock value will change + /// .Yarn file is imported, the base localization Lock value will change /// if a line's text changes. This means that if the base lock and /// translated lock differ, the translated line is out of date, and /// needs to be updated. diff --git a/crates/bevy_plugin/src/localization/strings_file/updating.rs b/crates/bevy_plugin/src/localization/strings_file/updating.rs index d84435a8..6affb6e0 100644 --- a/crates/bevy_plugin/src/localization/strings_file/updating.rs +++ b/crates/bevy_plugin/src/localization/strings_file/updating.rs @@ -96,11 +96,11 @@ fn update_all_strings_files_for_string_table( Ok(new_strings_file) => new_strings_file, Err(e) => { if project.development_file_generation == DevelopmentFileGeneration::Full { - debug!("Updating \"{}\" soon (lang: {language}) because the following yarn files were changed or loaded but do not have full line IDs yet: {file_names}", + debug!("Updating \"{}\" soon (lang: {language}) because the following Yarn files were changed or loaded but do not have full line IDs yet: {file_names}", strings_file_path.display()) } else { error!( - "Tried to update \"{}\" (lang: {language}) because the following yarn files were changed or loaded: {file_names}, but couldn't because: {e}", + "Tried to update \"{}\" (lang: {language}) because the following Yarn files were changed or loaded: {file_names}, but couldn't because: {e}", strings_file_path.display(), ); } @@ -111,7 +111,7 @@ fn update_all_strings_files_for_string_table( dirty_paths.insert((strings_file_handle, strings_file_path)); info!( - "Updated \"{}\" (lang: {language}) because the following yarn files were changed or loaded: {file_names}", + "Updated \"{}\" (lang: {language}) because the following Yarn files were changed or loaded: {file_names}", strings_file_path.display(), ); } @@ -144,7 +144,7 @@ fn lint_strings_file( .map(|asset_path| format!("at {}", asset_path.path().display())) .unwrap_or_else(|| "created at runtime".to_owned()); warn!( - "Strings file {source} contains the following strings for yarn files were not found in the project: {superfluous_file_names}. \ + "Strings file {source} contains the following strings for Yarn files were not found in the project: {superfluous_file_names}. \ Either you forgot to add these files to the project or the strings belonged to files that were deleted. \ You may want to delete these entries from the strings file manually. Yarn Slinger will not do this for you because it may lead to loss of work.", ); diff --git a/crates/bevy_plugin/src/plugin.rs b/crates/bevy_plugin/src/plugin.rs index 9962f40c..4a80c3be 100644 --- a/crates/bevy_plugin/src/plugin.rs +++ b/crates/bevy_plugin/src/plugin.rs @@ -7,7 +7,7 @@ mod yarn_file_source; /// The plugin that provides all Yarn Slinger functionality. /// In general, you'll want to create this by searching for Yarn files in "assets/dialogue", which [`YarnSlingerPlugin::new`] does under the hood. -/// You can also provide a list of yarn files to load via [`YarnSlingerPlugin::with_yarn_sources`]. +/// You can also provide a list of Yarn files to load via [`YarnSlingerPlugin::with_yarn_sources`]. /// If you however do not know the paths to any files nor have them in-memory at the start of the program, /// use [`YarnSlingerPlugin::deferred`] instead to later load the files by sending a [`LoadYarnProjectEvent`]. /// @@ -42,9 +42,9 @@ impl YarnSlingerPlugin { /// Otherwise this panics since Bevy cannot query folders on these platforms. /// Use [`YarnSlingerPlugin::with_yarn_source`] or [`YarnSlingerPlugin::with_yarn_sources`] there instead. /// - /// All yarn files will be shared across [`DialogueRunner`]s. + /// All Yarn files will be shared across [`DialogueRunner`]s. /// If [hot reloading](https://bevy-cheatbook.github.io/assets/hot-reload.html) is turned on, - /// these yarn files will be recompiled if they change during runtime. + /// these Yarn files will be recompiled if they change during runtime. /// /// Calling this is equivalent to calling [`YarnSlingerPlugin::with_yarn_source`] with a [`YarnFileSource::folder`] of `"dialogue"`. #[must_use] @@ -63,9 +63,9 @@ impl YarnSlingerPlugin { } /// Creates a new plugin that loads Yarn files from the given sources. - /// All yarn files will be shared across [`DialogueRunner`]s. + /// All Yarn files will be shared across [`DialogueRunner`]s. /// If [hot reloading](https://bevy-cheatbook.github.io/assets/hot-reload.html) is turned on, - /// these yarn files will be recompiled if they change during runtime. + /// these Yarn files will be recompiled if they change during runtime. /// /// See [`YarnFileSource`] for more information on where Yarn files can be loaded from. /// @@ -90,9 +90,9 @@ impl YarnSlingerPlugin { } /// Creates a new plugin that loads Yarn files from the given source. - /// All yarn files will be shared across [`DialogueRunner`]s. + /// All Yarn files will be shared across [`DialogueRunner`]s. /// If [hot reloading](https://bevy-cheatbook.github.io/assets/hot-reload.html) is turned on, - /// these yarn files will be recompiled if they change during runtime. + /// these Yarn files will be recompiled if they change during runtime. /// /// See [`YarnFileSource`] for more information on where Yarn files can be loaded from. /// @@ -169,7 +169,7 @@ impl Plugin for YarnSlingerPlugin { } /// The deferred version of [`YarnSlingerPlugin`]. Created by [`YarnSlingerPlugin::deferred`]. -/// Will not load any yarn files until a [`LoadYarnProjectEvent`] is sent. +/// Will not load any Yarn files until a [`LoadYarnProjectEvent`] is sent. #[derive(Debug)] #[non_exhaustive] pub struct DeferredYarnSlingerPlugin; diff --git a/crates/bevy_plugin/src/plugin/yarn_file_source.rs b/crates/bevy_plugin/src/plugin/yarn_file_source.rs index e24f2322..10f61f55 100644 --- a/crates/bevy_plugin/src/plugin/yarn_file_source.rs +++ b/crates/bevy_plugin/src/plugin/yarn_file_source.rs @@ -80,7 +80,7 @@ impl YarnFileSource { .load_folder(path) .unwrap_or_else(|e| { panic!( - "Failed to load Yarn file folder {path}: {e}", + "Failed to load Yarn file folder {path}: {e}.\nHelp: Does the folder exist under the assets directory?", path = path.display() ) }) @@ -97,7 +97,7 @@ impl YarnFileSource { .collect(); if handles.is_empty() { warn!("No Yarn files found in the assets subdirectory {path}, so Yarn Slinger won't be able to do anything this run. \ - Help: Add some yarn files to get started.", path = path.display()); + Help: Add some Yarn files to get started.", path = path.display()); } handles } diff --git a/crates/bevy_plugin/src/project.rs b/crates/bevy_plugin/src/project.rs index cfa1cb66..3354187a 100644 --- a/crates/bevy_plugin/src/project.rs +++ b/crates/bevy_plugin/src/project.rs @@ -106,7 +106,7 @@ impl YarnProject { } /// Used to late initialize a [`YarnProject`] with a set of Yarn files when using [`YarnSlingerPlugin::deferred`]. -/// If you know the yarn files at the start of the game, you should use [`YarnSlingerPlugin::with_yarn_sources`] instead. +/// If you know the Yarn files at the start of the game, you should use [`YarnSlingerPlugin::with_yarn_sources`] instead. #[derive(Debug, Clone, PartialEq, Eq, Event)] pub struct LoadYarnProjectEvent { pub(crate) localizations: Option, diff --git a/crates/bevy_plugin/src/project/compilation.rs b/crates/bevy_plugin/src/project/compilation.rs index 78a5f0c7..77c6c439 100644 --- a/crates/bevy_plugin/src/project/compilation.rs +++ b/crates/bevy_plugin/src/project/compilation.rs @@ -58,8 +58,8 @@ fn load_project( bail!("Yarn project already loaded. Sending multiple LoadYarnProjectEvent is not allowed."); } assert!(!event.yarn_files.is_empty(), - "Failed to load Yarn project in deferred mode: no yarn files were specified. \ - Did run `LoadYarnProjectEvent::empty()` without adding any yarn files with `LoadYarnProjectEvent::add_yarn_file` and `LoadYarnProjectEvent::add_yarn_files`? \ + "Failed to load Yarn project in deferred mode: no Yarn files were specified. \ + Did run `LoadYarnProjectEvent::empty()` without adding any Yarn files with `LoadYarnProjectEvent::add_yarn_file` and `LoadYarnProjectEvent::add_yarn_files`? \ If you wanted to load from the default directory instead, use `LoadYarnProjectEvent::default()`."); if event.development_file_generation == DevelopmentFileGeneration::Full && !is_watching_for_changes.0 @@ -255,7 +255,7 @@ fn compile_yarn_files( ); return Ok(None); } else { - bail!("Failed to compile yarn files: Localization mode is on, but \"{}\" is not does not have full line IDs. \ + bail!("Failed to compile Yarn files: Localization mode is on, but \"{}\" is not does not have full line IDs. \ Cannot generate the line IDs automatically either because we are not in `DevelopmentFileGeneration::Full`", untagged_file.file.file_name); } diff --git a/crates/runtime/src/command.rs b/crates/runtime/src/command.rs index e52733fb..d1315fcd 100644 --- a/crates/runtime/src/command.rs +++ b/crates/runtime/src/command.rs @@ -34,7 +34,7 @@ pub struct Command { /// The parameters are returned without underlying type information, so you will have to convert them using `YarnValue::try_into`. pub parameters: Vec, - /// The raw, unprocessed command as it appeared in the yarn file between the `<<` and `>>` characters. + /// The raw, unprocessed command as it appeared in the Yarn file between the `<<` and `>>` characters. pub raw: String, } diff --git a/crates/yarn_slinger/tests/test_base/mod.rs b/crates/yarn_slinger/tests/test_base/mod.rs index 0a898f2a..d77c493d 100644 --- a/crates/yarn_slinger/tests/test_base/mod.rs +++ b/crates/yarn_slinger/tests/test_base/mod.rs @@ -252,7 +252,7 @@ impl TestBase { self } - /// Returns the list of .node and.yarn files in the third-party/YarnSpinner/Tests/ directory. + /// Returns the list of .node and.Yarn files in the third-party/YarnSpinner/Tests/ directory. pub fn file_sources(subdir: impl AsRef) -> impl Iterator { let subdir: PathBuf = PathBuf::from(subdir.as_ref()); let path = test_data_path().join(&subdir); diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md b/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md index e8fdd80d..2b023534 100644 --- a/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md @@ -8,23 +8,28 @@ Let's first look at how to use localization and then explain what's going on und ## Using Localization the Easy Way -We specify our supported localizations when adding the [`YarnSlingerPlugin` (or using deferred compilation)](./compiling_yarn_files.md): +We specify our supported localizations when creating the [`YarnSlingerPlugin` (or using deferred compilation)](./compiling_yarn_files.md): ```rust -app -// ... -.add_plugin(YarnSlingerPlugin::new().with_localizations(Localizations { +YarnSlingerPlugin::new().with_localizations(Localizations { base_localization: "en-US".into(), translations: vec!["de-CH".into()], -})) +}) ``` The *base localization* is the language in which your Yarn files are already written. The *translations* are all languages you want to support. Put the code shown above into the example used in the [setup](./setup.md) and run the game. -You should see that some files were generated for you: +Now take a look at your Yarn file at `assets/dialog/example.yarn`. +You will see that your + +You should see that a file was generated for you: + +![strings_file_generated.png](strings_file_generated.png) + +This newly ## Customizing diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/strings_file_generated.png b/docs/src/working_with_yarn_slinger/bevy_plugin/strings_file_generated.png new file mode 100644 index 0000000000000000000000000000000000000000..e1fe47be91a8aae10e002d7bf74f7626a5ed52d4 GIT binary patch literal 8767 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∈AsHwe{HS!gq`DyuNr%U8f*%GWCP_0{<^GJ(YVt%y|rt^MoKQoq*|Ff zLyhDnCL=l8t?M8D3`3n)v0X0@z+uR$)qkOj9@t59t3JjClc9#RtL?B7dU*v%=VN`* zqK_66ITS;NNc)G)L5>V&ra!3Ut64cHza6)i6I_h?Q)v?Ldyvo6th2torCRJyUSSgN zu1?P&=K`cYk$pDpDCmQxpfcF!lhZv0R(-t*9n~mR!}gwK6&5y;o@JdJzv|o@vv#>7 z^ubSmnZQ;rd5A;wtgEX5>4ARj{?^^e?|Ik9GQ(wCP2mmG>k>`K6{-%D%6M4GT&~Ej z)H?Vs@fQ7TGYnc8emi7mPKAu0_MM(R=nymkl3iVhAMLg$dkXAuqV*+iIyv81FxqH| zIM#0i*LN#L$D!Hk&1n-!TO&pk$!$wZN1Zi6Sr-41twBPFe5`uGa9Wt@T(lzryyqIB zmZd%SyE(L_Yw)*^9@k;gUm)IsRw~)#aW0IVap|_~*`~F0P^v6t^xJK-5y`sU8d?0N=`VJEQd7OvSG(YHms%rciR3!uUUmm# z!L3@z53jxP&uGXivqhE2fFpQU#Gu1EAea-3 z>~`2)`>ops#noZ2_hgOVXRT&&`9^1{ixrNE^o}xVZ)yZ|6eIZ@7dPo%5@%?^Wqhbc z`i@iD^bQhu)3dsj?f}~SF)WQbX9z^Bj$Xtw5bg%H0v>L+^7+3UeIx{|Tr7XZ>sV&p z+PCg~x5n^-J=eGXOUM2?)H&d$bS^EVzh?J-c7i%uWR{sx`N{L;ABP5pNFglUGWH5x z^?ZppJ$E;tg%+=TNAq^m>IWZFA}1-}zFk#%dL9hYa#^*?)}j9=*}GNbk!{%M*~9;obEnP}wP}+vEXg3(zP>klzsLcP)+ZG^ zXZ$wRw#(1R(QOfAOk(M1IoGwibm4B(RzKLdL<%@!`;SKS!ra3Zsl%(Lh}ED6Q||mO zE(#6v)Q7wLhqQ{F8dO`&_)w7x&#v%~>YOg*`sUhV!6+$VsHEfcc1Sg*HVF+g15ssa z>DmOgo+~`8nVrzOT)_IuN3*GtXFR=ZVfRE%p*ujV^&P#chL#NhF@BOaj_%MzD%fgn zibu(n=$t!=s*Q^9W(B&;kiev=eLS?ICo`D4H-5FTIR^3Pi>T*3j-rLI(Xx0FKRG4U#@+TY9Iv1vV* zHBd%s=>Rvw*5?A@!7tIaJxf}hAq@zc`au3x6-BD3;y?1m;{izBe999RD*w{)>^n~D zk8W~g$b$nTt||9P7%8E6+4{N)V!c?p4sgb%iBikP@lP9UE`Oq@{YQQ~@2@K<18K2M zY@FY=k^)5E`pY5*-%^f$@i(aZz25fn-QLZ5BRLf<6IKeTwa*7+e^lhIOzO*5voe}{ zI^Lh^7;I42?ZSTu2=HeE(Jp%;Tdf0UX;ulvY^oL>sr0b|J6kz8U#w6v=GQbuJDtu3 zmcyh~R3hLGpL-ou<9+7hSVm zo#K2K8sy)?U%$gYIx_I82UIqz!87?q2eiueOCv#InRlu&^;<<*Od3JCf!TKj1NH-y zCH;S|h|t$mcGpMTfhq$y`*>{~10Xczs6Si(kn!Dcn(o;-)TxY=n8klQ=LgLl%BD~Y zO)0>*si-iUZyen@+oDF#2k&g=(s=dKy6nKSco{8KR6jl+y3BqoIK|z+b<5aK;(mMH zz2$cw_11r$CM%gSXm_tBtX~|9)7pHT)cruE>G{)jlU%9&ukW#6!7ZZdA9y_}!+*<% z14d)@A{LKKXB7O15|hM^h%1v9!~gl66D8sq*?$NV8}sba`%g%i{o+D#qztEX54${E zX4B65$aqyPv-JG@rw4bI-qUIn^7qIVrHP4bC)^cR6Z39sD}6Ec!jAU-jXYCoBrGn~ zn3G_$P*(4n?)+C2UHUHGrQaEDGU0$ID2q4oq!T^b`6I+!<}+t6(S}IF34ivBXG~Jo zgYZ2IhMnHOY&IoBFE`dOl$5keGGK?-A_v7WPr?FN-0Ock%;b!GQkMpAf*d^;C-c*!zp{7ZKy{P>O0w4`nGj#73{@M7wS3X;+a2s~eJt~Lew!8`Jl8P$oR%SLKlc?q zAV@$M@VCEGS5GW3c7~-*MKH)6c9|h|`gU~%Qe+&$@=o9rZhTS}^5@BUiMfM*($zwQ z3-@5t>$%Mim!6bUwsD$>4)!^2|K^^ae_c7!o@SAA@YKNx5f&V;e}5(R*6_$&xweJF zUo&JRr6xwy?!yGkX&h4D`^4ZSjNo=xiWuXOE;Ab{&BMB4;sss}1qxUufQUj5Bqd{~ zGc`Gmx>s{3o|Ri!?tIpwd5L=xJbDg}qIE{Dzt^DYIK#VnriE5vw7Us@6v`_TRHW3ujCh_Z^;wt+0rWmH2AyuYZpO4yk}c|TqH*Ihbeur= zO>eb67yfZCYRg)&GVAZORC`w+h?uc^F_%G-1H^@IOS;SxjTBC z?#wDC#(_{zWLJf-o&Y%eHGfT$#Y>5R!$e+;LIPT&BjrT4v}B^7rQ=J*K{K{L_kbb4 zPaRkTY^$$ZobUYzi?aerwY%+36CHUWc#|YJSyTxx!Sa`edlDjIDKeq#QBj zj_=5eZDx7y9DJPj>T>)~e|)7X43+bw?=6i}(InoQOq>``fms0+(_)Z?LbR3)%>eR) zqU<(e^~G06(M$;?ypNlVg~ewK;x$w=nFeckI(T#dB9!dvqMV?Mr5M<1Oi3Dk#*vhn z_5CazCoXg=bHn_38CuF+9j}-tq?p!Av>4zr_Ljv~`U9AO0kjU93%24rk0z?dL@CNe z-92|c!+8dlY^%1`1{_Pdzx_nX_<4!P`PqM=P)wM`>aH}BW~0HKqH4!I+|06MegFHa z-trc|&GmpnwD~lnvdZ{%MR8?v1w}OqZX+%TskgYmE~C-4dpRmENK3)8fwOF*i&+Bn z0GL>g1&2MoI36L$sN4v*sY8pEDb@W>s7XqLP5XZvDf-C=gfTHIaK@|fA29;Aeo_&A z3hQ#}gH$NZM9pCNYX)1PjG&K8ne(&rFpP;$v{&Z7KIArk0kC)4QpcHh|E= z2HX2E!9|a55c~U79Vru>Pjys7is%aKyi6Raw4@K$dR%N#vrv&Cp=GD)Q8D*7%2|oi z7Me^Wk;=xe2}aM)!ea$a_@}w4& zBwcWd=V;>0>#=CWVO-ReZ_Es{Mb(!eQ0ESyxMWElvI;g7^2e(o5JQmFwzV|-w`Q(+ zru1=>!VjImb*@lMhc1u77zl6;HrZg zhxu4?%zG)NA{L)iXHQ!3+A_Rlwlu8=@DC!9tQLos;f%g{D{f zzHMx~X>Or-t87IOF(kNY)vYX|=7#xXZGxTODb%L8vk)=n9R*EHKjApv^&hiRRtf#X zd%!mzClofIr9I*-I{{gG|uQ2*bYj-_SViS)?W}s#WD3O+Y<3D$pCgkZb z65v!986`n@GOW=v*!+EIbNI45Ri1}-((OgPGp~DNHW=&nGw>zpTT1YgV9n7R5*GL= zL?w@_=&~EJw!BOz0GBhRO>}Z0pH?eMX#Z295wMd}wm;p6{i7}YyF|>r->PAWgat+Z zyqC1|R^7qE&K;d5y~0+?y}U%Pxtz$f&}z&N-Vq{OxTJ38@Tw+FBp9b0Rr0nKCoZ3aAy$25XkJ1XU42Lz@2nzo}XT^ zQ;lkG_dJ>LHy;{bec&<}GfmP<(H}Z-9gaukYCjpH;nUcL=PZRogBhlLdwUnWT1H)u zZseUJmYQ!e{PSz>x|=2M{+iDD_jEWrd_)xrkF;bsAazUY+>hW(^kXotDE7nde;?-L z!K-t~BCGC;6>dZ16$bMXS(C=lA9RDw;@U2M+k}<6 zwTY>7c9R;SV^fYvHJtcfV;1eSgyj3^JRR|zdECC5XI#L&$^$}l9$s*GLid>dMrDq| zu6(638~&~=cy)Iqh_80_0b^$|7c_;H?EeMwBt8Fsu4DdZ6ZPNQo2DoCPtseemYy6* zXSdWIN3y(otqd7X&FPdI8hZnM7LlBnS@jomR*n!bkd@l&@F ziskdJf}m9N3|6=JO^265=fRac;hYyt^5{;&e0O?F=ipkFcKlxPz$e}FJY>A~3vQX| zJEnr@bJIa3iPDOPc!a9=Ib;c1kWWX2fL1ZSVKzR&k6{7z3`STE zjf_oc)(M4T=CDYJ%1vGaX@C%AlMJnH`tq#kt-qw1BtubB#__N2SH=UQPO2)Pbpf z>`fL$Sre+H<&D4Opt=nU{oFrzgR?j4EX#SLNJsK$(%|Fc^|6(JUOa}b_38xo z&)8kt6cuishc7>mWq`!w@j{;b!@*IViF-0cox@qC*!E$Yaxx;Kl=}1gxV^aFx%4OL zaUmRg{{kgLQ=u?IBh3!(Tr9!c{Y%F-gk83;LH_seqz;4Bv~;X@`UuEjsfQk4Z$lg= zhl=7$+)!CT+-RLkGhHTh@xd7Jjf3we<722Tna#S1n^N)XZ|4E~!`lf%6T*z-sOcuv z;5`3t^IRMPJEMHc3i*u1^4f!QL1}j86goH&`!?7BrVvF7cbu^Q1lagUS}2nLaY1$- z9g56my!kyQ_KUV$CGv%cFyLiByC6}N6%Hkvk}R?w`K3iGL~7uh)u|;-4u1XmEjuyF zz{r4c#vNa%G8{V3C|DREQ>tWY>4u!KzY7a38YoqeC@^ePLNiSj?(Im1P%olcZ*ckQ zo{8!uAyTut{jLeFRN0W+5h@>#P78ykkE|T!HL=O3xmekXEdnFnkyhIhLsGKZ6tpc~ zrrjmkCoP&UPS>{mL`)IqmSn=%jmK&m#V@=KTOMaLZ-OUWhwANw)Rwz0HDl*H9%?IB zTZ7+$Xd6A!VksLsUr@Qo`q-vkgx4CO<3A}vRivTA9X&6)LZIp=eF1XUD5|UE zMFGf;!;9p5v|=%p38RRG)y0G$2YtHJG*6ELl7#caMMEC+I|6zsg-gt^H$B6K%P^!O z$A$CQ94UbpM@jNE<7(kxjIk=4IQgw?O;Woz0szDHjfHmN5>~YlewB%$h8_>U2@Sf; zt7IMphfHX}q>Dn?Sf*I^#V!^~si$@Wk0SP5ynuDJPN{V#yg+8WBF|(@bn?|Y=Q_`a zH2YrTUa39#tj%(8ll%j~cx&o$q{W?R#Km2eh)i~);1oQaM^rL9Y>7i6=0gpmd1CbH zKd#~{#SAB;bw@t6zUn3I^Zcn0srgWN5Y6@03~Z;gPfN^p#`-S5NU=!UnUwHX|Kt?!ak4kXkXT9Ic%^9V5U#U=ZB; zOjcP$6P`%aR2VoEPKzgm`qY0=eNr5%_SfWI@(Twz89&aUd(ABgPo_DzNjFC~F3>*EFO4%XV;N-f3vvbOZnL~6OOIgc!5oHYL~M;K3#?bSG~@g zAo{LJ{-L5v|2p=Kb6g<;=-8^aRuQ1YhN|i%JqQeD&~Wg{TYFEx6N?)}J)mEiY2{Y) zT+h8CDFWvadxBeP=^!6*%(fhV+e52Y^#32^e*A!Gu^j#))w}rdVh9FAK^ Date: Mon, 21 Aug 2023 16:59:09 +0200 Subject: [PATCH 11/17] Capitalize Yarn --- docs/src/working_with_yarn_slinger/yarn_files/lines.md | 2 +- .../working_with_yarn_slinger/yarn_files/running_examples.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/working_with_yarn_slinger/yarn_files/lines.md b/docs/src/working_with_yarn_slinger/yarn_files/lines.md index 69676b64..8867347f 100644 --- a/docs/src/working_with_yarn_slinger/yarn_files/lines.md +++ b/docs/src/working_with_yarn_slinger/yarn_files/lines.md @@ -1,7 +1,7 @@ # Lines As you might have figured out by playing around with the file from last chapter, a *line* -can be spoken by a character. The following yarn file... +can be spoken by a character. The following Yarn file... ```text title: Start --- diff --git a/docs/src/working_with_yarn_slinger/yarn_files/running_examples.md b/docs/src/working_with_yarn_slinger/yarn_files/running_examples.md index 98c09450..cea28ed7 100644 --- a/docs/src/working_with_yarn_slinger/yarn_files/running_examples.md +++ b/docs/src/working_with_yarn_slinger/yarn_files/running_examples.md @@ -1,6 +1,6 @@ # Running Examples -You can run yarn files by copy-pasting them into [Try Yarn Spinner](https://try.yarnspinner.dev). +You can run Yarn files by copy-pasting them into [Try Yarn Spinner](https://try.yarnspinner.dev). This is nice because it runs directly in your browser and so doesn't require any setup. Since Yarn Slinger and Yarn Spinner read Yarn files the same way, the behavior will be identical to how it would be in your game. The only thing to look out for is that Try Yarn Spinner will only start at a node named "Start". From 374580db4e7fee31b597715f34f9666d72ba5998 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Mon, 21 Aug 2023 18:33:26 +0200 Subject: [PATCH 12/17] Write about localizations --- .../bevy_plugin/localization.md | 82 ++++++++++++++++-- .../bevy_plugin/strings_file_another_line.png | Bin 0 -> 34520 bytes .../bevy_plugin/strings_file_new.png | Bin 0 -> 20718 bytes .../bevy_plugin/strings_file_translated.png | Bin 0 -> 34386 bytes 4 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 docs/src/working_with_yarn_slinger/bevy_plugin/strings_file_another_line.png create mode 100644 docs/src/working_with_yarn_slinger/bevy_plugin/strings_file_new.png create mode 100644 docs/src/working_with_yarn_slinger/bevy_plugin/strings_file_translated.png diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md b/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md index 2b023534..7698de70 100644 --- a/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md @@ -17,19 +17,91 @@ YarnSlingerPlugin::new().with_localizations(Localizations { }) ``` -The *base localization* is the language in which your Yarn files are already written. -The *translations* are all languages you want to support. +The *base localization* is the language in which your Yarn files are already written. +In this case, we specified that our Yarn file was written in English as spoken in the USA. +The *translations* are all languages you want to support. Here, we want to support German as spoken in Switzerland. Put the code shown above into the example used in the [setup](./setup.md) and run the game. Now take a look at your Yarn file at `assets/dialog/example.yarn`. -You will see that your +You will see that your line of dialog will contain an autogenerated ID, for example: +```diff +# assets/dialog/example.yarn +title: Start +--- +- Hello World! ++ Hello World! #line:13032079 +=== +``` +This ID uniquely references this line across translations. +For the sake of clarity, we will use diff highlighting throughout this chapter. +In case you're not familiar with this look, for our purposes the red line started by "- " shows how the line looked like before a change, +while the green line started by "+ " shows how the line looks like after the change. The "- " and "+ " are just visual indicators and not actually part +of the files, so don't let that confuse you! -You should see that a file was generated for you: +You will probably also have noticed a new file in your assets that was not there before, namely "de-CH.strings.csv": ![strings_file_generated.png](strings_file_generated.png) -This newly +This file is called a *strings file*, because it contains translations of each *string* of text of your Yarn files. +Let's see what it contains: + +```csv +language,id,text,file,node,line_number,lock,comment +de-CH,line:13032079,Hello World!,example.yarn,Start,4,7f83b165, +``` + +Since this is a CSV, let's open it in an application that renders the content as a table: +![img.png](strings_file_new.png) + +You can see that our line from before is in there! Notice how the `id` matches across the files. + +This file will be populated with new entries as soon you change the Yarn files. Assuming that you +are using hot reloading as described in the [setup](./setup.md), run your app again in case you closed it or advanced the dialog. +While you are greeted with the "Hello World!" message on screen, open the Yarn file and edit it. Let's add a new line: + +```diff +# assets/dialog/example.yarn +title: Start +--- +Hello World! #line:13032079 ++ This is a brand new line of text +=== +``` + +Save the file while the game is still running. You should see that our new line just got assigned an own line ID: + +```diff +# assets/dialogue/example.yarn +title: Start +--- +Hello World! #line:13032079 +- This is a brand new line of text ++ This is a brand new line of text #line:10414042 +=== +``` +In case you can't see this, your editor might still have the old state of the file cached. It usually helps to change focus, tab out to another window, or closing and reopening the editor. +The strings file should now also contain a new entry: + +![img.png](strings_file_another_line.png) + +Let's translate some of this. Change the string "Hello World!" in this file to "Hallo Welt!", which is German, and save it: + +![img.png](strings_file_translated.png) + +The game will currently happily ignore this as by default it uses the base language, which means it will take +its text straight from the Yarn files. But we can easily switch the language: + +```rust +fn spawn_dialogue_runner(mut commands: Commands, project: Res) { + let mut dialogue_runner = project.create_dialogue_runner(); + dialogue_runner.start_node("Start"); + dialogue_runner.set_language("de-CH"); // Use our translation + commands.spawn(dialogue_runner); +} +``` + +Run the game again and you should be greeted by this text: TODO ## Customizing diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/strings_file_another_line.png b/docs/src/working_with_yarn_slinger/bevy_plugin/strings_file_another_line.png new file mode 100644 index 0000000000000000000000000000000000000000..cfa6441cf64b2b68781aea4faafcf3de01b62bc2 GIT binary patch literal 34520 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 literal 0 HcmV?d00001 diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/strings_file_translated.png b/docs/src/working_with_yarn_slinger/bevy_plugin/strings_file_translated.png new file mode 100644 index 0000000000000000000000000000000000000000..4f636bf467a315f250f16c6c31ed78fd0878e9ac GIT binary patch literal 34386 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 T!uFeA8Gyjk)z4*}Q$iB}ZarR| literal 0 HcmV?d00001 From f84db4c9b52775c1a967e572cb8ca58b3388d254 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Mon, 21 Aug 2023 21:07:12 +0200 Subject: [PATCH 13/17] Enable translators to write comments --- .../src/localization/strings_file/asset.rs | 120 +++++++++++++++++- .../bevy_plugin/localization.md | 27 +++- .../bevy_plugin/translated_line.png | Bin 0 -> 27832 bytes 3 files changed, 138 insertions(+), 9 deletions(-) create mode 100644 docs/src/working_with_yarn_slinger/bevy_plugin/translated_line.png diff --git a/crates/bevy_plugin/src/localization/strings_file/asset.rs b/crates/bevy_plugin/src/localization/strings_file/asset.rs index 98a374a4..6990e99c 100644 --- a/crates/bevy_plugin/src/localization/strings_file/asset.rs +++ b/crates/bevy_plugin/src/localization/strings_file/asset.rs @@ -110,10 +110,18 @@ impl StringsFile { // This record's text was not translated, so we can safely overwrite it with the new text other_record.text.clone() }; + let comment = if record.comment.is_empty() { + other_record.comment.clone() + } else { + record.comment.clone() + }; changed = true; - *record = other_record; - record.text = text; + *record = StringsFileRecord { + text, + comment, + ..other_record + }; } else if single_yarn_file { removed_lines.push(id.clone()); changed = true; @@ -223,6 +231,27 @@ fn records_equal_except_for_text(lhs: &StringsFileRecord, rhs: &StringsFileRecor } const UPDATE_PREFIX: &str = "(NEEDS UPDATE) "; +fn combine_comments(full_old_comment: &str, new_metadata: &str) -> String { + let translator_comment = extract_translator_comment(full_old_comment); + let new_metadata = (!new_metadata.is_empty()).then_some(new_metadata); + [translator_comment, new_metadata] + .into_iter() + .filter_map(|s| s) + .collect::>() + .join(LINE_METADATA_PREFIX_SEPARATOR) +} + +fn extract_translator_comment(comment: &str) -> Option<&str> { + let mut split = comment.split(LINE_METADATA_PREFIX); + split + .next() + .filter(|s| !s.is_empty()) + .map(|s| s.trim_end_matches(LINE_METADATA_PREFIX_SEPARATOR)) +} + +const LINE_METADATA_PREFIX: &str = "Line metadata: "; +const LINE_METADATA_PREFIX_SEPARATOR: &str = ", "; + #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] pub(crate) struct StringsFileRecord { /// The language that the line is written in. @@ -295,6 +324,91 @@ fn read_comments(metadata: impl IntoIterator) -> String { if cleaned_metadata.is_empty() { String::new() } else { - format!("Line metadata: {}", cleaned_metadata.join(" ")) + format!("{LINE_METADATA_PREFIX}{}", cleaned_metadata.join(" ")) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn combines_comments_without_change() { + let old = "Foo, Line metadata: Bar"; + let new = "Line metadata: Bar"; + let combined = combine_comments(old, new); + assert_eq!(old, &combined) + } + + #[test] + fn combines_comments_with_deletion() { + let old = "Foo, Line metadata: Bar"; + let new = ""; + let combined = combine_comments(old, new); + assert_eq!("Foo", &combined) + } + + #[test] + fn combines_comments_with_insertion() { + let old = "Foo, Line metadata: Bar"; + let new = "Line metadata: Bar, Baz"; + let combined = combine_comments(old, new); + assert_eq!("Foo, Line metadata: Bar, Baz", &combined) + } + + #[test] + fn combines_comments_with_change() { + let old = "Foo, Line metadata: Bar"; + let new = "Line metadata: Baz"; + let combined = combine_comments(old, new); + assert_eq!("Foo, Line metadata: Baz", &combined) + } + + #[test] + fn combines_comments_without_meta() { + let old = "Foo"; + let new = ""; + let combined = combine_comments(old, new); + assert_eq!(old, &combined) + } + + #[test] + fn combines_comments_with_new_meta() { + let old = "Foo"; + let new = "Line metadata: Bar"; + let combined = combine_comments(old, new); + assert_eq!("Foo, Line metadata: Bar", &combined) + } + + #[test] + fn combines_comments_with_only_same_meta() { + let old = "Line metadata: Bar"; + let new = "Line metadata: Bar"; + let combined = combine_comments(old, new); + assert_eq!(old, &combined) + } + + #[test] + fn combines_empty_comments() { + let old = ""; + let new = ""; + let combined = combine_comments(old, new); + assert_eq!(old, &combined) + } + + #[test] + fn combines_comments_with_only_new_meta() { + let old = ""; + let new = "Line metadata: Bar"; + let combined = combine_comments(old, new); + assert_eq!(new, &combined) + } + + #[test] + fn combines_comments_with_only_changed_meta() { + let old = "Line metadata: Bar"; + let new = "Line metadata: Baz"; + let combined = combine_comments(old, new); + assert_eq!(new, &combined) } } diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md b/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md index 7698de70..6c3b66fb 100644 --- a/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md +++ b/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md @@ -52,7 +52,7 @@ de-CH,line:13032079,Hello World!,example.yarn,Start,4,7f83b165, ``` Since this is a CSV, let's open it in an application that renders the content as a table: -![img.png](strings_file_new.png) +![strings_file_new.png](strings_file_new.png) You can see that our line from before is in there! Notice how the `id` matches across the files. @@ -83,11 +83,11 @@ Hello World! #line:13032079 In case you can't see this, your editor might still have the old state of the file cached. It usually helps to change focus, tab out to another window, or closing and reopening the editor. The strings file should now also contain a new entry: -![img.png](strings_file_another_line.png) +![strings_file_another_line.png](strings_file_another_line.png) Let's translate some of this. Change the string "Hello World!" in this file to "Hallo Welt!", which is German, and save it: -![img.png](strings_file_translated.png) +![strings_file_translated.png](strings_file_translated.png) The game will currently happily ignore this as by default it uses the base language, which means it will take its text straight from the Yarn files. But we can easily switch the language: @@ -101,8 +101,23 @@ fn spawn_dialogue_runner(mut commands: Commands, project: Res) { } ``` -Run the game again and you should be greeted by this text: TODO +Run the game again and you should be greeted by this text: +![translated_line.png](translated_line.png) -## Customizing +Hurray! See how painless localization can be? -TODO +## Languages + +TODO format, asset vs text language + +## File Editing Workflow + +TODO needs updating, removing lines, autoclean + +## Shipping the Game + +TODO fallback, files to include + +## Customization + +TODO locations diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/translated_line.png b/docs/src/working_with_yarn_slinger/bevy_plugin/translated_line.png new file mode 100644 index 0000000000000000000000000000000000000000..e74c965eb341a2364e1fdb5ee53360c694cc0f6c GIT binary patch literal 27832 zcmeFZ2UJsA+b$Zn4J-BnN)bd61R)e7O+-iGVr>Q51;ks$BwZie#JB&6x$$tTUu9)* z&9N2t_9ry$xo2bJB=&Nhz?RoKM{gbcEYK?c$7u=Mj`tRmQtYapCZe|A&9oPsuLUtO>jp*%s%qh;l2Zs$@z8j{6fZ zW@qOIX3RUYo=(?s@(Ymr*-=AiOhfT&R!HL`#W3%5GZw~i)N!&Wjhg*`=2xkXi)PpA zU7jq!S+jy=%zf<2?Y-S;%&wRHmmP;xOiO7;;pH1*5=B@ZFxXr73w7TQyB`j;>DL-@ zSnQWd^6v98DlL@I%n@A=K4`2CUN7k6JmZnz;gyejPs8pgOw0GYbDEsCgENOLJ?70& zROX?;T<49I#?;V1rt69owrC+$gJhFTqRSIv+CsJ2J!gHc`GNaXx+G3#SrP&bN(;FK zEtP)w8b3d+spBsFqrBrGnN@Mg=*&vLk`a839mZ@Yi&bb|TG&AGxkj~@siZv(wl*rQ zI1w*<`!ES&Up0sn)_Ea_0w>A3yQCZzX~ zc(iJ#i@(1F>Z@Pm(%9DY9b&?+d)o7~?k*1(`lsr*Eqwv9@3!})gj%iCN($O~uCZPDcz()*Z z&ANCUs;*hw+wvB3{@QgPQ(hlBT2)o}IX6*I;Z|vYr)K6M@Xex!9_Req(_<#bR^sH3 zUli@T%!%?2^|UCr-HrU@65snlv);v|l*ZhWTY$6-&BB<)T@19(;TAtRQziJoyKiWx zmZ4VVcIyys|47$?{*v}!_MlH+aI#8|O~DO+WLz7{cBs&IK5wX>dBSq&e#x1-EymJx zw<`JP%p2!t#)aFwhz%|sy@fVfG>@MCvZG*#6wk+A_0#4h*&NGcGLy*3d_q$IGrX^l z!{I#5xripV^p%a;KjIebtsENVyPEiHxtUF4{fiwRm~)g(4pD7>AbWU#B+~t+AMKGp`{I}Xva)qS%E^q#Cx3Ue z#Sl*%>VW>N>2G+Zz^1=TZup_nDIF-#(-SsF@ktcrCUQ<_iTFC7OUQNyp`R$+Y~S(o z7qIigRV;^s@`g{SzA~g0iDQbvvs*lVx%QV!b`O<+k4pqbx{;E7wDsOsUeFfqQ?NMI zG=C2jy<43SKBM|--o9G3e12{Ce!qYpf{`cEGyl3Pd;mOaZ>6A1)aU0Ejn0dIi>dDuZFUuRS72^atYEV@Nmpnuke}M5 zdyXykJXfdmfDD#XV>`-wHtlOb?FlP1DJ6FIKRh|_)<>Lu)cuBSCyFfT@ayADzX%|l z=;?JCnjYWBj`B_*?CU*C^VW(|*?ru2BDzOGx5+WGAmcIi_~H*EX&X8F!2Uk_SXGVf zStG*C#lz)=uUqCmG{!^^@ycjEvg{~@kf+>0^`PmQO0PCd^>mh@wZD%hTF2k25ZT9T z@7x&NIQyO1((i~N7CZD!E?Rg}>N*UBt;>7Yvqf~~r^2}01Z7P>a*s>wbXHk~J&X6A z+187yaqXQHs$mN~{nGO#GL81*shnQJX+ktSF3-?Ze=9RGcMDO`!mJ+Y^GTmc&_m8_ zV!QlMnwRinMNj5WYsk~wpZ1QXHt1ckLp4r$cfLWhqPEN#vSoGDg}~D0$biF( zcjWBZ9Wl}yq-D-z?Z_P$?&~cb7yVO9#C2p+xiqmRE@!W@gF8|N?#MRRH@{%tQk;vjT#zs`nb$ckXJ=QCReEc8 zE;M6TrR^5J_r8uC5w=R1O7=mDvWNx9MA~*O}MxPlr#Tv1pi@>BIozAYrjNXFe*z4*CC{ndo2Kjw7=cM@eS z(uDVVtj*#y(hxTj=dw5f%&x*ObKA$Rl%B|+{qkkge84``@;1qA^K$~F1k|+PWc49X zSP~FDjXuICnd-SYbAJ%;!M*Bi<#~VswpV!c*IanYN^IURux@;{&!<1oei{c}Wl1^8 z-Ne0m(7ADIUTSRk+wpuU)L@rka`jdFI(>zZgel|X#d)GACmlPRE?+dC+Yrc_4a1In zZ0xz+a+?%6vlqvVtYrcXF9^=a))BLB>8n3zWlESRL zXYAtUdpdh&sk<9wsO2(_nxpSXFJoTDu8Z%N%e$oAP=3phq;3QDO6<{2RS$MiW58HS z_WZZO9A00dSJxz=V&0rH>QU~)(jco=OtmqXT>sP=2yeq+Cqq44!nJA-mQTiURlK@q zW=gWl`yOkBqiR*xa|N_p(1w)aRpi8*8E$Ej0RoHRa`u*ciSHHqL@Q?7ax^D5Bvl9}<{WBj|qo(cI>d6l!{$ccr$Q$<(G`Yt!ddSwM%X?AScH)&pv96k}? zRlj!U{mu|ntO7cqn zlb;IEwuwm!&b;YAWhJ zH{@K*?2+$PcI{u93`Q{ZdB6grG2o(ziEmv{`upcTQ(5xv1-B5UZ21AvGhK zW~!<}v-CORUUgQ^S*~RI9{F;dWpme$cjyH9oT|bo48<$)$LnNn9`IpX+Hu=Suu-*r}+ysMtkge5{^KJCAB92Kc zHU`C=9f?W20d?@uN5 ze>*rcQ>lDK*)O}Sc&5Eg6q8*#A%Wo$R0Di}SYHKUG1M6d2COs3^=dnt5cYJ$_@2O| z7kOu#avavXtU`v%V%4A5%$0K#73va&!MZ;Ce<@=*_l#H5R2TaVU7QwcFE1>}qNHu% zJNo>;41w4xXSd0#Ua|5V?i`dr`-xsSs#>Rb^Q)3hF6yg6>T`0wH#KYiuCfAW_(_EF z28Hd#EBeZ5*pXsEYygijy=lXQ=$lpgeeOIDT3)ln%(_e5cQQFQHOK$ps(N+J(|Z>0 zbS`9HWw9ju=49p`FJzaDr})j447!)`g3U;pZtUtIQ>`oJSm9)s>sS~}Z71((=_oPT zp=U~~r+L0kl=nNQ20IRZ^kGn)m0-Gej9h_xmJI|GHV#`+k#$uN6EX&z5*&T;`=tEJ@^Ldz!$4cd4uy(c4YbFN~Ei4MR zV(#NqS>QwcE=d%YoxYfoIJW1vG#kS|E?F4<-s(H>Y@5&5;@YyIL>Cw0ty9eQXE!#( zVB=wpf#cO-4QEwKPX`__4#ov;%Tx4=9qqZgK3-kgDzRuM>wPqFTFlZ^=)8gq(Y|t;@VanU;cccHh4< z9(&Aue#tVocXYwVZ5(mQG3cHuO7NW(UYKc3-t~?)yAsx3clgs}&*IEe6`3^IcD02O zV{Y)X?-M1LFbCYzvf@P~-;7SR=`tJ3Z*?9WW!V{`TYcem_`o5@fcOCe;{NHCdttCV zH%}cI6xVv_Lq2biL_{rg5uF@uq)-RpyID;{d-m^+ZVZc|vs8oKatd=;8sc;{7&dS1 zo1@Xnn^L=PNkoWjZP^inVET$Yot+yvv<7UdH;a|ZTYdyeY4)ay4v!iOhfYkcg}pV6 zIO$;jhvfOaZ;h=NgU#~pdzQppwVX)u8dW7+{LPC!w|GUywZ6asgPZ*v58p4-KUE>; zj}qQ}cc^oGCF}#mmX%j6EQtceFNSE+bc0(R4*qg&(s2u_c&11QT2@8Gs*MV+Gf^OLyPFw z51u#}#@ibFmhSl`?vY-*62a1RkB!b2!{8_6Q<9Ex{yz>ZoCIb6=y;g1bp0l_T);z07ej#+d5$IO$%kXdcJlR`^G#( zY(=E{s9nxRJ(46wCvC%<&@|2OS`I9iM%}5*Q5VZMx|7^LxH;T(OR=`ze80I;GoEGs zLOyk_#Pce&|6&?@=jkebX|!A`_yI|~j^}zzisX$*cpV6qhlr~CBt43x&#Xqyet!=u z-W$J7A8K>jd@y=Xc{L?YuPrKdN*W_0Y0m!-8h>*@Ft3@kVhkDg>o?p>zIV zR9ksTt*n+2ZtC|3_F6YNf_5JzuSLF7)UB!iP&Vw5gHc_4blmU$olL5{q6LT6Rrz{no#-^5Ky|lIm~LgR*H#-`C7znd(1URzkC9^`aua+WJDw z#gaKnXZoyhAvHOz)F}vnm+RZ?DkdHtv#ZG+GXKscEQqCPJ#h#L&=Q2f#HO4DnvKxW z_&TsogRQ#Q!ydKBEH%!4VM|I^dRi=;^$Otl=xRAc1N69&7$Wmw9dgUIOLNTcS5^GL zWWUu4z#Zd_U0xH~`zH)`!N#Ugw~oGYgQ|48ihYSnER!;uiyAX^k05?)ugbzV?-9*H z>)X^K4IEmldQpjMCkcpUtS5yUj|?Y1>$n;P{qdN7YS5rc%?*l|&W)#cU$AgVi+GxDiB?k<$oAag5^~TP=+>slZ@%TJa8l_3N*g7EVSB^xavdhsJhErEO zod2miNDv&6aG&5+glk>^>DxBu?iWVmh$a;KdVJB>7&kMa-)$*3%IM+blQ-gYElZt0 z-g`Jk72tpPnBaiuc({is;`XQW03tduNP|vkB%Hngaz;}??TMhNJ;fg$UW=cx7b{*t zz<1y7pY$ttZM-ry>b7))x90{#RY#K%+XvIcw&k_&cm>8_PstsjcfnCdoPF|1NCWgp z1HMkZVJP7YW29;KNKe_&gWcDf@D+Zl{2_e!=)mir@1`}JrOqsD(qbEGgYowxQROx^ z)1UPRWED}V_^P#|9lBc7gyA(^E{QsgnsXx>LwG-DP8YFpX~M4_9}n{olpZt)mWU&^ zzq{yWW`ucCdC8WduVB%h2LeQ9HGzb;bBo2K--aH66+!)+HGOuo9i3h{Z&eqV-c=a$OBtZOdd(Y;3KRzqzH|AW_&JKUzi z^UL%kE^0Ef&Qtu&ZDJAbhz+{CSz=Mdj=bt@5>g5!h^&zI3tw93tGo8&h~=Xb4V$#} z5$+1^h=ddFj2p3a$oAiD$w3Ba*+JQn+i}k8f5u?L%d75bB>JDi&WZy_)JHf9_k6f5 z(eZoV{&kJzaEmnwwM@SCP_ zvYS+u+;=q|cSnSfKrGt+e1(i1Eka%x@8AZU%4%0c$m!M#2#zi7Qk7cWfb6QHom*_5 z;3JlAdqeoHt(z1!cXH3>d8Mq(i8V>Z;FGxiOmjdu45mf|I{B41oE_AHr8b!A2+D zHS_!i5><;({w<^368$7almU7bborgsC|gRg%BtZgqAV2NPvm;ErBIeFLUVs#5))C2 zQ&|bF$aV;Y9%+iATq7wWHmE&0bIa1rtN|ZvSuFimo;yte@k&Z^-$h(!*);LpNZEt^ z^gfE5OG5fz@71^7?bT$Sgs_nb;1BkyP=SSwA;n)O+{xUA<{X-ICZX8Y;r$C7QK3XR zayh;f#oRr=1l3GChawq3I!GFcf8%`!hkx+=48y=c0+sdGbtj>%d7BIpxarn2Vo#~KGf1gfv4{<( z6C`9DUV*Tcf2CP{Es4GY%>(-bWP?vKgRsDAmPob)p$&P&zd*Tumb@iAzMzrIZzo*a!Zb#35~ za4rJdruMio1YeAG5VkH)4_L-+=MF@{dkLS@l^@@F6;nsgLQ@X7SLf;S2Y6LTg>cb1 z(h!|h2P%=PLyJ(!Ko*#lZ)UU0Qydd+OHo8LQ1Ny+07<%1L7m+Lw!5O1R>hWaRo0`UMBYC<<@hw%g$BCr9Ekb;m=lZZDj+nhk zdv-v!0bhh)of6^|UWWv@vi$E$>?GaN$R}q9ve4!!AZycGaq!(>03SEoY`qqTZ&O6w z_$4_Wh=3xU2!h|~)NZA+VpBuQ(iB-VH3q>UOnA7iB@E)=1c6#bIi3A-5~yfk@ek<57-D1} zfD(^8k38zWD-CRRIfRY51b;EIq9bs`mDE`507CrWZ_Vh8#>{N?oxkcz|B_u2+*|$KW}X#Nw`}G4hdPrAf+pL*3k`c z@STO~AQJEHx*_G4rE$L)U8uX9EOif{^u>Y=DE@`I$<)IiBg~{w#B5M*{)zyH_B`Dp zJr%+`KIBU^M2|!g!QOmfF-&AE)nc<#kqCf{E!<=6KmfYO#hZg1bd56cy+!Duv%t#` zyXAzkcjX{hg9SV&)Af>Ov4{j@lYi1cyF;k?@$`@gS9=^hP5C$I9X>ScfpF3Z7l(p0 zj(Ghxd$S^f8BcAG`+MS^oTlXMJ(rAcOH-~65=(tngf~nC#q7=_g{0Spil}RlV8^ z4brtTf^+|`>I=eM2w_A1>pJiT#B3;H{!855j)?Dggy(Ow5A}Nvqv-MQI^3gGZS_=q zjGGEGuev=ua=8XwN{fbDyPG`*DXVHOu@Elt!|7P47ao^$<*Vwb+%Z_S`7c(hkL|O9Y($X2O|#DBoG`!_y_n+b@=~# znJy%u=NXCqtXrt=XNZ{W4M%V`Y2PTUmUTCaf*X4qUM`IS<&T7Wrc1fHTy^a3;C(<< zh$p7j<2J-=p7TEzQ0pWUU>V(X#?f&Z^T^md$J?PPlBfgQF3DK9o7K~^T7+y$^p|&^ z2@X(mGE&-JCW5GF8HW*ww4>-FT2{VZ9!ve6_u`KlK!TBtyfj!$d{Fy$YBQnS)<*t? zYGaP^1C1L`EGIz;^Znp5Fva}&0hGejR|&q1&bOc=mPQm8Q#(}pE>5@6o{j07O~GP5|iF`SBrQlR0J<-bOpg_Nuf^d#Kz?ob8o3z1Zvn)~e-G%vX5^qHZ*M*C{S&}5 z86>SX6qVF`rfFLcQ!c0f?SOLrGR}!nSO$1-fhz@!tY{(<071`~zYwotDt;y&2$yCD zP=BgQ%~>(_ zpA+Il046V<+MSUR`WKS=10rZq_~2*S?*YX~#gk7E6bdqJf8sFN80kS04Igu(U>icF z#e<#)vTSVK-er`zZl&rfSBOxaiF|X-t6<9#lZC3PSv^ip;3tYV{KRJw-Dt|JA_|b> zzF5^9529^-&=%Yj@PFt7vrnqAx8T#UD+2fw*N_y{WxHd19-jx!yw`AGN#(Lrk4JP zut-11Hac5+bt{$;UARN&pxNwy0(IreC?wFkWcOH>-ZP*SrzwN($6s;)cn8dy=0m7_ zhtPN8=cNA|j1~wuh7^#(H1idrh#8f#kG-Pp$i<3aqRZvRp69E(SDVf9@zGnQHT8ge zDSDcxpgyM^vFjj^;y01;GtQy;B%Jea%S#Or1=Ur-1(?~++OZ4 z0A=_I1`syANf~uM2EJP_5`3K4DAA+mRU!7*H_{ z02f(cYye8x^0pxw8r#+a@4!$Vc5Ab|Fs~0W|Kn4_r_E|vXDXthHN7scpxf-N*Dn>C ztn{?m`-q~WCgX0K!ZCM-#W1Qwd3_wQ$o?0y4kBs>58s>igM>>eCkWsAA=HTIyoC1~ zD;kv#Gd0%8M*t^FLXFk}n;dagguY-WAPynPJwermLRt>{QrXefmxZhy@Tu(Bus^TQ z{72LaLWQ2EJK$9HO&+0N!i=kqN}eB>%F&p$duc5zh@Jj)DDW#Z{F7QjXC2g2U1O@R z2%#KGQ(brC^4cPolmJNZ5=VUm5ZHinX^Gai2%V8aMF0lWzy7m)P>Zov883wL`K)NS zdf(Qtc5Xu@_D|@pAG~i|OLdK{wh;1in1Aq`usMNxSQSv{pZh&UKqPp5bO7 z>$TP7K~lQ1ryV7nXsB!3ke3o}GLm%&nzyTRLRg1=Y3x17yg~R$%I2;gdy=W&gzrwP z%;uBm2ByN@KftZhlw)!5CEWqef43&V1&8!RD#hoi6K*jV8pNHd?MS82hCH5T!UNf` z)0Esz+VvzPjZXm9bzE{|?6-BR&Z|E9DDcbVJ?uQYhGk*FSLQO$^ecuo<{<^{7VO&w zHY_d&!AzjO-=bj3Hu^6j8NF|vLd(2;B}8hkyT4%LMC=XMU=Rl4C=fRg|GoM3B4B9x zK;%+p*5mCghM9VuwiL5FfghA(wkkkx++KPUpT>@_#t3xWc-Jk2c4Gkb6)YPNOiWtS zmC#;)gS8w8qPGa~SzFQ% zNK;FFUIbK0gZud5dvo#dQO`(FortS*{kUU5UTt(r8jnuT6V#dz4TNsh?til@jh#^K zD%3c$N6;SiB~Q0^%c}y0K{RpW&=J&;o`?pd0Dy3OfF_1IuWOu)?Py7&s?UB7OPYQG z=`VN4A=NHIH4f@SHtNq3|EiuE?S%{{X*a4eL7@Qxn|zYG;gkhKi-T))dWv8?3l{a{ z4`Kf1zI67!#*+zJe8D&iEfe7NhA++l`NCUZQmX$6oN{wWhI7XOdK@7b8m+^%AsdZn zq0&?+FGsvOvKlk&whQPM4A4RlxQjoEbEhEE13KnYL?&Mci@Nb2bmFFZx@%&!mnP%h z@Lp-u+APC*`m;^ieLSFu<4}wdO>`~&)Wr^q&KwcHk$0n}L%g;7pbr-85~4Zy*GyE; zL>QoV$U&vKNc<6s3>q>}FD4mENGhwO;XvPuu%q;?IY*fiLveJlml4CSqT)fyThFii z?R`I=Z`;VIIk_afI6dL(ee9=-5CxvSlZv+!d|_|ifA_Ps>4d?PL+W4GZP#jt2JzP8 z^R!XFdM=719zmRQ4zI(psC!z3B#;N|_Xf$K-0Sc$iMD)gIZgSo0cEq54u$c!z&zl) zX>td}Pznvj`CE;q_eT9{p`3PetY&*Wyhsl~>nS|ZtqdoiW&Q~7a|md&JCsyb(IxR7 zR3zE8WA!+r>aO z`kKvsIF)M;eX?^yC`*ab;%(foDZ1g~@t<&@5y9ye(xJ=(VTS#!Z$A*p5}QJq)#kQ1?#{yvkPO2d zLKF6A;4gG$DW*b#?RCGG(BHwidaa0TZmU#*QH@0MY7t|qr zW7i09GK7MELs-COU$nOLg@L`vc>8H{!t@F#Xzq;OgC^Wz{vqD5@h_YrG6Fg=pq)fQ zs{Fda;cg2vL#mB|Q^bTCb%p{TRDV!8`!6p6n$G}k=Esz)weed~0JEy!_dWCNp^2bG ztGhfO1m77A{rjOifHGcKeaZ&t3ete9Af;1zL=0 zf>-O2Q(GL^aB?k({o#U6DBFYU)@5z=W=gp^L#BZ!8L@=?U{zm$go z(9v>-{c^{@x7l}tCVu}D=&#P(ei>&lNPz$h564rlItwUX`S-FpEH%;$`l@Mb|Gp_` z-~h+h`S*$l(CO3H105qb29gMRss%9%+UO`ZU51nHFApfN=-+~f>V;}#Z(g-`VsUiP z70)r~s;VWDp|)Yb$#YFTh{n%wl;ux(pRYdHQcl<6G~eeSTATrUi9jT5{d-9$8==w( zvKT`S)VhmD{h;!ZniI0Emj2sGzG&&WtCl{pF&fCfS_1}^BYy&kcI=YrZr0)LP!AYL z@jnGI%C9r5521MvOe)I=A_aH&A{UB>_};3Tk( zl`dy@h(p46qc$NDWPZ7kt$7O2@Cg%W;k!R|SWReCE^DwLTXn&pmZy_%IQ&_Vj-W=K z&zF^=@59z=eA6a>5?%O_(TVXaXaGmSU;_LZ1U0u_8Ks%}?mUGNiI7pNAIKu%hgTMZ zZV^~@%H9Dd)Q_fznt3x{MHjxB9jW)#d-xq#6doE>wuVQ~XJRLF;%TJ}Wpbv~Xt$7r`>whp7b(YXBNEOtvPOXT z1t{Xr%4fd@(YbKW46q!Ol1m^bAz^Xcdf`0h(OLDEF>3=Ft!JC#3MS=!KZmT@5dW&b zabct}-X(x(ar8*=1InBDKOq~_+vE}ogv!VgFFMqkO*|-|G zDgu*|XK=~GJazCw92g>DKWL<@O4IPed&!!FchO6gc>R@e|8z`lXIza^+G<6IrW0{rIFXwm`{^@;rn5w zNK@dbHLuMYLpj0BVmu7|_AuUhVbI#SadC{bFjkJo`Szlk=@01L>TrrSM?@E=Yq(KFt%ZKA9^*>~Oedymw8{}*?{AL>#}VI=VHu*0kEORy zemkpGTr@XUlG(g-R4Imi-g?#~-!kuVnW72*llJYKwdQ|Jx%+ks)vG50G&rhk=~}fD zgU!M6n4SHZIpxJX*$TFB#b=Sl`kZ-vKbPBOvqHs;boD{$VOl6N{8hJmqece)Otk@* zt2O^{u_C7H4(WvS;fM9x-ZX~D zm%krnQ7v3B2ie981I8WwD6KjAsK)V;x1ZvBXA*nqUSuqfhVAzMrX%XO`txeT$jedi zZj>FV9GnLz;2I37_0AY|nj!P9l=kfemdg82t*3J1@-f&&E>;vI?mMY>@MKWK=s{vY z-x<+)4c8W4R%Rj*76)qSQ|Zw}W==&p`H}Q_$=@G?c|b*O#dL^En*`~xT#AR&3dq7e zKZ1DF(_{EQ z=eEQYMcqyUqfVODt1HU+k1kV?-Adg-;0On^-O04uag0h z_rORcc|_FPbB@u{rc^!C4T6Y)a7F}hGRl}8sra#>qRHwZcl6vVrGppmrsqsfq-&M! zga;?(B0FRU0HHoD<2*aE?Xq3Iq;ovQyJD_8$5LV{+p8>-S3H;|9^keMGeNiM?o8;J zNMo$U{#e_ICXIy-9HV}4ICKuG8?h_E?&9}O-`xlH6my`?fL8e5JXADK1u_TOuL9XI z+HGnw2U}Leh(~u!Ub$lFaoL?_>6Je@n5SE%&Mj)hEHJUWoKanImUoSsIih4R)}rG{ zXX&89-EofAB4>2yLbaYpq^w?qO6!HaM3M9FM5jNj?T~&DDH&jB*LQo=d_x-ZLaagZ z`Iar0CEX!yD53iVU~*G-jrC5{Er<~2OqKO~l}fowR9G%XWfZ{m>s!GdvMEvC908v( z1U7~VL-Z3`Mo0+2)`sid3V3W~)H{U-t1`N_oZj|=)SkRJldOv6dSPkxq)^qKc6-w8 z(!+?T@c9xfm(|huB4>Z&jTR<$K5Wr7d?5Pp`GdF?6!rG0x@amv`d-?m6SuQ+I4iY& ztimnpUJJ!&q^;7I+N!yMsI+zKT4)QSOHE1`Ti=*BGy=SK))~KYU zxE?6PATai1kZ_Xc&*bP3^;1V2%HpZXdas<{e+^=oCeL0f>5A5G+k2_BqZ4w#^xZ{*k1XK9`d37P$H6+`>QQ={7=Q zVNnAx%v@?nD&ngXFITx0z`}{6VGT%(On_bFM7ZP5HfY;p-52M2D*`mzd*{i$c{q68 z)p?5ur*jk05zW4GdT~^XnS0S~M%Jdx(p=ANA6ksm2xK$q4e6x#@@&tGt+U5=8v5`Mn=2<{K)UXz31Q+}OSQBabAWw!5qp zw0!94x3MnzwdR)T*VQAw@##q8{RI?bjU22k! zvq>u1O^uO{)9AdR#rfofxQh8fGFi2^i|WAH!b_00JN?mZI5naNuqGI%Yo*M!pK-~woA(oZ_}ovulq>l&IeB(w%x zFf$y#q}gf6TKpoo@Lc1HewtnTO!q?yVd#*@Bn?FBTT~`HJgw31=9z*HyK`UVq~s7rqHOJ+Jd62e?tv-x+@F~^~KFpY2TgL*+g zb@|x`qOTCP#S!1Hh$LzN+WW6O$d)poRQ}V~b4?LtcNTbzaPWYWagZ6p5ZEv6|Apbv z160)y0$Xd4*gp`{Z;=r4U-C}#DP#>5UuOuKW5Amj!z7=c{(NeHq*kYh0v7PzEw;e$ zSxd+NLZ5&&OcNno!XQ~XW&^=OMan%0fAm+P14F3Y`efs8p2DJj>-^?rM@fq$l7QyR z1iq^cL$?(aDNBMDfc1R!6ymu6YXNg70Ra@&wpEyA@1I2= zI$!sVuxisR zK9SP9yuPD(5IBM>LAR}Q%PNG0*e?uI1kobL32>w4i=PuPABIc~`t&+=IEsq|3geQQ znI9B~aMZ&9Qt?C86_J2u7^E6Q9AEfubR!_L_x_WD0*op6>SYHm#N>WTDBs+GO$_ww zYUvw+a1(86F&%8DD!@Nli(mRX)=pZD-q_jS#9KPu&5RPMw&NE(|-y_ONyxYxlzQD(vr6Y!7&01 z8j=55b=6+r&2>{bG@;|u;gGHjNS)G>q(c4-DTJYm;lyFSB&y;`238}e+u>vYbxXt` zS^@`>raM7>Ffv3jRKmO~C6>Yo^SIhah~)s*Bspx|@5lcEgAS_K12dNuVw(8~b&% z#Gln1k1)VM{m%A(m6H|z9UTGRbvTi4imDxWLZai3vr0J~JGhXP5iH8rwcD2`PjlCO z*Z-&z@i(U;%3abE(@K3~e)zi<37YwzioT}49X4xBG(C8+FvAmoS#09naGZJgymiO?NaKPN$7O+BffN32%zJ|k*dL&= z2>3+8&QPXOxs62l%x4Kyhg~_4SX5T6)0VMxbVQg+Lp>7%hf{#Mf6I}EWbaOl*$nd- z%xS0O`I>$12Ao-1MS0P1T0*>qOIdyqL?CF$;K0_LSsD#kp{{2>XXC3qgnA>C6GWjh z2YDmI<3T&@kCDAFr@czk$DuBB?{sMI&9U;iG5f7&c;)kh z@-7vdv8BJ=A>6HYhk7?dHk!|p{(z)%L}(6zBMrP;Dsdzv{h}1gj$t6$GzeVFpoM=xj~@M>kW*Q3nu}?F)*4rrB@p) zscTDy{8PKrixP^jS{`o^+WjO6>)IE5NCoIe1C@dZ*a!R5A15jgX}+5oPF@&hv?MP~ zXlD4%fn%d%CIt&vU3Z8k`T$PfQQ&b2`{U2Gg`=$t@(X?PQ+hoRK4YK)8K`(jJxH7` z<}Yc#Qc{1BJ!h$iZ_;*b1b&r-;2$Z#odob5qzBZgN5kWk7Yj!xj&>~yJvmFTL zBjD4U*2StY!%y-kta&32fTt-tGvx!>A!NROH0}Y3|GO=3U*voa3(PC(dn_~c!lsQ` z+Tp+vtjh4`B=kB30=`ygX^^u}7r)|z*~xy@P%s>hf(Xed62Xijz5}>Dm2u=IIMol# z&Gg4jE7t>sKN`xNXPRKw&u{5Glk8f(mpm9}-7`PhyMW=)fT%%EjkD^QuQZ-N&FLD_ zEbQ)*kaF7`7_G+9%FY0D&)w z8RNxat$cdU74QuUbGeQeZ)bVfpU5%PYPA|{uwHQEKq|qg?NF-e6=xX<#kr*O5B9KrAM69 zSYU^_fM!PE8=oPyUiy5SHSco5ijuEE!W}0@3%tq7v^<=`&a&@UCr@B`leEIoonBub z>@L9i*n`uA?dw7N8N*Qqk0;mMKBjfV4anFH{Jj4aNi2E<$e~F+aQrWy4f(0x?+ODQ z>{}7fXXL?Ab@C&s`TTt2qQ5(btXjBjYSaZ=;`2$kr-=#_u|-w_qy%EhtoRzzr0-K) zN5;+gekd+gjD4GOYFAag>9UxVv zKC5D0I=CHZCr*#>zz!KsJeX3{;7bWh+qfT8&W%@L*IQop8vB-qC5@&ygha|=Hjjha zlI~M)n$&#l)}O1%`82D}QXpSB1MyN|@Ot*}TLWI2i_>-)k%s=5Q@- zNd16)!!P~&vCF1AS+8~gMRfY)fdMCy*{lKj+KO#Tgofi|@B2F*a2G;;10R2`9iqZ+ zidVo87TaBs#kZrdDSqiMMB0=YrB+^n&0d9%Y+h@dJb3=`1%eQl#saKJPok= z+)O=hcocPn-wl#Be1yliO~m0LPg1w1b>pUHYo8kz%la$sz+k)n2<*KX5JZg}M%r_G z{9M#R6&^pmoWpUfVI6{9-KD9rO-R*Y{*`NVwW-jR2=WmmF}E;f7HJE?q|b;lPt5P$ z4*Q@^&qrUGQ#*(CD4*^FN1Abutvs@P6R)U+t%f~2B*eWrpW+%`ts}JC!T(jSwvfC- z*DLmRbiIl^I9jNPauc$4XPAP6OHOh)Vs457fTTFh=a7#Wn1BwT687;-w$6rxdG2WT z%$b!5_uO-0VYY_Cm;`Jn^7i~*3U;4jO{Z^C={!- zx!L<%|AEjjC8K6<>1rd*w7X;-s6qQ9+JNE++&F5=_DdK+FBvjh?&=>+oN~J!A?K%LUSS&cApaQ(! zIt9)AUV&pCyQaZvDwpvxM9$ILgWnl({3n*Y0`}qB=SAV&*KTQZHURy2R0jH1hYx%H z_EQ#CE3^ou|1(_%2w6WbslUs;(asV$b)KaCPs$9$tzmZz&z^w}yYhMSVRf|1Zm664 z4@6-3O!Oa+9&zD$^My@kpfFlB6UkmIq zRkBv;M{v);xi6i8EEymPK#(5x!33yyz#Y+u_o&19K?VV7K&50g!v%oXJVtZ*xLL+O zX0A-oyWP+Lu=?_;8Zb7C;fMI(ThD*(+k*40I5@^QBZRtXNu_{YAHH3S^G}V2YluK6 z*i%ZQOem+CPLZnXah^`ghYsx~ zYH@f#e*Xn5BTq9%%F%uHmG1NMc1^gSHPOVjy_g;HM01WCa{r9m_ z-~b+!dU>95!#u@59fY&!`oCO4_>MhpQa5@R!NHQz36GT`^Zv_obXsNJ1~fb{izsl` z)yz4CM`!F#|&2PK59Of>KOU!|RS zINSO5$9t!pYkIXqH;SoLTe=`EiYk>sX{$w-DH7WdqJ$b%Diw5_SYmC7z0rks+K>{o zCFqnS)@Z9q#Cn?)(-LXK5)yhpNtfw7bLT$u{C@uMc1OzI^a^ewf(A0ux;y>atTK;R#(1ap}mc{qgyEiw3N zj!~Q7xdQ?($TGp;Wnf+Fj8^Q>irZ@``NgTAH+DPd`4xk%r^4*MH+6-y(v2#6z@!5D z>G8==#!B3wtT>rIhsOS2o)g1I&Wv0dQM}G~lviq5gPR5g^R+%_pQ!nzcdnm*D{TDD zerNt8U%3&3S4`h8>ZoLvz;(12 z($Z3myLxLWcJgHk*p?W1)epD?hrw{L)UoiYHlaVh=>SfF-2iPC3b4aEVGE7aah=63 zdh?av0DSwYhKccpN_J#SeQK(W;?I9P)?)7c?vi?cO{OV6!6m25yq#TuVIR4&G{6t= zvy^S{J2fGj3VPT3seuahF28}i)8EfgDVNjt&Gd{mg8Yf9Wbz(NsWx?nb7V1H=Dt3-CJ29WR^8&0h_olj)?1b8y%HBA~U{p=E& z;-wYq5j(JPVB5g%eJh+@^|h;*O>7Hn(E*aUB~rWk*IVY%9sfKK_O2&V+l@-FYIu@< zIPHzakdpj-;jp#5ht62`Y5iu#oSZOAl(S!@A3h4vZkIvfn~xWD*2J(+cToB~yto3Z zip16j_d~QdzW(|^nP7U^+$E~b;>Pq0mlnfI!l8|&CIq+%Cb>|zucRW(5$QG(avGHQ za$Xy-i;_UKUU}-UNtf)#OX#V5l^xm-E~dEs<^YSnY{$VI{Iz_gHljGp`QHrQs~PLG z_IUsT-5NJ7;(kd41>59s&|Bqd08t!mLYF=+=a;DwZLsx#n%n0us5}oVmtR46SsH-( zI$~1|8XVZC?>EaKzJGzxbvc|ej0_=j&h$g9H@;R<@$4J>7p#h@qt&8o+woeXVtJy> zPJ_}w%JbCgceuWWxyDb;yXvSBesxiHQ4ZuL!9qNq2X$80P$_{@0=ZLk)vA{38!Btu zm}hTAHbwHMSAKKoS}|*jVME@q`JSftMoXT^@}||z453;XJLGF-q#>7c5&r@wb-^V$>kJ3VQG2 zSJxhVWob_6){-uBdUQMK!LV@wVY!Dx5KrT8BWC{wg;u_cMXvVyrGxH?MA8Rxr-H9c zp*P8%&)&wL@r3Xf4!!_g&d2q>g-grrTDBS+;oqdJHW|8cj5%4aC2Lw~3%ZL5dZ4Z= z2()L!0OaDh$!k*ocVL1wU_j(;^IMreKAW-9@sPfKS;xKXr>?hTxG*yrQH>kIC0(^JZ?Vs;{Em|27 z6mhZLzZ^daNqmpgcp8-o>2)*2Nm^?(s@LBrBM48X=QCR-{a*;PdZPl~T`i3+z!uv}$LVA`DSyi?mf?~l4rw=1eyQI%MzzMb z0^dj?Vu`?S!dTJq)3pLkp%5MEVKF!q7}?z%7|ZfYB&O&9(7GW?pEf(4Z3Cd8WT>^B zk##8y03c;P&OQbuM+{8-4TT+wWN5is#NUj<6kl^^?N3 zOr2P4B7Q>LelXCcd;B}P4HH#9@pa8E%JMNp;ezrr_q|U8@b+)pG$Kl_WOFN^I^vML ze%ta_=#Kr{<%r0gXf?8FAmU*7QquB#?|m_Pp3gSnM>MK>Xce9bdVcqi76V56%fQVT zHm_89PvS+gA*$@@V^F^u7OX6wB6(T1{zNdom)xknhXo` z7In`Up{XAs@RfP|X{pX;`a;Q4f4DL6skkM){dmVyH2njO%H9Cn30Lp$w+EFJ z(^hV~vuA!c1ZrrMwg7*%7P(kRDDtfnM^u^h;`2UDs3@;{n1iu-nnmx4n7g64!PT?3(31?Ilkr zOOf0|qR*!M`xF1;rmWER_ptWxI6WlPza$G}z#aAFA$i{WkfmedR;l#G8BfJ`F$$$Be@0lc+NqgGw!+9)beAJk_QZy&k9Hf82 zPoJ71zbt&J1yD^?P4Vw#mynw+;cK$ zYaNC%pPQf><_?7JKz>)JOp}(Vh@5QLKvc2VKtu$( zn^2)&?vLvY0Ce#cyo86HEj)@*GO-(d=*=>loQ$Lw`)~(AgM3T|Iil;@MeQMo=sT)A8l;g270T3ZrX7628`lIm0dp7q`6FgI{o^61LyA&G1- zo|dE2C0A%@rm>$bt?{w%*@I?k$QFrC4c zih9n&v^|6j z8Rt|YK!rx&iR3)T#N7B6fLE78*|K&&?9IOoh}Er#vIf}*N=ONd6F?5k#AS-&tYchc zOgy=0>tfw#r5H{%NtcYX#z6d@Hq#b{%3^&AABtwXn=LJM8k7MUJWxiR*J!T_r_j^q z`r!p6sGUG=P;`>W*(@r39_mRi%`|2V(79PO*loUgUMqNR1SddEAC^uQtP(C13}=PT zH*gDyB)-g#30Ua0y>lR9x>?GfVelwGrF#h!k+P@@7;CjyK9EFN%Z*pD^Y3Bvuf`f6 zu<&1FP(WXFV{&x;Y9M05=h<7Bb@l!|A-=RoJQOv$%Oy9NVGkLoeGgD9s~uev;o{K8rG~L1JD1(w)|KvyY9V zQpv2C0{MjLp1ZfUHGa z2-cy>5Q(Gbfa*u^=&(aH=VUSnh?oX8drXEkV+tp)1l=aJ`^fqU+ZTUbxY@>8(HQRB z@82l0`z2QVXK9hszro)1J}z7BV`sGL;XTRt!qJ-Z*yZx1!u=$+d2Z~e6&Ul(yrO~X zL1^u}J;0mJz5>y{=FL<7$U0aR1PHqTx_*2lb+B*D^j(j&quWob?k|VKebyKSwy$fv z&}%>6Dbo63umjo_W;>TEnvGS3X_%m8>j|r13Q>x_?F}=^nUdDMKz?A7f6|8@I7*pC z@+=xnnSmhNy2-C+cAcw!vlqA>R`5vqToQ3pmnEA42*`GuoV{-T0iS1Qced|9=XaL5xzRCsK2Saoz@9X-Yq zGdM)v(U77GmOaE~?P)vH7g%Faj@Z^sdGveWQX3}3tY8&SRe0>a9Y|Rgu(5C4V z*2@|%NY%w&|LdRr*CTzoQM Date: Mon, 21 Aug 2023 21:10:29 +0200 Subject: [PATCH 14/17] Actually use new code --- crates/bevy_plugin/src/localization/strings_file/asset.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/crates/bevy_plugin/src/localization/strings_file/asset.rs b/crates/bevy_plugin/src/localization/strings_file/asset.rs index 6990e99c..3c89e07a 100644 --- a/crates/bevy_plugin/src/localization/strings_file/asset.rs +++ b/crates/bevy_plugin/src/localization/strings_file/asset.rs @@ -110,11 +110,7 @@ impl StringsFile { // This record's text was not translated, so we can safely overwrite it with the new text other_record.text.clone() }; - let comment = if record.comment.is_empty() { - other_record.comment.clone() - } else { - record.comment.clone() - }; + let comment = combine_comments(&record.comment, &other_record.comment); changed = true; *record = StringsFileRecord { From 1874192525628b65b831e35538b4b057b1757ff3 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Mon, 21 Aug 2023 22:13:47 +0200 Subject: [PATCH 15/17] Clean up folder structure --- docs/src/SUMMARY.md | 42 +++++++++--------- .../bevy_plugin.md | 0 .../bevy_plugin/assets.md | 0 .../bevy_plugin/compiling_yarn_files.md | 10 ++--- .../bevy_plugin/custom_commands.md | 0 .../bevy_plugin/custom_functions.md | 0 .../bevy_plugin/dialog_runner.md | 18 ++++---- .../bevy_plugin/dialog_views.md | 0 .../bevy_plugin/localization.md | 18 +++++--- .../bevy_plugin/setup.md | 6 +-- .../bevy_plugin/strings_file_another_line.png | Bin .../bevy_plugin/strings_file_generated.png | Bin .../bevy_plugin/strings_file_new.png | Bin .../bevy_plugin/strings_file_translated.png | Bin .../bevy_plugin/translated_line.png | Bin .../bevy_plugin/variable_storage.md | 0 docs/src/introduction.md | 4 +- docs/src/working_with_yarn_slinger.md | 4 +- .../yarn_files.md | 0 .../yarn_files/apples.png | Bin .../yarn_files/basics.md | 0 .../yarn_files/commands.md | 0 .../yarn_files/cond_options.png | Bin .../yarn_files/dice.png | Bin .../yarn_files/file_system.png | Bin .../yarn_files/functions.md | 0 .../yarn_files/graph.png | Bin .../yarn_files/hello_world.png | Bin .../yarn_files/lines.md | 0 .../yarn_files/markup.md | 0 .../yarn_files/narrator.png | Bin .../yarn_files/nodes.md | 0 .../yarn_files/options.md | 0 .../yarn_files/options.png | Bin .../yarn_files/running_examples.md | 0 .../yarn_files/variables.md | 0 .../yarn_files/variables.png | Bin 37 files changed, 55 insertions(+), 47 deletions(-) rename docs/src/{working_with_yarn_slinger => }/bevy_plugin.md (100%) rename docs/src/{working_with_yarn_slinger => }/bevy_plugin/assets.md (100%) rename docs/src/{working_with_yarn_slinger => }/bevy_plugin/compiling_yarn_files.md (91%) rename docs/src/{working_with_yarn_slinger => }/bevy_plugin/custom_commands.md (100%) rename docs/src/{working_with_yarn_slinger => }/bevy_plugin/custom_functions.md (100%) rename docs/src/{working_with_yarn_slinger => }/bevy_plugin/dialog_runner.md (85%) rename docs/src/{working_with_yarn_slinger => }/bevy_plugin/dialog_views.md (100%) rename docs/src/{working_with_yarn_slinger => }/bevy_plugin/localization.md (78%) rename docs/src/{working_with_yarn_slinger => }/bevy_plugin/setup.md (93%) rename docs/src/{working_with_yarn_slinger => }/bevy_plugin/strings_file_another_line.png (100%) rename docs/src/{working_with_yarn_slinger => }/bevy_plugin/strings_file_generated.png (100%) rename docs/src/{working_with_yarn_slinger => }/bevy_plugin/strings_file_new.png (100%) rename docs/src/{working_with_yarn_slinger => }/bevy_plugin/strings_file_translated.png (100%) rename docs/src/{working_with_yarn_slinger => }/bevy_plugin/translated_line.png (100%) rename docs/src/{working_with_yarn_slinger => }/bevy_plugin/variable_storage.md (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files.md (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files/apples.png (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files/basics.md (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files/commands.md (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files/cond_options.png (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files/dice.png (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files/file_system.png (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files/functions.md (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files/graph.png (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files/hello_world.png (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files/lines.md (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files/markup.md (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files/narrator.png (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files/nodes.md (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files/options.md (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files/options.png (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files/running_examples.md (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files/variables.md (100%) rename docs/src/{working_with_yarn_slinger => }/yarn_files/variables.png (100%) diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 7f152ed0..9fba0e16 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -1,24 +1,22 @@ - [Introduction](./introduction.md) -- [Working with Yarn Slinger](./working_with_yarn_slinger.md) - - [Yarn Files](./working_with_yarn_slinger/yarn_files.md) - - [Basics](./working_with_yarn_slinger/yarn_files/basics.md) - - [Running Examples](./working_with_yarn_slinger/yarn_files/running_examples.md) - - [Lines](./working_with_yarn_slinger/yarn_files/lines.md) - - [Variables](./working_with_yarn_slinger/yarn_files/variables.md) - - [Options](./working_with_yarn_slinger/yarn_files/options.md) - - [Nodes](./working_with_yarn_slinger/yarn_files/nodes.md) - - [Markup](./working_with_yarn_slinger/yarn_files/markup.md) - - [Functions](./working_with_yarn_slinger/yarn_files/functions.md) - - [Commands](./working_with_yarn_slinger/yarn_files/commands.md) - - [Bevy Plugin](./working_with_yarn_slinger/bevy_plugin.md) - - [Setup](./working_with_yarn_slinger/bevy_plugin/setup.md) - - [Compiling Yarn Files](./working_with_yarn_slinger/bevy_plugin/compiling_yarn_files.md) - - [`DialogRunner` and a High Level Overview](./working_with_yarn_slinger/bevy_plugin/dialog_runner.md) - - [Localization](./working_with_yarn_slinger/bevy_plugin/localization.md) - - [Assets](./working_with_yarn_slinger/bevy_plugin/assets.md) - - [Variable Storage](./working_with_yarn_slinger/bevy_plugin/variable_storage.md) - - [Custom Functions](./working_with_yarn_slinger/bevy_plugin/custom_functions.md) - - [Custom Commands](./working_with_yarn_slinger/bevy_plugin/custom_commands.md) - - [Dialog Views](./working_with_yarn_slinger/bevy_plugin/dialog_views.md) -- [Differences to Yarn Spinner for Unity](./differences_to_yarn_spinner_for_unity.md) +- [Yarn Files](yarn_files.md) + - [Basics](yarn_files/basics.md) + - [Running Examples](yarn_files/running_examples.md) + - [Lines](yarn_files/lines.md) + - [Variables](yarn_files/variables.md) + - [Options](yarn_files/options.md) + - [Nodes](yarn_files/nodes.md) + - [Markup](yarn_files/markup.md) + - [Functions](yarn_files/functions.md) + - [Commands](yarn_files/commands.md) +- [Bevy Plugin](bevy_plugin.md) + - [Setup](bevy_plugin/setup.md) + - [Compiling Yarn Files](bevy_plugin/compiling_yarn_files.md) + - [`DialogRunner` and a High Level Overview](bevy_plugin/dialog_runner.md) + - [Localization](bevy_plugin/localization.md) + - [Assets](bevy_plugin/assets.md) + - [Variable Storage](bevy_plugin/variable_storage.md) + - [Custom Functions](bevy_plugin/custom_functions.md) + - [Custom Commands](bevy_plugin/custom_commands.md) + - [Dialog Views](bevy_plugin/dialog_views.md) - [Porting Yarn Slinger](./porting_yarn_slinger.md) diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin.md b/docs/src/bevy_plugin.md similarity index 100% rename from docs/src/working_with_yarn_slinger/bevy_plugin.md rename to docs/src/bevy_plugin.md diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/assets.md b/docs/src/bevy_plugin/assets.md similarity index 100% rename from docs/src/working_with_yarn_slinger/bevy_plugin/assets.md rename to docs/src/bevy_plugin/assets.md diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/compiling_yarn_files.md b/docs/src/bevy_plugin/compiling_yarn_files.md similarity index 91% rename from docs/src/working_with_yarn_slinger/bevy_plugin/compiling_yarn_files.md rename to docs/src/bevy_plugin/compiling_yarn_files.md index e683ec61..5f1d8fb4 100644 --- a/docs/src/working_with_yarn_slinger/bevy_plugin/compiling_yarn_files.md +++ b/docs/src/bevy_plugin/compiling_yarn_files.md @@ -7,7 +7,7 @@ you when the compilation is finished. You can however steer how and when this is ## Starting the Compilation Process Generally, you'll want your game to compile the Yarn files as soon as possible. This -is why the [`YarnSpinnerPlugin`](./setup.md) will start doing so by default when it is added to the app. +is why the [`YarnSpinnerPlugin`](setup.md) will start doing so by default when it is added to the app. If for some reason you do not wish to start compilation right away, you can *defer* this process. To do this, construct the `YarnSpinnerPlugin` with `YarnSpinnerPlugin::deferred()` when adding it. Then, whenever you are ready @@ -44,18 +44,18 @@ As you might have guessed by now, `YarnSlingerPlugin::new()` is simply a shortha `YarnSlingerPlugin::with_development_file_generation()` accepts a `DevelopmentFileGeneration`, which tells Yarn Slinger how aggressively to generate useful files on runtime. "Useful" refers to the developer and not the user. The default is `DevelopmentFileGeneration::TRY_FULL`, which will be `DevelopmentFileGeneration::Full` on platforms which support filesystem access, i.e. all except Wasm and Android. See the documentation for the full list of effects. Suffice it to say -that this is not very important when developing without localization, but becomes vital otherwise. See the [Localization](./localization.md) chapter for more. +that this is not very important when developing without localization, but becomes vital otherwise. See the [Localization](localization.md) chapter for more. Since these settings are intended for development, you can use `YarnSlingerPlugin::with_development_file_generation(DevelopmentFileGeneration::None)` when shipping your game to optimize the runtime costs and avoid generating files that are useless to the player. ### Localization -The settings accessed by `YarnSlingerPlugin::with_localizatons` are important enough to warrant their own chapter. See [Localization](./localization.md). +The settings accessed by `YarnSlingerPlugin::with_localizatons` are important enough to warrant their own chapter. See [Localization](localization.md). ## After the Compilation Whether you used `YarnSlingerPlugin` or `LoadYarnProjectEvent`, as soon as the compilation finished, a `YarnProject` resource will be inserted into the Bevy world. -You can react to its creation by guarding your systems with `.run_if(resource_added::())`, as seen in the [setup](./setup.md). +You can react to its creation by guarding your systems with `.run_if(resource_added::())`, as seen in the [setup](setup.md). -Once you have the `YarnProject`, you can use it to spawn a `DialogRunner` which in turn can, well, [run dialogs](./dialog_runner.md) +Once you have the `YarnProject`, you can use it to spawn a `DialogRunner` which in turn can, well, [run dialogs](dialog_runner.md) diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/custom_commands.md b/docs/src/bevy_plugin/custom_commands.md similarity index 100% rename from docs/src/working_with_yarn_slinger/bevy_plugin/custom_commands.md rename to docs/src/bevy_plugin/custom_commands.md diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/custom_functions.md b/docs/src/bevy_plugin/custom_functions.md similarity index 100% rename from docs/src/working_with_yarn_slinger/bevy_plugin/custom_functions.md rename to docs/src/bevy_plugin/custom_functions.md diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/dialog_runner.md b/docs/src/bevy_plugin/dialog_runner.md similarity index 85% rename from docs/src/working_with_yarn_slinger/bevy_plugin/dialog_runner.md rename to docs/src/bevy_plugin/dialog_runner.md index 4c149b8c..dcc93ed9 100644 --- a/docs/src/working_with_yarn_slinger/bevy_plugin/dialog_runner.md +++ b/docs/src/bevy_plugin/dialog_runner.md @@ -1,17 +1,17 @@ # `DialogRunner` and a High Level Overview The main way to actually manipulate the state of your dialog is through a `DialogRunner`. -You create it from a `YarnProject` (see [Compiling Yarn Files](./compiling_yarn_files.md)) with either +You create it from a `YarnProject` (see [Compiling Yarn Files](compiling_yarn_files.md)) with either `YarnProject::create_dialog_runner()` or `YarnProject::build_dialog_runner()`. The first uses default configurations which should be alright for many use-cases, while the latter allows you to add or change functionality. ## Dialog Flow -The actual navigation through a dialog is handled by a [dialog view](./dialog_views.md), +The actual navigation through a dialog is handled by a [dialog view](dialog_views.md), which is responsible for back-and-forth interaction with the player. As such, most of the methods provided by a `DialogRunner` are to be called by such a view. -The one you will want to call yourself, as seen in the [setup](./setup.md), is `DialogRunner::start_node`, +The one you will want to call yourself, as seen in the [setup](setup.md), is `DialogRunner::start_node`, which will tell the `DialogRunner` to start running from the provided [node](../yarn_files/nodes.md). ## Variable Storage @@ -30,19 +30,19 @@ For information on how to create your own variable storage, see the chapter [Var ## Functions and Commands Yarn files can contain user-defined functions and commands. These can be accessed with -`DialogRunner::library()` and `DialogRunner::commands()`. For more information, see the chapters [Custom Functions](./custom_functions.md) -and [Custom Commands](./custom_commands.md). +`DialogRunner::library()` and `DialogRunner::commands()`. For more information, see the chapters [Custom Functions](custom_functions.md) +and [Custom Commands](custom_commands.md). ## Text and Assets We make a distinction between *text*, which are the written words organized into *lines* contained in Yarn files or in -[localization files](./localization.md), and *assets*, which are supplemental data associated with a line. +[localization files](localization.md), and *assets*, which are supplemental data associated with a line. Assets are referenced over a Bevy `Handle` and can be used for things such as voiceover sound files or images that might need translation. -Of note is that using assets **requires** using [localization](./localization.md), or at least thinking about it. +Of note is that using assets **requires** using [localization](localization.md), or at least thinking about it. As a consequence, language settings are split between text and assets. After all, a player might want to hear lines delivered in the original recorded language but read the text translated into their own language. -You can read more about how current language can be set for a `DialogRunner` in the [localization](./localization.md) chapter. +You can read more about how current language can be set for a `DialogRunner` in the [localization](localization.md) chapter. Text is provided by a `TextProvider`. While it can be overwritten, the default `StringsFileTextProvider` will be a good choice for nearly all users. The only reason you might have to create an own `TextProvider` is if you want a very custom localization strategy, such as @@ -50,7 +50,7 @@ translating text automatically through AI. Assets are provided by `AssetProvider`s. In contrast to the `TextProvider`, you might very well create your own `AssetProvider`. For your convenience, Yarn Slinger already ships with an `AudioAssetProvider` that you can use for voice lines and a `FileExtensionAssetProvider` -that can load any asset based on naming conventions and file extensions. See the chapter [Assets](./assets.md). +that can load any asset based on naming conventions and file extensions. See the chapter [Assets](assets.md). Text and asset providers can be set through the builder API and accessed later with `DialogRunner::text_provider()` and `DialogRunner::asset_providers()`. If you know the exact type `T` of `AssetProvider` you want, you can call `DialogRunner::asset_provider::()` instead. diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/dialog_views.md b/docs/src/bevy_plugin/dialog_views.md similarity index 100% rename from docs/src/working_with_yarn_slinger/bevy_plugin/dialog_views.md rename to docs/src/bevy_plugin/dialog_views.md diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md b/docs/src/bevy_plugin/localization.md similarity index 78% rename from docs/src/working_with_yarn_slinger/bevy_plugin/localization.md rename to docs/src/bevy_plugin/localization.md index 6c3b66fb..669f34a5 100644 --- a/docs/src/working_with_yarn_slinger/bevy_plugin/localization.md +++ b/docs/src/bevy_plugin/localization.md @@ -1,14 +1,14 @@ # Localization If you only want to support a single language, you can safely ignore localization features. -As soon as you want to support [assets](./assets.md) or multiple languages however, you will need to use localization. +As soon as you want to support [assets](assets.md) or multiple languages however, you will need to use localization. Fortunately Yarn Slinger makes this quite easy! Let's first look at how to use localization and then explain what's going on under the hood. ## Using Localization the Easy Way -We specify our supported localizations when creating the [`YarnSlingerPlugin` (or using deferred compilation)](./compiling_yarn_files.md): +We specify our supported localizations when creating the [`YarnSlingerPlugin` (or using deferred compilation)](compiling_yarn_files.md): ```rust YarnSlingerPlugin::new().with_localizations(Localizations { @@ -21,7 +21,7 @@ The *base localization* is the language in which your Yarn files are already wri In this case, we specified that our Yarn file was written in English as spoken in the USA. The *translations* are all languages you want to support. Here, we want to support German as spoken in Switzerland. -Put the code shown above into the example used in the [setup](./setup.md) and run the game. +Put the code shown above into the example used in the [setup](setup.md) and run the game. Now take a look at your Yarn file at `assets/dialog/example.yarn`. You will see that your line of dialog will contain an autogenerated ID, for example: @@ -57,7 +57,7 @@ Since this is a CSV, let's open it in an application that renders the content as You can see that our line from before is in there! Notice how the `id` matches across the files. This file will be populated with new entries as soon you change the Yarn files. Assuming that you -are using hot reloading as described in the [setup](./setup.md), run your app again in case you closed it or advanced the dialog. +are using hot reloading as described in the [setup](setup.md), run your app again in case you closed it or advanced the dialog. While you are greeted with the "Hello World!" message on screen, open the Yarn file and edit it. Let's add a new line: ```diff @@ -108,7 +108,15 @@ Hurray! See how painless localization can be? ## Languages -TODO format, asset vs text language +Languages are specified according to IETF BCP 47. +You can add as many translations as you want. Each will receive an own strings file. + +To switch languages at runtime, simply retrieve a `DialogRunner` through a Bevy query inside a system. +When you use `DialogRunner::set_language()` as shown above, you will set the language for both text and assets. +You can be more granular by using `DialogRunner::set_text_language()` and `DialogRunner::set_asset_language()` separately instead. +This allows you to support use cases such as showing the text in the player's native language and play voiceover sound in the original recorded language, which might be a different one. + +To read more about how to use and localize assets, read the chapter [Assets](./assets.md). ## File Editing Workflow diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/setup.md b/docs/src/bevy_plugin/setup.md similarity index 93% rename from docs/src/working_with_yarn_slinger/bevy_plugin/setup.md rename to docs/src/bevy_plugin/setup.md index 3d999569..c06736a3 100644 --- a/docs/src/working_with_yarn_slinger/bevy_plugin/setup.md +++ b/docs/src/bevy_plugin/setup.md @@ -19,7 +19,7 @@ The line `cargo add bevy --features filesystem_watcher` ensures that we can use while the game is running and it will reload them automatically on change. The dependency `bevy_yarn_slinger` is for the Yarn Slinger Bevy plugin proper, while `bevy_yarn_slinger_example_dialogue_view` -gives us a nice default [dialog view](./dialog_views.md), so we can actually see the text we've written and have options to click on. +gives us a nice default [dialog view](dialog_views.md), so we can actually see the text we've written and have options to click on. ## Adding the Yarn Files @@ -101,7 +101,7 @@ This self-explanatory line initializes the plugin. When using the standard const files ending in `.yarn` will be compiled as soon as the game starts. The plugin makes sure all components of Yarn Slinger work except for any actual graphics. You need to -instantiate a [dialog view](./dialog_views.md) for that: +instantiate a [dialog view](dialog_views.md) for that: ```rust ExampleYarnSlingerDialogueViewPlugin::new(), @@ -127,7 +127,7 @@ fn spawn_dialogue_runner(mut commands: Commands, project: Res) { ``` The main way of interacting with Yarn files during runtime and managing the flow of a dialog is through a -[`DialogRunner`](./dialog_runner.md). To do this, we use the [`YarnProject`](./compiling_yarn_files.md) resource we referenced in the `run_if` section above. +[`DialogRunner`](dialog_runner.md). To do this, we use the [`YarnProject`](compiling_yarn_files.md) resource we referenced in the `run_if` section above. It represents our compiled Yarn files, which we use to create a new dialog runner. We then point it to the [node](../yarn_files/nodes.md) named "Start" of our Yarn file. We use `start_node` for this, which will "move" the dialog runner to the provided node and start executing the dialog in the next frame, diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/strings_file_another_line.png b/docs/src/bevy_plugin/strings_file_another_line.png similarity index 100% rename from docs/src/working_with_yarn_slinger/bevy_plugin/strings_file_another_line.png rename to docs/src/bevy_plugin/strings_file_another_line.png diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/strings_file_generated.png b/docs/src/bevy_plugin/strings_file_generated.png similarity index 100% rename from docs/src/working_with_yarn_slinger/bevy_plugin/strings_file_generated.png rename to docs/src/bevy_plugin/strings_file_generated.png diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/strings_file_new.png b/docs/src/bevy_plugin/strings_file_new.png similarity index 100% rename from docs/src/working_with_yarn_slinger/bevy_plugin/strings_file_new.png rename to docs/src/bevy_plugin/strings_file_new.png diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/strings_file_translated.png b/docs/src/bevy_plugin/strings_file_translated.png similarity index 100% rename from docs/src/working_with_yarn_slinger/bevy_plugin/strings_file_translated.png rename to docs/src/bevy_plugin/strings_file_translated.png diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/translated_line.png b/docs/src/bevy_plugin/translated_line.png similarity index 100% rename from docs/src/working_with_yarn_slinger/bevy_plugin/translated_line.png rename to docs/src/bevy_plugin/translated_line.png diff --git a/docs/src/working_with_yarn_slinger/bevy_plugin/variable_storage.md b/docs/src/bevy_plugin/variable_storage.md similarity index 100% rename from docs/src/working_with_yarn_slinger/bevy_plugin/variable_storage.md rename to docs/src/bevy_plugin/variable_storage.md diff --git a/docs/src/introduction.md b/docs/src/introduction.md index 174410ad..a2f2c354 100644 --- a/docs/src/introduction.md +++ b/docs/src/introduction.md @@ -1,8 +1,10 @@ # Yarn Slinger Book Welcome to Yarn Slinger, the friendly dialogue tool for Rust! +Yarn Slinger is a port of the widely used dialogue tool [Yarn Spinner](https://yarnspinner.dev). + Please click on the link that describes your situation the best. - [I'm new to all of this](./working_with_yarn_slinger.md) -- [I have used Yarn Spinner for Unity before](./differences_to_yarn_spinner_for_unity.md) +- [I have used Yarn Spinner for Unity before](./bevy_plugin.md) - [I want to port Yarn Slinger to another language than Rust or another engine than Bevy](./porting_yarn_slinger.md) diff --git a/docs/src/working_with_yarn_slinger.md b/docs/src/working_with_yarn_slinger.md index ab130f74..bb488396 100644 --- a/docs/src/working_with_yarn_slinger.md +++ b/docs/src/working_with_yarn_slinger.md @@ -1,5 +1,5 @@ # Working with Yarn Slinger -Yarn Slinger is a port of the widely used dialogue tool [Yarn Spinner](https://yarnspinner.dev). + They both share the idea of writing dialog in writer-friendly text files called *Yarn files*. We -will take a look at how to write these in the next chapter, [Yarn Files](./working_with_yarn_slinger/yarn_files.md). +will take a look at how to write these in the next chapter, [Yarn Files](yarn_files.md). diff --git a/docs/src/working_with_yarn_slinger/yarn_files.md b/docs/src/yarn_files.md similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files.md rename to docs/src/yarn_files.md diff --git a/docs/src/working_with_yarn_slinger/yarn_files/apples.png b/docs/src/yarn_files/apples.png similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files/apples.png rename to docs/src/yarn_files/apples.png diff --git a/docs/src/working_with_yarn_slinger/yarn_files/basics.md b/docs/src/yarn_files/basics.md similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files/basics.md rename to docs/src/yarn_files/basics.md diff --git a/docs/src/working_with_yarn_slinger/yarn_files/commands.md b/docs/src/yarn_files/commands.md similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files/commands.md rename to docs/src/yarn_files/commands.md diff --git a/docs/src/working_with_yarn_slinger/yarn_files/cond_options.png b/docs/src/yarn_files/cond_options.png similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files/cond_options.png rename to docs/src/yarn_files/cond_options.png diff --git a/docs/src/working_with_yarn_slinger/yarn_files/dice.png b/docs/src/yarn_files/dice.png similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files/dice.png rename to docs/src/yarn_files/dice.png diff --git a/docs/src/working_with_yarn_slinger/yarn_files/file_system.png b/docs/src/yarn_files/file_system.png similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files/file_system.png rename to docs/src/yarn_files/file_system.png diff --git a/docs/src/working_with_yarn_slinger/yarn_files/functions.md b/docs/src/yarn_files/functions.md similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files/functions.md rename to docs/src/yarn_files/functions.md diff --git a/docs/src/working_with_yarn_slinger/yarn_files/graph.png b/docs/src/yarn_files/graph.png similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files/graph.png rename to docs/src/yarn_files/graph.png diff --git a/docs/src/working_with_yarn_slinger/yarn_files/hello_world.png b/docs/src/yarn_files/hello_world.png similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files/hello_world.png rename to docs/src/yarn_files/hello_world.png diff --git a/docs/src/working_with_yarn_slinger/yarn_files/lines.md b/docs/src/yarn_files/lines.md similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files/lines.md rename to docs/src/yarn_files/lines.md diff --git a/docs/src/working_with_yarn_slinger/yarn_files/markup.md b/docs/src/yarn_files/markup.md similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files/markup.md rename to docs/src/yarn_files/markup.md diff --git a/docs/src/working_with_yarn_slinger/yarn_files/narrator.png b/docs/src/yarn_files/narrator.png similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files/narrator.png rename to docs/src/yarn_files/narrator.png diff --git a/docs/src/working_with_yarn_slinger/yarn_files/nodes.md b/docs/src/yarn_files/nodes.md similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files/nodes.md rename to docs/src/yarn_files/nodes.md diff --git a/docs/src/working_with_yarn_slinger/yarn_files/options.md b/docs/src/yarn_files/options.md similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files/options.md rename to docs/src/yarn_files/options.md diff --git a/docs/src/working_with_yarn_slinger/yarn_files/options.png b/docs/src/yarn_files/options.png similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files/options.png rename to docs/src/yarn_files/options.png diff --git a/docs/src/working_with_yarn_slinger/yarn_files/running_examples.md b/docs/src/yarn_files/running_examples.md similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files/running_examples.md rename to docs/src/yarn_files/running_examples.md diff --git a/docs/src/working_with_yarn_slinger/yarn_files/variables.md b/docs/src/yarn_files/variables.md similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files/variables.md rename to docs/src/yarn_files/variables.md diff --git a/docs/src/working_with_yarn_slinger/yarn_files/variables.png b/docs/src/yarn_files/variables.png similarity index 100% rename from docs/src/working_with_yarn_slinger/yarn_files/variables.png rename to docs/src/yarn_files/variables.png From fb454fb1b055174291fc3914bb02cfe275009639 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Tue, 22 Aug 2023 18:01:34 +0200 Subject: [PATCH 16/17] Finish writing about localizations --- docs/src/bevy_plugin/localization.md | 47 +++++++++++++++++-- .../differences_to_yarn_spinner_for_unity.md | 0 2 files changed, 43 insertions(+), 4 deletions(-) delete mode 100644 docs/src/differences_to_yarn_spinner_for_unity.md diff --git a/docs/src/bevy_plugin/localization.md b/docs/src/bevy_plugin/localization.md index 669f34a5..3d1b4c7a 100644 --- a/docs/src/bevy_plugin/localization.md +++ b/docs/src/bevy_plugin/localization.md @@ -116,16 +116,55 @@ When you use `DialogRunner::set_language()` as shown above, you will set the lan You can be more granular by using `DialogRunner::set_text_language()` and `DialogRunner::set_asset_language()` separately instead. This allows you to support use cases such as showing the text in the player's native language and play voiceover sound in the original recorded language, which might be a different one. -To read more about how to use and localize assets, read the chapter [Assets](./assets.md). +## Assets + +Since assets require using localization, they are searched for in folders named after the language they support. +For the example used throughout this chapter, the assets for the base localization would be searched for in `assets/dialog/en-US/`, while the assets for the `de-CH` +translation will be searched at `assets/dialog/de-CH/`. This is however more a convention than a rule, as a given `AssetProvider` is allowed to look for its assets wherever. +The asset providers shipped by Yarn Slinger will additionally expect assets to be named after the line ID they belong to. For example, the `AudioAssetProvider` would look for the +voice line reading our "Hello World!" line at `assets/dialog/en-US/13032079.mp3` for the base localization. + +To read more about how to use assets, read the chapter [Assets](./assets.md). ## File Editing Workflow -TODO needs updating, removing lines, autoclean +The strings file can be freely edited by a translator in the *text* and *comment* fields. +While you can translate the texts yourself, the format being straightforward allows the translator to also be someone else that is not involved with the coding part of the game at all. + +You might have some questions regarding what happens when one person edits a Yarn file while another edits the strings file. As a general rule, +the strings file will try to "keep up" with the Yarn file without ever destroying anything that was already translated. + +As you've seen, new lines will be amended. If the Yarn file has a line edited, it will be changed in the strings file as well if it was not yet translated. +If there is already a translation, it will be marked by a "NEEDS UPDATE" prefix in the text. If a line was deleted in the Yarn file, it will also be deleted +in the strings file if it was untranslated. Otherwise, it will be left untouched. + +Bottom line: if there's a translation, it will **never** be removed. ## Shipping the Game -TODO fallback, files to include +Once you want to build your game for a release, you should disable the automatic file creation and editing. +To do this, add the following line to the plugin creation: +```rust +YarnSlingerPlugin::new() +// ... +.with_development_file_generation(DevelopmentFileGeneration::None) +``` + +This will change the behavior of missing translations to simply fall back to the base localization. + + +While you're on it, you might also want to disable Bevy's hot reloading. ## Customization -TODO locations +You may have wondered what the `.into()`s were for in the lines at the beginning of the chapter: + +```rust +YarnSlingerPlugin::new().with_localizations(Localizations { + base_localization: "en-US".into(), + translations: vec!["de-CH".into()], +}) +``` + +They're here because a localization is not just a string with a language code, but an entire struct, namely `Localization`. +You can construct this struct directly the path to the strings file and where assets are searched for. diff --git a/docs/src/differences_to_yarn_spinner_for_unity.md b/docs/src/differences_to_yarn_spinner_for_unity.md deleted file mode 100644 index e69de29b..00000000 From fbb23679ed8c39041f771ae5f6da42adb732522d Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Tue, 22 Aug 2023 18:20:14 +0200 Subject: [PATCH 17/17] Write a bit about assets --- docs/src/bevy_plugin/assets.md | 23 +++++++++++++++++++++++ docs/src/bevy_plugin/localization.md | 1 - 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/src/bevy_plugin/assets.md b/docs/src/bevy_plugin/assets.md index 2d10c044..f66bb4fb 100644 --- a/docs/src/bevy_plugin/assets.md +++ b/docs/src/bevy_plugin/assets.md @@ -1,3 +1,26 @@ # Assets +While Bevy as a whole has assets, Yarn Slinger can associate specific assets with lines. +These are always [localized](./localization.md), such as voiceovers. + +## Using Metadata Instead of Assets + +Before we jump into assets, let's first help you out if you don't care about localization. +The mechanism in place for this is *line metadata*, which are strings you can add to Yarn lines after a hashtag: + +```text +title: Start +--- +Granny: It's hard to believe that it's over, isn't it? #smiling +Granny: Funny how we get attached to the struggle. #laughing +Granny: Promise me tat you'll take care of yourself, okay? #smiling +=== +``` + +A [dialog view](./dialog_views.md) will be able to read the metadata "smiling", "laughing", and "smiling" again from `LocalizedLine::metadata` and accordingly load things like character portraits. +These annotations will also be written into the "comment" field of strings files, which are explained in the chapter [Localization](./localization.md). + +## Asset Providers + TODO + diff --git a/docs/src/bevy_plugin/localization.md b/docs/src/bevy_plugin/localization.md index 3d1b4c7a..bf5767a5 100644 --- a/docs/src/bevy_plugin/localization.md +++ b/docs/src/bevy_plugin/localization.md @@ -152,7 +152,6 @@ YarnSlingerPlugin::new() This will change the behavior of missing translations to simply fall back to the base localization. - While you're on it, you might also want to disable Bevy's hot reloading. ## Customization