From 06fc68b6a11548f14b42ba522caa1e0beaf10ead Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sun, 1 May 2022 21:43:33 +0300 Subject: [PATCH] networking first draft, stair jumping, clip materials --- Content/Common/PlayerPrefab.prefab | 4 +- Content/Materials/ClipMaterial.flax | Bin 0 -> 30131 bytes Content/Materials/SimpleMapMaterial.flax | Bin 32370 -> 32370 bytes Content/Materials/common/clip.flax | Bin 0 -> 482 bytes Content/Materials/sky.flax | Bin 29986 -> 0 bytes Content/Materials/sky/skynight1.flax | Bin 0 -> 541 bytes Content/Scenes/AerowalkScene.scene | 5 +- Source/Game/Cabrito/Console/Console.cs | 27 ++++ Source/Game/Cabrito/Console/ConsolePlugin.cs | 13 +- Source/Game/Cabrito/EngineSubsystem.cs | 23 +++ Source/Game/EngineUtilities.cs | 26 ++++ Source/Game/Networking/NetworkManager.cs | 94 ++++++++++++ .../Game/Networking/NetworkManagerPlugin.cs | 61 ++++++++ .../Game/Networking/NetworkManager_Client.cs | 93 ++++++++++++ .../Game/Networking/NetworkManager_Server.cs | 134 ++++++++++++++++++ Source/Game/PlayerMovement.cs | 34 +++-- Source/Game/Q3MapImporter.cs | 34 +++-- Source/GameTarget.Build.cs | 13 ++ 18 files changed, 532 insertions(+), 29 deletions(-) create mode 100644 Content/Materials/ClipMaterial.flax create mode 100644 Content/Materials/common/clip.flax delete mode 100644 Content/Materials/sky.flax create mode 100644 Content/Materials/sky/skynight1.flax create mode 100644 Source/Game/EngineUtilities.cs create mode 100644 Source/Game/Networking/NetworkManager.cs create mode 100644 Source/Game/Networking/NetworkManagerPlugin.cs create mode 100644 Source/Game/Networking/NetworkManager_Client.cs create mode 100644 Source/Game/Networking/NetworkManager_Server.cs diff --git a/Content/Common/PlayerPrefab.prefab b/Content/Common/PlayerPrefab.prefab index 33c75d4..6345ce5 100644 --- a/Content/Common/PlayerPrefab.prefab +++ b/Content/Common/PlayerPrefab.prefab @@ -66,9 +66,9 @@ "ID": "eb46ab96465957dc67a052bd0e2ad1e5", "TypeName": "FlaxEngine.Camera", "ParentID": "51c770f24232abbb112cc98b296820d8", - "Name": "Camera", + "Name": "PlayerCamera", "StaticFlags": 0, - "FOV": 65.0, + "FOV": 78.69999694824219, "Near": 1.0, "RenderLayersMask": 4294967291 }, diff --git a/Content/Materials/ClipMaterial.flax b/Content/Materials/ClipMaterial.flax new file mode 100644 index 0000000000000000000000000000000000000000..723fec2851fe480ca380a82a56fad1c0899f6864 GIT binary patch literal 30131 zcmd43c{J5u8~<%8^Hj!=S!A9vCYhCFj4~x;EQC-bnWs?3kg+0jnT{ib;~YcC5Hg3% zA@h`He?E@x@Ar4#>-WdA*0a`Qt?ZnN2i5z`2XSyx;${1I9%XQBK$en3x@xV zgYzmmSs}V%<0ABu68t%kBFx7A3fwPT9Nb5KV-~{qoK*{#Uf_`vck|-nQh?v@^EUHt z@(%J2^P+gSd3$+3^LFu~!K+^IGw^HN8|uU!#!TQJ(2Ku+aN$$I`9D7r`aoWsQ#c$r zX%3`}v|_cj&OBM~8y{CIf%JMf)n&ta+X(6#nRN%J;E?E*Drr;b_}(`#w0DH!+Tke z+Q&XHKA|!uG5AG3CmG=>X*GRnK3-`RpRkzBg#0Sh!1S!#;x;3LFt7Y2L{)vuFC?aK zWrIk6pNg3GoQ{EWcwprFqUOQ2)wXqy?~)U- zOA4rJ>v-6Q`bB@J!?gXF__cZVESI4@KBKUNrCLgEIXF^2884s4B|9g-M+xy|wV0OP z? z>quU>Zf#M!pDE( zadAoIiwg82DJ>WKSp_W#rE5&KuHjKPpN2gOPQ#hsV-}J-G%>#G_{{(LP2Z`u_n!y) zhX1e$-?-z(qH)VAC@${h%wgHc&$VrOE)E^b@P{79=f8$M|C_FM`nT>mg(W>Fpl1^X z&;Rr4It~$^z?y=Z{-dDK>_pekReh8DTRnqkC8Ts`B-9Pa9&_ z8mo@U#6Qg;VaUN^=n@$oQdJuKH2MISf{p2bUPnUOO~=*gskysf`KRXLEfktxKtjmf z%<7?#i)UeJ?EsP(zxK!BHUTZ2fV$S(r_oWFMJ4%vm_BT7QF0TBOY)qTxNcD0H36SL zCCMn^X-0Jkehp10mw>pGl#ZtE^5-s|BddRi__x-$O?7TRmD1KR`t)^lb^*1#OUkIC zDlDz*cKd!vc;5Y(#4le*xA*$QB}CoLZa4-;y)Ni%Z_97!;vt~lAgAL}kB`>0bMnlJ zEom&M>0H?%j+gb3kwvJ;hGAlK!q-kh*orj8&_ij$5;k}1}Aro!6_3ib6uYAHj z)V8d1sDpXUZxxx4SY28hoA(`$oPtUIqN*$#-x(gk^qALa=$fvjQp9-Rm|HYg)84Z9Jv_0t4AqiRTvqpMmr~oxD#%E_XODgxI#Z~3iHCP}2y?!L(b04*Yg25F-AJ41tmhKMX6)S#y6Z=M%O5R$ zTbC$B%}2pel~V^qxRe4iq&&hB>c%z>x|%Jy4b{WT^Xt1f#84dLdmZ{bwIB~sKZ9tR z9v37fI)6c0HQL_F!RJ-}YJT4U-=8fS>T?oT)NIu?Oib*;V&dPgbqo#vT;DZhVE2 zHSkqUOD{bCC@EK`ep3>QhzJ|oCHu-nwRtI&=<7L?pmDE(p5`J$uC0{d>uxO{9GiwVRT05y7JA7 z4&E6#pTPYuAO7-t_ax=H;Aa_mRc5YFLi2alem5_VZ7|UYiplG%|Ks?H;P^S%`LE*m zC@crrfT`_YAt7U0o+0Jdx_9SMaC)M_ou^?*@ccth8mlU(+j#^hm6jB@w^wg4Qnz8& zes1EibEmz{fB&s7Wj`9z(zUTk$i}UpagJA6{g!npGNbo%$Miz))+!mHs)&+|xl!-f zB0PT{d3+oj-up?y$1WwRcHcTECaciZJL+9i-OpdUxQv^BXjpIas2JUL2Jw9WH8)GR z#UU)BDszR;Ht^Z=0z^a)qM?g=VPjiUkoU5omQ8+eblkhL(iPlq3tL2InS5ytWHdGG zgS|qM3lLQF-$gF#kh2Sk@O!6tKYSP&pZnnxqrb<8#&08k=%{1_WL0@^C`JDH{112x zE+}f)xCZJux!x^kj3zom!*fAe;p&5@kD_uj%iB>MEAe@`b)DT~v!rAgc~||pqhm86w-D7^ z__c+Ui0Lek*iA!45dWTGMy6LtODca$s4|+~wF{33eP2=YxpRDP{SWE-;pFNeIUK(% zkyX{r1)n>+7NDO?3ma}s_1@pf;CT)85*CHMX*BL%-(;FsUo)Nhz?=e07>&b75KGhG7Zjsct3|!MS z_j;^p^}L`KJ-f@1+nDxH9dtf1@ z1pgfC-~jF}9)&P}4v4?sa*@d1J~C=%>N7l|5hAiCy0>h+<3nHNt`SmF(4G-FsmiLR zuO8qPoYYJ}U-HMm!o~CL2jn7yjP!L4Qwtf-kfO|*I`qo^W)FvexQ05frq(SR!N7=j zRp`{bUt5Ixbo8s%TI$yJK5=Q7kH{wE_}tIq`Ja_`!@)cAoqu!fRNo37xtfZRwZ6EL zicNZQaCmEKWm6l))NfjCa38N)ICyz~of^rJ- zBV$wH{DE-BQcKU)`)TOAf$89!%J=KEi~{0ZQfFLzRdb8l8~WCh^Kx6hb&M`;((4%6 z89LpIYMBfG=RY;}lY)gu_<>XGLlFPmJr-B@;q_bXP|Zr!((Oh2*Wsi5!}e|8=bwKF zXsI{^Pfl$Sz~lEpRDS>dHxdSJaScNwB|T$k{rNlpnkXuYaSnd_;s?@?ydDoz*_^6Ez*P-(#{rpz3?RuWXQX_0O7E zIE04jx#sq?_HE;z;@T6|x+*KDZDB1B=ARFI{>^B4c>TTWlkA`IrU=!FsHgrP$A8zq zjgQC4BdiF;zvrfIo-t`S#D6eD{9I?G6|}X?ZNuYUylMK}GCT1$wGdS^wlKd&aPG`y zZ7~0j@~^z_+jz7*BD6dvN^VbHJx#{H@l2u%f>>m92Hle5q zHMn9fap{4I>P>66vbv0)Q(HKc7nJk~==o%f&ui+%n%g~zOhtUgP!2AhATp$v^^>u( zu6!B?^2eruj~?wq%iDwnr8p9XTF%y9FMSF#3lJ#{`#YOlJR%yZGFmP=j$r*t%4|oD z&2E(nF$l@a%V^$C2@J__uEw;MRrQZ;ORx!ZC~6vWf%?TeHRn@qPh0PTDg_ObptP!O zOh9s=Q%GQ5YT2jRo;`v+Q+<&CG&wkVg9L2tTPxx-`uO?d(y-jc&fhdRe>)VD)sd6e zHUaskOF|X;>+oC}HyOE-tlA|bJ}%XSoVO(y6r!CRHGJYb37wQwu(juVm#99kC#hL= zU85s2`&8t&onw@YZ9x2J`G{??H}v^ zeN09Ngc-W1HCZFU0F%!_ zKgS`gXkz>b@i;AawH7nFxW9u-X>#&lrxn8N*q5%@o_)D6l3T zRQ6UkH;qg#Lh*Y|PuV-{=cV-+RE%VUQu7Ot?P&xHdkoa< zYPzO|KJSxW)&*Y&h8M9&|YwqHMM^n_;_M6bD5f{``l%H>f5dnN?!f}mZhc0 z7jqM9)nA5o*Y`}VWCdid8aOt-eU({?o~vkXpPv1F&@wfxOnu^tdC1FTx9ShQQ2pA| zzkGg=@%M&48~3Xxi7)detAF%vt!@rkJhT(@bhMSnybuRm^{(GCbicVE%R zPqhPm9N6*iVWVqs?_ci+3%@?evJ zmcv&{SHMHf;I4~Td|tuY*XCbSCqSG%>!)dI=!JTolAS|JUDJ%|OJAmG;b)P?1bhGYk)1BuMzNlkw?GWFWSbd0?oRT78IKw3^rLO3qf9rvJNK8U@ z11{n0?mDR(6LDyT3V+gJW#9rDu*WujCh3cg@MlY;l~rEUIT|{m47%P0hgyV@g%`==kbB zwEl@&>RGynhdoE;cjqr{<1-AhE*)@OP`_>%^dKxUDbv}1tT63g_s`0=xwoPoGrdZ1 z@i(26u<9kfM=p=Syd*lw^a<1roSb4>s*j-SPYVl=&Hd2VK1eI0Vkjj6X7D{P@5ong zz93pls~V=8*9b`n*(Kz(Xdi1BIuxZhwtSkO!=YiBJdh*WaL~4}vd<5HpNg((?ny^b zVB^2!tLM?#h@sZ%n*M>GYbxeO)L{LG*U#?N;_g<&93C;37@vlrxkpB9gk5+-Qf65n zrh9~Mhl5W-N#=>8D&whs?^$!**fbgskAX=-;p*DP z@%X(5*AMg@r=y|>& z3R(i1x^{2U!U7Aw7j-rcGR^NY(*vC$=XGW5$`(;!ZF3^Jqks4pApz4Fu-s|d1wV>A zn*Zo63VNX5otM0b^i&i`a_&c>XSLR5ceM0y?(~38|T<)m84? zce?j7E)k6Ll#; zCGGjx&@`RC+y14WL|RtG*fZp*cg~yosJ6t9C^-LSR3Idi*9^Yx?9z%IKQdh0isa@7 zjvk@$ApeMcUez%?yhF^k$EB_qS_tZonxdTiPnbT*K?dSeVhZZ~VE#FO`c$4;*j?Sc zJR_rPNN4Gnka9D(@m)^hXl*M35s(Ou-_kv;OnE}n&fg)cC>KwMWTa#Il2gH9wV#(_4D<~p+)yCQ>qU;M;-$sSSv|Mipi2E5k1O}&66(a|FzK3TOSAUJkETNND z*EO|gv5E{yEUPR6^~6?B`?BC3shPB{jcL%U@RwPi{ln5WThODE>?@~jtnIy%!n!}y zwIZPPPadp)lKzh`8hZytMm?);>~7%`RXuqfaPs1gQOU&|6Q{CJu)8*yc`8izrJ&?Z}i-XU<4}Jc>$3OV|;On=*c~@Zi zCl+^(;xD(Jw^L~5zwqMpw_zbz0*8GylN8-^SkG zy!ao_|2qXGrwqNZq^yRC;mWHyr z>q8u-!E?%sOdNb#SI-~mw+TORh#4jZwg`4OvH4fg%2pf|yMXRP%+S#KMghoMn04&! zLSo{IlTcv%R?aif639y#$jGahg}Oz=<(o}b^$(0u(Vk%7J~S}9>Ex~D6ZSTvxGSS+ zdiaol==8oI7(e+AK4C9&@vF?}=JgeG|WOjl&(!D8Wt9PUpo z1oaEcv3>{i_wJ;^gMpusAF`Ud2S*oAGBF6tN$cNo3Gj@IO{@JfF!*a34~*NR{QctF zf(mqX6X_XlI&QJmb#iM*Tdxq4?%ZlrMLkGDelKhS{rw57UjiMY6oc-a!`DB<%qOQJ z_Z;XiT@#C|KYro<8rV9iPRuXir)z!}jQ{wz2Nh8L6}xb_PkNqT=(-BaZLh~61$ln) zt-UiF6qHOtq&kvnMmje410!CW#w5PzoklS8Xk4*#bMQ#Y{!oSbo>4rH!1T-)+day+xh1Sa5{)hfFAC;nsv$cN%@ZV~B`d1Fv_~bQ# zK7LbL=hi*D@Rt0vD%>BVi%VpNv>^X6H>!;Af0c7k`L)2K^ZSp*!xnyyH9a+F3lH_M z*b-E2AC!O5@`_z#l#np8unUsYeP7l1wRw5#B%1k1e{cy%Fb+&aeW@txKf9$Mx5dmR zq_3sz;Po;oD80F>Zhn`5a)XCNL0w!X0@jb`3-NFpyXUu0^9d=bU9zw#8J`O#peN}n z^r)(>`7yOX!brm;CUH>@)PF$#u9{fbqB+ZSAZH-6p<-|ML@wb~PI1$Zv}r;*w#kcX z+NSp+p277~G7{Z1^m_rsPf-8E`dQzLqWZ4`pQS|fSp>w@RE2%7-@4=ESDpapAEz|A z;P`jse`M9Re<>&kC`e!3COs>|zoV=N&fmTW&i@+9#s|KG@ek`ag5kkQnN>5<8Tm_O zoIKp>v=$DJ0;9{{!tt}3wO2w1+>VtnY)-7&tpjoZJxMtwriMi5-T@dxPr?LBSFO9#YT zCr-1O32JNFSp_skzsNsHLL)3;Ois;rPFXqI3dH}e=7z4x*;P#&n}EmZg~*nwl*#$S zeHO+8Rc%WS1+8lW&H?YzKYbcZ8{TE+J3G6y%W$l}HB97wEdTkwtg|=09tr2~y!sw@ z!{ds}9=Z6x-N&bA5CqpRuB4=6mHgyGLS->(w~z|)wQEvZRn7s--z1a7yCD7n5qErb zh6K)k)oM)9W86t{QpH{>`F;xQ~w{58GBtFnY%ybVGa37AF}Uy{za>^9K(- zqu|Wp-nr-WFj7(TV`KMl-+R>G`0?znpI^`yP(L*< z)6Zk|8_~GHketl2_AfDwVEq#$AU!9o?i-D*e~P+WmiC4i&N7L~#KfiF0^=_%Fu&?E zlCo=i3A_GyBxiR{yoT!kd`!o}Z(_)Q(t>om8+WY!#!rp|Eyj!R^~(k1WtI4kLiu;! zDRxC|V?M`c`Y&^qTdM zSzr6|)b?q4X#GoZ@c{Yb-}S-MmcrDkZpvSK+awHD+-gy3Q2jHJRoMQm;I@6wV+omc^`f6vAE#HUsk)Hkk=5bqO%@qbanP+S$(kAr90+IxQuZJ*@lxa?)^ z`2ggM8df{3hg__#kp`curler?X0nZ=J_vK}^?P*){Xc8e-Wlg3V zwt+8lj^i)uATbf`1xZ;;ol6d2{sz=^py%fXDSq<^Uov#Qtzu*97a01o23r65SD^eQ zAPSCu9m}P)-*P{f_x{-VL*G^3qV`w+Muq3C;hkdR#9lwBKXubGi|U7p)|$IydAX1E zKV)%xTQ#y{Y)TRye_pR#{A0fTD6Vd3A1mL4^S=lmTU!m&yN|spp!mJCJh~{(!6Bl2 zJpbV1SAOsKO-#--ygNL%?(P0KG#2UCg;^@br8p}hN^5XlQ`>@5&@UXkf1?@p&li7k zN$F_m-nPGW*S8;?+t}Un^ALy5h|5i1%iPn!yYCHHf0&jwPtveB3&|OumkzMGTNn)G zzqmh^7B|VBhKVcdnHs)Fy^AjSSlv^B?t<%oa$Ye*HD@CSx2&v^#`yZ#1tMGq5mBzI zQW{3oc2NFj>DJiTy?CO!k4{!p*XZc^xn~qN0P_^~?;pxNkJdGR7@Fx>{T!NqApYCR zUAn@n`NIA~SwdibO(F1KM>fg$s6|v23?1yBwk5qOtU|c}|3CCYEjb;J#6>wh*gtV~ zkII``$2-A=2gPsT-&n^!0qf69HC+FW2+JyIS$I5z^^d?Oz(+iapEe=}%JCM^^ABo< z^{eZaXCeL8QA6ADL0A{af7`jF6t9E%ttT&Y1@?bGga=5$G z@kg24x`w`pUk39B@Efs9i-$DK(+eQ0dF9+gmOx6*1W~ zaa{jcm^waw7IU+yrm`1N(=>uvBcs7>5MVpA*K8oNff=6CuQ&I(+->R|8v%rf_5H7d8UVPJY*ML?8aSXReAUoSE& z`c+EaRNpcYF1`rFU-|yazmcKhJk7-)SKoPOd~P%sNjmi^skR(5I5|a3M1P)BO#POL zZD7iavUgqICV~GitO59oYe)0XsvY@bZgGKxL0m*s>-G&vCt07cCzvnQRX|5N+@=+f z67)|8{7q|8VL7G^hjI#=|7uGcnWuXP1cLeptUr76r)lUV|U0O;-MmfOP29$4oLqNYCSfit37h(nc(OVz?XF0$( zMHjRTj7=A|kCxT_hW#^%OBts2F8=Q;P%CF3{c+}K{w7%3%=Tfv0{xuf6wH6T^hrog zDQR!P-Kd(LT?PInuac?#Yil>O-GjJ<(x!&a!4;fC9ZRR!XU}7O9{WTUxB=9^z<-`$;FQ8;UBRV-`Kc!|DZU-+PP24WD^MdcL&J-S|!0@ zTIB`$tF@54x}0xZN`WJ?wZE@@o06V?!H^8nKW;g=J@cQKA1D3l4fNOaKVra^P%RVOYod(n8#GM9jw*ovimYw^I!cHJYPtF!p#Ld8i^fq8=mbc~aym>zmP z4M;2St;70*9+YwG9#{jDM?qw!Na?U`+w6T%XruGWq|f&R7G zHT5lS9$j4vv&2*k>|{{<;CD-Xi^%U99&8_KZ*J(UB_>P}uB zDkcr!{U57HYsXhe$(f}nrB#icLL4%4YKp0u7Pog8C;<;D0>$4q|IzP6lmJHqKYv6| zT5feCs;sOh9n>F7ROk5(RZJhN8{P%)|2k0GN%?qO76g`rI!xuH5-Ae+bV% z<>I8G^2+vHR8=Fd8l=C1x-rez(K9Zq;;@`;W_y#2;+Q}9P#7@Szp@6$e_1nO?D;ni zC9aZwDXDIoo?0Xw=o4JVRW`Wm`Zyye)AeOfNfzLS;QH+({!I}<9nGWsCwqzN3_rJu z)>TGHr|Xv4WzAoa^-U8Z;xyNc*aei-?QeT|qL*@sPU28f!TQ0YWZ@7{Upo4QCn4~5 z8hd}P?y+&PJHON|tn`n}dY4x}P#G9ClU;a7b(Te4Ugw?+zrX1%FplB))3GeM%Sf=H zYIfHtPf(G>5`1TfRi36Y90y}aG0!;bD>gb}ZT zhGDvWU_e?`Llb514j~bv09Zeb^L#y@r!MC;_S&Y!bdLWapzG%mQn_Yg{V*n}@XZI1 z$HDc}FVd?(ztFJ)*B=Ms$3*YqQXe0eoPvg#Vf-`y)RI!bziqbnuyze^?9-F6aVp)? zweyZld7V|?IyAd%X>dD&=emKdS5SCSK}E~J$mZT3auEqN1K__qKJ<*q$UeZ`x2?zO zXOrg?Rd3ljJ`N~KZ)zU{>u)y~w~UHD@R2M`y+ae@ZN4=PZ4htoGM_RQy<}?R0`ZR? zpRoP|{!M)w{+NI?D|Am^{wNXoSw8fzth^@MZRfc3X9hOl`eFWOXLgN@kQ&5)2UoAK z$dsZP(kWz3=fJ}HHXSr?r?$?X2mIR`zpmlF{Vi}k2Xg8cR5dId-Mtcw@-ax5U+r4} z`VW)7k7r0uqHp!rTm)u}mx}$EpF!MDN=&Us4D_!MP_E&50De_k*Z8(;4#dykVqpFt zCQ-KJbJubG_V@aMK1wL!1pI@7lE%1**RiQoSpJ&a|L&8(c)*2yhyCNe@l|;KT(}D2 z>*J`I6J$KZG&n&2zbvhzn`RRk{GzP!>oCOM>@$l>=}2AHGH@;IYFU`XZ#*NVLP$o; zz^WQ`+s-l6KdGejAN2=`v>~Mq_V`h4{hJ#MluQyDYBO@iCU+qI*T%6C@OK+@Y+TZ+ zt!BmRU+b zQJF?gK~%m38~?t*^~+UxJxeR6M}cvO>R8UItx}}BtgW@hUW_t1P zK=U|$0{yE1%b(y0@I`3x0{s;5;w|qgi@vrmZ>^A>v=SH4zXkcH6EnzKv@NQAZg>?* zN696nVo8HT=^mF@R@ytf^iTaa`n7UF5~8XTGyH$ie{Dnnf8gx`>+gTBKQQcBdVwic z|J_^cnmV})KnK64DKLNhV`Gop7Wgy8W!=RkY*_xq%CiL3I3YOoR?m+gw$8>hBg7GmkNpx~<9q6w~u~qe7(=gvaemuUm_lKHU2g~2w zTW+5Hxk}4$>MYRL86~Ad`ib}`BLk0sp>bLXqH40|=iK@@wtn(GCm^S*1CJjt zzS&O8DY*KGhyecC#moOoQEFXv69NhJgN{GsbW*^7gY^qNZ|B&Qdt}zti*T0RF-=G9%lqf1tb?&GW7M^j!QDDteO7 z^Qx?|{LcyE#RUomLGHi)%SV{s8rYd_B*XG={3daQA8LBgZJS$EY@F-Am#Gx7^|KYs zzmn1siiju!ecuC)e@%6OAvxBMC3W=gy2poklruw6S>HYRujfBgfoUF` zo+Y6(a&eQ_vB_@fL-ijV9>*^?#w+r&S4~Wxgm?WoB&+EH{3sQT@Z;MLQc^1)#>J-= zgXib__xNl)G-8w@8QA)%@fWp-f{Lo*1{?JQr;xZj5dTBE76CsgAfkNw$xW}|$oQoH z`~3SOB6>wd9ON$#3PJrajqdE~*!+otgw&D$ z^g8faJQ#m){I!x2QN3d9=-3!M@$CSI$Rh|9izsXu=-ZI|2mdz$^9LaRgzHD{mroMo za*7}KPpu-p_I=%3CTHX0RaS=lC)hs~6C@;}JrC+9F#cn*f&X**-RuSl0~3>*xZ-7y zUzUDsYw4XP*kk2UyzTa3j&3_=`FJDqoT_lT(F4q<*$DeR6%<l;Vuw`tFS`tw+SLDseAwj|Ew7oLRp;{)vc%X<)oK01G51;Gm!RLppF zEMJ5C_o)6S?_O2byJhE={QSe);<~;WD*U?Pl|QGM>BJP3ja5SuGNS*X{{+My^&hRGp|6B^-b6DkNG>kk@F>%=&*z+I!vjpiM_$>d_FWQ@zyC&pmSVg3G#N<8#|GTL_ z?aV3>BQMZ@H5?y7{D?2$A2;3>FD`5l@Y!%G-npOe6`wpAU-JpQD%D3r!QmUAB%*mW z*38Q<3h1v;{Ut+6LoX6q@;Nd!x$OO?4tx{>gGozo8<-_!VCT9Zs$u2i|0M2(UruD~ z`1S@B9+Sk)+g?FWlXKpecL#by{F#WdnCfk}M}VhS)P>f+$h@4^PR!gQ86%A(@Jnu0 zjX?ZgQ(Noc`rauT7O}v<$eNazr1Gln>0g`c2WJE>YnYn4*_MW6WmO>o=j7(`GA(_q zwg1m1E-Qzyw!Yi5z@UJrl)QJJd%jK{kTT9}xVgt>y~$}A9GDA81M!`hnoFKW@p@eD zyZVZ@?|>hzEo;P#Pi-(dg8r#1S037i92_37^0i2);@x(n5ZAwB9h41xf&S?=Dts0> zL3KkbS3ff^Pptn9uRjZiL-`heBNM-H_FN;9Z9M{FOG=TsA8Wo1;j=K&Fp5bU=-%}52kXnoavq|oz{kb2 z2{SW$l8NIyuei2>n^#QSo8;`~Zxg?k;rkEtomkZbOT@k2uuY-^5=O;kz@IbGi>oS| zIr~N=&%DX4`!+PN1^9K}=)!b_>D|!qsN6ize=z#zB=y;IE*W_~KFO)oU%rhFOyd!e z3n*%sT#fhfh)67`t7(}f_w)~_`%w4o+Z-VtrHGKst$Y5@V=<6+~F@uDoSt}@Yd>NWcbr3*;xyo~RRf-+=Oux90<}sy7x}KX3N<=2yK$1?fKq@}20H)T zkMGL|CVy|AI0N*j+jc=uv))uR*L;~@TqPnCP?p-cebd%6=3Q=iJLpuHd3TDnRzY*d z!SgJ{d)f5#O|Jf?X2SFgZ|+(7g8B2n>G6x?)ck79GAi@W; z%93wG^SdkfXSsj`W8h)$7!#44*EKjWLooU4kn!e8>IY(%l5f~|_l^AAr!PeJO^)J| z`$WaOFEn%hGCKqK<=VD(@GDC=c+~5nlJf3> zk;N4vQYJGM)vFePA(6>dBSWjCGhPvIGYUJ~d$!k4oQLW?6H7f`zXHJTPIgWlGBBRe zv3d~n^yRA@eVagExc@=^n!;5l-{6?+3gCbC^&(m@bIq`S?fPW_FmxcOQ_=7?HTIPow z=wBe(n*jV6%pZd~_HX~&9}en^av=YB9U4;grU=B(3Jhv>@qms6@M|FkW??>Ii-7+n zm|xt%r(tqC?%((X`*(-kyDL!tAjmJAoc!D1{*%YPFn`@f$e|={0=PEAsML1>QIRDd zQ70jOjB4YWsqH`b=Tl@HA`<+U4EX)P;jYOrz>pG{1fR1?du{fB=B z{d*cR)(##(U(d;{i!J=z(X}9>Od=qoY+&;8xc`FXU;K7vO_K0eU@ajd_kR8_Xk4$YrB#d`iG&=Ky!{WnX;{O03p8k&Ya z_ddMJ{(xW%JmTNmb~%J)EkXay6{O7v@%F!CP4DR|wJ&7pz)Z8_>3H0|Pe(FuQS9n}5x^v+4;R*!{ zy}aT@JGaV`9@u~I$ZYSP*})+?$G{EvBWp*`(8R~b{Rj9GYPxcYDwa?Eyh06&oBhMn z02cla{<{&Yf7Bmt6B!E11O7emh<`al)qx`p*%6JsDiq+%?cQw|MP#ytigw>x)R%iFy*kwV-uBi2c=&+KK;)0f`?Z!PK;Q!MJT-GxH^Dn#r0p9=en4e>b zatV)!I9rGfl-7SiAU!JqA};PSx!Ip`a}^6$s}m;54}r??gMZ&`-~`e)=6k?z|f zJHLd%{{yWx( zZiYwo&wu={Q}UN?m`GgHGj$8W@)w+V5PuyI1^Va0lTuPzYL_Z1nnrS)!TjgYFog8S z`$}KM1B26%g<$<21Yj>7C7Ybs&AZ?^9_vrr+))3^as7Ja|H`Wa|JGc?+{wq=KlESz z(TI?N3E&?LkNf{>ApTPEpZe9~z4=idDn?#OJ%byLfUkk`|A?yo-qjTXQU*?SA&pyR zK!0qn!RlY|@jdPu9_v>?e;6g$1O9W6nfVPDD1Qh3pU(09gZViYfK@)I!1Rnv?e$Sm z@bal#kp%M#){m@?`yZBoD+l^NO=B`rst{edp9`S=p{s;a(n41Z%p4<=qu}}noFDDc z^YgqF@ZeGC%MRSd6VvO5;Q8OzxSHY~p8L8A)zQBlpHP6T1su(>e&hnxZ!en`<^lg9 zCQYx-tE{Jg*YBw@sIRLaey{Jp`mbo1wg{*}|C5&dKlwq)V}9{3zk&;{AC8}o|I0tG z`^3&B4Ef*3`b*OS;P-}z#AU(wRWgY1^NDz$U)0%DlwSk*E5J{%#CSXe^bLYWjePw(D0{|0!cL zkC+r4BM`@d|FllcDk{OKprmVNA{c??@AK!$nNCUYlV7#AR}9L@%)@-{9m5+K5&R$H z7x-U1yi$O_i+W)C;AvofWz8P!UmvgEsMhx7WBusk0?B!1sQ+BSEh;$o4d9PrHn#y2 z&3ACjuLJ(Gq_;61_MfH+^)w72{;;E}w!NU`>nu0Sza95~EU&K6u=0J`XE=2ztZ-f6 z0>nRNgyvTkv=D*%`wD}gq{h|yPT-p#`=7nP|Ll`9$bkM=mfL|Z!wNDRdk6X}KjCw+ zA4tOev!MP}i^+Fe$J?gh7T^&xumb&;K#%nagYti1e?sGrlvhbxOV`2+>VL?o8Uq_( zP%;Pz1ODN7{!Pv_{rEMz1pG&Eolgziydz_?%P?rbe?A{x+oEErZvoFA=+6&}GOMDd z765-h%_FLHRZa~bj6b<>!0&ZN|C-z;WuRUalQF&H^U%ffK^ZDJ^=)oz!@&H;CeB%L zf$K&F79jtP$jw81n^@mCNqGkFSHLWX{KsZY$58h;=NUes%X*;y${ouOc_a*sF8sz> zBViO0Rr*K%@gM*D=>4Gou^rq0qAY(&-P%GmE4c)LLC+uuhJHZ(Pd0!*NmFKc6BYEFufc5ltgF5r6mol?sz@St6AA<8tC7C3+kt)ftgv- zeF~-v0-VtP8%b|ozr*zXT->7=-=m^ob#ae~EJD=ucdhU3(^FkgRv0IQ`0dofA|&7` zVzS=~h=BgTb)s`@7p~p{{OXgq?A-dMzQL=jCn>nNb?)3tOaD~Y(z1#BgF~2DO-2mz zQ)~+>;rbKkub@6m9|2(M5&tTvuIlWXUx%40$;jI$BNjLV>S3>-tfa!4`hlUncrtFL zb6VH6Zh8rV{;uLX&Od{95>K(#D`@UQeu-RcHLSma`j8JjJ26jm`V6;*)g5<`e}3s7 z_%Q|Qe;y`@Yua{h4@%Ua3XtD0V^ixy=J68q;?UzRFwU(p?3pVBM9EhT6#9rOx~%9$MGwdg;oBNCK(+As9$f{*abXGdh?!( zj2hN2XnF3M-V67MO)98qoY`3+ravblC9P^28&+7E*wESWYiH|GNG;^oZuCsA;c`&( z8w0QTFkz$T}86NEs|IQ&0A zf4FcN?~XHHu=fKS-{8o1Ux5BVfzLulE+Tu)7uFxJ&o9zHAR`-I|Hzn>G_|fe_(Z)3 zb@6W>9$cS4pr8;jd|>D66O)wRX4bp0M@c}>%%^d%K+WXID_5aoHs%u$NDC{uh1AKtGA7 z>Y1J?A17hr6=s0=zq>X?uiy5JjaS0;8v!Hk#)E)_v?mEM2+-G4^7#+oNML@5|DL)f z%+G=Ksdkodh4zBFqN=&wU;a$^sQ!Bb=Ft)VI^F!w{SyG+4e4Jn|MuqHI>a9?9ryn~ zu59{RSXtISvV0!mXUUj617jio8P?yBeWzu`4Afm71^|Dzr0UBuoIk4T3jMSHh?h`7b&FGa)t$Iv9{Rz)MGW_*X3>I|y z*xfFv>DvXPfqq@u+rziBP0I=5ufB|uPOPJc7w~_odNAGFC)Js#MN~BEJCnWQvkQus zVf{A05xK+13-!g@X@!QxRyAN+!Tu1qU_TpKRRMKU8xaZ6e|^k9k@v5fYp8qMhX&QX z{fGhn*Vln9z`sHK%~fMJEPn&*&xX$OApS%Bm(fomQsMg#`WJ-+dRI zMd11sfg}X}w5X-AhfzXyF38_nR(6T-e)5W|8(aeXgP5R_rd=1L{~oP>huTccQc(ZW zSZ!MY=s#Fp-z7Lt0Usae)7`5iNR49bAHKQKCeI?d9?pdKOa9deoPf*G+iu!zXaFM0huFU{rk<#d_l(KK8wG)h1H81 z1k}H_dWKv2X#bycFh6#0tZ`suLxl63w35aZehYcP|HQSlmRB9^|6^qS)c=UT_x}W> z^AG#`bc{?wzKXVf0S`>Q^Al5%U#n3AINN)K0(?Lxf%5;l?5a9!w)%XAs-9C2? zp1=24l|laGlKl=EKl~H&z<)N-ydo(L_$R->%>L11|KajQd3~b?J`lfCbkG3K5AbUX z^vrV9vZ}_4aQ{QdQT=hq3HGnh0sTXF?81-g-(&q>N8_Gw$n%tfBmR|z^#HqnM;z$C ziGh6Vs~0-zZms2dVU9&MvRXXe*R#+dIS2WQ}ce-cdi`qZwz7QuEgOCWc2&l5j(9Ja&8`$zv`f$BNY?Sv;>RVQT_(*%L$PGO3JHpY3bev+$8K@&{K~CK4FJL zPzCh=gGSrj*ROg@5f!} z?vFi-kToU4eRKPJgZ~)+C7^-3w*6NcZdV5tJ@0jMN1u$i_{_48$-k-a2cY`FkWd)# zYd73uUgf{}aJm=tr)_dEu_{~@0Q|A5`^&FK`U^4WpEzf%stMiyFQKzg{Z|RFSm6Kj zG0WkSuwnI|;xVv)!A~wozmdhiNzEq+_(^mTvVCRo#11pl4&1+^43EE+azuN_@SlsU zI$-?SS(rOU0{#<<|6(Hg3{d^+VRRkvA8!L=-skuIIK2t_4*|dG{P+B+OCWy!;~+UR zrxXL&zv5wJ@V%_iV4%NkG0-v#Uu5J{x@G|Ok4TIu1o3ygz7yg|4sUAOc|44Nm041q z48||@(kwA8v!L5CKfC(5iK!coKho;SvKl(EcO8-O(Yb3Kt-T`)RGd6V{%0_>{~DHm zAH}1hr4`cFfcnSHVycmtu`WnI-K0>`kyO?&WQF6Ovp?RqsReK#F%vCyJE^d^_!2CC zygExr!^i0+Z>pQ^5gL}Wm-%&IVGq=Q>=NQpw(#>uWAFcQ|81J(ZRgI3ao|52Sd2sa z*n$1A{_^jy{ScE=m3x5ykQQf@!tQ@!^sdH#bO74FiC6MaLBmPvS-fRRIVQQfwtZ-N z{QwVGJ%*MB4(^Wt5(f1zoL^G1#Jiw!6|4Uwbk-N4+P@M&`r#G58`hwGH1R0@`@`!G zDHZ1hZXJ6knTWW=5|ICmg1iaTXAD=RB$RHjK8E#kf51=wCgY@Ey?Dvg$p`2^@cOm! zc>wGm0rgKn`UBw8VE&lDjes2NUn3Qv;PE;(rv~)DOz+^52(W09|J{G4VdBjPM0@UM zz-JxhUq}02Sf%75K>ul8W8=is!9M90g@}{}%x^vWd;H`6H)PGHZop4N^}nXBjsN5H zv<#SkfcO(CpwCeW%3V|R(7R#h<_r8nFmC|A3h@V6{ryczUOQ>nXV8CmH2$&vtC2TW ze;Zj|BA^2MUr5`){r7H>(V%~$lM(dap7y@y6Oec`|8eo*{sl*~BmcOkuV)+L&;HYY zf7#g4$@f`mHX6jgc|y9Ar@U3+{?pEhl%w-cO0Puz^^b3*zC}Xy_Z$%+4ZAog%>Ri6 zUD3@y>Yph@(+dFo@`kmC_jSvo`$q=$pP>>Eh4w8=Gj#V3%gsA{JvqBaglj3td+`Re ze@eRJlf?ekuf1P}W(jxis7naTSmlL){i~M$pTf>OoXV~J;~6q!E;2`B2*4Slp)EO$h;9ETc*r}WELXPu`^^ABJaJP?J2$Q`CY%iyIecl^Q^V* z@9q)wgt|t)bm6IHd*sLEyKfW&Jw;(;SggQxg>O4Na=;=o^@wU=Wd1R@6PU z4D0_>QqH^5uIaF+q>9(?2Zmo?F72`*pv%Gd2`fnXAD1Wxd%eno)3E*eict=HMkZNlWj4n{I zOG??I`4;@&!M>?6VJSK_Sy|nS7j9Gh+x{h(e=+~IxaOCCYiSMn8|2>tf8u}r+lCeY zcFz&iWApWyn#mO2`9|~1yq&vn%pn5}2a^EIf9~iTpf7$Y((=R5eprCoMah{5YUqa@9o|S|5E%*DrX}RtB)a^o3gk>8? zN6#=Nb^Xh>DF4K>N8u=Z|K=V(EBvCVnGJ$M^NgGVM%wzK1O!H~0sk_+yqP>syOz;i zR>$C){R8i~*yr!ZsMw^0{sZ*qyFn37E;rEr!Bm-50B^N^aUi{{i*Cd3OjNJ#TSMRonO$>{B^&G#f?5#P?JBue;AEe-g5EI;)y5%JsjHp@*y|5;N<2Wr?{^*QKmDj{9vo-+7yqYhdX_^%SmvaHhJ=DD#y|7PMEM)?KmX$Y z;`)EATWETAA^iQ@IwvN+{V-#{rfy&Y^H*Eyi{;Ri^2+Yfuipg(_h}nnf%*4VFcIeG zwF~4SP9AO{!b1;pGpFE)EK*lTUiP~l$iHLx&COiD`>%96RZcObN6Yj}=!E2_VWdtTJt2>HKO=wBT((35p=f0{+|t$0cK{nfYc zl~L4;x`FpU$-|)MT1sR5-9YHy)}%g5ZDkuK&wk&+u?h0ul>BS_0x$T#P2E%UGaE5} zCw%{Cehlj#{=vY)^?mooV{*!>yw`1f?nhj-ZKd!hWcM4R{24a?Q{Epj{QY@|_2(j> ze@dQ$^$+;9rz8*SdtSl#SDkFrX#L&7BL@5gBF;~>PkGzh|7DPp-`ik&$4&3TFaHzk zuixApd=&U6vDo@g#QAd+{!Ke2f47GY{0XdoMO?{`N_;({c=3{jtB;g@SYQe|e|}}> zhPiS3X*7TQ%wIFT%YpYldTEiHNB9sG=x^qJp^4VSrig)2S~gC|fAVfSY{Y@*SN%ul zhraP}h!Lcfw_5q?WS4fl{SuOpS^-?6g;^%99g^xqS9gp*mstL$ZElH1fLr>svHLaK zw4|2>O-<9(j6aySN~kGmm_mTufeb1%@<#A}WB%<`1IX_N0D!8n zBD|oo3;2)!<-esgI3rNXpo`Hi^B;x0Q zK8ES9uDE|x8=aa*2j4&LzXqWG@#p%ymT)w`kiQKB|KZ?a`2RUm^1nH=eW-uBp8gVz zp{W!4`{VuPRy@B9`YZUq!P(${PA{^sY&8GP|3mppoIeWtILucqjlGT2a#()nzJ{5Z zi&tpE3#K<|`AsduX-u@@A1V8%jM87E!uv@tyPNtKs3EI(+W6K@SKpMlT3EL#$={%V zJbFsu)CE{5TnvBXw_P^#^T+f18;Cxpd%Nei|QI;^77UFZe%Up}AG1z@MGu-3sR)3cv4gR&Z=GRI(FtI~#iB zjnMpy@hkiPj?2pH8L4j@yHn#n*}KSElU0vdJLcN^OwD<0qEb43*!(! z0M^&v`7=xbWlf(^e~(^N`Jl>m!8?aw9|8Vk<{UlsdkNsbOR8Rm{Qj-S+LvA3q8|cZ z0(u1!vVw zEHdwa?|+w_$KN5AR=)808-!8+Oj=r7U)Rd*7k^h+9Qx_}+DZhiz#w}U&&b@VvhL;~ z#6QHIzX)&lM~O>a9j_`^@~2!|<^eQpr=#Z?{4^{nx4UVKc8N!bPxA@~@FzX*1ti-} zP*c+bKTKj?OIPO-W&QQV_79l!87mxA{L9Mz9`t5=ir?kNr03Kk{to89i(vUHq<_6)U=iCU|8a~{h}z(s)YGKe z>b{Qg30CH9TaW1)vS^)?eVUz9*Dx^mFe?V>?dk?rwgS@XY9>~8{`X=sNwr-~Unkg^ zd1Oo={|5a|=r2#<{R8Wrn(C&&KaGn?2mKHHi(mXC2@7wZr0D88iv9)pd(eMDKVQXv z#rngXDF2bMlK-IT{s{a}cF~<~!BMdO;QjB`PiI6|^P3R=1kR1ne^*veLjC(@$loy4 zWYkxGi2l0F{>NTP`4i(*`vM}2BcFzma^DS%4bckl?a({}=b!7h0}{_ceyU@BoMH2* z5qy8*GDk9A=Xbmx_l_wlc-`}9foW;8=%Kxe$IZJT=E(~B+ai~O`Yjb5lM9zTU83WX zUNkj+7@4A%Q`0s!x&ZuK;6bG{Hj;;Zv(igmcasNT-&8!T>%1#?rGJ$33G$CJvIhs( z(74=z^(UjeVdx(g=8e+g3dc0;uX@~zN-wNM`KwusUj_L;g1mL=20QegK}yY&F$|!iUeL$*_svoD>k}lQf8p#E@YF8{`0p?4oBG+dNke~KL(S1S`{P(FJpaQ@0<;XgCqxvK z^z|KY);@@;FRHY)Z|)_J53EJ`7hT}C>^hC{v;CmA5Bj6Kw&ZQtO8;Ot z%71~rSB&`iGg%lvUtdB^{uIXljDMBM@_Gn6|1tr;@zBZh(NQiTDQg(JM;Mv;xVM^% z?IIYYL4s&M|=v|aX5s6Y5Ob%Pbvy+TW9|FK2SuMgxgCaPVm;owOR#1HF>Tg@+ke$Ebq8{ohGdjAJ8egQM^?=Ru~yFAX7{vhPLN>h`; ze$(b@tmgg2Hk#GP1fSp-+AHX?FUX()Nk4 z(5$@5#`e|sFF^nHNlNZNP~O-E=MMtSWfQx5>Y>ka-FnB!H0)c}ivoWL)-RpFr1dzpxl}t<`{s-s^&_8vGjBrHyFV_DZV^RnG!pYy} z9^&sc)D5p2Wna5z|LzSs7i16V1cLrB`=X#3_}K^61OJV}->T|QPc1G3{Q{N~MS|)v zWzCE5^Kky2T43v$qu;(+ax?IEiPwR@2mAIq2m8zxdHKFPTJy{%kHa zm&g`^>=h_`Y2T!_q2fBCxKisvr2 z&H=ww-z(`E==1NtFsz*i{x_47Ch$KG9MFxrYzF5a(o`v|BiP?hR_9@H)~nfqD)7Ho zKHu}Q9r*9f-$!cscgXHNt}Ar~{5K6-#J}}O>n{NPT|q)t&&pZ~@{cG#|2Yo&w?>FR z-^nT7ukiEV)1rFXI_IdmctC%E=Lqg!3HN@OP+bW9y*!xz7I&ik|42YM(ys<7`CaJ$ zE33eyVqS&m7xcSEAwRi(n_QTkJ<4Aq|9gx|h(kh68~hKMj1tKA;r;orz^0kSwF0tm z{)PLI%tPa|GmASu=e98kgC2Vd@-Jt=YI&S;$0ss5=t&;80Kd#(7Sx{(^|#C?)uteR zvDC~u@yi>9j0`W^IknnmWEHJpYatJ=nPuS%lvg#-eU|npj`W^9HbTA3DM-*dW^~>M z&p$!`B%{2xZV-6ao7m}5e%;M4C^76c1QW|}{TcEfPqS;w2jQI0THS#1uhzf=4a<04 ze8C0!FRh*AFY@#2)~|g22k>#H2Zm)^A-zT6_fY!B@ORtB0r^usu>(gnRUhTXp#DA6 zvPnYDo7xdZY5_SK%K86}hi7DTd3AHs#1iv{KX_@`f9<~$6AVleyH6-zFf#Q3Zkgj1 z8{bKv>Wb#>WjOySSVI1sxN`qRa?T&1kDqbn6S;C#<=RZF z{hkTlaAHx#$K_dCiErrtEd=>_W6VDzR`kvELH`HKABDL*ev(x60Pa5+XK5uU8vW(q z0VZp6(82^ie_}#zqPk8?x<_37acJOc` z{}a1EVl1t$Dhc?}-OKAh{|0^`)}Qu6{GjA%m`FCuXdc%_{6+Bhi;}8{pX~r*JaIQx`l3} ze_;Hs6PD>K{cWs24gTPMQ_r)WN$C*EZ^wS#9?x$VCWOSKH_!+|sSn$KqZ~}UgMyzG znm^2? zt>c3HtsK}Cq?4=S_(APcV;t>_{ytuseOLJYzk}$#0z}oRnV0z+<>iW;Kll(k9+tjc* z0`9lS%qS`i%U;oc^!F<7{}cGX0ii(?#3ugI_gMZ6)_;>5F`(~a{Vjg3pWi?B_wPsf z5A6I>NS?*=M`tb*K!04(-vvPbQXzQXP=Qa4vPCtmJD{Qmd7_)a zvAN}COXG_s3B-*2mJgr6e-)G5b>fQA4I7U@VnJm$%#BoxKlvwmTKMzRzgtvUQBB_! z_;(n8nd;~K=e!m8i2**5b6Ed|idn>xT~bWb1g=_(P01wH)OCHOUb9Yupk-}$C&Ix$ zE*JQ*Z%0DHk_y{udq&4;H;O`U&cyI2^gpotV%2+meiVbUT?(lL_*Z0%-$cXmlfN*O z3o6zytqSD-ZB!0lH}%Ubu=bpUejavyy6WzO^?My%?+*MgxM^)*iXCi0xc^HU_CKsY z1^Vnt{s8A+j0TstylET%&T|gw|8Ogww(*N6VWA1BtsR`e--iAL literal 0 HcmV?d00001 diff --git a/Content/Materials/SimpleMapMaterial.flax b/Content/Materials/SimpleMapMaterial.flax index a84903044000588343164169fdcf9429de7f64cc..079cc558dcb8340c6222eabdc3c9d2c9b30bd005 100644 GIT binary patch delta 399 zcmV;A0dW5E`~mX(0kF6M0T8pf0iOdG0RRO6000C62LJ#7000035dZ)H0001!Zw2E4 z0kcyE5CjV~B@aXZ(+NY?8i=!Q3f(V%955+JM=&%`n|yGDma3e^#19}V^AjQ@C32OE zt+%z$;otP~FHpPB+Ti)g$rBDUgFgTf)4+$+Nf%xaBxMNfRP6KtrvhzOlToy28xg7&YyG{9#mm zKT0YzPoSlRl*!TM0s9{vAUQZ=Q)a2OUut@UkI?0(3;bus)Zgp13J5DWK|otrBS=+6 zV|;(f-qo)G4jwQu{0l!!4-sQ>dWe&BZOPb_q_D#O3_L(NSXXd_k6XLEz0$11*SqHb z00uqgll delta 399 zcmV;A0dW5E`~mX(0kF6M0TQ#h0iOdG00069000000009K000000RRO6000D&Zw2E4 z1G7^G5CjW;iTy(dzF0#OoOZKr3f(V%BO@|QMR|2kT4HQ}+1K#%xW(=G1yw01DPmGy zS9`_I;mEW6{!v`T-RA5E)z={|K2T9SIYd>AyK$4M==AjuBlPy-u4I~Q+Rr}#BFwll%3)8v%qJNgWcxt{0-^jJ4g=~D@RpD zV|;¬dJatQ{skOilR%SrIfXikPXnYtGQ=_y-6HDEaUc3n?^3mztY(zsjn#&mScP z6irtlE>1P3G`G)zr(X+&FIXnmEnqQSh-(JMShAucXJQHiTx tYE3wPsWzyypyp=Vbv7g*MAcblyIW%6WmZEiP)9EL=O3INe9XgElw@UOUz9Lin-?}`ec@5mij8yf^=GCWQ!G@`{>a2 L@&E4(vCC!vUx9q# literal 0 HcmV?d00001 diff --git a/Content/Materials/sky.flax b/Content/Materials/sky.flax deleted file mode 100644 index 9320cb1ad4cb18af55dfc468161a52925b27698d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29986 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 GmHz|!YG2&| diff --git a/Content/Materials/sky/skynight1.flax b/Content/Materials/sky/skynight1.flax new file mode 100644 index 0000000000000000000000000000000000000000..f00e5d30d8f73271ec5e15e3b80c71db7aabf7a4 GIT binary patch literal 541 zcmZ>E3wPsWzyypyp%lA(%ir}!Ja#A;_qws{V0UB4VMt`CU~px~V@PMn1d^!?dJMim zu@WGw2q=;WRN)B}F9wPv0_kL+IQ75*piv-qT>=u`P-6$18(E<4`cDA>8FBUPyV-g` zx?0IIw;;c$Bp|UQL&-`>Ne9XgElw@UOUz9Lin-?}`ec@5mij8yf^=GCWQ!G@`{>a2 z@&E4(vCC%6z%XO1s=ptvpPTQx_U$AlUd~GzjEsChrGGSzX?)YTsc}c+sKyVCD;fti PE@&JF@~!~IfYOWr2aS instance.IsOpen; diff --git a/Source/Game/Cabrito/Console/ConsolePlugin.cs b/Source/Game/Cabrito/Console/ConsolePlugin.cs index 41c6d95..ac342a0 100644 --- a/Source/Game/Cabrito/Console/ConsolePlugin.cs +++ b/Source/Game/Cabrito/Console/ConsolePlugin.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.Serialization; using FlaxEngine; using Console = Cabrito.Console; @@ -13,16 +14,15 @@ namespace Game { public override void Initialize() { - Debug.Log("ConsolePlugin init"); -#if !FLAX_EDITOR + base.Initialize(); + Debug.Log("ConsolePlugin Initialize"); + Console.Init(); -#else - Console.Clear(); -#endif } public override void Deinitialize() { + base.Deinitialize(); Debug.Log("ConsolePlugin Deinitialize"); } @@ -33,6 +33,7 @@ namespace Game Description = "Quake-like console", Version = Version.Parse("0.1.0"), IsAlpha = true, + Category = "Game", }; } @@ -41,7 +42,7 @@ namespace Game { public override void Initialize() { - Debug.Log("ConsoleEditorPlugin init"); + Debug.Log("ConsoleEditorPlugin Initialize"); Console.Init(); } diff --git a/Source/Game/Cabrito/EngineSubsystem.cs b/Source/Game/Cabrito/EngineSubsystem.cs index 13846c3..7b3bb04 100644 --- a/Source/Game/Cabrito/EngineSubsystem.cs +++ b/Source/Game/Cabrito/EngineSubsystem.cs @@ -190,5 +190,28 @@ namespace Cabrito Level.FindActor("ViewModelCamera").IsActive = boolValue; } } + + + // Horizontal field of view of the Camera + [ConsoleVariable("fov")] + public static string CameraFov + { + get + { + float valueFloat = Level.FindActor("PlayerCamera").As().FieldOfView; + float horizontalFov = (float)(180.0f / Math.PI * (2*Math.Atan((4f/3f) * Math.Tan(Math.PI / 180.0f * valueFloat / 2.0f)))); + return horizontalFov.ToString(); + } + set + { + if (float.TryParse(value, out float valueFloat)) + { + valueFloat = Mathf.Clamp(valueFloat, 0.01f, 360.0f); + + float verticalFov = (float)(180.0f / Math.PI * (2*Math.Atan((3f/4f) * Math.Tan(Math.PI / 180.0f * valueFloat / 2.0f)))); + Level.FindActor("PlayerCamera").As().FieldOfView = verticalFov; + } + } + } } } \ No newline at end of file diff --git a/Source/Game/EngineUtilities.cs b/Source/Game/EngineUtilities.cs new file mode 100644 index 0000000..456a18b --- /dev/null +++ b/Source/Game/EngineUtilities.cs @@ -0,0 +1,26 @@ +using System; +using FlaxEngine; + +namespace Game +{ + public static class Utilities + { + public class ScopeProfiler : IDisposable + { + public ScopeProfiler(string eventName) + { + Profiler.BeginEvent(eventName); + } + + public void Dispose() + { + Profiler.EndEvent(); + } + } + + public static ScopeProfiler ProfileScope(string eventName) + { + return new ScopeProfiler(eventName); + } + } +} \ No newline at end of file diff --git a/Source/Game/Networking/NetworkManager.cs b/Source/Game/Networking/NetworkManager.cs new file mode 100644 index 0000000..b550298 --- /dev/null +++ b/Source/Game/Networking/NetworkManager.cs @@ -0,0 +1,94 @@ +using System; +using System.Diagnostics; +using System.Text; +using System.Threading; +using FlaxEditor; +using FlaxEngine; +using FlaxEngine.Networking; +using Console = Cabrito.Console; +using Debug = FlaxEngine.Debug; + +namespace Game +{ + [AttributeUsage(AttributeTargets.Class)] + public class NetworkPredictedAttribute : Attribute + { + public NetworkPredictedAttribute() + { + } + } + + // TODO: insert code to update variables with this attribute? + // rename to NetworkReplicatedAttribute? + [AttributeUsage(AttributeTargets.Class)] + public class NetworkedAttribute : Attribute + { + public NetworkedAttribute() + { + } + } + + // NetworkMulticastAttribute: calls methods marked with this in all clients + + public static partial class NetworkManager + { + private static bool initialized = false; + + private static NetworkPeer server; + private static NetworkPeer client; + + private static ushort ServerPort = 59183; + private static string ServerAddress = null; + private static ushort MTU = 1500; + private static ushort MaximumClients = 32; + + public static uint LocalPlayerClientId { get; private set; } = 0; + + public static void Init() + { + if (initialized) + return; + + if (Engine.CommandLine.Contains("-server")) + { + StartServer(); + ServerAddress = "localhost"; + ConnectServer(); + } + else if (Engine.CommandLine.Contains("-client")) + { + ServerAddress = "localhost"; + ConnectServer(); + } +#if FLAX_EDITOR + else + { + StartServer(); + } +#endif + + initialized = true; + } + + public static void Deinitialize() + { + if (server != null) + { + Scripting.FixedUpdate -= OnServerUpdate; + Scripting.Exit -= Deinitialize; + Level.ActorSpawned -= OnServerActorSpawned; + NetworkPeer.ShutdownPeer(server); + server = null; + } + + if (client != null) + { + Scripting.FixedUpdate -= OnClientUpdate; + Scripting.Exit -= Deinitialize; + Level.ActorSpawned -= OnClientActorSpawned; + NetworkPeer.ShutdownPeer(client); + client = null; + } + } + } +} \ No newline at end of file diff --git a/Source/Game/Networking/NetworkManagerPlugin.cs b/Source/Game/Networking/NetworkManagerPlugin.cs new file mode 100644 index 0000000..31034b4 --- /dev/null +++ b/Source/Game/Networking/NetworkManagerPlugin.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using FlaxEngine; +using Console = Cabrito.Console; + +#if FLAX_EDITOR +using FlaxEditor; +#endif + +namespace Game +{ + public class NetworkManagerPlugin : GamePlugin + { + public override void Initialize() + { + base.Initialize(); + Debug.Log("NetworkManagerPlugin Initialize"); + Console.Init(); + + NetworkManager.Init(); + + Level.SceneLoaded += (scene, guid) => Console.Print("scene loaded: " + scene.Name); + } + + public override void Deinitialize() + { + base.Deinitialize(); + Debug.Log("NetworkManagerPlugin Deinitialize"); + } + + public static PluginDescription DescriptionInternal = new PluginDescription() + { + Author = "Ari Vuollet", + Name = "NetworkManager", + Description = "NetworkManager for Goake", + Version = Version.Parse("0.1.0"), + IsAlpha = true, + Category = "Game", + }; + } + +#if FLAX_EDITOR + public class NetworkManagerEditorPlugin : EditorPlugin + { + public override void Initialize() + { + Debug.Log("NetworkManagerEditorPlugin Initialize"); + Console.Init(); + } + + public override void Deinitialize() + { + Debug.Log("NetworkManagerEditorPlugin Deinitialize"); + } + + public override PluginDescription Description => NetworkManagerPlugin.DescriptionInternal; + + public override Type GamePluginType => typeof(NetworkManagerPlugin); + } +#endif +} \ No newline at end of file diff --git a/Source/Game/Networking/NetworkManager_Client.cs b/Source/Game/Networking/NetworkManager_Client.cs new file mode 100644 index 0000000..9f29e5d --- /dev/null +++ b/Source/Game/Networking/NetworkManager_Client.cs @@ -0,0 +1,93 @@ +using System; +using System.Diagnostics; +using System.Text; +using System.Threading; +using FlaxEngine; +using FlaxEngine.Networking; +using Console = Cabrito.Console; +using Debug = FlaxEngine.Debug; + +namespace Game +{ + public static partial class NetworkManager + { + public static bool ConnectServer() + { + client = NetworkPeer.CreatePeer(new NetworkConfig + { + NetworkDriver = FlaxEngine.Object.New(typeof(ENetDriver)), + ConnectionsLimit = MaximumClients, + MessagePoolSize = 2048, + MessageSize = MTU, + Address = ServerAddress == "localhost" ? "127.0.0.1" : ServerAddress, + Port = ServerPort, + }); + if (!client.Connect()) + { + Console.PrintError("Failed to connect to the server."); + return false; + } + + Scripting.FixedUpdate += OnClientUpdate; + Scripting.Exit += Deinitialize; + Level.ActorSpawned += OnClientActorSpawned; + return true; + } + + private static void OnClientUpdate() + { + using var _ = Utilities.ProfileScope("NetworkManager_OnClientUpdate"); + + while (client.PopEvent(out NetworkEvent eventData)) + { + switch (eventData.EventType) + { + case NetworkEventType.Connected: + { + LocalPlayerClientId = eventData.Sender.ConnectionId; + Console.Print("Connected to server, ConnectionId: " + eventData.Sender.ConnectionId); + break; + } + case NetworkEventType.Disconnected: + { + Console.Print("Disconnected from server, timeout."); + LocalPlayerClientId = 0; + break; + } + case NetworkEventType.Timeout: + { + Console.Print("Disconnected from server, connection closed."); + LocalPlayerClientId = 0; + break; + } + case NetworkEventType.Message: + { + // Read the message contents + var message = eventData.Message; + var messageData = message.ReadString(); + + Console.Print($"Received message from Client({eventData.Sender.ConnectionId}): {messageData}"); + + // Send hello message to the client back + { + var sendmessage = client.BeginSendMessage(); + sendmessage.WriteString($"Hello, Server({eventData.Sender.ConnectionId})!"); + client.EndSendMessage(NetworkChannelType.Reliable, sendmessage); + } + + client.RecycleMessage(message); + + break; + } + default: + throw new ArgumentOutOfRangeException(); + } + } + } + + private static void OnClientActorSpawned(Actor actor) + { + + } + } +} \ No newline at end of file diff --git a/Source/Game/Networking/NetworkManager_Server.cs b/Source/Game/Networking/NetworkManager_Server.cs new file mode 100644 index 0000000..590a955 --- /dev/null +++ b/Source/Game/Networking/NetworkManager_Server.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; +using FlaxEngine; +using FlaxEngine.Networking; +using Console = Cabrito.Console; +using Debug = FlaxEngine.Debug; + +namespace Game +{ + public static partial class NetworkManager + { + private static List ConnectedClients; + + private static List NetworkedTypes; + + public static bool StartServer() + { + ConnectedClients = new List(MaximumClients); + server = NetworkPeer.CreatePeer(new NetworkConfig + { + NetworkDriver = FlaxEngine.Object.New(typeof(ENetDriver)), + ConnectionsLimit = MaximumClients, + MessagePoolSize = 2048, + MessageSize = MTU, + Address = "any", + Port = ServerPort + }); + if (!server.Listen()) + { + Console.PrintError("Failed to start the server."); + return false; + } + + Scripting.FixedUpdate += OnServerUpdate; + Scripting.Exit += Deinitialize; + Level.ActorSpawned += OnClientActorSpawned; + + NetworkedTypes = new List(); + + AppDomain currentDomain = AppDomain.CurrentDomain; + Assembly[] assemblies = currentDomain.GetAssemblies(); + + foreach (var assembly in assemblies) + { + // Skip common assemblies + var assemblyName = assembly.GetName().Name; + if (assemblyName == "System" || + assemblyName.StartsWith("System.") || + assemblyName.StartsWith("Mono.") || + assemblyName == "mscorlib" || + assemblyName == "Newtonsoft.Json" || + assemblyName.StartsWith("FlaxEngine.") || + assemblyName.StartsWith("JetBrains.") || + assemblyName.StartsWith("Microsoft.") || + assemblyName.StartsWith("nunit.")) + { + continue; + } + + foreach (var type in assembly.GetTypes()) + { + if (type.GetCustomAttributes().Any(x => x is NetworkedAttribute)) + NetworkedTypes.Add(type); + } + } + + foreach (Type type in NetworkedTypes) + { + Console.Print("tracking networked type: " + type.Name); + } + + return true; + } + + private static void OnServerUpdate() + { + using var _ = Utilities.ProfileScope("NetworkManager_OnServerUpdate"); + + while (server.PopEvent(out NetworkEvent eventData)) + { + switch (eventData.EventType) + { + case NetworkEventType.Connected: + { + Console.Print($"Client({eventData.Sender.ConnectionId}) connected!"); + + ConnectedClients.Add(eventData.Sender); + Console.Print("Connected clients: " + ConnectedClients.Count); + + // Send hello message to the client back + { + var sendmessage = server.BeginSendMessage(); + sendmessage.WriteString($"Welcome, ({eventData.Sender.ConnectionId})"); + server.EndSendMessage(NetworkChannelType.Reliable, sendmessage, eventData.Sender); + } + break; + } + case NetworkEventType.Disconnected: + case NetworkEventType.Timeout: + { + Console.Print($"Client({eventData.Sender.ConnectionId}) disconnected!"); + + ConnectedClients.Remove(eventData.Sender); + Console.Print("Connected clients: " + ConnectedClients.Count); + break; + } + case NetworkEventType.Message: + { + // Read the message contents + var message = eventData.Message; + var messageData = message.ReadString(); + + Console.Print($"Received message from Client({eventData.Sender.ConnectionId}): {messageData}"); + + server.RecycleMessage(message); + break; + } + default: + throw new ArgumentOutOfRangeException(); + } + } + } + + private static void OnServerActorSpawned(Actor actor) + { + Console.Print($"actor spawned: {actor.Name} ({actor.TypeName})"); + } + } +} \ No newline at end of file diff --git a/Source/Game/PlayerMovement.cs b/Source/Game/PlayerMovement.cs index d5c7d87..c47b308 100644 --- a/Source/Game/PlayerMovement.cs +++ b/Source/Game/PlayerMovement.cs @@ -26,6 +26,7 @@ namespace Game //public Vector3 maxEndPosition; } + [Networked] public class PlayerMovement : Script { [Limit(0, 9000), Tooltip("Base Movement speed")] @@ -617,7 +618,8 @@ namespace Game return slideMoveHit; } - return slideMoveStepHit; + //return slideMoveStepHit; + return slideMoveHit; } [Flags] @@ -792,6 +794,7 @@ namespace Game private const float jumpBoostTime = 0.5f; private const float jumpBoostVelocity = 100f; private const int jumpBoostMaxJumps = 2; + private const bool jumpStairBehavior = true; private const float maxAirSpeed = 320f; private const float maxAirStrafeSpeed = 30f; @@ -867,9 +870,8 @@ namespace Game // jump if (onGround && jumpAction && !jumped) { - if (OnJump(traceGround, ref velocity)) + if (OnJump(traceGround, ref position, ref velocity)) { - onGround = false; jumped = true; lastJumped = Time.GameTime; numJumps++; @@ -966,19 +968,17 @@ namespace Game return traceGround; } - private bool OnJump(TraceInfo traceGround, ref Vector3 velocity) + private bool OnJump(TraceInfo traceGround, ref Vector3 position, ref Vector3 velocity) { float jumpVel = jumpVelocity; if (Time.GameTime - lastJumped < jumpBoostTime) jumpVel += jumpBoostVelocity; - // reset velocity from gravity + // Reset velocity from gravity if (-Vector3.Dot(Gravity.Normalized, velocity) < 0 && Vector3.Dot(velocity, traceGround.hitNormal) < -0.1) { - Console.Print("vel before: " + velocity.Y); velocity = Vector3.ProjectOnPlane(velocity, traceGround.hitNormal); - Console.Print("vel after: " + velocity.Y); } velocity += Vector3.Up * jumpVel; @@ -990,7 +990,25 @@ namespace Game velocity.Y = jumpVel; } - Console.Print("jumpvel: " + velocity.Y); + onGround = false; + + // Allow stairs to eat the first jump to allow easy stair jumps + if (jumpStairBehavior && jumpBoostMaxJumps >= 2 && numJumps == 0 && -Vector3.Dot(Gravity.Normalized, traceGround.hitNormal) > 0.85) + { + // Try stepping into stairs without vertical velocity + Vector3 stairCheckPosition = position; + Vector3 stairCheckVelocity = velocity.Normalized * (stepHeight / Time.DeltaTime); + stairCheckVelocity.Y = 0f; + + SlideMoveHit blocked = StepSlideMove(Actor, ref stairCheckPosition, ref stairCheckVelocity, true); + float movedUp = stairCheckPosition.Y - position.Y; + + if (movedUp > 0 && blocked.HasFlag(SlideMoveHit.Step)) + { + velocity.Y = 0f; + onGround = true; + } + } if (!predicting) { diff --git a/Source/Game/Q3MapImporter.cs b/Source/Game/Q3MapImporter.cs index 0d9480f..bc95606 100644 --- a/Source/Game/Q3MapImporter.cs +++ b/Source/Game/Q3MapImporter.cs @@ -191,7 +191,7 @@ namespace Game vertices = new Vector3[0]; } -#if FLAX_EDITOR +#if false//FLAX_EDITOR [OnSerializing] internal void OnSerializing(StreamingContext context) { @@ -248,7 +248,7 @@ namespace Game ScriptsBuilder.ScriptsReloadEnd += onScriptsReloadEnd; #endif - Debug.Log("LoadMap"); + //Debug.Log("LoadMap"); LoadMap(false); } @@ -280,7 +280,7 @@ namespace Game root = MapParser.Parse(mapChars); sw.Stop(); - Console.Print("Map parsing time: " + sw.Elapsed.TotalMilliseconds + "ms"); + //Console.Print("Map parsing time: " + sw.Elapsed.TotalMilliseconds + "ms"); bool oneMesh = false; bool convexMesh = true; @@ -303,7 +303,7 @@ namespace Game worldSpawnActor = Actor.AddChild(); worldSpawnActor.Name = "WorldSpawn"; worldSpawnActor.HideFlags |= HideFlags.DontSave; - worldSpawnActor.HideFlags |= HideFlags.DontSelect; + //worldSpawnActor.HideFlags |= HideFlags.DontSelect; } List brushGeometries = new List(root.entities[0].brushes.Count); @@ -351,7 +351,7 @@ namespace Game else { // TODO: engine doesn't seem to always load the asset even though it exists, bug? seems to happen at low framerate - Console.Print("Material '" + textureName + "' not found for brush, assetPath: " + assetPath); + //Console.Print("Material '" + textureName + "' not found for brush, assetPath: " + assetPath); materials.Add(textureName, missingMaterial); brushMaterial = missingMaterial; } @@ -374,7 +374,7 @@ namespace Game brushIndex++; } sw.Stop(); - Console.Print("Pass 1: triangulation: " + sw.Elapsed.TotalMilliseconds + "ms"); + //Console.Print("Pass 1: triangulation: " + sw.Elapsed.TotalMilliseconds + "ms"); // pass 2: texturing brushIndex = 0; @@ -494,10 +494,11 @@ namespace Game geom.model.LODs[0].Meshes[i].MaterialSlotIndex = i; geom.model.MaterialSlots[i].Material = geom.meshes[i].material; } + brushIndex++; } sw.Stop(); - Console.Print("Pass 2: texturing: " + sw.Elapsed.TotalMilliseconds + "ms"); + //Console.Print("Pass 2: texturing: " + sw.Elapsed.TotalMilliseconds + "ms"); // pass 3: collision sw.Restart(); @@ -516,6 +517,17 @@ namespace Game for (uint i = 0; i < indices.Length; i++) indices[i] = i; + if (geom.meshes.Length == 1) + { + var info = geom.meshes[0].material.GetParameter("IsClipMaterial"); + if (info != null && (bool)info.Value) + { + var entries = childModel.Entries; + entries[0].Visible = false; + childModel.Entries = entries; + } + } + CollisionData collisionData = Content.CreateVirtualAsset(); if (collisionData.CookCollision(convexMesh ? CollisionDataType.ConvexMesh : CollisionDataType.TriangleMesh, geom.vertices, indices)) @@ -539,7 +551,7 @@ namespace Game brushIndex++; } sw.Stop(); - Console.Print("Pass 3: collision: " + sw.Elapsed.TotalMilliseconds + "ms"); + //Console.Print("Pass 3: collision: " + sw.Elapsed.TotalMilliseconds + "ms"); } else { @@ -699,11 +711,11 @@ namespace Game return new Vector3(float.Parse(points[0]), float.Parse(points[2]), float.Parse(points[1])); } - /*Color ParseColor(string origin) + Color ParseColor(string origin) { string[] points = origin.Split(new char[] { ' ' }); return new Color(float.Parse(points[0]), float.Parse(points[1]), float.Parse(points[2])); - }*/ + } //Console.Print("light"); PointLight light = worldSpawnActor.AddChild(); @@ -715,7 +727,7 @@ namespace Game if (lightEntity.properties.TryGetValue("_color", out string colorStr)) { - //light.Color = ParseColor(colorStr); + light.Color = ParseColor(colorStr); } float lightamm = 200f; diff --git a/Source/GameTarget.Build.cs b/Source/GameTarget.Build.cs index 806317a..cf7d1e1 100644 --- a/Source/GameTarget.Build.cs +++ b/Source/GameTarget.Build.cs @@ -1,4 +1,6 @@ +using System; using Flax.Build; +using Flax.Build.NativeCpp; public class GameTarget : GameProjectTarget { @@ -24,5 +26,16 @@ public class GameTarget : GameProjectTarget Modules.Add("Game"); Modules.Add("FidelityFXFSR"); } + + public override string GetOutputFilePath(BuildOptions options, TargetOutputType? outputType = null) + { + // For IDE builds only, these do not work during cooking + if (options.Configuration == TargetConfiguration.Development) + options.OutputFolder = @"C:\dev\GoakeFlax\Output\WindowsDevelopment"; + else if (options.Configuration == TargetConfiguration.Release) + options.OutputFolder = @"C:\dev\GoakeFlax\Output\WindowsRelease"; + + return base.GetOutputFilePath(options, outputType); + } } \ No newline at end of file