From 321a7d22f96ec64b59b4a891c85fa0a32cc35239 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Sat, 31 Oct 2020 20:42:14 -0700 Subject: [PATCH] newgrounds io shit incoming --- .gitignore | 3 +- art/thumbnailNewer.png | Bin 0 -> 135692 bytes source/NGio.hx | 140 ++++++ source/io/newgrounds/Call.hx | 227 +++++++++ source/io/newgrounds/NG.hx | 475 ++++++++++++++++++ source/io/newgrounds/NGLite.hx | 287 +++++++++++ .../io/newgrounds/components/AppComponent.hx | 44 ++ source/io/newgrounds/components/Component.hx | 13 + .../io/newgrounds/components/ComponentList.hx | 25 + .../newgrounds/components/EventComponent.hx | 16 + .../newgrounds/components/GatewayComponent.hx | 25 + .../newgrounds/components/LoaderComponent.hx | 44 ++ .../newgrounds/components/MedalComponent.hx | 21 + .../components/ScoreBoardComponent.hx | 114 +++++ source/io/newgrounds/crypto/Cipher.hx | 8 + .../io/newgrounds/crypto/EncryptionFormat.hx | 7 + source/io/newgrounds/crypto/Rc4.hx | 68 +++ source/io/newgrounds/objects/Error.hx | 20 + source/io/newgrounds/objects/Medal.hx | 118 +++++ source/io/newgrounds/objects/Object.hx | 33 ++ source/io/newgrounds/objects/Score.hx | 17 + source/io/newgrounds/objects/ScoreBoard.hx | 76 +++ source/io/newgrounds/objects/Session.hx | 65 +++ source/io/newgrounds/objects/User.hx | 19 + source/io/newgrounds/objects/UserIcons.hx | 14 + .../io/newgrounds/objects/events/Response.hx | 43 ++ source/io/newgrounds/objects/events/Result.hx | 109 ++++ source/io/newgrounds/swf/LoadingBar.hx | 23 + source/io/newgrounds/swf/MedalPopup.hx | 151 ++++++ source/io/newgrounds/swf/ScoreBrowser.hx | 250 +++++++++ source/io/newgrounds/swf/common/BaseAsset.hx | 35 ++ source/io/newgrounds/swf/common/Button.hx | 151 ++++++ source/io/newgrounds/swf/common/DropDown.hx | 88 ++++ source/io/newgrounds/utils/AsyncHttp.hx | 203 ++++++++ source/io/newgrounds/utils/Dispatcher.hx | 118 +++++ 35 files changed, 3049 insertions(+), 1 deletion(-) create mode 100644 art/thumbnailNewer.png create mode 100644 source/NGio.hx create mode 100644 source/io/newgrounds/Call.hx create mode 100644 source/io/newgrounds/NG.hx create mode 100644 source/io/newgrounds/NGLite.hx create mode 100644 source/io/newgrounds/components/AppComponent.hx create mode 100644 source/io/newgrounds/components/Component.hx create mode 100644 source/io/newgrounds/components/ComponentList.hx create mode 100644 source/io/newgrounds/components/EventComponent.hx create mode 100644 source/io/newgrounds/components/GatewayComponent.hx create mode 100644 source/io/newgrounds/components/LoaderComponent.hx create mode 100644 source/io/newgrounds/components/MedalComponent.hx create mode 100644 source/io/newgrounds/components/ScoreBoardComponent.hx create mode 100644 source/io/newgrounds/crypto/Cipher.hx create mode 100644 source/io/newgrounds/crypto/EncryptionFormat.hx create mode 100644 source/io/newgrounds/crypto/Rc4.hx create mode 100644 source/io/newgrounds/objects/Error.hx create mode 100644 source/io/newgrounds/objects/Medal.hx create mode 100644 source/io/newgrounds/objects/Object.hx create mode 100644 source/io/newgrounds/objects/Score.hx create mode 100644 source/io/newgrounds/objects/ScoreBoard.hx create mode 100644 source/io/newgrounds/objects/Session.hx create mode 100644 source/io/newgrounds/objects/User.hx create mode 100644 source/io/newgrounds/objects/UserIcons.hx create mode 100644 source/io/newgrounds/objects/events/Response.hx create mode 100644 source/io/newgrounds/objects/events/Result.hx create mode 100644 source/io/newgrounds/swf/LoadingBar.hx create mode 100644 source/io/newgrounds/swf/MedalPopup.hx create mode 100644 source/io/newgrounds/swf/ScoreBrowser.hx create mode 100644 source/io/newgrounds/swf/common/BaseAsset.hx create mode 100644 source/io/newgrounds/swf/common/Button.hx create mode 100644 source/io/newgrounds/swf/common/DropDown.hx create mode 100644 source/io/newgrounds/utils/AsyncHttp.hx create mode 100644 source/io/newgrounds/utils/Dispatcher.hx diff --git a/.gitignore b/.gitignore index 5f82e547..7dbb7d60 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ export/ -.vscode/ \ No newline at end of file +.vscode/ +APIStuff.hx \ No newline at end of file diff --git a/art/thumbnailNewer.png b/art/thumbnailNewer.png new file mode 100644 index 0000000000000000000000000000000000000000..a419673812b01b96f417e22dcf618017446e5e54 GIT binary patch literal 135692 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

