h&cxXvhIpa
z()I%rk(x0w4GD(P%cV|nE!726ha6d>?v3FXaTiuebm;Lr_u7b5dF&V(VSCeXb@_VY
zH_wyVkwSEs_ukFLs4&9QgUUn6g|CF)GBVv1&|&K|^+I6{y?3z`Zg6c%8SqqAx|}-f
zAmyofy5J=zJeHcM@=jo@w!Tk}p@xMWZYnqO4a2{Kj}GtTu@?jRXZIg1JMhQY|g~NP1yz%CuQ)_b=64Jvn4>aACGrxgj;Ec3dLO|T=Kru
zyn9nH{mPH&hpzguw@bP~H`i484WlBz&yv048!%;UDst&nGaD&Wi39^R33H*&_QT{v
zmDUtVwpfP$RF`l?oIeY}>Gy^zXHXCIg)QXWKoCJZ3_xX0RE)n;kC?stTU_>SC)Gi3
zE!rAevfbr8%G^vBgdTWJ7a&Smnj9J$U=ROD&ojQcM3vK}BoUJGKD-2f#hCw8!VDQ(
zWH_;?ydM)~ZMFoyH*Ql;dQDeC_$YK(2e-PK@5fO;S!M~5xuP}C=3q@;RYs`GPxg=|
z4%zzbf4+@;Km4wB91z81gz`g?^V~Y$Tw^Cla=lgpMO})6M2)H5w;cRp4@n6r>~}Nr
zsNpN6^%nrged~@2YL}w{Q;oV&S=xjfg$}AOgYdZQ%16tt7A?eHXL(rzDW9<>(
z;^wvY(e1oRMgfg3a$EdL^=Ra7wW2*KgdK_qbI}&W;&c5-3c+C)bZ>Vsw9l$kCjAp-
zc$3w;&*KLN4m3R5y2N-6&67Z(mI8AlMYxZyY=U2D@*($+%iW9B?DF6BRR*2^rUlYJ
zBDBLEG9x+_)v+@zK&J(t23O5ka}rpf$7IYV;$=_)Te8vLc9L;N-!c>$$^eQ5i3H9U
z;$=(>Xu9~LnwHhA1kFuqJ;;tzd+jo`wN*86-IpSa95c{kuTGe2@n#Nt^Gbq6J_Da9
zOg@=COGWYQo=T@;Eb&|D{h)ZD<;917+-TbyzuvY
zrQUOqLK)s(e?Zk>#r14;P7fO_Vha2dGz>6Z8zLSEGGMhpMBHPKvZpFqs6-=8lCbjX
zsQKskX!Rq)nl+B~WIWf^Xlb5eBg?dQ9rI4(JEw2(4{y1wh%|$`4RZWr;r&3
zZnUBZE3^dHJImv!AJud5O+f1cD&;t9Xaa01@RwQmd5aD=^HQZFqthI!MMKqG3E(L+00}aj3{+_9o=q~fQ`}h*@qCSuswxJp3G3hb0~JJVwnx+>Mn!+
zWx{Cz!@W+=&aaybHH_I1ND-3_X94TXEv0)i#_CC4x|O4XIcy7&r}?m2h97@Y)=O>=
zDAJ@3_rX&A`qyrdS_T?H-frcXNq@(WT?;NwF^sWBQuIdH-sv)kld0+S)#0*DKsn0m
z#z^YnS~PW4rGeE2tr%8&w_@HS
zpz%&;V6Eg$llSQ90Ek-zLVu1o*iv3oFSSm?Rd2eaSbIF`OhCpn7jjni`W0#WYa)^`q8LM
z+Ll!6E2hc$;=9{M7gDPf<@-RjL^^o%q8*jsuFjmk8Yt<`>BJ)QKo9Z+Rlip2^NJNy
zQs9yy&YcDlwH%w4UBDn&D*I@KeTZ`lqBFOdt6hATD^AenFIuJ5exisl6`udK7jb1`
zrJiz-#BJkN=`B_`XP<@zE~sa);8D_->bV10o3)^>au9)S5CSzxfhj&-M!=qV?}wN8
z8cP&?Je%3JzumEHOmoV_{5Z^>A8VoLNGr<(&GiQd#t7qqGXc)$%fVRs?2&eu_t>@s
z_h;$Z-H!cji4hm?&F=`*{>hKItTJg#>rlp*vhC-!u=vUW?5efLO1F^rSg3G6YHnV1
z-jc-+TiFS$0Me(=t~}b%*>8WUx`aJgRt;7?zx~-%_IE@69!45tyw#3`DbAj!buLHR
z6pCloaLt3%
zMek>B5$v9AeEU?cQ#)Zd8vG(Q86W*~v4`HfndXzv&(Tl`;&Q*ye;qRl`jRfL`8lJZ
zVO~wE%%_mE`ekmglWUIV1UJa;(BeZL2kEoeMsdae>(KxIe*i5Z_joPMPB2bsm#&95
P1&*@3hFtl3v!MS6SNyft
literal 0
HcmV?d00001
diff --git a/bot/assets/end.png b/bot/assets/end.png
new file mode 100644
index 0000000000000000000000000000000000000000..0ee85502857012f10e598099be5483ac8588a8a3
GIT binary patch
literal 5446
zcmaJ__d6R76IYa?_8zrjRE^fG5$UpvR<*TfVsC0kv{tEEYR0HiF;XEEQKLp0GitP`
zo!F&>8XfC!8R=8ah{=$5+2!}O(_-iP?$wMppZ+bs9
z-Sl2sC=H2P4K4Yw3F+oUybK0_=`&Rzu@b5fFEwhhcX3j$kZf1K#Yxf$5uD!}&ZrdS
z4|%joln!br8@_xYAS$0d;D%StiCk!qvq3|6+IKV-f{>>((MKJKqvH8UHNF??-%B67
zX1S*Me;mr!34Cv~U)koS;1u+LnX*}+X6g_`vn~PEb|*Hje_F3!|GZAtt>=^eOlYZ1
zWkq?>6s6d(*7~f(dilO5bPq$dE>tkt`clm?rV6&KJfyn3;a1aLZ&2=>~AZu!ohw#>=f~S!E(RG*@
zoH(~w);}Bs%CAb|v-)|{&(*#+tJT;k(7bFLQ6KLWwHJ09uCkX4D1O>~A6C@D1~m>;
zevl)ru$(CO$o(7VLY(ZBIy!yuRf6N`ta0{w(ZD0+JDI_mvyiHY_6!Gp@ziBk&?8?u
zk?~omP4)!!lPown8JRT^CoR*bD>~!AqC#sCnZ2H0@!FwWB@?+BEPwGKX&)mtX5c}c
z4`XsKzY%^(*y<6K#g*NiXuGMB!U2n%jI&62ttsM!ZIsH;D6}_H#!p-hgUn4xwN;r+
zByg-fK{#<;`RG>K%g;H+`*P@Rt4FH(xB#i|#Di(K;&z%ZyAJ2r{jF!W_StzLYB57*
z>srdI#J4_50tdQmwZfORM8JAKp&1sFekG`$F>fNv<1_)IFAwoCDAl295oDtCiaV
z0j{?f-}*GH5rA
z3{}$Si%n@ECW)gbNg<{voED(3pA`qCP5u4*uIqJBuXvu-YyID{)*1~8js2{XP}+Ek
zW(I$CNn1oAIXJBG{6lJZaM=F+LW(~gS7~O+q=Z}c62^C11JRu^)@||o3Y|1P-J0(V
zCIs+gK5o}xntbqqG*1^YJPcCuFN)HAY#GZ@CD5ZS0{Bo#2T8!L0Sk3i!yugvUb{TQ
z?SFainK2tlcqR8jX?qI=GWZobo!N(~x&WsNwOw8valEfEbdqDLx}KnfcuYais^{*g
zqvQP+Xl{#tehsPb9P6g&+tT}(fXLDK5jOl|h}nTl$~__&&*t&2McrPL7uxu|W{3Vt
zY_!FOEimvZiTuQxRublUJwJK!2{*p~Hs28AMa9NABEg_%lW+&Ausf>6YeVbYf>Zzo
z7QPzcJrl1x>7OGoUMw@c!_?Ifo|1f9z*m{Au{YpMbXM4NgWmdKtVht&TW~gJH%Eqd
zNAcBgyi&17E@s^fTTNhpP;OS60Y*_X+laFd)-IwgmPUK`5=o;c*Uek-_PUr)Z$iG@
zN7yYP)Z!gxxIs;_6qlDGtSJoBA@J^_xYW994{Mulv^8DvCR3}$>;4L_8W^UO(=1O6Szo>b7_XCc-H%F!noq2pWaLMABm22b=!TNO;?wToR
zd_6ujZNI}J$?{cT(Dkq){8yWE16BHQCPm&Ag$jXhoX=Q{xTS@$3>?}<8Oe96AXxXU
zxLF4vB5Nkws7WR}OcmW%&w)yu7O{bwuk>Zzv3w{g8?*W2mNr|EQw!T;p_b|!q^Hkf
zbkg}mvZMZm>IJ3j@7`cBmCfEVzY+eps@%y}(u##X%hR*PXlv{;cEK509pha(j{5Bw
z{Y=s=Ch6JAR~yx_WiL;@ZE-#?6o4+5X400v7{ijW&Q5%_Rei(Y3KqZe-W04Hr$8_A
zMF?nbhrfEnSDb6kCDnQ(U!yrjRe`=Fg{!$b=HzjNWCZ)0IfHhA+Y{>kKh$?8)bD;c
z-eN@9ed-QYWr2Md6@dg_eqDX--O38-qyOZ3$o@(=_mroQkg!5W->}OCj?`u8d97xy
z<$;6>ih87tF+;tYS|4oTgFsfq-0}E(Vr71B2dJeCuwSOC9_)u(;KiabLp6&H1%b$f
zfURNO*a$&}M<8{>as88M9(^+M_uecY0UvcipD>;|)P+!9nWi
zYsa4j9l`tv9!r@+w@F)5YcT&Ek{hq7+OIILj%<(fz&r=NC2GOwLob_z&{y)if4=l5
z5KwM_X}d;uG{N&m&$ule=*@^TFvG4P`?U-F66}|^m`Tk{2F{`YiS%e99DsvB71`z{
zE^YIW75u6alF6ITM&4F3ZR_&sMH9yiPc9;oP%Y~s=@*SK42bR+_7{%+Jf
z6C=)JSQmbKnZ(`9ZPCdpyGHp|w;R-)-~Yh#x|rQEa`enRDE~qvS10W}V!|7v(+ri@
z0n9xI%0J&VgYpn>w5xQ?I@}raK{fHLp96Fi&It-=|9!T(Cx3*HJuw87w0!Ph4oVl!?`9)Y
zENJAEAsNP-`y{d~yJp5n<5Olf+T=I5KHm6FME9dLlS`&dJ@J>-&Od*OlZO#XJme)U
zJ`Kk;afI|m_((!WJ)Op!ncj5TH|F0Q?>}-1V5r4PhUL6_nNHYuR^IXWcCN2g>Vxf-
zQ&=iT-hLlB(lY5(5oI9knzrEWl!=sPxt05FH%V_tyHoo*W+>#e$0><_Et3OyJLfLd
zPj}VO;NvW(tt
z(5nd@7y6@S>p1KEuZ_K{u(_Awl9Y1PxhJUJ>c4NM1=56kwFWk3(ss{%^f%fMuFLwJ)?Xw8U-=IT*^e%-wquQ}k^6JbjE%vE
zzq$3Nb5PhZXSJL1bRvE-s~Og@3=fl!lZ+6FtT}mPYjwg+Eo$re@H_{3tvBOe*M%c6
zU^R!%k9p}T!9t^(Ns3nb6TXSAi9v*!HySV-#p9O7L?tV?4Iw!+^e#feR%14ZFTq8`
zZ!XyVMJU~ZwNAa-$c$S_G-~HPUT6zV`6&+iVb7a*WA=HdP=-CF>
zC_i54`Qbg$+I6DNX=y3%2g=f+c!=lbM%K!9ICSGs9F!C6%Sv?aSoU9&Q*s|StF
zWVtl?lFOiZRhu)yhD$s$b7jz#6wwkCcFdNNDJ{Gu>B^(d0TLaYVX~4KoZ0W`Jms}KlA^`Nw)yd0lHHp|4YX4=
z%lX}06f@bD{a2Aqet{gK7uk`2ykOp`RC0iZ>ViUb#M2S1_v>sI$~yYWuy24l{TS2`
zxJYllvdSk}?3cd-XlFi`6*OO>-=ue5A=i2PQB+NE%kGvSn_S5T14U)zj6C%Wvo>B<
z{pqEx70f|+hwlUP(HiNLe(x*pl(9umva=YBrgZVY4L>H4g|ED#ry)Z{(=9cQPWLDD
zPZmnLB(fQ7>H0OTBxV_`1!c!V$4NwdvPVCq2
z_k+Ty^@!d2xpL5DAwyw>wpNjtm7J(T#^rqmWs5#cbhK17vjp#Ffe*~-L(5wLh1#{!b
z_8|Vfs)owIo^)W?4>li5c+Z(v&{v#v;6!fBr0cl&;N*y&0?vt
zB}1zzg{Q6F2kG~Iqt{0#YFlYEZ-^G4L4r`qJvF!9jkm}K5d2Q%3v_q%(U#2@(JR9I
z8*7Wf8czo`P$N$+gycMJOR&6X{I8+W&Wt^Dx49MNd_!(GAgbcTcM+i!Zk%%`oBtg3
zs-&H+Y&j`35=rohB3Y>5dVCEqe(0_xS*iyD5uVCEC85w
zDb{!`i@5-PKRU0A-D>Ui#*296*GH|QY!@}joIBg)j_(e(eomCN$~5-$_PQylEBpq+
z4KZTYB%P}kz+8O)n$lOC+xQPu$wHo9l^ib@cxhni?Ak4%XiO|%CzKq$4d)S5&MO<<
zpEf?2G46$Ud1{OC#ETWw%M=~J$GUK-9u&(Quw(bP7xS6HY9C2U2`U}JX~&&&mmW;@
z-;8dj!Bu)0tO^Q_t5*yt7WG)Sr)~(1PE@yo*s`bI-5aP-!E2Y$fjTm3J1$3p1;*7(
zdSrhCOZ4>B2_nCjC-jTjE=EIGV2wqGV7qc!yB-y_K}?dZu3fc2g<0j8A#pZHW+^fW
zE1AmsWO|>Vk`ZR$O-AFBtB^m}uQWNdAV-MUr_Vk2BgC@xnK^XiZyFOTjobvjK#D5A
zJsj_Yg$wjSWuBd}lum+M2p>J#i28p0@dKwTD!vn|`+F*|>NERj#caJ#^T{&5at(Df
z>NH*L|*1QSXl~=4C
zozs{n+y7lRAa2Ub6wYT-gM3Y$nh$Fhe{dsvblLknEYnt<+NqJR
zj4ICr{C+d5YcJ4#Q&S~b2S?Q;6)^G>@>nrR@H6wKL8-f!65?|!N@{;Jr?*erd-`pP
zix&ru(yM*o$=LAu#3rjH*g!i;Zc-ZBLI=;AdOI{TlX;I|rMP50=VJ)*c}Qr{o5W2v
zNnY*RB>PVwjss%=e0&d!t9~Wq2I&uRsbADH?wZ%VT;jzTi|0Tw7V89iYhso
zDGIH~sMk(17dRVf&D0Myli92Xu%D*soOb}&p-ac69Ik}S-4NB;NwJJDx&F@dU=Qaw^_6WDMTV`I=_!0+k|@l8tE;j
zYy*wO)ADQ^Q{~%{3Sq->(-EN
z0TUVuJa(Earb0x00UJ*F5Z>C6D877=dLQcMTnJA8z3^JjLn$qq1vU|P`ILtTt&_9IA6}DKbD~1X*BW<=^s%u2Ipa_k*K8ZNus)@
zv4Zpwc9R~;ey{nh*B5Yjq=V2gI8;c#l~~uw`6_6eg_H9LYc_ukH@ZaFNhW^M4%no(
zeG$j+9LUOt@rssn5K4@9I^H<9{CUXN&x=SZ{kGYjfZ9@iQn%2Tbqdx1c>@7%EPPhN
zN%06U-&V;$u(tX1K>|B(65+;}b!a$wDZ-hY!>8pg(TwYh
z5eBd_z%R|bJYTqlZkVieSj0H4Cy5=rf17qYrBKT~E&%e#4|x)xc8!;<-P~ZKsGBtc
z;g1fzp%Z7WKB^TTOpjO(-Lq{x_T%I{t#|@+XB1?``fq*b;^PFLL;*wHl|q(I?@uBC
z213Q%OQeUYbSW=IBy^Fcv`Ft=I#Ie1
zAao&=&;tqZ;r;HpKkkp&a`t(4cV=gH_H2xvjv5^`8#M_D37v-e(-+ru=s&qhab0#R
zS`S@UR37RkFcK0P;6EWHL1eL#kT4Z$JXJRE%i77NGcef5=yQCDs+%7lA1~i6n)iv%
z>%T7^S^%f|5>6efudg@3y-XP!e}>~n2v2Z7iwDQDsg$wB$C5g%nkh4>#!ETZw`!!k
z8<&_bit)*ix|ns5wmqufP*vXx+MpLVs?hM>y~?_}yBoN8>Yo!Bf4<^_J25fYtYD0h5#1WS;7sE*4@@n=;>=E=e--l)I%$EsI~h7
zca8P}@lLrmQ&Ga0$|V{MMdNW`^;t2N7c~~28p5V;)uU~B
zhQdWSz6D+Xxl8!GK`_GN{h~YP^Hq2f5!>%CP$ih>8$e~bIXV#gx?|^J{bgwkG|`Zz
zW090t@*uUuKhNjt!4?6ve9wM8_VKbj0-{PB7{-61{pQZq>Y~b9_u!YGkdVV|g)XpQJPEF{L^B}kZYQJ}jFDge
zBC{So>yxqseHXc0=-}4`Xe;APKSZRVUL@gcH}ZN$Ne7C$EQ2GH*Bq4mdQEI52&-uO
zwHhV>vB89Qzgl^x!DPM5(lhc6LvEOkFf{&UtL3P>;cHD&3`16gn1|F`7cpX=smaNV
zV^WzTNh3wIm)RECW!{riIHfKamFhn
z=O8T(lWW{O%CB5>vIj{U7Ut;AOtreCRt*Z8uY%g$XIx2T1=_G_iSb|N&
zPtzq~$Gt07J#XZ2sul&*C5F@TUTmQF?4R|+-=w)yUn-&WZ}1k-D7jWI?Y*^MNU$}(
zuoh>nQ6!c&z@2giZK}8EsNSso=5Ho>)J!6g;Lh4Gomxv_dG1uBGjxx
z_Iqg2(a~fGjh7)*$bxkg2OIeE>Ow8;9uR}H
zhv%pJCoiVl>-Dh}cax>;qbhCGfH$u_cN`jT8^;L>ZH@
zF#cmFD)VEq^j+@e;YdsGRQ^|LozV=0uv}@XdYutwcsCBFf4~zq>)*KERq149IC8sU
zf}K>w?N?MT^nVcrxMHoR83>wW3;V80S1ZH$YXk@B!wT09Z)M8MRP+C{9cr(#)3Zp7
zZf3NYAPe{On>YIm_MPr;tqfJjjo8>aqOsWHC6?9YlhQxo?(COGRJ`Ln;j`o5&oozW
z6(Zt~%^k}q|LN~a=GJKM$v!2%7)pKkSJIYj&;qEmvOggxaXa{>LPXzIqgNRxttrdp
zN2-Q3M6ahYj;^cSnQU+#_|I#kr$rC_IE)ge!){AYZ*^Y}xaA@Q@jsVP?1^G9h`Q9B
zU`@f7W?T50LVDUi48)9;>*FY6G7-kpcA&l(EoJjY_=eAl_hrzu*M2H3uZ7Q=(nOlC
zP+rRXKa-=HfNxH+^N<5L)P%^I7F{}OBAkm51`T9)Yg{+UCuzUH^ohBQ%Gi&NSdW#-
zpY3}04d!oTv8T$eD7kuijlgq5DkAwR4Pj@KY$D6mWWgDV@P8WDD-uPAKWBCqeqq-;
z+d{LO!+zj%@{MJW1lZ<+$C9>%ybzRElTHUHBiI?7jySDM~#E=W~7r_
z;BEG0c5>xvE62nBP+2BeOA$e@Qm#zzq+5QcczCIw7J^rlj3OhR*%})`n8^ZYbNp>J
zcsYmWdu`wHadx}+;)$Zfd_RFJ#SnqGjl`lWqA0JNvvx#CK7t4`@;vLCwCZ6YcCZ`|
zNXD%+^e!D1F1ttxvyvxY1$MHY2=}jZWCulBWVs3va}82XQ@YJBHSVzPhp?ZJL+{n=
z%-2g1lNsBH??qeu_E?k3hCu_+IN9Y_=L|nQH;1Vfz}+FO2*{d9dfH1!=j667v5_+Yc6SHtvkyk^eau7IM&=Me%;^;z7)Wni`6kQN^L-R9t)
zn^3za>qq>t5QY*)@5UEH-VTj3+C`DYs}%?ge@SnbJbkm2JdKuSLj{@0JRdt73^EyR
zaF+=A71KN>fOl_fBu-h2EK6T>w1-HzwZc3!yIBIPB;-N;Wbw_Rm5PoGcGvWU#oqv%
z1V5%ZIat#qz`gl15yp}pvP+@ja~4(UOYi27k5fx-eJfFNfhoZ-n4{&GZ000GT&w}?H?6%JDAcmo*pYP6aSg545ghz-
zbnBWbkaA@v#VFSbFGIHLv*6P0$BGj2ZBfa$IkZK{qGmpA0Gz@tUnLW;Dt;kBH~)p=
z4=uEucO)}Be=UOuZzNgV)XJgran+!=v{X!Hki@EWsbsVWCJKUL98}eS(Q3$@>QP-F
z(dfqScG(Z7(or4Ji>Krv{$RIkbUvl!TYn1O@_sr@YFdu=f!uENyz>%gGx7+Eq48`Ul1u;Kd+200`SNd2K#=@M-UTL*%SkqFbf!a4SNU
z0Nui6Ke247yTLs7MJw+4@^T{U#GeuB!qC^7gQO*xy*~VUW3i!U03N^_5)i=qSFRij
zHil;1RKV*NFCE;2@s??fOZ_vnZ$=8I^Oy&=$3W`CIf00soHbyZE((KEI+20!r48?v
z;oCszJE-#n@O3x@y0SE?Zr3_Cc&{7dnhTB{w@q^?NZBWX{4Lnr{CAopQja&$Z9?&0
z*$p69_0|)F)sCJE_C@2@^ycp~Q{wHJ0pPT9)Ym7)(+v4%8C*4`eX|N*v4n$j19Lg&
z)Z!PFL3>KW{@^?H5QmFfJ84!Iw;+nJ7yf3#bvG6PuB=`8@hTYc;;H~!#uGZe8pofN
zCiPTOwAQUCG*jvb2W~R{hiHVf_qr3p%9ffl8;zJ@hNm34P`fM21LRsoBktOmOLYEZ
znw=oz9FGIYYC^xn=F|NB!$nj|IL&y8bJ==Jw$EF4yl#Tio+#oX&J{7~HA|eigYeN{
zKcNgM|54b$xi-$6dJqv?)^>|p
z*c}-l7DF5~8BfNzXD1Hj*3Tt6DR>kj*7mgr>{7w|A&R2OerBBfX$UJABS?dwDToKZ
z9kOb(Kn#QGxmAiaQ~b4j-55^>hD$#+Rm|0ysQcXLI@oSs0a3bHM$!TX|H2$yM&UdD;%H
z9biAMu)+iUs6l|MF6LOs>A*!7Q@MpKf8Th~q^rdH-9?0di1B`Ct1vA!8X(O5YrWd1
z3JE3ob62hMM`sJ?Q|))>5uGj5JHXqqv!b8VS;$V@7b@j0Vjuna4ApwBzB=8bI-{ZIZKh8aL}){HN0k#>S>
z2~|y_MYiSR+feMp@F>7$M23f}AX~?9mkp4tAl&P0slLPZbhkp;uh8E{-U_(Q_B1m~
zWtFb(*?+dhDet!uKlP&Iv#;OHz6axCJeKXFT~07VbOL)YfW7hV&eK`W?)pPgwQ~34v_Kt-w{$wW#^izUmhrOIw9=
z>ViDk_wOdsR8XDtElrliAG(rxLWBPdbOa%X=RqjM#eP=Op?8Csb`_L9U2Y-FnBqeO
z0#HMaY%$}c%#~$cQ)0(T+IsHrl2v6N`3iqOHTtoU5dcPKZE&6$m
zq31x$UjTI8bFwjmbq*&NB@Ttj1Xs${>GEg6#RVqbi6qQZuG~)=lE?T~0JS|t=+jZ?
z`r&Ek5vNx00`MfOvf77O7dAavc|5ZtMZ(;;nea%
z*^;E0d0nF~+GTglE2>~cU86&3^mWmF)RYdr4U48b7ShV9?5$5Nxq6s^SAtblz?;+O+!APC&9kSFP$k7pLf!S#C144TUjo
z6O)pLM&0Lq@WZ0Rj3O33=7@b~`WZlH1rTQ;>Njy{?o-jUGu>7V(%RWMvoW4V>ZH7k
zG`+1Rtgn{m&sF@5Rk1WSOb5i-@pUvMP=+Esz_Ks65c~rRzFAWtN71*$3PH${LO+96{3Vg9ufVX|6qoM>Kj)GCkl^mJ|yp&zzDD7m{!bJHEju@<18OF
z-+4grv_?hDPqR5~eD=3{N^XHIB(lze_-`r9BP!m%aT%_}LLpPaF)wNLRHUZ(-Yhy)
zJFmH-yH={DR)4)?&!9Dad-m<+U!IL(@86KO_HCK3y`=)AXYgOS*bLklaTA9K=E1#awc&FTDam+%77*j&k3r5|oU
z_F8=*l)|^`ymG03kJB-y{&)D*X|b*TQ>kZ5j+(2I%Cuaz1QmqPoXV5f_Uj%
z(}$i}+i@FqP`&2D%F7+4k3+BsT~)EQIC*N#`8LLyla&|F&|eLemuVOS%fa^<&YR#D
z&LH;Uhq$a=8a6dOUjcK1XL$o-%`;5$M%}Zji#T~Q&H1TDMVZma71?{FPPs9du|FPD
zEwfP{#xHKV?`R%n++@z7+5kE(fCOpl)qyQ+q|-}H!cD=N;J=eM&vUTdnH$|)#^b
z=m;T2{;GE=n@?mGA)wJZSP+gP^lBOwWIR2VSsDCW(yWOzpd7TcagOUhQ_NCe87+hb
z;aA}xMVZB@Plrnafr86hvU5E@OzXMT^)DughN{lfiYHd#{{#Az
BsD%Ik
literal 0
HcmV?d00001
diff --git a/bot/assets/init.png b/bot/assets/init.png
new file mode 100644
index 0000000000000000000000000000000000000000..5d50a81f7aa6ffd955bc6bb031515afddebb0488
GIT binary patch
literal 8540
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
literal 0
HcmV?d00001
diff --git a/bot/bot.db b/bot/bot.db
new file mode 100644
index 0000000000000000000000000000000000000000..fd1cfc91ced4f26285002ef163a5b7bc40b6121d
GIT binary patch
literal 20480
zcmeI(O>Wvi6bJB`7>cMA=mxQ!xT+eYCYmwEak7dVtQ7H)#x+$~RLH@0WvP$|jMPmR
zQBTk#^aQ<7PS9me&@msT6-}~?kp53L9u3b=^L}291s~2^Q5>-FYCQB}RwXY8rR10~
zLP&OT%F8S=@-sP?L6?IEu356*{IM+)G6jVc^Mzl9o*W<`009U<00Izz00bZa0SG|g
zDFociv+}DF{T7Y<;Ole}jQhhue>#o)WSl*5Y|FJ-x6?T9+N{y3+ZRmzJ4TP^n9X|ye;$C`HU%{+D9
z$w$jMd1pDhTCG+|vt@>~dNd(<4l28^LNw`n{xBM?FGiLh2cM%!Joe(~YSj0=Sen-5
zqjVc>J6%O3*_+eiPa+Ql1Rwwb2tWV=5P$##AOHafKmYigQ^LC6Q()N39$HG_x38|a1?>WAFZxTfz3z9$SOsz None:
- if isinstance(cmds, str):
- return self.command(str)
- if isinstance(cmds, list):
- return [self.command(cmd) for cmd in cmds]
-
- def __del__(self):
- self.disconnect()
-
class States(enum.Enum):
NOTHING = 0
INIT = 1
@@ -41,7 +24,6 @@ class States(enum.Enum):
class Minecraft(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
- self.servers = dict()
transitions = [
['init_game', States.NOTHING, States.INIT],
@@ -68,21 +50,12 @@ class Minecraft(commands.Cog):
server_name: str
Server on which the Session should be initialized
"""
- server_name = server_name.title()
-
- c = None
- for container in containers:
- if server_name == container.name:
- c = container
- break
+ c = get_server(server_name)
if not c:
await ctx.send("---The server doesn't run---")
return
- conn = RCON(str(c.ip), c.rcon_pass, c.rcon_port)
- self.servers[server_name] = conn
-
cmds = [
"/effect give @a minecraft:resistance infinite 255 true",
"/effect give @a minecraft:saturation infinite 4 true",
@@ -92,9 +65,29 @@ class Minecraft(commands.Cog):
"/worldborder set 5",
"/whitelist off"
]
+ c.rcon.rconnect()
+ c.rcon.sendcmd(cmds)
- conn.sendcmd(cmds)
- await ctx.send("init Border Wars Game")
+ embed = discord.Embed(
+ title=f"Border Wars @ {server_name.title()}",
+ description='''
+ Session initialized
+ Get ready to get a good armorset.
+
+ **Explanation**
+ This phase last as long as the moderator wants.
+ Every player is immune to damage and can't die by hunger.
+ Look out for a good direction to scout.
+
+ Happy Border Wars!
+ ''',
+ color=color,
+ timestamp=utils.now()
+ )
+ file = discord.File("../assets/init.png", filename="init.png")
+ embed.set_thumbnail(url="attachment://init.png")
+
+ await ctx.send(file=file, embed=embed)
@commands.hybrid_command(name='safe')
async def safe(self, ctx: commands.Context, server_name: str):
@@ -108,25 +101,12 @@ class Minecraft(commands.Cog):
server_name: str
Server on which the Session should be initialized
"""
- server_name = server_name.title()
+ c = get_server(server_name)
- c = None
- for container in containers:
- if server_name == container.name:
- c = container
- break
-
if not c:
await ctx.send("---The server doesn't run---")
return
-
- conn = self.servers.get(server_name)
-
- if not conn:
- await ctx.send("---Border Wars Session not Initialized---")
- return
-
-
+
cmds = [
'''/title @a subtitle ["",{"text":"bei ","color":"blue"},{"text":"BORDER WARS!","bold":true,"color":"red"}]''',
'''/title @a title {"text":"Viel Glück!","bold":true,"color":"blue"}''',
@@ -137,9 +117,29 @@ class Minecraft(commands.Cog):
"/effect clear @a"
]
- conn.sendcmd(cmds)
- await ctx.send("Switched to Safe Phase")
-
+ c.rcon.sendcmd(cmds)
+
+ embed = discord.Embed(
+ title=f"Border Wars @ {server_name.title()}",
+ description='''
+ Switched to Safe Phase
+ Hide from other players and scout for resources.
+
+ **Explanation**
+ This phase lasts 30 minutes, after that the fighting phase begins.
+ Every player who dies will keep there inventory.
+ Get a good armorset and be ready to fight.
+
+ Happy Border Wars!
+ ''',
+ color=color,
+ timestamp=utils.now()
+ )
+ file = discord.File("../assets/safe.png", filename="safe.png")
+ embed.set_thumbnail(url="attachment://safe.png")
+
+ await ctx.send(file=file, embed=embed)
+
@commands.hybrid_command(name='fight')
async def fight(self, ctx: commands.Context, server_name: str):
"""
@@ -152,25 +152,12 @@ class Minecraft(commands.Cog):
server_name: str
Server on which the Session should be initialized
"""
- server_name = server_name.title()
-
- c = None
- for container in containers:
- if server_name == container.name:
- c = container
- break
+ c = get_server(server_name)
if not c:
await ctx.send("---The server doesn't run---")
return
- conn = self.servers.get(server_name)
-
- if not conn:
- await ctx.send("---Border Wars Session not Initialized---")
- return
-
-
cmds = [
'''/title @a subtitle {"text":"ÜBERLEBEN!","bold":true,"color":"red"}''',
'''/title @a title {"text":"Möge der beste","color":"blue"}''',
@@ -179,8 +166,28 @@ class Minecraft(commands.Cog):
"/gamerule keepInventory false"
]
- conn.sendcmd(cmds)
- await ctx.send("Switched to Fight Phase")
+ c.rcon.sendcmd(cmds)
+
+ embed = discord.Embed(
+ title=f"Border Wars @ {server_name.title()}",
+ description='''
+ Switched to Fight Phase
+ Now the real fun begins.
+
+ **Explanation**
+ This phase lasts 60 minutes, after that the game ends.
+ Every player can die now and therefor will lose.
+ Look out for other players.
+
+ Happy Border Wars!
+ ''',
+ color=color,
+ timestamp=utils.now()
+ )
+ file = discord.File("../assets/fight.png", filename="fight.png")
+ embed.set_thumbnail(url="attachment://fight.png")
+
+ await ctx.send(file=file, embed=embed)
@commands.hybrid_command(name='death')
async def death(self, ctx: commands.Context, server_name: str):
@@ -194,33 +201,40 @@ class Minecraft(commands.Cog):
server_name: str
Server on which the Session should be initialized
"""
- server_name = server_name.title()
+ c = get_server(server_name)
- c = None
- for container in containers:
- if server_name == container.name:
- c = container
- break
-
if not c:
await ctx.send("---The server doesn't run---")
return
- conn = self.servers.get(server_name)
-
- if not conn:
- await ctx.send("---Border Wars Session not Initialized---")
- return
-
-
cmds = [
'''/title @a title ["",{"text":"Sudden ","color":"dark_blue"},{"text":"DEATH!","bold":true,"color":"red"}]''',
"/playsound minecraft:entity.ender_dragon.growl ambient @a 0 64 0 80",
"/worldborder set 5 600"
]
- conn.sendcmd(cmds)
- await ctx.send("Switched to Sudden Death Phase")
+ c.rcon.sendcmd(cmds)
+
+ embed = discord.Embed(
+ title=f"Border Wars @ {server_name.title()}",
+ description='''
+ Switched to Sudden Death
+ Only one can be the Winner.
+
+ **Explanation**
+ This phase lasts as long as only one player survives.
+ The worldborder will now shrink 'till zero zero.
+ Good Luck.
+
+ Happy Border Wars!
+ ''',
+ color=color,
+ timestamp=utils.now()
+ )
+ file = discord.File("../assets/death.png", filename="death.png")
+ embed.set_thumbnail(url="attachment://death.png")
+
+ await ctx.send(file=file, embed=embed)
@commands.hybrid_command(name='end')
async def end(self, ctx: commands.Context, server_name: str, playername: str):
@@ -236,24 +250,11 @@ class Minecraft(commands.Cog):
playername: str
Player which is announced as the Winner
"""
- server_name = server_name.title()
-
- c = None
- for container in containers:
- if server_name == container.name:
- c = container
- break
+ c = get_server(server_name)
if not c:
await ctx.send("---The server doesn't run---")
return
-
- conn = self.servers.get(server_name)
-
- if not conn:
- await ctx.send("---Border Wars Session not Initialized---")
- return
-
cmds = [
"/worldborder center 0 0",
@@ -264,8 +265,20 @@ class Minecraft(commands.Cog):
"/playsound minecraft:entity.ender_dragon_death ambient @a 0 64 0 80",
]
- conn.sendcmd(cmds)
- await ctx.send("Ended Border Wars Session")
+ c.rcon.sendcmd(cmds)
+
+ embed = discord.Embed(
+ title=f"Border Wars @ {server_name.title()}",
+ description=f'''
+ *Game Over*
+ Congratulations **{playername}**.
+
+ Hope you had fun @ **Border Wars!**
+ ''',
+ color=color,
+ timestamp=utils.now()
+ )
+ file = discord.File("../assets/end.png", filename="end.png")
+ embed.set_thumbnail(url="attachment://end.png")
-
-
+ await ctx.send(file=file, embed=embed)
diff --git a/bot/cogs/spawner.py b/bot/cogs/spawner.py
index c779b33..9c35089 100644
--- a/bot/cogs/spawner.py
+++ b/bot/cogs/spawner.py
@@ -4,35 +4,65 @@ import docker
import random
import socket
from contextlib import closing
-from datetime import datetime
-import pytz
from dataclasses import dataclass
from ipaddress import IPv4Address
import secrets
+from mcrcon import MCRcon
import asyncio
+from models.users import *
+import utils
+
+class RCON(MCRcon):
+ def __init__(self, ip: str, secret: str, port: int):
+ super().__init__(ip, secret, port)
+
+ def rconnect(self):
+ self.connect()
+
+ def whitelist(self):
+ pass
+
+ def sendcmd(self, cmds) -> None:
+ if isinstance(cmds, str):
+ return self.command(str)
+ if isinstance(cmds, list):
+ return [self.command(cmd) for cmd in cmds]
+
+ def __del__(self):
+ self.disconnect()
@dataclass
class Server:
container: None
name: str
- ip: IPv4Address
+ rcon: RCON
port: int
players: int
- rcon_pass: str
- rcon_port: int
# Global List of all running Containers
containers = list()
+def get_server(name):
+ name = name.title()
+ for container in containers:
+ if container.name == name:
+ return container
+ return None
color = discord.Color.from_rgb(13, 183, 237)
def seed_generator():
+ '''
+ Generates a random minecraft seed
+ '''
seed = random.randrange(1_000_000_000, 100_000_000_000_000)
if random.randrange(0,2) == 0:
seed *= -1
return str(seed)
def find_free_port():
+ '''
+ Returns the next available IPv4 Port
+ '''
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
s.bind(('', 0))
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
@@ -75,6 +105,13 @@ class Spawner(commands.Cog):
enable_hardcore: bool
Enables Hardcore Minecraft
'''
+ try:
+ User.get(User.username == ctx.author.id)
+ except:
+ await ctx.send(f"{ctx.author.name} isn't registered!")
+ return
+
+ # Send user a Waiting screen to avoid confusion
embed = discord.Embed(
title="Starting Server",
description=f'''
@@ -83,17 +120,21 @@ class Spawner(commands.Cog):
This could take up to **5 minutes**
''',
color=color,
- timestamp=datetime.now(pytz.timezone('Europe/Berlin'))
+ timestamp=utils.now()
)
file = discord.File("../assets/clock.png", filename="clock.png")
embed.set_thumbnail(url="attachment://clock.png")
start = await ctx.send(file=file, embed=embed)
+ # Set up needed variables
+ # Server Stuff
port = find_free_port()
server_name = server_name.title()
+ # Rcon Stuff
passwd = secrets.token_hex(32)
rcon_port = find_free_port()
+ # Image Enviroment
env = {
"EULA": "true",
"TYPE": "FABRIC",
@@ -120,7 +161,6 @@ class Spawner(commands.Cog):
"MAX_MEMORY": "2G",
"USE_AIKAR_FLAGS": "true",
- #"MODS_FILE": "/extras/mods.txt",
"OPS_FILE": "https://git.cyperpunk.de/Garde-Studios/Uno-MC/raw/branch/main/ops.json",
"SYNC_SKIP_NEWER_IN_DESTINATION": "false",
"MAX_PLAYERS": max_players,
@@ -138,6 +178,7 @@ class Spawner(commands.Cog):
}
+ # Decide between seed or world url if no ones given seed would be randomly generated
if not seed and not world_url:
seed = seed_generator()
if seed:
@@ -145,6 +186,7 @@ class Spawner(commands.Cog):
if world_url:
env["WORLD"] = world_url
+ # setting up the container
container = self.client.containers.run(
image='itzg/minecraft-server:latest',
environment=env,
@@ -157,14 +199,18 @@ class Spawner(commands.Cog):
volumes={'mods.txt': {'bind': '/extras/mods.txt', 'mode': 'ro'}}
)
+ # Connect Container to the appropiate network
net = self.client.networks.get('bot_rcon')
net.connect(container)
- ip = self.client.containers.get(server_name).attrs['NetworkSettings']['Networks']['bot_rcon']['IPAddress']
- server = Server(container, server_name, IPv4Address(ip), port, max_players, passwd, rcon_port)
+ # save container info
+ ip = self.client.containers.get(server_name).attrs['NetworkSettings']['Networks']['bot_rcon']['IPAddress']
+ rcon = RCON(ip, passwd, rcon_port)
+ server = Server(container, server_name, rcon, port, max_players)
containers.append(server)
-
+
+ # Send user the confirmation
embed = discord.Embed(
title="Success",
description=f'''
@@ -174,7 +220,7 @@ class Spawner(commands.Cog):
garde-studios.de:{port}
''',
color=color,
- timestamp=datetime.now(pytz.timezone('Europe/Berlin'))
+ timestamp=utils.now()
)
file = discord.File("../assets/docker.png", filename="docker.png")
embed.set_thumbnail(url="attachment://docker.png")
@@ -191,12 +237,17 @@ class Spawner(commands.Cog):
ctx: commands.Context
The context of the command invocation
'''
+ try:
+ User.get(User.username == ctx.author.id)
+ except:
+ await ctx.send(f"{ctx.author.name} isn't registered!")
+ return
embed = discord.Embed(
title="Currently Running Servers",
description="List of all currently running Minecraft Servers",
color=color,
- timestamp=datetime.now(pytz.timezone('Europe/Berlin'))
+ timestamp=utils.now()
)
for container in containers:
@@ -223,6 +274,11 @@ class Spawner(commands.Cog):
server_name: str
Name of the server that should be removed
'''
+ try:
+ User.get(User.username == ctx.author.id)
+ except:
+ await ctx.send(f"{ctx.author.name} isn't registered!")
+ return
server_name = server_name.title()
@@ -247,7 +303,7 @@ class Spawner(commands.Cog):
title="Killed",
description=f"{server_name} killed!",
color=color,
- timestamp=datetime.now(pytz.timezone('Europe/Berlin'))
+ timestamp=utils.now()
)
file = discord.File("../assets/rip.png", filename="rip.png")
diff --git a/bot/cogs/user_management.py b/bot/cogs/user_management.py
index 5283d20..8d4ba66 100644
--- a/bot/cogs/user_management.py
+++ b/bot/cogs/user_management.py
@@ -1,12 +1,165 @@
+import discord
from discord.ext import commands
-from sqlalchemy import create_engine
-from sqlalchemy.orm import DeclarativeBase
+from models.users import *
+from mojang import API
+import utils
-#engine = create_engine("sqlite://user.sqlite", echo=True)
-#connection = engine.connect()
-
-class User(DeclarativeBase):
- pass
+color = discord.Color.from_rgb(79, 227, 119)
class UserManager(commands.Cog):
- pass
+ def __init__(self, bot: commands.Bot):
+ self.bot = bot
+
+ def gen_user_info(self, user_name: str, user_id: int):
+ '''
+ Generates user output Embed
+
+ Parameters
+ ----------
+ user_name: str
+ given user name
+ user_id: int
+ discord user id to access database info
+ '''
+ user = User.get(User.username == user_id)
+ embed = discord.Embed(
+ title=user_name if not user.is_admin else f'{user_name} (Admin)',
+ description=f'''
+ Name: {user.mc_name}
+ UUID: {user.mc_uuid}
+ Registered since {user.registration_date.strftime("%d.%m.%Y, %H:%M:%S")}
+ ''',
+ color=color,
+ timestamp=utils.now()
+ )
+ return embed
+
+ @commands.hybrid_command(name='info')
+ async def info(self, ctx: commands.Context):
+ '''
+ Registers Users to internal Database
+ and links there minecraft username to there discord account.
+
+ Parameters
+ ----------
+ ctx: commands.Context
+ The context of the command invocation
+ '''
+ try:
+ user = User.get(User.username == ctx.author.id)
+ await ctx.send(embed=self.gen_user_info(ctx.author.name, ctx.author.id))
+ except:
+ await ctx.send(f"{ctx.author.name} isn't registered")
+
+ @commands.hybrid_command(name='register')
+ async def register(self, ctx: commands.Context, minecraft_name: str):
+ '''
+ Registers Users to internal Database
+ and links there minecraft username to there discord account.
+
+ Parameters
+ ----------
+ ctx: commands.Context
+ The context of the command invocation
+ minecraft_name: str
+ The minecraft user name to link with
+ '''
+ # Get minecraft uuid
+ api = API()
+ uuid = api.get_uuid(minecraft_name)
+ if not uuid:
+ await ctx.send("Username doesn't exist")
+ return
+
+ # build user
+ try:
+ user = User(
+ username=ctx.author.id,
+ mc_name=minecraft_name,
+ mc_uuid=uuid,
+ is_admin=False if not ctx.author.id == 418848241036165160 else True
+ )
+ user.save()
+ except IntegrityError:
+ await ctx.send("You're already registered")
+ return
+
+ await ctx.send(embed=self.gen_user_info(ctx.author.name, ctx.author.id))
+
+ @commands.hybrid_command(name='delete')
+ async def delete(self, ctx: commands.Context):
+ '''
+ Registers Users to internal Database
+ and links there minecraft username to there discord account.
+
+ Parameters
+ ----------
+ ctx: commands.Context
+ The context of the command invocation
+ '''
+ try:
+ user = User.get(User.username == ctx.author.id)
+ user.delete_instance()
+ await ctx.send(f"Purged {ctx.author.name} from database!")
+ except:
+ await ctx.send(f"{ctx.author.name} isn't registered!")
+
+ @commands.hybrid_command(name='op')
+ async def op(self, ctx: commands.Context, member: discord.Member):
+ '''
+ Toggels if User is an Admin
+
+ Parameters
+ ----------
+ ctx: commands.Context
+ The context of the command invocation
+ '''
+ user = User.get(User.username == ctx.author.id)
+ if not user.is_admin:
+ await ctx.send("You're not allowed to use this command")
+ return
+
+ if member.id == 418848241036165160:
+ await ctx.send(f"{member.name} is always an admin")
+ return
+
+ user = User.get(User.username == member.id)
+ user.is_admin = not user.is_admin
+ user.save()
+ await ctx.send(embed=self.gen_user_info(member.name, member.id))
+
+
+ @commands.hybrid_command(name='all')
+ async def all(self, ctx: commands.Context):
+ '''
+ Returns User info
+
+ Parameters
+ ----------
+ ctx: commands.Context
+ The context of the command invocation
+ '''
+ try:
+ user = User.get(User.username == ctx.author.id)
+ if not user.is_admin:
+ await ctx.send("You're not allowed to use this command")
+ return
+ except:
+ await ctx.send(f"{ctx.author.name} isn't registered")
+ return
+
+
+ embed = discord.Embed(
+ title="All Users",
+ description="Registered Users in Database",
+ color=color,
+ timestamp=utils.now()
+ )
+
+ rows = User.select()
+ for row in rows:
+ member = await ctx.guild.fetch_member(row.username)
+ member = member if not row.is_admin else f'{member} (Admin)'
+ reg_date = row.registration_date.strftime("%d.%m.%Y, %H:%M:%S")
+ embed.add_field(name=member, value="{}\n{}\n{}\n".format(row.mc_name, row.mc_uuid, reg_date))
+ await ctx.send(embed=embed)
diff --git a/bot/models/base.py b/bot/models/base.py
new file mode 100644
index 0000000..ecd1b90
--- /dev/null
+++ b/bot/models/base.py
@@ -0,0 +1,10 @@
+from peewee import *
+from playhouse.postgres_ext import *
+import os
+import datetime
+
+db = SqliteDatabase('bot.db')
+
+class BaseModel(Model):
+ class Meta:
+ database = db
diff --git a/bot/models/containers.py b/bot/models/containers.py
new file mode 100644
index 0000000..45de73a
--- /dev/null
+++ b/bot/models/containers.py
@@ -0,0 +1,13 @@
+from peewee import *
+from models.base import BaseModel
+import datetime
+
+class Container(BaseModel):
+ # Container
+ name =
+ # players =
+ port =
+
+ # RCON
+ rcon_port =
+ rcon_pwd =
diff --git a/bot/models/users.py b/bot/models/users.py
new file mode 100644
index 0000000..df0b1b9
--- /dev/null
+++ b/bot/models/users.py
@@ -0,0 +1,12 @@
+from peewee import *
+from models.base import BaseModel
+import datetime
+
+class User(BaseModel):
+ username = CharField(unique=True)
+ mc_name = CharField(unique=True)
+ mc_uuid = CharField(unique=True)
+ is_admin = BooleanField(default=False)
+ registration_date = DateTimeField(default=datetime.datetime.now())
+
+User.create_table()
diff --git a/bot/requirements.txt b/bot/requirements.txt
index a6dbfe8..193aae9 100644
--- a/bot/requirements.txt
+++ b/bot/requirements.txt
@@ -11,13 +11,18 @@ docker==7.1.0
frozenlist==1.4.1
greenlet==3.1.1
idna==3.10
+Jinja2==3.1.4
+MarkupSafe==3.0.1
mcrcon==0.7.0
+mojang==1.1.0
multidict==6.1.0
+peewee==3.17.7
+psycopg2-binary==2.9.9
+Pygments==2.18.0
python-dotenv==1.0.1
pytz==2024.2
requests==2.32.3
six==1.16.0
-SQLAlchemy==2.0.35
transitions==0.9.2
typing_extensions==4.12.2
urllib3==2.2.3
diff --git a/bot/utils.py b/bot/utils.py
new file mode 100644
index 0000000..78235ce
--- /dev/null
+++ b/bot/utils.py
@@ -0,0 +1,7 @@
+import datetime
+import pytz
+
+now = lambda: datetime.datetime.now(pytz.timezone('Europe/Berlin'))
+
+if __name__ == '__main__':
+ print(now())