#FAyOTgVvLJ3 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�=Kw&jG8Jfa}8 z(xn1cWw^*0^U@GzR6Yxy4+XDcY=i)|Q5hfygyGn~2}JN6Cz(g2N+MI$_^zF@{!V`^ zFc8|=e=gEv#+U)*x#3`l*%=3%5-tzr^C;ReUPvy_=cCe)+t79yOKA908^vfzzKIY2 zlq&$j70UEEYhJ>q#);I7@;fbH>^yCNt~+)$8D{4jN?9Q5#mxJ~Jrc2yQs;-tf2%~Q z$vG{opwoG+epJ2sOKY@axRBrN%eNEFZmQzUKz3@&F3}2xITt!5b#4_OeNaWB?%EaL zWIAl<=&&xYaDGrZ+c^2bDn*oP>eCAF4zvM9t~;Md?)G9+uu#%S#2J6^rMj#dLYzX$ z7GsF1D+j^M8Q8Z{K;ZWHBuw4dhxIE=OG{yA{$c)1;soec@GHy;JVz8C)MYu}lMgfq z1kE;tLNuPH)Bh;ZlfW8G+7px=v_OxxNpZvEygP>3fV~x}D=PReQL#M!ExkJyO-ry6ZU{5ww z$KM}{If!wqE?;PVz2uSvNxX|J{9PI?t zH1IH-Q$A$Ov}O1jJihJYkVpssQGOw)SXG`c-bX&%05+TRXDxugY_^v`jVU*X7|Ann zsb8aJ7&z=61>Ad+j5=QpTsK}6-a2Ii){^IbJ$!+QCelAqs8pg1 zS&}`5-;GNo?21dtp}*|cc^oj4l39?I6y4dxB$DSH{(vWSq?^FymLYJ9jPM%mMNhR9 zMs{cWI<}#qg=u%6L(=KiAdB^K>tN{cY!$D2X)3rBlJ9xvv}uzYGzcu1zAU=01OL{L zw6wv>376}P+u>N^O?r7r5txfW#El-)F$~DI0~W~T?2VaA(nPJ$@*K?Y0@hi<-*o3a z|K8P7GsLSi@1dL`TZ}75Id?v|a;L!CUh}HcX`H2|PSO1U*moE@X=qMYcXa3MW{(;s zx*sZVE<2A6>r$PM8zOI)jiR7B1t-GRYvb>ULWkyuYTTrh%T&f{)*q4s1{gUK2B0XC zIpqBDJGAOWE{GJ9jCc)eelQDs@rqb=I=6?$((fp89#Bi28!oWrM^#e3xr&A%1=X`0 z&zrTzS=;e0T>q}`l_^mXZrkI$FGy@$7H@&63;W%jDcL>bMQxbT5evfexsEh^?O&c_ zZ|-KQmCRsw+#L-?kJ0 z3EAl{N$ROW*>yIwlC$a-?~K!@2ye+i6s+?uyYFXz3;{&i#eyNp@8p6K^F(j{6YCX? zR`&d{$#mXIHoG`P=Lr2B;-AAsIdGMO7aT`xAm{!&U&M&{0P~T2L3O*6-9R`DSLX#} zmN(cp!+oGNAV@@j8Y<#D@-RtD$0}GA+ba~<5Yc9Lz#?q3g=C=|$LPDo6FukBkS|Od zU5FaYLi%;0)IH)-R)sHxU{@Ew)271AXH~vBf1RB&AD+4Mr{Ai5$IZn@lJB7M zg(G6E5C~4}UjPqr3Sc)F^8jb9!ifQWJ}w9#5gDwcXU=@b*g&Avb>e63uYCu$o9()1 z?i(CRgYe*Sy!mv8PU8^sJ;bz8!_y}A!JsU?KjqzU26>tFImfI1#D&_GC0qI|Gb4`e{?yAkQbSl$=y!AOi5W0|>&I$^ zz&xFqJ=!i6X(=x+{J95J;xG?4BNr%pZIE@II>nwgEb+6bi7%`#Oy}3tB|;Gv{N6Dm zQZ6AJo&U4q(IZD>6h{KR0Be!yXhp2c*kziHl_JlO_Yd$Ladf@yG5V!zRPk64G}a4x z-dZL~u6Zyz3ckd%aMw;a=PGe>l|xH2KvL+;ya1%tW4Bg^V-p8fvvI5w`yV~fx)$C% z2qU>4{y=TQRy(`gHwXpsi(d~pzsl6@Zel*gtW#9+Jp$USK3}*1$>g?%I5`UF3zNEdh0ny5PRvZD+%sMMU#)w^4<_E2}lBEnyc7P3PT^pKKBZt8JyJ9#Qsw{DH(V|mc{%OWl#L>&4sWOU32AgjuxJy;*J{+(?Aj6c+B zL8=G5hmGY5MD4z+ zXw6S;3OV6Lw)5dp?Wj8uH3l`6c>k#99S=Ta^dev>FQnAlxhE}MAEWwJB7plBNt&@j zlu#5xUtz&m^#XnVj!U&|Wt1%Z7vQLrQ?j){Y|A?bEd=c*r1=V~ruh&$>&DyvyDb%r zX4Q1xOV->4>^LaT8dR8ASD05?Etn-305~YEa*E=B^2MNzCIjFCoVMu3l_=gX?rm@w zWx`-{P` zOL31im#j^3LBaXEP{BrC%P>^V;`-p7nH3*Ch@1NdT&OLF^YqQHdsY|otAr+x_0r-L z6V}6hyssrq2=><8G=KXdON)N>IEAPBmn#=av~z@OWfu97bK0lf0&J?z)p(A(9QpWp z&by6tJ-^%E)~qGg@{vkIm`Z$>#@^fXJ8ZfEhEfFK#YYmh7x6A%cRH(!ZX0tvF8}ro z^R7?T!{kp^6wg#3$P}zZy8K#VbmBBOAnI)ENwr;a_>M8;T&A%jm;%blo~Gn>v4zG; zbRPMS{lbdux;8Nj{XHLF(pL8Ta95qd)egbYISj7e zY%l)s;YU$f9q}&g1KDP4Vp#1n0F+tRwz)^;-bGt-tVBbw)GY+EVK0GBkp#)9)5=~$ zlkS1sANj`&|210|@B|>La1lB|{ksp>Q=~{fu3*2f(3yAr_$zR~C50GnRODl_aHhzs z{HhgQP(Q((p15;2L-=gF59M`_B+_OoV|XM@Rl@er76TydiP z81T3W(%b0Drxaxh2dYH#B`r-=I^!;Qjz z&5tL4+e^{4jo+I{1v9dP(=X}s6DVMIhs4><(77X>*a2~UNbS{s)5sr!LW_XYwrLsb zkg>O=IQjlqomfS9?`bZFMhj4z5+~qN zZNeFG@_J!i*#JIMd?1@}vm@9jxjR&}+aD234413n z=)Tu3NN`nGl&>c!)puq~^jj$hIQCjW@H<<2wotlKCDh_}mN=_kH{WtajEOkL;VxU1 z*&X14$0*3Bomf{aRGPhtcIt$wu>5Vb@;z9rsF!+?I1gaGe2VTxq3(d|1LJx7>49m( z6qjD>G_QaSm5a_&@cPK2Pv9%%ce)jyQM1pa=(&JULg+jzEWA;Y{~clr5{{50*ZW#p z6psK2hn~sW?wb&&KY?#TCO$O^BiRUt3lYG(Feq*6aD4pmQ%=Y-_E0hYdUWo;0XAke z!xDVrZ!oY_gtF=oTBplq7I=KeoB+e4*VMOMnHVxlvGa~giAagJw5-6Ov4bK0L)ZBX z48iFY127hg8bZ-=?bv*BTCu%|dzmYoQb#4}M(h2J8=zz9v!aBA+f(warPgGhA{HPA z;xn*Qz_VdR?I)~4@Vx;<5-=M4z_6Z9nG8KSOtv&tVsN2TULE)BpiqaY0t_r(XAh&! z1Yj=SI+sd|xgzP|cFJ|}a9w>3yp|3r-vN?ddD%poYknaSv(mgB+0_&Cc&paPrkFlX zwb>NyD433i6$|1MtR=%5q>26cyZ^Y=-2X)TxvC5AygvN{^P+O`RvgD}G93M~NVM?` zRl*X6hJ@*ZqA`ZV!p0U8M|&z%fi9B9RF1dqlZdw#M^}zuI|`sEN|oQF$egl0KHvB2 zc4O^i1p@bzUN7Ta>rU4zU7W0L=I5{G8*5IAPub#5esTQzF*K3M*uOv`$8i;fQ&P%2 zp)rp_MG4Cku-QWxB^(b6jn$d$MvWB3E*O;Y;F<{I$XgA1Ws_(eL-u*LJ=)nSlw-yax>T z2T^!`KpY-%Zq@m=E!sWDGuoOq4mHu&URrpC&}3a1;%*stmH()2-3baaQg>a|u~^$c z^Qn6DjmhG6`lN!>r*L`IpCcy|JeD%sYqLN&z(A(mdL7$9FU^{QI07aObbi||ak;cR ziI^C~VI~&@GEN}mb>Fz2;Y?ZS%Z*#rZU)-<$%tC;lqcXI!K7A$|$Q#?-^8C(Jig&c~#AZ(VbYY?MuXrU>3a>JP=Es7zfam(lgz zc6d7gcWrqz+Op#V~5K~^`SP(EV@H?kybR1&@5kdu2$je7xW0XKi zCQeGVfm5 z1KB?{^IwL_QbQZ4h;9M)wzljRuqRg>pnnFIo9vhPD8vG5e=(>^ zA|DF?%?oC_E?lzz><{`04$e>>o({ww~#Zf#2I*{K1J-kV;b)9PQatSj@&xiUhiWqVy${*MNyrb@fRz4k0QKyZ~*MIe7PUhmIV#i2|65Ii@5x(cEZT_X%XVj``%1juSf_HjHTV-ml2Lx@dn>guu9ZuseWuF}2G%*GH>G3Ro{uZRfYc0XO$YAXwIJ>#LwDld zN~wkfL-&y_lu{hF=Dx9gKcFk^ZHjN=^acoHWil4k*LdK&HNY^D@qMyOFg!jnNTxsZ znmR-%9daand5CT7lI4r!b=##Drk{R7T9CjVLLrN0X)Dy$6E)^P4O2qOaP+qgz%Lz3 zfwnQ6Ku)unra)@cr6=j?ReG+AU{XR49q9cipj?Jz$^C@1DA6_=7GKDgnwi9{d#aSu zp!|64k-cId`~6|SF^pwcmN(NhSMM$)%GFZp)ggR#Di2wVGH$nm*dbPQm?32d*q-w^ zMJWl^9~Pu06o|22R_p#uDE<7t{Tk7Ob99ADt#N1&l;Sn8%=BjIh~u)fp-6d`q3eu#e+K<?JbOcCGJ>9fxESvBURz6JDDy8&RkTGlsO(B>6P|N!KJ@);SHXNVwq8 zi~5pkTmi~*zMl(O3aNa_tq~z9^rwkKM&GMQDYxc-?!pU#ub_@&mLBByz{m!%V$&Ak}}R zrYzU5A1C09+3I9w=BH@aVyAlqlpqm{CBRgQP%*a2)xuEXaS|dhXdyq5`yv^Gpn7hq z#Z0nqW!QW~T2|&ZZm{fV>Atf{%UsfyW?{f%jVVc2#iO(UZn~eR2PvDl3-&BqGorsy z>8iiLtHEicREWpReiiiXIv6MIn{Ktg0DKx%S=q3aI`c)}EvRMx2IOHD@TkqcSc0a4 z0)TS6Ur`a`0z~{`(xpWV6yT+TN%$@lw$kRRcSvT}kh+ zfEl=s)uE0Avpo){x&`@%gHx-_Ej{*xImgPJgTuI6CyjUFu7==t7&+9IP`I$RTmhQf z7wS)|N4$uPDN^oa;l+^{^cC%+88JMHw06`86ATnmSb^pKTnjV4_l@VO7H`>ZcABk( zen+x~4c{>kZ(hG$OD@yXMNp zJFbpQ5LqpWHYF|;uz>N_Vpdzj2CL9Laye~! zSDS*Dj5NKX%J|5=@8LMOIjEM(EZExwv`8b+baHi6IQDc%0CxYrMRr-GX4JZ#tl$gPm=4T54H@v_fzk?+kFF5czlt--2`iSS zVRz(ap=NCnA!BTt->CP0KlDzoB45N2=#qmL@u(^?%`CKJkw#Kk3oxH5utMjU+ld>b*0)<}mMo(&SyK7vt zd@TyGk{c4fz$G$KvP{3X+a^xG$*tkt^(4|AWI4qYJC8T{4MKl7X8t=700z^^3UvcT zXc^}M6r;NK?o-|Qu@m9-}6%7VB!8@!;R~g zW!h1?QoRygnoQn*cSz8MYiLQT+jeWaayxR_b(C&132*w?LtUH1!SU}?$MNPDvesysT zO#+A@1v#Frg9@X&P0^Qh{}iB0CHuJ;r_^g;nj}}x&(AMMSz@r3X$gyye}SvJ#wFW8 zaRbp#PzzikC@#`FWQP=}2a22kDek(35}rWPMUy1)WQ_|{BUvq*b*P7}2ywTtW-iVJ zHP44^)Bj@lhJ7NEF3il5OWbn9%`F!~C+jLuGrK?CV_Zm@$#fRgNcm(^HJ4H@*Ir+r zm;B3fOG9Ao29=z7{VLCK{!h&yof1`w(~I3_D1po8UuM*1LD+=H@2pDI8ZHDq7usyc zY7$EU%}*E$Itg?j1O{f_FG(S|PD^5Jk>kdw1w}OGBb5~ubB@vdig0GCDli$PF~g*V z^P51Zwz8I@4Jf z*7aLzk_Qo^7mV)OY&z`*L=6Y!FTzL3k7_|P$rOze||$9BtKz-M6Md3$@^ z9Y3f-&R&%1T0A{nj-FxKC!bh}tCp~?H5hD0R&1*rrSdL4ES2yhT~r$x!}u}GaD2fD z-#I3x%0wj~AvF>WlfG|OQg}`u{`-tdEoT(=s@-oNU@qi!T38OX&hJy?0mIiCVR3 z*Yjqh#0T9yNN8l1Um!s%Tdo~JvVlUb>$jh7fh_ZRTooe(krnX#g;mpF?O(@&-I8`h zC>o(D=LXMAR93g31c35@RlVu??coB22HE^zH~7R5XK8Kax4%Sk_cwsTL$uH|VIv4Y zN*ID*7hPKEeO^Kx?MBiJe5gA#E$)2&#sy8?z75Nm-x-PYyC>7Taycwa8;|loh0fcFu~j&M-Nr}G5CH+Hr~P}rUpjZdbtP656uoAwKdXneDB21oR;ocWVz6^#UQ z=3+rp^g=XPgq0ZzSt8%ZE#b__?&fnp}dIF@h|)kjHjK&MhaVMpL}L5FYk) zQ#Mfd4{bQ)lz989H4d-_U1<_<|1n@XjqFhS>mG5HpZTOjA=?_MF%j=H?$wy6&oQVV zECGm+NXYJ80oESGR!JDFDVDSA9Ri&Zq z{EUou^OQ#Nak9vQ1Iq**; zNRZ~hL_L~=;Y^o5$w59vSPc2NIa2&0L&`4ghxStrOy2#I``+{fIBvgM8|eXI`BK=Q z^A0XvzGz`8i-q(tPeZYP!M%nhF zNwUo08c47&OtRFADYD<&izv=<*u7=9h~fqhNHPf~opyX(mHa>U>1Ix4C>Nhf_)3BD zC&}RvvLFLWY{&{c=Bw+Qo<(}n+Y{7n2wUlO+Ss4R9NlRng$Mhy6*QjqSd_IFYOLxi zOAj6o7nHh3YOJP@FH^hescCO0-I`o+0yK!^!c#{ksN)lz>5!ruXWSKD0mzjMcTSU8 zsncw-8{Hc=n;m)_rNdM|q@Bl?o0FrRh|30hM3*34;Fi)A9JM)l*14U1*r3|12Pnc3 zp=Pjaz)Ymd`AWg#MsH!O!*+Ya1a?i#NfXkpJ=ULifFm>)#5%b?QaU;`Ufjb$uqY7EY8HPbFj>4d*C3i;*oDAx zE#G5SP&6-75BNg|hC>L%^X|EIQ$ z2|lbWQ3o>Yy)$GJ;YwY}he91uS+N6c3FWF8%mDPP5)jDOx9gX$-3&4MGLyr@Unon9 z`;S4``Xv0fHaFKbMW5~!t=)6YSmu5%kLPD+y=rWYvu?HF`}R)^@|Uc!gxhmWy>8NA zPx=()4`pB@!QUF=8ErzHOS^B$7}@zUolwnZ`RFyZI813?oK_Bok=>=3$mDWgHae@+ z-*i1s(i-&OOp|Z^=TZ&&H~vG8=z!6C3+X?e5nqm{`;_bhf_gh687T`qcbT`CkahAJ z2Duf+{btD_+5~S0fD*QHdS`skdfqOLK`z}Feo^cwl|T`Z#xLz7zl2*c;SHQ;pH1y( zTpLh&M2)e_yP>8cc}dCF?R@0fBvVID;$^ejsY zR*4o-06XVup)(^2Ck7Qe-VCRnE(?0kUzL;wH=nI_FIE}8ajNzlB|C>o&3iV}jGvM0 zSYA&?iYAL4)WlBPb`@ zo4?V7{|&FCo6JsBlTE&%cTS$E^MZzzE{2Uz6+Qqo=w|H>XREO_nYwPEpmdUA1 z(!&w_w!`XggP-5rHI{$yS8d)_sAFV*Vq2VHmEG5;?&#$#zFtkHETow8Q^$e{-tZ|+ zGhoJ0$|5k(URjdM@`zv2+{QuWdL=I4@>Q|agXPKu3m`;*)>vlfy-!pc<*VY}wZvp{ zg)7EmpMZ+PBS*aMHmClixH20sN8X*R0eV=&7YWeJ&jS&Z4S-l7^^-a=9vI{Wztwca zsUEmsF1f5)m988UNE?gh85Yy?Apz_~y}y)~IWY}YaOY{E$+tnlQ2-X7a<1$WSWrOg zNZ!m=C-74=*?tUvNv8~q7x96zT9d{yJHb^-;>xySW}ItN z>FKG=lA<-z(m5o;(t3@j2CNs&{}O|fGm@z4_5}ez&pz z%QZO|femH)Qxv`3aYSbTF|aBE-`Hl8RbCM@}lz7uFI(p8YzmwBb zt_q}}iz2nm^{y=pM7otW3cRk=7-9<6X(a-V!2O!ea~Z4UrpgWaG@p9+Pr1@7IL*eR zVdPVP(Jx}HH88-kn#x#i%-!$rK^sP}pS@}+@(AfP`mW-&$NJnTSt*$xznuMavoT~~ zjn7TPj=YEis&F1`EcxNEHKeBefI<;^S#OnU<}=O29y=5Sw+>e4|I$jGmo#Kf2CBOC zBvt4ceC4*J2Ca!H+j2gTOJ(NaYbc**fr1^7?saU0@K6`-yWEx-6wVy&_EVVhEz;hL zz-0jHqb9CTy4TzKh3}H+9_BnP7m0d5`VT?@04h9%t*I9uNNsy)hU9DPgxMdvy{TjV zjJh_{(?F3btE!Ae=`i0mlY#g0PwU;5Mb%uN(ob`hs}JGNG^@|ELJF?=tL)F!=A}EIOhVr$>jq|^y?qb;K{ZBUggc=T&B^F7RJ#;Cw ztdgd*B~JMjYIYwwd3?Pd)SUir*lqG2^lh8SQn7Mzo1mRt%xpe@kUgeWe(x}th+odb zLy^_!*rUXA`>4b#*2s}7tM^*5%&G$^WGXIRGShm@;GA}GsBPSMCj~~u(N;FJqs7ZD zQM>u|!MLP*^mMsp+^Gsc@?-#g74y^2M*k@u_Z}ZPL*f)P%u@*RPB0~VQJcV0SAp*2JJfbP3U_uXQ|X2u-tdXxnAF1& z3!ix2^Pn?lV@*>^Qy zO(HC_9hC!HGYAecJ+Lr3CU29Y4K1b4zXVgVojzTYBjw_!3{8{JjCQ#x z2);Rgs^?1LF_k)CW#t~f&Z5wh)@uh~%V*F6^j0x#%|%`u1tRX&KX-I{6P#lsR#E|( z9WP-mkV=~-asqe5SjY7u;*{*x!?rJhOSa#eF`P=TXujR@n{ z($v|eJB3?OFMr_#({3Ixv_juf5`$?qOpZw~QLw1^mM%O{)jJXxl+B){X3J}1Eg)s@ zlW|(yv_{LXh}1+{UC#tR@rS*Cy+0FF)o4D!0pGS_+pWB#fE{wZQw|ngWMf|dhnkLc{p4@XNLN-h zKDinp=KL^ccVvh%nPRfuF;S9Zwi*qVJ3GOlX|>pBA8tsyE@3>!hokLC?nO@1P?!+{ zJ;^C5p}U`1JSr=oHlnrl`1ZJDg_SAc%@al$T^V_M_pON${RZQ^p2_mnX zi?GBoA?&|c@9nKuNxL0)FG&YZECp+MHP}<#C+bZ88C>%Un0I-PC*5Zz!Zn_)*UfN) zuY6tr#+FTc^D|&O`+z*OGZKY|*;H9`LyERHhoDO46FN7%@#0h{$BMYGvNVfjjO1ZnyY$E#Cx9W7kEwJ>YPHZe2zO>$ket! z?oBzxUKCyq@WKs8H&e6UQU{v7l~DO6fs~Zd=PL@Sb7Mr7d5&m)!Y3M9TC*x9hKR74!g@ zhY(2on4hn;*LQ{mKGw(j(7V1Evs0j3Tx}1`Isq)vzjxNZV&ngb z@7}XEq+)jn+paId_*ps!bjD*CNsx3efk3v)uO;a><4eV!6WhIMLlq9xNS~)2zMI8! ziNDK;0zW?V+}+Qw?6Ug?)X*y-4sOClzl^WWN`9A8XlQDJC(Wg7)vtquXn%ut;R3e5 zx&Q|4dcC?r$=L6s?DSrmLjT|ISl^`P(gXbqPtDVx zjOL=o2ixNSF|BfC#-R_zrQ}wQXRHPJX7L8DKm%ZlPb{TD2ZDK!;mRRn3dpkiWs2uEOFuB`sLP1 z2DysT;nI0lIyXL*JwV4 z|LMtA6RY2PTSlc{jATyWY7mpb!gQ_s1&p4VerrvCi?>=)n&UaX`8K-;Bpm)2JB^Zt ze!*Cf>g5AyQT(>^v!4!!IiTGy)_q^jU{4w|=d)x$vJ_%94PXdXA!oE!p$2}d{gD0Y z)b8Wo-_}40kH2>5BYe@?X{S_5+uPff&9$lt#i!(>VOcL%GvFwH-0HF@%|E$C>PZ|` zXgv)#w1e@*wzJ~ z*QH>EhRdmo;^3;^HHtk)=D?Wn)=A;nzKcCX-2iygNI>47=78_im~`nh z;$)i;`F{xkeV?d-g2!jA&M1f>>vC2UmGb^g44ahYj}xi;=O5>70HS9KfjaAlXk|_N zKK{&wV8t^M-rmalw4=l4A--V%$73bsdkr`g7`E@a+NYLxHw1pvEzKQnqzqnU8z>J_ z{_%0NScOzfsy8ze3S`gsv zZk)hZhVPV0eVtblRK&1T{l=fHd5hg8Lw#L)^DW|VjK(6Tx|@*0>bz!t-+BT=bX}{S^7#Hs4_%Cm4J9 z{;$2S?204mx=euJ?j!_lpm7Th!9oab0UCD;?ht~zL*wp{;O_1Y!5xCTyH4?}k#|1K z516%HzOcHW>q?!fx_6&__O?Z~DLr-^x9z_jol@UI-^JiH{yg)KLI8l8M+yX=_KIUv zI`93@AAoT$d|q6=8+DczUz*q388BX)loL!Fu_8JVO+5zWA&r*r_NZYYI5ECWIwdcylaC&G`b!^Hgab2(LN6wjGqU&~V*bxAhMGct&D2OIa zX_+S?jkNZ*r2t?#ZybXEGP+rZP)~-$BXrhRm>7(EUMDH2pbP$RySVzy8DnKU?X=wJ z7(mD9M;hJS?pBoO)2U(#a|D#(W*Q2XA^AbYrlQDl3$zDKG!?Mp;CdS`UdvclJi z5yd^-34>MaxB3x$9b~_NE%El|?x-z&nWT+@pE)!ilH7IG7eef8u-h z>}QGH`9_rfje!uXw(FX*`Cx<)3G#OY^k=4iM)JW2O{-5<3h7!)%}L#n+c1=D9g{Nf z`7$ZS2E@VUN3&%aNuSK1Jb;aq^pARui@OIP<2oq@hDu-${zOpTZPzm4zdH^{o~k0iT14v-$>s9|wPJ z}{fKromD} zDtC6OfBO6KPSJZmKBwO__o<)^)@C&9e&Fy#DifmZ2V*pH0iI%~2$_^cMi1B^IdsulwBIWywgn8N7I(#D2gR(4De$k!6}Hk~iKD zpta0Jo_+Ye83>vz#YNBSOhfXq$E_DZ9(%L%>dt1N#a(YJuTB_dPhR2+y}3ypu_Xmk z8)565RXpOX*RDWOnPq^rINm?2<;Ja&2XLj%<2u0+d*>HQ_F#`46Q}0u8PLXG=Ja`h z3Ob`cJU}v9keO(=B7))=(FIB~fB!DIac}j0rq1G#4RRK!%$e52dB`s@|1}6L{^(NC zxRAz^BdROuSFqymlf%|prYx{xnA_U8Z#av6Q<=b)oBai+Qq}Da?ZL)`U+&>=dJ!x# z0G^B$XGKk0vVPbgeKEC5;z^dkAd+_>vC(;2Cul35=^conNm;aN8hK5(s>K)^pbh(v z3-$-!9ioc7`Rv#%cpe=I`NaoV#{4$)nT|4fyQ0qhv8p2b?0Bqz1&dr8)BF%H!#Ep1 zT#LB&b&I9#a1tNeJA46XuzWhOf`52Eij&#yydMRCGvD*z=`(=5UR!!VlksbU0aD)H zijY{%7TgV8`fI{2+s0<*`)?O`X`^0wT<$6x-J>mWZIz$0m#H~f58mgN?P9Zr07R3x zN}dfR>GtOoSUoOJk3G6l6Bzr8v(B51JqB?#gzpLtQG+iuD#%M_4d0&om92@sx86^e zB?Fw@#8*3!M}RHJnWSE7=PCfM09WP7*2^K)v5#_hLFspXU{XJSQuR517f22_-b~4B zhe4ExLe-51HM9rBG9h&irDG`QNwJ4RTX$K(`V)A#p@X;mjwY1S(yxS;CVD-J?zb0i zeMT}Clx@z>+{^=C0Ba16>FH_XLkQ6%l@<1lV6`Kqcm%^YX}-3EG52Hp=r51%_cAfh z1<%y|adYHG&yq5{E!hy2l@TDZ+8jH%N9t;=-knVdN&^sL6tDN0k7PMM^R7tPO7Wpz zVt&6RTeX!FzG3=3;ufy|78(+(md_W=yK(r_zuh=wmED?eN@p60}C)ICI~&s}Aeri)5_*0vV9X z!C9a*(L3AV?tm9A_mmQ5Jn&`l- zIB%{z%^yOMB+i9Iyo$)q4=|FxOeOO@X}c?A&(XCgkxIv(npX(oos}adFLf7pvAT7~N^u6H)E61%Etsq(iw}=WXyd5 z%Tdl67Jt|k%QD7Rs{LqialbIy_np44zmPs5{#r+FFYKa8Dz1Om>G#Ib6!%t|rk=_) z2Pz2HFY@cAY1LAtL_Mx8X7jcmLTD>W&M%1C3TbfVbk$ypH%%u`AJashPcyWO_gU-h zVGQcwRz(tdKIr}F8_KP8!+t`(A_so&C-4QW{rQ60G0B-!4<`bsHsm5~h>^D`drbv! zy^6Gr07@iBRUbH6sjC{J^n?}W^z)>+BEB4@_#KVge*}D^UiEY>t;|bl;{NZ?PpN@`?CjBVTTP&Azmp`mcqR|c*OT-x-Y&QP1 z!POTheY|l?!uRavQaB+P3dIp8+>AH|`<#kE z-=$sd#29)3q>Qm8phT0Wj-rtjgi1B(q7SbJCH(eVkLB269bMJuexPNzhHd_CK+Z$o zs`bve2qc@x(xLvV;vU`z(;!b83UZYW^PL0~0!(i0;d*8jJoxM^pWqLT?lFD_+C#>6 z0%{@?a-scVv8maJde=d$q+BgO3+OnuvPW)qvC?}_8thyB9WcH%UbQY?H1 z2K+uyCD%g&t3Rha?|%M^XyZAtoU_}ap`ly-p67ZppCS``$ZAsmhw2OEaTfM$=_YOu zas~GF{^UI@18%adj!(le1~V}Ob+_u;u?WB}k}hXvPSiv`zTz$=9UTedI(`#&ehY|k zE(qQak&)J&2opIqG;f#wWH|nK_EjQ?ad4Ytt=1myT(3>HJObxt6ubr5eii$-jO?PO2ey)Un403Ze+u2@Q)!MfYMk+O z3A68=7}&HWj3sDXgo2{^0fRzDaqUK@G)sXKB{(sx9#*A)^CLSKDQ2G4?%Xg>@JA-S zGS7`+X?WgfwDFjlw zee9YN76ixGV9cds0d&zrN@RGV{Er-e`;OuTOKFZhw6Z>CAw-zdA75c33;p`DsP(~l zHMcs2$38zW8R>wtnoznJnYJ5#6`*u)e^|Z!N-p=og^4=;()S?+jn;8Z*q}5w-8zbe z+)z;hl_Zu+OTxvu5l4jX^oBMc>vb!(F%#I`t}PB^drMM-{TX8}j3!@q51g{m zeqLk0w%Iw&G2UTSDr?{R+ZZ)Gpjl%0%8)ZO9$!#D@!=pBtJxNQV%f{|!>>`1AO<^< z&#f|dQ)2fi@4ii{bXLIU@YJzy2$O<>I5kK7lbi1z#@N4wWyg4V!;G}(DiYPH2fiex z>CIPsVt0xPALG->v!`JB`MBff>mt7pniJI5d*z?jpMNAB|3Ok#VX4I}K~3W#lZgLP zKC4B-QJ8CLjCIP~>URb`67#fi` z=hG0wfXaQkf2L~D@e>IRNrffO3C?D#;Sc9Rol6^5uh&rI;pfixl3Iig5+Ub9pC1kl z%$Syfzdv){LEv@x-=5auDc*(y8St;{#jrh!*bUo)$Qzw~pRZYm3IdB_Q4dN>arG2H zt(gCk1P;r)7WAu+B%jJA$;MmyY}kwUDYIskn(j}Gcdi|?ETOFxo48_cmKARTk^~

860IjjX+lhaHRzJ^-Q0Vj37t>p-8wr1-O>J#@Q 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 literal 0 HcmV?d00001 diff --git a/source/NGio.hx b/source/NGio.hx new file mode 100644 index 00000000..9e350e25 --- /dev/null +++ b/source/NGio.hx @@ -0,0 +1,140 @@ +package; + +import flixel.FlxG; +import flixel.util.FlxSignal; +import io.newgrounds.NG; +import io.newgrounds.components.ScoreBoardComponent.Period; +import io.newgrounds.objects.Medal; +import io.newgrounds.objects.Score; +import io.newgrounds.objects.ScoreBoard; +import openfl.display.Stage; + +/** + * MADE BY GEOKURELI THE LEGENED GOD HERO MVP + */ +class NGio +{ + public static var isLoggedIn:Bool = false; + public static var scoreboardsLoaded:Bool = false; + + public static var scoreboardArray:Array = []; + + public static var ngDataLoaded(default, null):FlxSignal = new FlxSignal(); + public static var ngScoresLoaded(default, null):FlxSignal = new FlxSignal(); + + public function new(api:String, encKey:String, ?sessionId:String) + { + trace("connecting to newgrounds"); + + NG.createAndCheckSession(api, sessionId); + + NG.core.verbose = true; + // Set the encryption cipher/format to RC4/Base64. AES128 and Hex are not implemented yet + NG.core.initEncryption(encKey); // Found in you NG project view + + trace(NG.core.attemptingLogin); + + if (NG.core.attemptingLogin) + { + /* a session_id was found in the loadervars, this means the user is playing on newgrounds.com + * and we should login shortly. lets wait for that to happen + */ + trace("attempting login"); + NG.core.onLogin.add(onNGLogin); + } + else + { + /* They are NOT playing on newgrounds.com, no session id was found. We must start one manually, if we want to. + * Note: This will cause a new browser window to pop up where they can log in to newgrounds + */ + NG.core.requestLogin(onNGLogin); + } + } + + function onNGLogin():Void + { + trace('logged in! user:${NG.core.user.name}'); + isLoggedIn = true; + FlxG.save.data.sessionId = NG.core.sessionId; + // FlxG.save.flush(); + // Load medals then call onNGMedalFetch() + NG.core.requestMedals(onNGMedalFetch); + + // Load Scoreboards hten call onNGBoardsFetch() + NG.core.requestScoreBoards(onNGBoardsFetch); + + ngDataLoaded.dispatch(); + } + + // --- MEDALS + function onNGMedalFetch():Void + { + /* + // Reading medal info + for (id in NG.core.medals.keys()) + { + var medal = NG.core.medals.get(id); + trace('loaded medal id:$id, name:${medal.name}, description:${medal.description}'); + } + + // Unlocking medals + var unlockingMedal = NG.core.medals.get(54352);// medal ids are listed in your NG project viewer + if (!unlockingMedal.unlocked) + unlockingMedal.sendUnlock(); + */ + } + + // --- SCOREBOARDS + function onNGBoardsFetch():Void + { + /* + // Reading medal info + for (id in NG.core.scoreBoards.keys()) + { + var board = NG.core.scoreBoards.get(id); + trace('loaded scoreboard id:$id, name:${board.name}'); + } + */ + // var board = NG.core.scoreBoards.get(8004);// ID found in NG project view + + // Posting a score thats OVER 9000! + // board.postScore(FlxG.random.int(0, 1000)); + + // --- To view the scores you first need to select the range of scores you want to see --- + + // add an update listener so we know when we get the new scores + // board.onUpdate.add(onNGScoresFetch); + trace("shoulda got score by NOW!"); + // board.requestScores(20);// get the best 10 scores ever logged + // more info on scores --- http://www.newgrounds.io/help/components/#scoreboard-getscores + } + + function onNGScoresFetch():Void + { + scoreboardsLoaded = true; + + ngScoresLoaded.dispatch(); + /* + for (score in NG.core.scoreBoards.get(8737).scores) + { + trace('score loaded user:${score.user.name}, score:${score.formatted_value}'); + + } + */ + + // var board = NG.core.scoreBoards.get(8004);// ID found in NG project view + // board.postScore(HighScore.score); + + // NGio.scoreboardArray = NG.core.scoreBoards.get(8004).scores; + } + + inline static public function unlockMedal(id:Int) + { + if (isLoggedIn) + { + var medal = NG.core.medals.get(id); + if (!medal.unlocked) + medal.sendUnlock(); + } + } +} diff --git a/source/io/newgrounds/Call.hx b/source/io/newgrounds/Call.hx new file mode 100644 index 00000000..bd5d7aca --- /dev/null +++ b/source/io/newgrounds/Call.hx @@ -0,0 +1,227 @@ +package io.newgrounds; + +import io.newgrounds.utils.Dispatcher; +import io.newgrounds.utils.AsyncHttp; +import io.newgrounds.objects.Error; +import io.newgrounds.objects.events.Result; +import io.newgrounds.objects.events.Result.ResultBase; +import io.newgrounds.objects.events.Response; + +import haxe.ds.StringMap; +import haxe.Json; + +/** A generic way to handle calls agnostic to their type */ +interface ICallable { + + public var component(default, null):String; + + public function send():Void; + public function queue():Void; + public function destroy():Void; +} + +class Call + implements ICallable { + + public var component(default, null):String; + + var _core:NGLite; + var _properties:StringMap; + var _parameters:StringMap; + var _requireSession:Bool; + var _isSecure:Bool; + + // --- BASICALLY SIGNALS + var _dataHandlers:TypedDispatcher>; + var _successHandlers:Dispatcher; + var _httpErrorHandlers:TypedDispatcher; + var _statusHandlers:TypedDispatcher; + + public function new (core:NGLite, component:String, requireSession:Bool = false, isSecure:Bool = false) { + + _core = core; + this.component = component; + _requireSession = requireSession; + _isSecure = isSecure && core.encryptionHandler != null; + } + + /** adds a property to the input's object. **/ + public function addProperty(name:String, value:Dynamic):Call { + + if (_properties == null) + _properties = new StringMap(); + + _properties.set(name, value); + + return this; + } + + /** adds a parameter to the call's component object. **/ + public function addComponentParameter(name:String, value:Dynamic, defaultValue:Dynamic = null):Call { + + if (value == defaultValue)//TODO?: allow sending null value + return this; + + if (_parameters == null) + _parameters = new StringMap(); + + _parameters.set(name, value); + + return this; + } + + /** Handy callback setter for chained call modifiers. Called when ng.io replies successfully */ + public function addDataHandler(handler:Response->Void):Call { + + if (_dataHandlers == null) + _dataHandlers = new TypedDispatcher>(); + + _dataHandlers.add(handler); + return this; + } + + /** Handy callback setter for chained call modifiers. Called when ng.io replies successfully */ + public function addSuccessHandler(handler:Void->Void):Call { + + if (_successHandlers == null) + _successHandlers = new Dispatcher(); + + _successHandlers.add(handler); + return this; + } + + /** Handy callback setter for chained call modifiers. Called when ng.io does not reply for any reason */ + public function addErrorHandler(handler:Error->Void):Call { + + if (_httpErrorHandlers == null) + _httpErrorHandlers = new TypedDispatcher(); + + _httpErrorHandlers.add(handler); + return this; + } + + /** Handy callback setter for chained call modifiers. No idea when this is called; */ + public function addStatusHandler(handler:Int->Void):Call {//TODO:learn what this is for + + if (_statusHandlers == null) + _statusHandlers = new TypedDispatcher(); + + _statusHandlers.add(handler); + return this; + } + + /** + * Sends the call to the server, do not modify this object after calling this + * @param secure If encryption is enabled, it will encrypt the call. + **/ + public function send():Void { + + var data:Dynamic = {}; + data.app_id = _core.appId; + data.call = {}; + data.call.component = component; + + if (_core.debug) + addProperty("debug", true); + + if (_properties == null || !_properties.exists("session_id")) { + // --- HAS NO SESSION ID + + if (_core.sessionId != null) { + // --- AUTO ADD SESSION ID + + addProperty("session_id", _core.sessionId); + + } else if (_requireSession){ + + _core.logError(new Error('cannot send "$component" call without a sessionId')); + return; + } + } + + if (_properties != null) { + + for (field in _properties.keys()) + Reflect.setField(data, field, _properties.get(field)); + } + + if (_parameters != null) { + + data.call.parameters = {}; + + for (field in _parameters.keys()) + Reflect.setField(data.call.parameters, field, _parameters.get(field)); + } + + _core.logVerbose('Post - ${Json.stringify(data)}'); + + if (_isSecure) { + + var secureData = _core.encryptionHandler(Json.stringify(data.call)); + data.call = {}; + data.call.secure = secureData; + + _core.logVerbose(' secure - $secureData'); + } + + _core.markCallPending(this); + + AsyncHttp.send(_core, Json.stringify(data), onData, onHttpError, onStatus); + } + + /** Adds the call to the queue */ + public function queue():Void { + + _core.queueCall(this); + } + + function onData(reply:String):Void { + + _core.logVerbose('Reply - $reply'); + + if (_dataHandlers == null && _successHandlers == null) + return; + + var response = new Response(_core, reply); + + if (_dataHandlers != null) + _dataHandlers.dispatch(response); + + if (response.success && response.result.success && _successHandlers != null) + _successHandlers.dispatch(); + + destroy(); + } + + function onHttpError(message:String):Void { + + _core.logError(message); + + if (_httpErrorHandlers == null) + return; + + var error = new Error(message); + _httpErrorHandlers.dispatch(error); + } + + function onStatus(status:Int):Void { + + if (_statusHandlers == null) + return; + + _statusHandlers.dispatch(status); + } + + public function destroy():Void { + + _core = null; + + _properties = null; + _parameters = null; + + _dataHandlers = null; + _successHandlers = null; + _httpErrorHandlers = null; + _statusHandlers = null; + } +} \ No newline at end of file diff --git a/source/io/newgrounds/NG.hx b/source/io/newgrounds/NG.hx new file mode 100644 index 00000000..3445443e --- /dev/null +++ b/source/io/newgrounds/NG.hx @@ -0,0 +1,475 @@ +package io.newgrounds; + +#if ng_lite +typedef NG = NGLite; //TODO: test and make lite UI +#else +import io.newgrounds.utils.Dispatcher; +import io.newgrounds.objects.Error; +import io.newgrounds.objects.events.Result.SessionResult; +import io.newgrounds.objects.events.Result.MedalListResult; +import io.newgrounds.objects.events.Result.ScoreBoardResult; +import io.newgrounds.objects.events.Response; +import io.newgrounds.objects.User; +import io.newgrounds.objects.Medal; +import io.newgrounds.objects.Session; +import io.newgrounds.objects.ScoreBoard; + +import haxe.ds.IntMap; +import haxe.Timer; + +/** + * The Newgrounds API for Haxe. + * Contains many things ripped from MSGhero + * - https://github.com/MSGhero/NG.hx + * @author GeoKureli + */ +class NG extends NGLite { + + static public var core(default, null):NG; + static public var onCoreReady(default, null):Dispatcher = new Dispatcher(); + + // --- DATA + + /** The logged in user */ + public var user(get, never):User; + function get_user():User { + + if (_session == null) + return null; + + return _session.user; + } + public var passportUrl(get, never):String; + function get_passportUrl():String { + + if (_session == null || _session.status != SessionStatus.REQUEST_LOGIN) + return null; + + return _session.passportUrl; + } + public var medals(default, null):IntMap; + public var scoreBoards(default, null):IntMap; + + // --- EVENTS + + public var onLogin(default, null):Dispatcher; + public var onLogOut(default, null):Dispatcher; + public var onMedalsLoaded(default, null):Dispatcher; + public var onScoreBoardsLoaded(default, null):Dispatcher; + + // --- MISC + + public var loggedIn(default, null):Bool; + public var attemptingLogin(default, null):Bool; + + var _loginCancelled:Bool; + var _passportCallback:Void->Void; + + var _session:Session; + + /** + * Iniitializes the API, call before utilizing any other component + * @param appId The unique ID of your app as found in the 'API Tools' tab of your Newgrounds.com project. + * @param sessionId A unique session id used to identify the active user. + **/ + public function new(appId = "test", sessionId:String = null, ?onSessionFail:Error->Void) { + + _session = new Session(this); + onLogin = new Dispatcher(); + onLogOut = new Dispatcher(); + onMedalsLoaded = new Dispatcher(); + onScoreBoardsLoaded = new Dispatcher(); + + attemptingLogin = sessionId != null; + + super(appId, sessionId, onSessionFail); + } + + /** + * Creates NG.core, the heart and soul of the API. This is not the only way to create an instance, + * nor is NG a forced singleton, but it's the only way to set the static NG.core. + **/ + static public function create(appId = "test", sessionId:String = null, ?onSessionFail:Error->Void):Void { + + core = new NG(appId, sessionId, onSessionFail); + + onCoreReady.dispatch(); + } + + /** + * Creates NG.core, and tries to create a session. This is not the only way to create an instance, + * nor is NG a forced singleton, but it's the only way to set the static NG.core. + **/ + static public function createAndCheckSession + ( appId = "test" + , backupSession:String = null + , ?onSessionFail:Error->Void + ):Void { + + var session = NGLite.getSessionId(); + if (session == null) + session = backupSession; + + create(appId, session, onSessionFail); + + core.host = getHost(); + if (core.sessionId != null) + core.attemptingLogin = true; + } + + // ------------------------------------------------------------------------------------------- + // APP + // ------------------------------------------------------------------------------------------- + + override function checkInitialSession(failHandler:Error->Void, response:Response):Void { + + onSessionReceive(response, null, null, failHandler); + } + + /** + * Begins the login process + * + * @param onSuccess Called when the login is a success + * @param onPending Called when the passportUrl has been identified, call NG.core.openPassportLink + * to open the link continue the process. Leave as null to open the url automatically + * NOTE: Browser games must open links on click events or else it will be blocked by + * the popup blocker. + * @param onFail + * @param onCancel Called when the user denies the passport connection. + */ + public function requestLogin + ( onSuccess:Void->Void = null + , onPending:Void->Void = null + , onFail :Error->Void = null + , onCancel :Void->Void = null + ):Void { + + if (attemptingLogin) { + + logError("cannot request another login until the previous attempt is complete"); + return; + } + + if (loggedIn) { + + logError("cannot log in, already logged in"); + return; + } + + attemptingLogin = true; + _loginCancelled = false; + _passportCallback = null; + + var call = calls.app.startSession(true) + .addDataHandler(onSessionReceive.bind(_, onSuccess, onPending, onFail, onCancel)); + + if (onFail != null) + call.addErrorHandler(onFail); + + call.send(); + } + + function onSessionReceive + ( response :Response + , onSuccess:Void->Void = null + , onPending:Void->Void = null + , onFail :Error->Void = null + , onCancel :Void->Void = null + ):Void { + + if (!response.success || !response.result.success) { + + sessionId = null; + endLoginAndCall(null); + + if (onFail != null) + onFail(!response.success ? response.error : response.result.error); + + return; + } + + _session.parse(response.result.data.session); + sessionId = _session.id; + + logVerbose('session started - status: ${_session.status}'); + + if (_session.status == SessionStatus.REQUEST_LOGIN) { + + _passportCallback = checkSession.bind(null, onSuccess, onCancel); + if (onPending != null) + onPending(); + else + openPassportUrl(); + + } else + checkSession(null, onSuccess, onCancel); + } + + /** + * Call this once the passport link is established and it will load the passport URL and + * start checking for session connect periodically + */ + public function openPassportUrl():Void { + + if (passportUrl != null) { + + logVerbose('loading passport: ${passportUrl}'); + openPassportHelper(passportUrl); + onPassportUrlOpen(); + + } else + logError("Cannot open passport"); + } + + + static function openPassportHelper(url:String):Void { + var window = "_blank"; + + #if flash + flash.Lib.getURL(new flash.net.URLRequest(url), window); + #elseif (js && html5) + js.Browser.window.open(url, window); + #elseif desktop + + #if (sys && windows) + Sys.command("start", ["", url]); + #elseif mac + Sys.command("/usr/bin/open", [url]); + #elseif linux + Sys.command("/usr/bin/xdg-open", [path, "&"]); + #end + + #elseif android + JNI.createStaticMethod + ( "org/haxe/lime/GameActivity" + , "openURL" + , "(Ljava/lang/String;Ljava/lang/String;)V" + ) (url, window); + #end + } + + /** + * Call this once the passport link is established and it will start checking for session connect periodically + */ + public function onPassportUrlOpen():Void { + + if (_passportCallback != null) + _passportCallback(); + + _passportCallback = null; + } + + function checkSession(response:Response, onSucceess:Void->Void, onCancel:Void->Void):Void { + + if (response != null) { + + if (!response.success || !response.result.success) { + + log("login cancelled via passport"); + + endLoginAndCall(onCancel); + return; + } + + _session.parse(response.result.data.session); + } + + if (_session.status == SessionStatus.USER_LOADED) { + + loggedIn = true; + endLoginAndCall(onSucceess); + onLogin.dispatch(); + + } else if (_session.status == SessionStatus.REQUEST_LOGIN){ + + var call = calls.app.checkSession() + .addDataHandler(checkSession.bind(_, onSucceess, onCancel)); + + // Wait 3 seconds and try again + timer(3.0, + function():Void { + + // Check if cancelLoginRequest was called + if (!_loginCancelled) + call.send(); + else { + + log("login cancelled via cancelLoginRequest"); + endLoginAndCall(onCancel); + } + } + ); + + } else + // The user cancelled the passport + endLoginAndCall(onCancel); + } + + public function cancelLoginRequest():Void { + + if (attemptingLogin) + _loginCancelled = true; + } + + function endLoginAndCall(callback:Void->Void):Void { + + attemptingLogin = false; + _loginCancelled = false; + + if (callback != null) + callback(); + } + + public function logOut(onComplete:Void->Void = null):Void { + + var call = calls.app.endSession() + .addSuccessHandler(onLogOutSuccessful); + + if (onComplete != null) + call.addSuccessHandler(onComplete); + + call.addSuccessHandler(onLogOut.dispatch) + .send(); + } + + function onLogOutSuccessful():Void { + + _session.expire(); + sessionId = null; + loggedIn = false; + } + + // ------------------------------------------------------------------------------------------- + // MEDALS + // ------------------------------------------------------------------------------------------- + + public function requestMedals(onSuccess:Void->Void = null, onFail:Error->Void = null):Void { + + var call = calls.medal.getList() + .addDataHandler(onMedalsReceived); + + if (onSuccess != null) + call.addSuccessHandler(onSuccess); + + if (onFail != null) + call.addErrorHandler(onFail); + + call.send(); + } + + function onMedalsReceived(response:Response):Void { + + if (!response.success || !response.result.success) + return; + + var idList:Array = new Array(); + + if (medals == null) { + + medals = new IntMap(); + + for (medalData in response.result.data.medals) { + + var medal = new Medal(this, medalData); + medals.set(medal.id, medal); + idList.push(medal.id); + } + } else { + + for (medalData in response.result.data.medals) { + + medals.get(medalData.id).parse(medalData); + idList.push(medalData.id); + } + } + + logVerbose('${response.result.data.medals.length} Medals received [${idList.join(", ")}]'); + + onMedalsLoaded.dispatch(); + } + + // ------------------------------------------------------------------------------------------- + // SCOREBOARDS + // ------------------------------------------------------------------------------------------- + + public function requestScoreBoards(onSuccess:Void->Void = null, onFail:Error->Void = null):Void { + + if (scoreBoards != null) { + + log("aborting scoreboard request, all scoreboards are loaded"); + + if (onSuccess != null) + onSuccess(); + + return; + } + + var call = calls.scoreBoard.getBoards() + .addDataHandler(onBoardsReceived); + + if (onSuccess != null) + call.addSuccessHandler(onSuccess); + + if (onFail != null) + call.addErrorHandler(onFail); + + call.send(); + } + + function onBoardsReceived(response:Response):Void { + + if (!response.success || !response.result.success) + return; + + var idList:Array = new Array(); + + if (scoreBoards == null) { + + scoreBoards = new IntMap(); + + for (boardData in response.result.data.scoreboards) { + + var board = new ScoreBoard(this, boardData); + scoreBoards.set(board.id, board); + idList.push(board.id); + } + } + + logVerbose('${response.result.data.scoreboards.length} ScoreBoards received [${idList.join(", ")}]'); + + onScoreBoardsLoaded.dispatch(); + } + + // ------------------------------------------------------------------------------------------- + // HELPERS + // ------------------------------------------------------------------------------------------- + + function timer(delay:Float, callback:Void->Void):Void { + + var timer = new Timer(Std.int(delay * 1000)); + timer.run = function func():Void { + + timer.stop(); + callback(); + } + } + + static var urlParser:EReg = ~/^(?:http[s]?:\/\/)?([^:\/\s]+)(:[0-9]+)?((?:\/\w+)*\/)([\w\-\.]+[^#?\s]+)([^#\s]*)?(#[\w\-]+)?$/i;//TODO:trim + /** Used to get the current web host of your game. */ + static public function getHost():String { + + var url = NGLite.getUrl(); + + if (url == null || url == "") + return ""; + + if (url.indexOf("file") == 0) + return ""; + + if (urlParser.match(url)) + return urlParser.matched(1); + + return ""; + } +} +#end \ No newline at end of file diff --git a/source/io/newgrounds/NGLite.hx b/source/io/newgrounds/NGLite.hx new file mode 100644 index 00000000..0c9d5bdf --- /dev/null +++ b/source/io/newgrounds/NGLite.hx @@ -0,0 +1,287 @@ +package io.newgrounds; + +import haxe.crypto.Base64; +import haxe.io.Bytes; +import haxe.PosInfos; + +import io.newgrounds.Call.ICallable; +import io.newgrounds.components.ComponentList; +import io.newgrounds.crypto.EncryptionFormat; +import io.newgrounds.crypto.Cipher; +import io.newgrounds.crypto.Rc4; +import io.newgrounds.objects.Error; +import io.newgrounds.objects.events.Response; +import io.newgrounds.objects.events.Result.ResultBase; +import io.newgrounds.objects.events.Result.SessionResult; +import io.newgrounds.utils.Dispatcher; + +#if !(html5 || flash || desktop || neko) + #error "Target not supported, use: Flash, JS/HTML5, cpp or maybe neko"; +#end + +/** + * The barebones NG.io API. Allows API calls with code completion + * and retrieves server data via strongly typed Objects + * + * Contains many things ripped from MSGhero's repo + * - https://github.com/MSGhero/NG.hx + * + * @author GeoKureli + */ +class NGLite { + + static public var core(default, null):NGLite; + static public var onCoreReady(default, null):Dispatcher = new Dispatcher(); + + /** Enables verbose logging */ + public var verbose:Bool; + public var debug:Bool; + /** The unique ID of your app as found in the 'API Tools' tab of your Newgrounds.com project. */ + public var appId(default, null):String; + /** The name of the host the game is being played on */ + public var host:String; + + @:isVar + public var sessionId(default, set):String; + function set_sessionId(value:String):String { + + return this.sessionId = value == "" ? null : value; + } + + /** Components used to call the NG server directly */ + public var calls(default, null):ComponentList; + + /** + * Converts an object to an encrypted string that can be decrypted by the server. + * Set your preffered encrypter here, + * or just call setDefaultEcryptionHandler with your app's encryption settings + **/ + public var encryptionHandler:String->String; + + /** + * Iniitializes the API, call before utilizing any other component + * @param appId The unique ID of your app as found in the 'API Tools' tab of your Newgrounds.com project. + * @param sessionId A unique session id used to identify the active user. + **/ + public function new(appId = "test", sessionId:String = null, ?onSessionFail:Error->Void) { + + this.appId = appId; + this.sessionId = sessionId; + + calls = new ComponentList(this); + + if (this.sessionId != null) { + + calls.app.checkSession() + .addDataHandler(checkInitialSession.bind(onSessionFail)) + .addErrorHandler(initialSessionFail.bind(onSessionFail)) + .send(); + } + } + + function checkInitialSession(onFail:Error->Void, response:Response):Void { + + if (!response.success || !response.result.success || response.result.data.session.expired) { + + initialSessionFail(onFail, response.success ? response.result.error : response.error); + } + } + + function initialSessionFail(onFail:Error->Void, error:Error):Void { + + sessionId = null; + + if (onFail != null) + onFail(error); + } + + /** + * Creates NG.core, the heart and soul of the API. This is not the only way to create an instance, + * nor is NG a forced singleton, but it's the only way to set the static NG.core. + **/ + static public function create(appId = "test", sessionId:String = null, ?onSessionFail:Error->Void):Void { + + core = new NGLite(appId, sessionId, onSessionFail); + + onCoreReady.dispatch(); + } + + /** + * Creates NG.core, and tries to create a session. This is not the only way to create an instance, + * nor is NG a forced singleton, but it's the only way to set the static NG.core. + **/ + static public function createAndCheckSession + ( appId = "test" + , backupSession:String = null + , ?onSessionFail:Error->Void + ):Void { + + var session = getSessionId(); + if (session == null) + session = backupSession; + + create(appId, session, onSessionFail); + } + + inline static public function getUrl():String { + + #if html5 + return js.Browser.document.location.href; + #elseif flash + return flash.Lib.current.stage.loaderInfo != null + ? flash.Lib.current.stage.loaderInfo.url + : null; + #else + return null; + #end + } + + static public function getSessionId():String { + + #if html5 + + var url = getUrl(); + + // Check for URL params + var index = url.indexOf("?"); + if (index != -1) { + + // Check for session ID in params + for (param in url.substr(index + 1).split("&")) { + + index = param.indexOf("="); + if (index != -1 && param.substr(0, index) == "ngio_session_id") + return param.substr(index + 1); + } + } + + #elseif flash + + if (flash.Lib.current.stage.loaderInfo != null + && Reflect.hasField(flash.Lib.current.stage.loaderInfo.parameters, "ngio_session_id")) + return Reflect.field(flash.Lib.current.stage.loaderInfo.parameters, "ngio_session_id"); + + #end + + return null; + + // --- EXAMPLE LOADER PARAMS + //{ "1517703669" : "" + //, "ng_username" : "GeoKureli" + //, "NewgroundsAPI_SessionID" : "F1LusbG6P8Qf91w7zeUE37c1752563f366688ac6153996d12eeb111a2f60w2xn" + //, "NewgroundsAPI_PublisherID" : 1 + //, "NewgroundsAPI_UserID" : 488329 + //, "NewgroundsAPI_SandboxID" : "5a76520e4ae1e" + //, "ngio_session_id" : "0c6c4e02567a5116734ba1a0cd841dac28a42e79302290" + //, "NewgroundsAPI_UserName" : "GeoKureli" + //} + } + + // ------------------------------------------------------------------------------------------- + // CALLS + // ------------------------------------------------------------------------------------------- + + var _queuedCalls:Array = new Array(); + var _pendingCalls:Array = new Array(); + + @:allow(io.newgrounds.Call) + @:generic + function queueCall(call:Call):Void { + + logVerbose('queued - ${call.component}'); + + _queuedCalls.push(call); + checkQueue(); + } + + @:allow(io.newgrounds.Call) + @:generic + function markCallPending(call:Call):Void { + + _pendingCalls.push(call); + + call.addDataHandler(function (_):Void { onCallComplete(call); }); + call.addErrorHandler(function (_):Void { onCallComplete(call); }); + } + + function onCallComplete(call:ICallable):Void { + + _pendingCalls.remove(call); + checkQueue(); + } + + function checkQueue():Void { + + if (_pendingCalls.length == 0 && _queuedCalls.length > 0) + _queuedCalls.shift().send(); + } + + // ------------------------------------------------------------------------------------------- + // LOGGING / ERRORS + // ------------------------------------------------------------------------------------------- + + /** Called internally, set this to your preferred logging method */ + dynamic public function log(any:Dynamic, ?pos:PosInfos):Void {//TODO: limit access via @:allow + + haxe.Log.trace('[Newgrounds API] :: ${any}', pos); + } + + /** used internally, logs if verbose is true */ + inline public function logVerbose(any:Dynamic, ?pos:PosInfos):Void {//TODO: limit access via @:allow + + if (verbose) + log(any, pos); + } + + /** Used internally. Logs by default, set this to your preferred error handling method */ + dynamic public function logError(any:Dynamic, ?pos:PosInfos):Void {//TODO: limit access via @:allow + + log('Error: $any', pos); + } + + /** used internally, calls log error if the condition is false. EX: if (assert(data != null, "null data")) */ + inline public function assert(condition:Bool, msg:Dynamic, ?pos:PosInfos):Bool {//TODO: limit access via @:allow + if (!condition) + logError(msg, pos); + + return condition; + } + + // ------------------------------------------------------------------------------------------- + // ENCRYPTION + // ------------------------------------------------------------------------------------------- + + /** Sets */ + public function initEncryption + ( key :String + , cipher:Cipher = Cipher.RC4 + , format:EncryptionFormat = EncryptionFormat.BASE_64 + ):Void { + + if (cipher == Cipher.NONE) + encryptionHandler = null; + else if (cipher == Cipher.RC4) + encryptionHandler = encryptRc4.bind(key, format); + else + throw "aes not yet implemented"; + } + + function encryptRc4(key:String, format:EncryptionFormat, data:String):String { + + if (format == EncryptionFormat.HEX) + throw "hex format not yet implemented"; + + var keyBytes:Bytes; + if (format == EncryptionFormat.BASE_64) + keyBytes = Base64.decode(key); + else + keyBytes = null;//TODO + + var dataBytes = new Rc4(keyBytes).crypt(Bytes.ofString(data)); + + if (format == EncryptionFormat.BASE_64) + return Base64.encode(dataBytes); + + return null; + } +} \ No newline at end of file diff --git a/source/io/newgrounds/components/AppComponent.hx b/source/io/newgrounds/components/AppComponent.hx new file mode 100644 index 00000000..1ea5b8b1 --- /dev/null +++ b/source/io/newgrounds/components/AppComponent.hx @@ -0,0 +1,44 @@ +package io.newgrounds.components; + +import io.newgrounds.objects.events.Result; +import io.newgrounds.objects.events.Result.SessionResult; +import io.newgrounds.NGLite; + +class AppComponent extends Component { + + public function new (core:NGLite) { super(core); } + + public function startSession(force:Bool = false):Call { + + return new Call(_core, "App.startSession") + .addComponentParameter("force", force, false); + } + + public function checkSession():Call { + + return new Call(_core, "App.checkSession", true); + } + + public function endSession():Call { + + return new Call(_core, "App.endSession", true); + } + + public function getCurrentVersion(version:String):Call { + + return new Call(_core, "App.getCurrentVersion") + .addComponentParameter("version", version); + } + + public function getHostLicense():Call { + + return new Call(_core, "App.getHostLicense") + .addComponentParameter("host", _core.host); + } + + public function logView():Call { + + return new Call(_core, "App.logView") + .addComponentParameter("host", _core.host); + } +} \ No newline at end of file diff --git a/source/io/newgrounds/components/Component.hx b/source/io/newgrounds/components/Component.hx new file mode 100644 index 00000000..3c588ff1 --- /dev/null +++ b/source/io/newgrounds/components/Component.hx @@ -0,0 +1,13 @@ +package io.newgrounds.components; + +import io.newgrounds.NGLite; + +class Component { + + var _core:NGLite; + + public function new(core:NGLite) { + + this._core = core; + } +} \ No newline at end of file diff --git a/source/io/newgrounds/components/ComponentList.hx b/source/io/newgrounds/components/ComponentList.hx new file mode 100644 index 00000000..315abf4e --- /dev/null +++ b/source/io/newgrounds/components/ComponentList.hx @@ -0,0 +1,25 @@ +package io.newgrounds.components; +class ComponentList { + + var _core:NGLite; + + // --- COMPONENTS + public var medal : MedalComponent; + public var app : AppComponent; + public var event : EventComponent; + public var scoreBoard: ScoreBoardComponent; + public var loader : LoaderComponent; + public var gateway : GatewayComponent; + + public function new(core:NGLite) { + + _core = core; + + medal = new MedalComponent (_core); + app = new AppComponent (_core); + event = new EventComponent (_core); + scoreBoard = new ScoreBoardComponent(_core); + loader = new LoaderComponent (_core); + gateway = new GatewayComponent (_core); + } +} diff --git a/source/io/newgrounds/components/EventComponent.hx b/source/io/newgrounds/components/EventComponent.hx new file mode 100644 index 00000000..2e631773 --- /dev/null +++ b/source/io/newgrounds/components/EventComponent.hx @@ -0,0 +1,16 @@ +package io.newgrounds.components; + +import io.newgrounds.objects.events.Result.LogEventResult; +import io.newgrounds.NGLite; + +class EventComponent extends Component { + + public function new (core:NGLite){ super(core); } + + public function logEvent(eventName:String):Call { + + return new Call(_core, "Event.logEvent") + .addComponentParameter("event_name", eventName) + .addComponentParameter("host", _core.host); + } +} \ No newline at end of file diff --git a/source/io/newgrounds/components/GatewayComponent.hx b/source/io/newgrounds/components/GatewayComponent.hx new file mode 100644 index 00000000..4f0ece61 --- /dev/null +++ b/source/io/newgrounds/components/GatewayComponent.hx @@ -0,0 +1,25 @@ +package io.newgrounds.components; + +import io.newgrounds.objects.events.Result; +import io.newgrounds.NGLite; + +class GatewayComponent extends Component { + + public function new (core:NGLite){ super(core); } + + public function getDatetime():Call { + + return new Call(_core, "Gateway.getDatetime"); + } + + public function getVersion():Call { + + return new Call(_core, "Gateway.getVersion"); + } + + public function ping():Call { + + return new Call(_core, "Gateway.ping"); + } + +} \ No newline at end of file diff --git a/source/io/newgrounds/components/LoaderComponent.hx b/source/io/newgrounds/components/LoaderComponent.hx new file mode 100644 index 00000000..717cc2eb --- /dev/null +++ b/source/io/newgrounds/components/LoaderComponent.hx @@ -0,0 +1,44 @@ +package io.newgrounds.components; + +import io.newgrounds.objects.events.Result; +import io.newgrounds.NGLite; + +class LoaderComponent extends Component { + + public function new (core:NGLite){ super(core); } + + public function loadAuthorUrl(redirect:Bool = false):Call { + + return new Call(_core, "Loader.loadAuthorUrl") + .addComponentParameter("host", _core.host) + .addComponentParameter("redirect", redirect, true); + } + + public function loadMoreGames(redirect:Bool = false):Call { + + return new Call(_core, "Loader.loadMoreGames") + .addComponentParameter("host", _core.host) + .addComponentParameter("redirect", redirect, true); + } + + public function loadNewgrounds(redirect:Bool = false):Call { + + return new Call(_core, "Loader.loadNewgrounds") + .addComponentParameter("host", _core.host) + .addComponentParameter("redirect", redirect, true); + } + + public function loadOfficialUrl(redirect:Bool = false):Call { + + return new Call(_core, "Loader.loadOfficialUrl") + .addComponentParameter("host", _core.host) + .addComponentParameter("redirect", redirect, true); + } + + public function loadReferral(redirect:Bool = false):Call { + + return new Call(_core, "Loader.loadReferral") + .addComponentParameter("host", _core.host) + .addComponentParameter("redirect", redirect, true); + } +} \ No newline at end of file diff --git a/source/io/newgrounds/components/MedalComponent.hx b/source/io/newgrounds/components/MedalComponent.hx new file mode 100644 index 00000000..7e56621c --- /dev/null +++ b/source/io/newgrounds/components/MedalComponent.hx @@ -0,0 +1,21 @@ +package io.newgrounds.components; + +import io.newgrounds.objects.events.Result; +import io.newgrounds.Call; +import io.newgrounds.NGLite; + +class MedalComponent extends Component { + + public function new(core:NGLite):Void { super(core); } + + public function unlock(id:Int):Call { + + return new Call(_core, "Medal.unlock", true, true) + .addComponentParameter("id", id); + } + + public function getList():Call { + + return new Call(_core, "Medal.getList"); + } +} \ No newline at end of file diff --git a/source/io/newgrounds/components/ScoreBoardComponent.hx b/source/io/newgrounds/components/ScoreBoardComponent.hx new file mode 100644 index 00000000..7417e67c --- /dev/null +++ b/source/io/newgrounds/components/ScoreBoardComponent.hx @@ -0,0 +1,114 @@ +package io.newgrounds.components; + +import io.newgrounds.objects.User; +import io.newgrounds.objects.events.Response; +import io.newgrounds.objects.events.Result; +import io.newgrounds.objects.events.Result.ScoreBoardResult; +import io.newgrounds.objects.events.Result.ScoreResult; +import io.newgrounds.NGLite; +import io.newgrounds.objects.ScoreBoard; + +import haxe.ds.IntMap; + +class ScoreBoardComponent extends Component { + + public var allById:IntMap; + + public function new (core:NGLite){ super(core); } + + // ------------------------------------------------------------------------------------------- + // GET SCORES + // ------------------------------------------------------------------------------------------- + + public function getBoards():Call { + + return new Call(_core, "ScoreBoard.getBoards"); + } + + /*function onBoardsReceive(response:Response):Void { + + if (!response.result.success) + return; + + allById = new IntMap(); + + for (boardData in response.result.scoreboards) + createBoard(boardData); + + _core.log('${response.result.scoreboards.length} ScoreBoards loaded'); + }*/ + + // ------------------------------------------------------------------------------------------- + // GET SCORES + // ------------------------------------------------------------------------------------------- + + public function getScores + ( id :Int + , limit :Int = 10 + , skip :Int = 0 + , period:Period = Period.DAY + , social:Bool = false + , tag :String = null + , user :Dynamic = null + ):Call { + + if (user != null && !Std.is(user, String) && !Std.is(user, Int)) + user = user.id; + + return new Call(_core, "ScoreBoard.getScores") + .addComponentParameter("id" , id ) + .addComponentParameter("limit" , limit , 10) + .addComponentParameter("skip" , skip , 0) + .addComponentParameter("period", period, Period.DAY) + .addComponentParameter("social", social, false) + .addComponentParameter("tag" , tag , null) + .addComponentParameter("user" , user , null); + } + + // ------------------------------------------------------------------------------------------- + // POST SCORE + // ------------------------------------------------------------------------------------------- + + public function postScore(id:Int, value:Int, tag:String = null):Call { + + return new Call(_core, "ScoreBoard.postScore", true, true) + .addComponentParameter("id" , id) + .addComponentParameter("value", value) + .addComponentParameter("tag" , tag , null); + } + + /*function onScorePosted(response:Response):Void { + + if (!response.result.success) + return; + + allById = new IntMap(); + + //createBoard(data.data.scoreBoard).parseScores(data.data.scores); + }*/ + + inline function createBoard(data:Dynamic):ScoreBoard { + + var board = new ScoreBoard(_core, data); + _core.logVerbose('created $board'); + + allById.set(board.id, board); + + return board; + } +} + +@:enum +abstract Period(String) to String from String{ + + /** Indicates scores are from the current day. */ + var DAY = "D"; + /** Indicates scores are from the current week. */ + var WEEK = "W"; + /** Indicates scores are from the current month. */ + var MONTH = "M"; + /** Indicates scores are from the current year. */ + var YEAR = "Y"; + /** Indicates scores are from all-time. */ + var ALL = "A"; +} \ No newline at end of file diff --git a/source/io/newgrounds/crypto/Cipher.hx b/source/io/newgrounds/crypto/Cipher.hx new file mode 100644 index 00000000..2f4c0075 --- /dev/null +++ b/source/io/newgrounds/crypto/Cipher.hx @@ -0,0 +1,8 @@ +package io.newgrounds.crypto; + +@:enum +abstract Cipher(String) to String{ + var NONE = "none"; + var AES_128 = "aes128"; + var RC4 = "rc4"; +} \ No newline at end of file diff --git a/source/io/newgrounds/crypto/EncryptionFormat.hx b/source/io/newgrounds/crypto/EncryptionFormat.hx new file mode 100644 index 00000000..6e8f17fd --- /dev/null +++ b/source/io/newgrounds/crypto/EncryptionFormat.hx @@ -0,0 +1,7 @@ +package io.newgrounds.crypto; + +@:enum +abstract EncryptionFormat(String) to String { + var BASE_64 = "base64"; + var HEX = "hex"; +} \ No newline at end of file diff --git a/source/io/newgrounds/crypto/Rc4.hx b/source/io/newgrounds/crypto/Rc4.hx new file mode 100644 index 00000000..54dafa74 --- /dev/null +++ b/source/io/newgrounds/crypto/Rc4.hx @@ -0,0 +1,68 @@ +package io.newgrounds.crypto; + +import haxe.io.Bytes; + +/** + * The following was straight-up ganked from https://github.com/iskolbin/rc4hx + * + * You da real MVP iskolbin... + * + * The MIT License (MIT) + * + * Copyright (c) 2015 iskolbin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +**/ +class Rc4 { + var perm = Bytes.alloc( 256 ); + var index1: Int = 0; + var index2: Int = 0; + + public function new( key: Bytes ) { + for ( i in 0...256 ) { + perm.set( i, i ); + } + + var j: Int = 0; + for ( i in 0...256 ) { + j = ( j + perm.get( i ) + key.get( i % key.length )) % 256; + swap( i, j ); + } + } + + inline function swap( i: Int, j: Int ): Void { + var temp = perm.get( i ); + perm.set( i, perm.get( j )); + perm.set( j, temp ); + } + + public function crypt( input: Bytes ): Bytes { + var output = Bytes.alloc( input.length ); + + for ( i in 0...input.length ) { + index1 = ( index1 + 1 ) % 256; + index2 = ( index2 + perm.get( index1 )) % 256; + swap( index1, index2 ); + var j = ( perm.get( index1 ) + perm.get( index2 )) % 256; + output.set( i, input.get( i ) ^ perm.get( j )); + } + + return output; + } +} \ No newline at end of file diff --git a/source/io/newgrounds/objects/Error.hx b/source/io/newgrounds/objects/Error.hx new file mode 100644 index 00000000..6e82e4e2 --- /dev/null +++ b/source/io/newgrounds/objects/Error.hx @@ -0,0 +1,20 @@ +package io.newgrounds.objects; +class Error { + + public var code(default, null):Int; + public var message(default, null):String; + + public function new (message:String, code:Int = 0) { + + this.message = message; + this.code = code; + } + + public function toString():String { + + if (code > 0) + return '#$code - $message'; + + return message; + } +} diff --git a/source/io/newgrounds/objects/Medal.hx b/source/io/newgrounds/objects/Medal.hx new file mode 100644 index 00000000..3cecc7a6 --- /dev/null +++ b/source/io/newgrounds/objects/Medal.hx @@ -0,0 +1,118 @@ +package io.newgrounds.objects; + +import io.newgrounds.objects.events.Response; +import io.newgrounds.objects.events.Result.MedalUnlockResult; +import io.newgrounds.utils.Dispatcher; +import io.newgrounds.NGLite; + +class Medal extends Object { + + inline static public var EASY :Int = 1; + inline static public var MODERATE :Int = 2; + inline static public var CHALLENGING:Int = 3; + inline static public var DIFFICULT :Int = 4; + inline static public var BRUTAL :Int = 5; + + static var difficultyNames:Array = + [ "Easy" + , "Moderate" + , "Challenging" + , "Difficult" + , "Brutal" + ]; + // --- FROM SERVER + public var id (default, null):Int; + public var name (default, null):String; + public var description(default, null):String; + public var icon (default, null):String; + public var value (default, null):Int; + public var difficulty (default, null):Int; + public var secret (default, null):Bool; + public var unlocked (default, null):Bool; + // --- HELPERS + public var difficultyName(get, never):String; + + public var onUnlock:Dispatcher; + + public function new(core:NGLite, data:Dynamic = null):Void { + + onUnlock = new Dispatcher(); + + super(core, data); + } + + @:allow(io.newgrounds.NG) + override function parse(data:Dynamic):Void { + + var wasLocked = !unlocked; + + id = data.id; + name = data.name; + description = data.description; + icon = data.icon; + value = data.value; + difficulty = data.difficulty; + secret = data.secret == 1; + unlocked = data.unlocked; + + super.parse(data); + + if (wasLocked && unlocked) + onUnlock.dispatch(); + + } + + public function sendUnlock():Void { + + if (_core.sessionId == null) { + // --- Unlock regardless, show medal popup to encourage NG signup + unlocked = true; + onUnlock.dispatch(); + //TODO: save unlock in local save + } + + _core.calls.medal.unlock(id) + .addDataHandler(onUnlockResponse) + .send(); + } + + function onUnlockResponse(response:Response):Void { + + if (response.success && response.result.success) { + + parse(response.result.data.medal); + + // --- Unlock response doesn't include unlock=true, so parse won't change it. + if (!unlocked) { + + unlocked = true; + onUnlock.dispatch(); + } + } + } + + /** Locks the medal on the client and sends an unlock request, Server responds the same either way. */ + public function sendDebugUnlock():Void { + + if (NG.core.sessionId == null) { + + onUnlock.dispatch(); + + } else { + + unlocked = false; + + sendUnlock(); + } + } + + public function get_difficultyName():String { + + return difficultyNames[difficulty - 1]; + } + + public function toString():String { + + return 'Medal: $id@$name (${unlocked ? "unlocked" : "locked"}, $value pts, $difficultyName).'; + } +} \ No newline at end of file diff --git a/source/io/newgrounds/objects/Object.hx b/source/io/newgrounds/objects/Object.hx new file mode 100644 index 00000000..32abd0fe --- /dev/null +++ b/source/io/newgrounds/objects/Object.hx @@ -0,0 +1,33 @@ +package io.newgrounds.objects; + +import io.newgrounds.utils.Dispatcher; +import io.newgrounds.NGLite; + +class Object { + + var _core:NGLite; + + public var onUpdate(default, null):Dispatcher; + + public function new(core:NGLite, data:Dynamic = null) { + + this._core = core; + + onUpdate = new Dispatcher(); + + if (data != null) + parse(data); + } + + @:allow(io.newgrounds.NGLite) + function parse(data:Dynamic):Void { + + onUpdate.dispatch(); + } + + + public function destroy():Void { + + _core = null; + } +} \ No newline at end of file diff --git a/source/io/newgrounds/objects/Score.hx b/source/io/newgrounds/objects/Score.hx new file mode 100644 index 00000000..0eb69826 --- /dev/null +++ b/source/io/newgrounds/objects/Score.hx @@ -0,0 +1,17 @@ +package io.newgrounds.objects; + +/** We don't want to serialize scores since there's a bajillion of them. */ +typedef Score = { + + /** The value value in the format selected in your scoreboard settings. */ + var formatted_value:String; + + /** The tag attached to this value (if any). */ + var tag:String; + + /** The user who earned value. If this property is absent, the value belongs to the active user. */ + var user:User; + + /** The integer value of the value. */ + var value:Int; +} \ No newline at end of file diff --git a/source/io/newgrounds/objects/ScoreBoard.hx b/source/io/newgrounds/objects/ScoreBoard.hx new file mode 100644 index 00000000..1859b080 --- /dev/null +++ b/source/io/newgrounds/objects/ScoreBoard.hx @@ -0,0 +1,76 @@ +package io.newgrounds.objects; + +import io.newgrounds.components.ScoreBoardComponent.Period; +import io.newgrounds.objects.events.Response; +import io.newgrounds.objects.events.Result; +import io.newgrounds.objects.events.Result.ScoreResult; +import io.newgrounds.NGLite; + +class ScoreBoard extends Object { + + public var scores(default, null):Array; + + /** The numeric ID of the scoreboard.*/ + public var id(default, null):Int; + + /** The name of the scoreboard. */ + public var name(default, null):String; + + public function new(core:NGLite, data:Dynamic):Void {super(core, data); } + + override function parse(data:Dynamic):Void { + + id = data.id; + name = data.name; + + super.parse(data); + } + + /** + * Fetches score data from the server, this removes all of the existing scores cached + * + * We don't unify the old and new scores because a user's rank or score may change between requests + */ + public function requestScores + ( limit :Int = 10 + , skip :Int = 0 + , period:Period = Period.ALL + , social:Bool = false + , tag :String = null + , user :Dynamic = null + ):Void { + + _core.calls.scoreBoard.getScores(id, limit, skip, period, social, tag, user) + .addDataHandler(onScoresReceived) + .send(); + } + + function onScoresReceived(response:Response):Void { + + if (!response.success || !response.result.success) + return; + + scores = response.result.data.scores; + _core.logVerbose('received ${scores.length} scores'); + + onUpdate.dispatch(); + } + + public function postScore(value :Int, tag:String = null):Void { + + _core.calls.scoreBoard.postScore(id, value, tag) + .addDataHandler(onScorePosted) + .send(); + } + + function onScorePosted(response:Response):Void { + + + } + + public function toString():String { + + return 'ScoreBoard: $id@$name'; + } + +} \ No newline at end of file diff --git a/source/io/newgrounds/objects/Session.hx b/source/io/newgrounds/objects/Session.hx new file mode 100644 index 00000000..887df792 --- /dev/null +++ b/source/io/newgrounds/objects/Session.hx @@ -0,0 +1,65 @@ +package io.newgrounds.objects; + +class Session extends Object { + + /** If true, the session_id is expired. Use App.startSession to get a new one.*/ + public var expired(default, null):Bool; + + /** A unique session identifier */ + public var id(default, null):String; + + /** If the session has no associated user but is not expired, this property will provide a URL that can be used to sign the user in. */ + public var passportUrl(default, null):String; + + /** If true, the user would like you to remember their session id. */ + public var remember(default, null):Bool; + + /** If the user has not signed in, or granted access to your app, this will be null */ + public var user(default, null):User; + + //TODO:desciption + public var status(get, never):SessionStatus; + + public function new(core:NGLite, data:Dynamic = null) { super(core, data); } + + override public function parse(data:Dynamic):Void { + + id = data.id; + expired = data.expired; + passportUrl = data.passport_url; + remember = data.remember; + + // --- KEEP THE SAME INSTANCE + if (user == null) + user = data.user; + // TODO?: update original user instance with new data. (probly not) + + super.parse(data); + } + + public function get_status():SessionStatus { + + if (expired || id == null || id == "") + return SessionStatus.SESSION_EXPIRED; + + if (user != null && user.name != null && user.name != "") + return SessionStatus.USER_LOADED; + + return SessionStatus.REQUEST_LOGIN; + } + + public function expire():Void { + + expired = true; + id = null; + user = null; + } +} + +@:enum +abstract SessionStatus(String) { + + var SESSION_EXPIRED = "session-expired"; + var REQUEST_LOGIN = "request-login"; + var USER_LOADED = "user-loaded"; +} \ No newline at end of file diff --git a/source/io/newgrounds/objects/User.hx b/source/io/newgrounds/objects/User.hx new file mode 100644 index 00000000..1ff7ce00 --- /dev/null +++ b/source/io/newgrounds/objects/User.hx @@ -0,0 +1,19 @@ +package io.newgrounds.objects; + +typedef User = { + + /** The user's icon images. */ + var icons:UserIcons; + + /** The user's numeric ID. */ + var id:Int; + + /** The user's textual name. */ + var name:String; + + /** Returns true if the user has a Newgrounds Supporter upgrade. */ + var supporter:Bool; + + /** The user's NG profile url. */ + var url:String; +} diff --git a/source/io/newgrounds/objects/UserIcons.hx b/source/io/newgrounds/objects/UserIcons.hx new file mode 100644 index 00000000..b5e56b22 --- /dev/null +++ b/source/io/newgrounds/objects/UserIcons.hx @@ -0,0 +1,14 @@ +package io.newgrounds.objects; + +typedef UserIcons = { + + /**The URL of the user's large icon. */ + var large:String; + + /** The URL of the user's medium icon. */ + var medium:String; + + /** The URL of the user's small icon. */ + var small:String; +} + diff --git a/source/io/newgrounds/objects/events/Response.hx b/source/io/newgrounds/objects/events/Response.hx new file mode 100644 index 00000000..107dc2be --- /dev/null +++ b/source/io/newgrounds/objects/events/Response.hx @@ -0,0 +1,43 @@ +package io.newgrounds.objects.events; + +import io.newgrounds.objects.events.Result.ResultBase; +import haxe.Json; +import io.newgrounds.objects.Error; + +typedef DebugResponse = { + + var exec_time:Int; + var input:Dynamic; +} + +class Response { + + public var success(default, null):Bool; + public var error(default, null):Error; + public var debug(default, null):DebugResponse; + public var result(default, null):Result; + + public function new (core:NGLite, reply:String) { + + var data:Dynamic; + + try { + data = Json.parse(reply); + + } catch (e:Dynamic) { + + data = Json.parse('{"success":false,"error":{"message":"${Std.string(reply)}","code":0}}'); + } + + success = data.success; + debug = data.debug; + + if (!success) { + error = new Error(data.error.message, data.error.code); + core.logError('Call unseccessful: $error'); + return; + } + + result = new Result(core, data.result); + } +} diff --git a/source/io/newgrounds/objects/events/Result.hx b/source/io/newgrounds/objects/events/Result.hx new file mode 100644 index 00000000..eaf87261 --- /dev/null +++ b/source/io/newgrounds/objects/events/Result.hx @@ -0,0 +1,109 @@ +package io.newgrounds.objects.events; + +class Result { + + public var echo(default, null):String; + public var component(default, null):String; + + public var data(default, null):T; + public var success(default, null):Bool; + public var debug(default, null):Bool; + public var error(default, null):Error; + + public function new(core:NGLite, data:Dynamic) { + + echo = data.echo; + component = data.component; + + data = data.data; + success = data.success; + debug = data.debug; + + if(!data.success) { + + error = new Error(data.error.message, data.error.code); + core.logError('$component fail: $error'); + + } else + this.data = data; + } +} + +typedef ResultBase = { }; + +typedef SessionResult = { + > ResultBase, + + var session:Dynamic; +} + +typedef GetHostResult = { + > ResultBase, + + var host_approved:Bool; +} + +typedef GetCurrentVersionResult = { + > ResultBase, + + var current_version:String; + var client_deprecated:Bool; +} + +typedef LogEventResult = { + > ResultBase, + + var event_name:String; +} + +typedef GetDateTimeResult = { + > ResultBase, + + var datetime:String; +} + +typedef GetVersionResult = { + > ResultBase, + + var version:String; +} + +typedef PingResult = { + > ResultBase, + + var pong:String; +} + +typedef MedalListResult = { + > ResultBase, + + var medals:Array; +} + +typedef MedalUnlockResult = { + > ResultBase, + + var medal_score:String; + var medal:Dynamic; +} + +typedef ScoreBoardResult = { + > ResultBase, + + var scoreboards:Array; +} + +typedef ScoreResult = { + > ResultBase, + + var scores:Array; + var scoreboard:Dynamic; +} + +typedef PostScoreResult = { + > ResultBase, + + var tag:String; + var scoreboard:Dynamic; + var score:Score; +} \ No newline at end of file diff --git a/source/io/newgrounds/swf/LoadingBar.hx b/source/io/newgrounds/swf/LoadingBar.hx new file mode 100644 index 00000000..9c7c590a --- /dev/null +++ b/source/io/newgrounds/swf/LoadingBar.hx @@ -0,0 +1,23 @@ +package io.newgrounds.swf; + +import openfl.display.MovieClip; + +class LoadingBar extends MovieClip { + + public var bar(default, null):MovieClip; + + public function new() { + super(); + + setProgress(0.0); + } + + /** + * + * @param value The ratio of bytes loaded to bytes total + */ + public function setProgress(value:Float):Void { + + bar.gotoAndStop(1 + Std.int(value * (bar.totalFrames - 1))); + } +} diff --git a/source/io/newgrounds/swf/MedalPopup.hx b/source/io/newgrounds/swf/MedalPopup.hx new file mode 100644 index 00000000..f55ef426 --- /dev/null +++ b/source/io/newgrounds/swf/MedalPopup.hx @@ -0,0 +1,151 @@ +package io.newgrounds.swf; + +import io.newgrounds.swf.common.BaseAsset; +import io.newgrounds.objects.Medal; + +import openfl.text.TextFieldAutoSize; +import openfl.text.TextField; +import openfl.display.DisplayObject; +import openfl.display.Loader; +import openfl.display.MovieClip; +import openfl.net.URLRequest; +import openfl.events.Event; + +class MedalPopup extends BaseAsset { + + static inline var FRAME_HIDDEN:String = "hidden"; + static inline var FRAME_MEDAL_UNLOCKED:String = "medalUnlocked"; + static inline var FRAME_INTRO_COMPLETE:String = "introComplete"; + static inline var FRAME_UNLOCK_COMPLETE:String = "unlockComplete"; + static inline var MIN_TEXT_SIZE:Int = 12; + + public var medalIcon(default, null):MovieClip; + public var medalName(default, null):MovieClip; + public var medalPoints(default, null):MovieClip; + + public var alwaysOnTop:Bool; + #if !ng_lite + public var requiresSession:Bool; + #end + + var _animQueue = new ArrayVoid>(); + var _scrollSpeed:Float; + + public function new() { + super(); + + mouseEnabled = false; + mouseChildren = false; + + hide(); + addFrameScript(totalFrames - 1, onUnlockAnimComplete); + } + + function hide():Void { + + visible = false; + gotoAndStop(FRAME_HIDDEN); + } + + #if !ng_lite + override function onReady():Void { + super.onReady(); + + if (NG.core.medals != null) + onMedalsLoaded(); + else + NG.core.onLogin.addOnce(NG.core.requestMedals.bind(onMedalsLoaded)); + } + + function onMedalsLoaded():Void { + + for (medal in NG.core.medals) + medal.onUnlock.add(onMedalOnlock.bind(medal)); + } + + function onMedalOnlock(medal:Medal):Void { + + if (requiresSession && !NG.core.loggedIn) + return; + + var loader = new Loader(); + loader.load(new URLRequest(medal.icon)); + + playAnim(loader, medal.name, medal.value); + } + + #end + + public function playAnim(icon:DisplayObject, name:String, value:Int):Void { + + if (currentLabel == FRAME_HIDDEN) + playNextAnim(icon, name, value); + else + _animQueue.push(playNextAnim.bind(icon, name, value)); + } + + function playNextAnim(icon:DisplayObject, name:String, value:Int):Void { + + visible = true; + gotoAndPlay(FRAME_MEDAL_UNLOCKED); + + if (alwaysOnTop && parent != null) { + + parent.setChildIndex(this, parent.numChildren - 1); + } + + while(medalIcon.numChildren > 0) + medalIcon.removeChildAt(0); + + cast(medalPoints.getChildByName("field"), TextField).text = Std.string(value); + + var field:TextField = cast medalName.getChildByName("field"); + field.autoSize = TextFieldAutoSize.LEFT; + field.x = 0; + field.text = ""; + var oldWidth = medalName.width; + field.text = name; + + _scrollSpeed = 0; + if (field.width > oldWidth + 4) { + + field.x = oldWidth + 4; + initScroll(field); + } + + medalIcon.addChild(icon); + } + + function initScroll(field:TextField):Void { + //TODO: Find out why scrollrect didn't work + + var animDuration = 0; + + for (frame in currentLabels){ + + if (frame.name == FRAME_INTRO_COMPLETE ) + animDuration -= frame.frame; + else if (frame.name == FRAME_UNLOCK_COMPLETE) + animDuration += frame.frame; + } + + _scrollSpeed = (field.width + field.x + 4) / animDuration; + field.addEventListener(Event.ENTER_FRAME, updateScroll); + } + + function updateScroll(e:Event):Void{ + + if (currentLabel == FRAME_INTRO_COMPLETE) + cast (e.currentTarget, TextField).x -= _scrollSpeed; + } + + function onUnlockAnimComplete():Void { + + cast (medalName.getChildByName("field"), TextField).removeEventListener(Event.ENTER_FRAME, updateScroll); + + if (_animQueue.length == 0) + hide(); + else + (_animQueue.shift())(); + } +} diff --git a/source/io/newgrounds/swf/ScoreBrowser.hx b/source/io/newgrounds/swf/ScoreBrowser.hx new file mode 100644 index 00000000..c4232c22 --- /dev/null +++ b/source/io/newgrounds/swf/ScoreBrowser.hx @@ -0,0 +1,250 @@ +package io.newgrounds.swf; + +import openfl.events.Event; +import io.newgrounds.swf.common.DropDown; +import io.newgrounds.objects.Score; +import io.newgrounds.objects.events.Result.ScoreBoardResult; +import io.newgrounds.objects.events.Result.ScoreResult; +import io.newgrounds.objects.events.Response; +import io.newgrounds.swf.common.BaseAsset; +import io.newgrounds.swf.common.Button; +import io.newgrounds.components.ScoreBoardComponent.Period; + +import openfl.display.MovieClip; +import openfl.text.TextField; + +class ScoreBrowser extends BaseAsset { + + public var prevButton (default, null):MovieClip; + public var nextButton (default, null):MovieClip; + public var reloadButton (default, null):MovieClip; + public var listBox (default, null):MovieClip; + public var loadingIcon (default, null):MovieClip; + public var errorIcon (default, null):MovieClip; + public var scoreContainer(default, null):MovieClip; + public var titleField (default, null):TextField; + public var pageField (default, null):TextField; + + public var period(get, set):Period; + function get_period():Period { return _periodDropDown.value; } + function set_period(value:Period):Period { return _periodDropDown.value = value; } + + public var title(get, set):String; + function get_title():String { return titleField.text; } + function set_title(value:String):String { return titleField.text = value; } + + public var tag(default, set):String; + function set_tag(value:String):String { + + if (this.tag != value) { + + this.tag = value; + delayReload(); + } + + return value; + } + + public var social(default, set):Bool; + function set_social(value:Bool):Bool { + + if (this.social != value) { + + this.social = value; + delayReload(); + } + + return value; + } + + public var boardId(default, set):Int; + function set_boardId(value:Int):Int { + + _boardIDSet = true; + + if (this.boardId != value) { + + this.boardId = value; + delayReload(); + } + + return value; + } + + public var page(default, set):Int; + function set_page(value:Int):Int { + + if (this.page != value) { + + this.page = value; + delayReload(); + } + + return value; + } + + var _scores:Array; + var _limit:Int = 0; + var _periodDropDown:DropDown; + var _boardIDSet:Bool; + + public function new() { super(); } + + override function setDefaults():Void { + super.setDefaults(); + + boardId = -1; + _boardIDSet = false; + + scoreContainer.visible = false; + loadingIcon.visible = false; + reloadButton.visible = false; + errorIcon.visible = false; + errorIcon.addFrameScript(errorIcon.totalFrames - 1, errorIcon.stop); + + //TODO: prevent memory leaks? + new Button(prevButton, onPrevClick); + new Button(nextButton, onNextClick); + new Button(reloadButton, reload); + _periodDropDown = new DropDown(listBox, delayReload); + _periodDropDown.addItem("Current day" , Period.DAY ); + _periodDropDown.addItem("Current week" , Period.WEEK ); + _periodDropDown.addItem("Current month", Period.MONTH); + _periodDropDown.addItem("Current year" , Period.YEAR ); + _periodDropDown.addItem("All time" , Period.ALL ); + _periodDropDown.value = Period.ALL; + + _scores = new Array(); + while(true) { + + var score:MovieClip = cast scoreContainer.getChildByName('score${_scores.length}'); + if (score == null) + break; + + new Button(score); + _scores.push(score); + } + + _limit = _scores.length; + } + + override function onReady():Void { + super.onReady(); + + if (boardId == -1 && !_boardIDSet) { + + #if ng_lite + NG.core.calls.scoreBoard.getBoards() + .addDataHandler(onBoardsRecieved) + .queue(); + #else + if (NG.core.scoreBoards != null) + onBoardsLoaded(); + else + NG.core.requestScoreBoards(onBoardsLoaded); + #end + } + + reload(); + } + + #if ng_lite + function onBoardsRecieved(response:Response):Void { + + if (response.success && response.result.success) { + + for (board in response.result.data.scoreboards) { + + NG.core.log('No boardId specified defaulting to ${board.name}'); + boardId = board.id; + return; + } + } + } + #else + function onBoardsLoaded():Void { + + for (board in NG.core.scoreBoards) { + + NG.core.log('No boardId specified defaulting to ${board.name}'); + boardId = board.id; + return; + } + } + #end + + /** Used internally to avoid multiple server requests from various property changes in a small time-frame. **/ + function delayReload():Void { + + addEventListener(Event.EXIT_FRAME, onDelayComplete); + } + + function onDelayComplete(e:Event):Void { reload(); } + + public function reload():Void { + removeEventListener(Event.EXIT_FRAME, onDelayComplete); + + errorIcon.visible = false; + scoreContainer.visible = false; + pageField.text = 'page ${page + 1}'; + + if (_coreReady && boardId != -1 && _limit > 0 && period != null) { + + loadingIcon.visible = true; + + NG.core.calls.scoreBoard.getScores(boardId, _limit, _limit * page, period, social, tag) + .addDataHandler(onScoresReceive) + .send(); + } + } + + function onScoresReceive(response:Response):Void { + + loadingIcon.visible = false; + + if (response.success && response.result.success) { + + scoreContainer.visible = true; + + var i = _limit; + while(i > 0) { + i--; + + if (i < response.result.data.scores.length) + drawScore(i, response.result.data.scores[i], _scores[i]); + else + drawScore(i, null, _scores[i]); + } + + } else { + + errorIcon.visible = true; + errorIcon.gotoAndPlay(1); + reloadButton.visible = true; + } + } + + inline function drawScore(rank:Int, score:Score, asset:MovieClip):Void { + + if (score == null) + asset.visible = false; + else { + + asset.visible = true; + cast (asset.getChildByName("nameField" ), TextField).text = score.user.name; + cast (asset.getChildByName("scoreField"), TextField).text = score.formatted_value; + cast (asset.getChildByName("rankField" ), TextField).text = Std.string(rank + 1); + } + } + + function onPrevClick():Void { + + if (page > 0) + page--; + } + + function onNextClick():Void { + + page++; + } +} diff --git a/source/io/newgrounds/swf/common/BaseAsset.hx b/source/io/newgrounds/swf/common/BaseAsset.hx new file mode 100644 index 00000000..da1f6126 --- /dev/null +++ b/source/io/newgrounds/swf/common/BaseAsset.hx @@ -0,0 +1,35 @@ +package io.newgrounds.swf.common; + +import openfl.events.Event; +import openfl.display.MovieClip; + +class BaseAsset extends MovieClip { + + var _coreReady:Bool = false; + + public function new() { + super(); + + setDefaults(); + + if (stage != null) + onAdded(null); + else + addEventListener(Event.ADDED_TO_STAGE, onAdded); + } + + function setDefaults():Void { } + + function onAdded(e:Event):Void { + + if (NG.core != null) + onReady(); + else + NG.onCoreReady.add(onReady); + } + + function onReady():Void { + + _coreReady = true; + } +} diff --git a/source/io/newgrounds/swf/common/Button.hx b/source/io/newgrounds/swf/common/Button.hx new file mode 100644 index 00000000..5f461752 --- /dev/null +++ b/source/io/newgrounds/swf/common/Button.hx @@ -0,0 +1,151 @@ +package io.newgrounds.swf.common; + +import openfl.display.Stage; +import openfl.events.Event; +import openfl.events.MouseEvent; +import openfl.display.MovieClip; + +class Button { + + var _enabled:Bool; + public var enabled(get, set):Bool; + function get_enabled():Bool { return _enabled; } + function set_enabled(value:Bool):Bool { + + if (value != _enabled) { + + _enabled = value; + updateEnabled(); + } + + return value; + } + + public var onClick:Void->Void; + public var onOver:Void->Void; + public var onOut:Void->Void; + + var _target:MovieClip; + var _down:Bool; + var _over:Bool; + var _foundLabels:Array; + + public function new(target:MovieClip, onClick:Void->Void = null, onOver:Void->Void = null, onOut:Void->Void = null) { + + _target = target; + this.onClick = onClick; + this.onOver = onOver; + this.onOut = onOut; + + _foundLabels = new Array(); + for (label in _target.currentLabels) + _foundLabels.push(label.name); + + _target.stop(); + _target.addEventListener(Event.ADDED_TO_STAGE, onAdded); + if (target.stage != null) + onAdded(null); + + enabled = true; + } + + function onAdded(e:Event):Void { + + var stage = _target.stage; + stage.addEventListener(MouseEvent.MOUSE_UP, mouseHandler); + _target.addEventListener(MouseEvent.MOUSE_OVER, mouseHandler); + _target.addEventListener(MouseEvent.MOUSE_OUT, mouseHandler); + _target.addEventListener(MouseEvent.MOUSE_DOWN, mouseHandler); + _target.addEventListener(MouseEvent.CLICK, mouseHandler); + + function selfRemoveEvent(e:Event):Void { + + _target.removeEventListener(Event.REMOVED_FROM_STAGE, selfRemoveEvent); + onRemove(e, stage); + } + _target.addEventListener(Event.REMOVED_FROM_STAGE, selfRemoveEvent); + } + + function onRemove(e:Event, stage:Stage):Void { + + stage.removeEventListener(MouseEvent.MOUSE_UP, mouseHandler); + _target.removeEventListener(MouseEvent.MOUSE_OVER, mouseHandler); + _target.removeEventListener(MouseEvent.MOUSE_OUT, mouseHandler); + _target.removeEventListener(MouseEvent.MOUSE_DOWN, mouseHandler); + _target.removeEventListener(MouseEvent.CLICK, mouseHandler); + } + + function mouseHandler(event:MouseEvent):Void { + + switch(event.type) { + + case MouseEvent.MOUSE_OVER: + + _over = true; + + if (onOver != null) + onOver(); + + case MouseEvent.MOUSE_OUT: + + _over = false; + + if (onOut != null) + onOut(); + + case MouseEvent.MOUSE_DOWN: + + _down = true; + + case MouseEvent.MOUSE_UP: + + _down = false; + + case MouseEvent.CLICK: + + if (enabled && onClick != null) + onClick(); + } + updateState(); + } + + function updateEnabled():Void { + + updateState(); + + _target.useHandCursor = enabled; + _target.buttonMode = enabled; + } + + function updateState():Void { + + var state = determineState(); + + if (_target.currentLabel != state && _foundLabels.indexOf(state) != -1) + _target.gotoAndStop(state); + } + + function determineState():String { + + if (enabled) { + + if (_over) + return _down ? "down" : "over"; + + return "up"; + + } + return "disabled"; + } + + public function destroy():Void { + + _target.removeEventListener(Event.ADDED_TO_STAGE, onAdded); + + _target = null; + onClick = null; + onOver = null; + onOut = null; + _foundLabels = null; + } +} diff --git a/source/io/newgrounds/swf/common/DropDown.hx b/source/io/newgrounds/swf/common/DropDown.hx new file mode 100644 index 00000000..a882cf39 --- /dev/null +++ b/source/io/newgrounds/swf/common/DropDown.hx @@ -0,0 +1,88 @@ +package io.newgrounds.swf.common; + + +import haxe.ds.StringMap; + +import openfl.display.MovieClip; +import openfl.display.Sprite; +import openfl.text.TextField; + +class DropDown { + + public var value(default, set):String; + function set_value(v:String):String { + + if (this.value == v) + return v; + + this.value = v; + _selectedLabel.text = _values.get(v); + + if (_onChange != null) + _onChange(); + + return v; + } + + var _choiceContainer:Sprite; + var _selectedLabel:TextField; + var _onChange:Void->Void; + var _values:StringMap; + var _unusedChoices:Array; + + public function new(target:MovieClip, label:String = "", onChange:Void->Void = null) { + + _onChange = onChange; + + _selectedLabel = cast cast(target.getChildByName("currentItem"), MovieClip).getChildByName("label"); + _selectedLabel.text = label; + + _values = new StringMap(); + + new Button(cast target.getChildByName("button"), onClickExpand); + new Button(cast target.getChildByName("currentItem"), onClickExpand); + _choiceContainer = new Sprite(); + _choiceContainer.visible = false; + target.addChild(_choiceContainer); + + _unusedChoices = new Array(); + while(true) { + + var item:MovieClip = cast target.getChildByName('item${_unusedChoices.length}'); + if (item == null) + break; + + target.removeChild(item); + _unusedChoices.push(item); + } + } + + public function addItem(name:String, value:String):Void { + + _values.set(value, name); + + if (_unusedChoices.length == 0) { + + NG.core.logError('cannot create another dropBox item max=${_choiceContainer.numChildren}'); + return; + } + + var button = _unusedChoices.shift(); + cast(button.getChildByName("label"), TextField).text = name; + _choiceContainer.addChild(button); + + new Button(button, onChoiceClick.bind(value)); + } + + function onClickExpand():Void { + + _choiceContainer.visible = !_choiceContainer.visible; + } + + function onChoiceClick(name:String):Void { + + value = name; + + _choiceContainer.visible = false; + } +} \ No newline at end of file diff --git a/source/io/newgrounds/utils/AsyncHttp.hx b/source/io/newgrounds/utils/AsyncHttp.hx new file mode 100644 index 00000000..4fbe1438 --- /dev/null +++ b/source/io/newgrounds/utils/AsyncHttp.hx @@ -0,0 +1,203 @@ +package io.newgrounds.utils; + +import io.newgrounds.NGLite; + +import haxe.Http; +import haxe.Timer; + +#if neko +import neko.vm.Thread; +#elseif java +import java.vm.Thread; +#elseif cpp +import cpp.vm.Thread; +#end + +/** + * Uses Threading to turn hxcpp's synchronous http requests into asynchronous processes + * + * @author GeoKureli + */ +class AsyncHttp { + + inline static var PATH:String = "https://newgrounds.io/gateway_v3.php"; + + static public function send + ( core:NGLite + , data:String + , onData:String->Void + , onError:String->Void + , onStatus:Int->Void + ) { + + core.logVerbose('sending: $data'); + + #if (neko || java || cpp) + sendAsync(core, data, onData, onError, onStatus); + #else + sendSync(core, data, onData, onError, onStatus); + #end + } + + static function sendSync + ( core:NGLite + , data:String + , onData:String->Void + , onError:String->Void + , onStatus:Int->Void + ):Void { + + var http = new Http(PATH); + http.setParameter("input", data); + http.onData = onData; + http.onError = onError; + http.onStatus = onStatus; + // #if js http.async = async; #end + http.request(true); + } + + #if (neko || java || cpp) + static var _deadPool:Array = []; + static var _livePool:Array = []; + static var _map:Map = new Map(); + static var _timer:Timer; + + static var _count:Int = 0; + + var _core:NGLite; + var _key:Int; + var _onData:String->Void; + var _onError:String->Void; + var _onStatus:Int->Void; + var _worker:Thread; + + public function new (core:NGLite) { + + _core = core; + _worker = Thread.create(sendThreaded); + _key = _count++; + _map[_key] = this; + _core.logVerbose('async http created: $_key'); + } + + function start(data:String, onData:String->Void, onError:String->Void, onStatus:Int->Void) { + + _core.logVerbose('async http started: $_key'); + + if (_livePool.length == 0) + startTimer(); + + _deadPool.remove(this); + _livePool.push(this); + + _onData = onData; + _onError = onError; + _onStatus = onStatus; + _worker.sendMessage({ source:Thread.current(), args:data, key:_key, core:_core }); + } + + function handleMessage(data:ReplyData):Void { + + _core.logVerbose('handling message: $_key'); + + if (data.status != null) { + + _core.logVerbose('\t- status: ${data.status}'); + _onStatus(cast data.status); + return; + } + + var tempFunc:Void->Void; + if (data.data != null) { + + _core.logVerbose('\t- data'); + tempFunc = _onData.bind(data.data); + + } else { + + _core.logVerbose('\t- error'); + tempFunc = _onError.bind(data.error); + } + + cleanUp(); + // Delay the call until destroy so that we're more likely to use a single + // thread on daisy-chained calls + tempFunc(); + } + + inline function cleanUp():Void { + + _onData = null; + _onError = null; + + _deadPool.push(this); + _livePool.remove(this); + + if (_livePool.length == 0) + stopTimer(); + } + + static function sendAsync + ( core:NGLite + , data:String + , onData:String->Void + , onError:String->Void + , onStatus:Int->Void + ):Void { + + var http:AsyncHttp; + if (_deadPool.length == 0) + http = new AsyncHttp(core); + else + http = _deadPool[0]; + + http.start(data, onData, onError, onStatus); + } + + static function startTimer():Void { + + if (_timer != null) + return; + + _timer = new Timer(1000 / 60.0); + _timer.run = update; + } + + static function stopTimer():Void { + + _timer.stop(); + _timer = null; + } + + static public function update():Void { + + var message:ReplyData = cast Thread.readMessage(false); + if (message != null) + _map[message.key].handleMessage(message); + } + + static function sendThreaded():Void { + + while(true) { + + var data:LoaderData = cast Thread.readMessage(true); + data.core.logVerbose('start message received: ${data.key}'); + + sendSync + ( data.core + , data.args + , function(reply ) { data.source.sendMessage({ key:data.key, data :reply }); } + , function(error ) { data.source.sendMessage({ key:data.key, error :error }); } + , function(status) { data.source.sendMessage({ key:data.key, status:status }); } + ); + } + } + + #end +} + + +#if (neko || java || cpp) +typedef LoaderData = { source:Thread, key:Int, args:String, core:NGLite }; +typedef ReplyData = { key:Int, ?data:String, ?error:String, ?status:Null }; +#end \ No newline at end of file diff --git a/source/io/newgrounds/utils/Dispatcher.hx b/source/io/newgrounds/utils/Dispatcher.hx new file mode 100644 index 00000000..699da01d --- /dev/null +++ b/source/io/newgrounds/utils/Dispatcher.hx @@ -0,0 +1,118 @@ +package io.newgrounds.utils; + +/** + * Basically shitty signals, but I didn't want to have external references. +**/ +class Dispatcher { + + var _list:ArrayVoid>; + var _once:ArrayVoid>; + + public function new() { + + _list = new ArrayVoid>(); + _once = new ArrayVoid>(); + } + + public function add(handler:Void->Void, once:Bool = false):Bool { + + if (_list.indexOf(handler) != -1) { + + // ---- REMOVE ONCE + if (!once && _once.indexOf(handler) != -1) + _once.remove(handler); + + return false; + } + + _list.unshift(handler); + if (once) + _once.unshift(handler); + + return true; + } + + inline public function addOnce(handler:Void->Void):Bool { + + return add(handler, true); + } + + public function remove(handler:Void->Void):Bool { + + _once.remove(handler); + return _list.remove(handler); + } + + public function dispatch():Void { + + var i = _list.length - 1; + while(i >= 0) { + + var handler = _list[i]; + + if (_once.remove(handler)) + _list.remove(handler); + + handler(); + + i--; + } + } +} + +class TypedDispatcher { + + var _list:ArrayVoid>; + var _once:ArrayVoid>; + + public function new() { + + _list = new ArrayVoid>(); + _once = new ArrayVoid>(); + } + + public function add(handler:T->Void, once:Bool = false):Bool { + + if (_list.indexOf(handler) != -1) { + + // ---- REMOVE ONCE + if (!once && _once.indexOf(handler) != -1) + _once.remove(handler); + + return false; + } + + _list.unshift(handler); + if (once) + _once.unshift(handler); + + return true; + } + + inline public function addOnce(handler:T->Void):Bool { + + return add(handler, true); + } + + public function remove(handler:T->Void):Bool { + + _once.remove(handler); + return _list.remove(handler); + } + + public function dispatch(arg:T):Void { + + var i = _list.length - 1; + while(i >= 0) { + + var handler = _list[i]; + + if (_once.remove(handler)) + _list.remove(handler); + + handler(arg); + + i--; + } + } +} \ No newline at end of file