From bb7a22f32a9c1707e5cc09e2e736bd3eca49edf0 Mon Sep 17 00:00:00 2001 From: MarkT Date: Wed, 30 Mar 2005 16:14:19 +0000 Subject: [PATCH] First draft of a GPG3-style profiler (including tracing into scripts, after a fashion) This was SVN commit r2090. --- binaries/data/crashlog.dmp | Bin 0 -> 31731 bytes binaries/data/crashlog.txt | Bin 0 -> 130256 bytes source/graphics/GameView.cpp | 6 + source/graphics/MapReader.cpp | 6 + source/gui/IGUIObject.cpp | 1 + source/main.cpp | 76 +++++++- source/ps/Game.cpp | 179 ++++++++++++++++++ source/ps/Game.h | 53 ++++++ source/ps/GameAttributes.cpp | 7 +- source/ps/Interact.cpp | 61 +++--- source/ps/Interact.h | 4 +- source/ps/Network/Client.cpp | 25 +-- source/ps/Network/Session.h | 1 + source/ps/Player.cpp | 11 +- source/ps/Profile.cpp | 250 +++++++++++++++++++++++++ source/ps/Profile.h | 147 +++++++++++++++ source/ps/ProfileViewer.cpp | 196 +++++++++++++++++++ source/ps/ProfileViewer.h | 14 ++ source/ps/World.cpp | 1 + source/scripting/JSConversions.h | 7 + source/scripting/ScriptCustomTypes.cpp | 10 +- source/scripting/ScriptGlue.cpp | 26 ++- source/scripting/ScriptGlue.h | 7 +- source/scripting/ScriptableObject.h | 177 ++++++++++++----- source/scripting/ScriptingHost.cpp | 42 +++++ source/scripting/ScriptingHost.h | 11 +- source/scripting/SynchedJSObject.h | 6 +- source/simulation/BaseEntity.cpp | 13 +- source/simulation/Entity.cpp | 41 +++- source/simulation/EntityManager.cpp | 32 +--- source/simulation/Scheduler.cpp | 4 + source/simulation/Simulation.cpp | 13 +- 32 files changed, 1262 insertions(+), 165 deletions(-) create mode 100644 binaries/data/crashlog.dmp create mode 100644 binaries/data/crashlog.txt create mode 100644 source/ps/Profile.cpp create mode 100644 source/ps/Profile.h create mode 100644 source/ps/ProfileViewer.cpp create mode 100644 source/ps/ProfileViewer.h diff --git a/binaries/data/crashlog.dmp b/binaries/data/crashlog.dmp new file mode 100644 index 0000000000000000000000000000000000000000..0eb01245fcd17b7a5b8c2bf31f7b7f87eceee103 GIT binary patch literal 31731 zcmeHw4OmrG*8je61yoQ%G$_iOT2eViNQz2&5mYo(QZyz4zK{ zueJ8tYk!@4&T&HGgp}1UMBeBxgs=e^cKUr6uTnzzB5@RuY7xSUczZ7)l6-{dg!FpA zjFCe4A>IJk2q2$WKndW?p}X)mcz~^l>>>oRA~am-FgCkjZf-&LxPp@Gy#C#VXg>bk zma9)}wbWA?1jw$H3FGqUfnhR59_ElMa?ROaJiQ$X6p3@iQ0Y* zY-NW%Q786lA$HIZ=1`^Rx1YKxi0BxUe_E*MtpkOq>TD)Px>C_EKIz|$B@XcQFIMz* zQIOHqgWjd+m!Iq}=}SPrXr7{9J4lEM4|3sD^w#DyNq++6Ki#e9a|R26e+YJY6&b-Y zUI{-Mj6VHkg3F=!b`?Jz?joum3yxn5S#MeooD#x`fN?>s_zy`c}yb?kpB=?JQn| zteG8@)fck%c$M|GlI83qK6P{wlOGR`-(Zr(*;o0zAL6$zGq=lgdZDbYYTA^hYU82? zG3FeGlAniMzYns0nGmhm)~RR`WF3&%}Q2=5MMna#50f;*t=u>MH}|c$IZX z*$`uSSr0$41G4H(vUES`*qbcQQ8iv=O;qiw?IBLZhl<0Hb*Zgm{YBsS+^ei=>}C<_ zd_vmhmWu5dY>u>2&7S_t_t`_mesr!aM?IDY&9QGGuvkiTLF>mELjrNYi z<&2@rt+EKRR)t%{Yml|u*1BEZWSQAgR-9K^?KpWi2wsvX0H| z@|=4)zHas^YlHF)duLIe1%Rx=4$7j>-|tn{%Sx8bA~yB1h+U9XZIY$Om5#l&i$1^3 ztE>-|4V^wB_8TAZ8_4>xgR*GD_q@vbqzELKdxiM$m=NznRvZS(x$HMQ{gCb2=T+9n zN|sZIo2CkJ75wmi4_V&)Fo1d*Ap&vG^*Yy9{Fdsk6pQHgSBv-y+VzfytTUbU*egyxt!}0BqCF>d&_Saor zW&KvkatiU|OF|q$yOwuQmRwW3%6eYOI_N9n?y-tAoKxz~LspGfS%=m5D)bS@F7g#` zqFtd-@Lc=L(}wk4WgR!hvJi7N3GsW#nsy$tn!U>UQOT{$gO0zgPzw{?#NaP<-s~ zV;OM)@2K+XZkM|EY39%Vn(ftwA!?4Q4G=fwc9vuLBHUKdHq`5uj=i;u{k77otWL(< z8z>6O1LeK143n((w2O08wO3jD)n3$&c{ERmO|aoQlPtXl)v>pBQP$tQ%DOEBByz31 zFVP~d!5p>QBum>)$7hpu%&V;B@}8;g>ASwHjK8A4yT5#Jx03g6bnMMHq|RP1k0@E# z+c1Pcmh&`OK87qG>4&7VLIb44+*(^0PgHHr{tOH8r28*vG8`Lb5A7>IN! zK!A@B36k4QVw{*L62&BO6EsLi4R@_Ukem*#B_d1Y;cuW33t?|Z{n?OM1TNX&K#p!M zlfmVD+B5+gPeVIW#1L`qFTi)Q2j7hI)R(p|lD%6jeuelBSmO?H9U#i2y&Y1{wQu6l zbJIjTEHKW)w%kacE0@WrpCBfSR1ss+qdgpSPmqVZf78y>Ui0ARMbfj2#Z35h9_;7l zKK?wp&k?im=jNAkp8U+(y1BN;ic{gwqtOqoM@f6e>R9-Lrza$zXS?pioX}b$ELgf{ ztB;#QdwOJ!oDo|4W_#+ZwQmA!>XzRgTNcatd_LCfEX-5$I>==%*5@ohDdxB$#2wQ` zwIvlE##zKX3%93VxeDBj(UR)nVeRQxj@Ed<#8zu^d+e&bd@Ot{31cqBWRdphF<)9W z6Z@kq$$>p2M0>1}kC~5qu>2Nlw4aBvMgn}SwV$?6k6g4N7kXr3_viMH_E>|vJMK0* zu7%=|gkEXgCueTSl+*T-wCH@m9J#aYSW6P&S@baOdCrBy=~~Q(EekN#2yPB%ZpZ0+ z;+tTDM5#k-d$z~Ri_n|&uPp51^IG+5D*W_(_QmtjE_%uxuyZDOyW4oaoF{>6HtZIU z_P1_%d#sm$+M}?V#bchi5!xjp&s|D;tTzcYMuWrD^O~y?umVlMoW~QB+e+;jS2v*M zQ~-DO9pk_;k%wLGTzI9M!}<199=J_MZxvvrzZQMv<~;E{z3U!mOWyyNC$22;n<7UamrV!B=xE`X12o~Lu3Kcy? zFZ?w(UnoLFmy6W52$qdSv<23ulh}=RY|iAXFLls2cgt z;V+KgHZ|_e0rzbid*p}1admNTzp`#g^~i(MU9Ud(_Mo_)3#TMKxwQY5m^XjE@5YC& ze^cXid|>re6CY}Nc*Ny@=yH3Q-+Lq8`E$jQ^@r|h$t!vPzSpz)GQEJIwFR1+ckXQz zgtMgrgSv~DfhWKrcA}qf?)8;kb@=3mWu12!eg5-~uRGf{f3q+5!;er+@As5N0e+$4 zJHK)VpGQr?v!`pmb2*eRH81(XfCZ|?aOYRRe5{!?zX7<<`yYTt9B`rsdc|Q zdGKV;DWB#c&5_NQH(%O3?Rax@1E3D(v7TyfE&!we#slI2+wNTDhys_LuLt8^Xf%EU zhz`oYf_7l1#gcV6M5NLE zEF;GnZ0C3-pIXF#s}vTjuYC9ZOj1Ay?;`9(wlkFmW>84>dUgGtBhxI zKwAl2Q&7GfPzHNMoeB}XUqboS)$?c*(yn;aP5-r#rp!TO6#gjcVq+kxk6J8ik)}=B z=gZWZLCw?qPwhXY^3}4ZRNqDiDQ~qc=1ijeMN+990Fq9$5B5PSt&^gWH+Q>KaqHGa2SptS5ix*5V=g`2@1lcp48Q9p{GC>?Io#azKxEGlIWHHY zE<@Eh)Q`L-ItV}ah}zJQZfaI>^Cpi}0A;iuPi`8@E;MM&bABmsvM(_2za?j<=%4_n z#j*|dL$~5Vi8HSgnHcK24(*zOwzAH)JB1wA72vTcXO&}s!Gr4(^+b zV{OVi?sD7(V7}wN94&PZc2&Z{9L)_!jJ~lfd6m*nK(oDnV)ImJLOvbR!}eqSlc>DI z0e;azYP4&rwtTq;?~l-T^G@+Sl1woGvDuehC_kGotI?-*R?^&>tGru(m2ayRT2IF2 z7Ad@Lm&%>qI=(f6_jioFkY}3vg0_5F;VhOwSdW7&@f`hS=c~cpGT<+Ppl8^P`a1ZE zYs7$`Ld20L7CE*BE|5O6rkB(4aGyiP+`BMv-L)a!j(INtvF1ZxYaFMZ>HOVZm*emn zyt{&Tj}`;}yGNalD8zjb?^)!YGfK!4G#d<>RD&k0x1!-HKzrzbDOd7x7<6)tMtw~a z3_Jt#ne{Hm-G6X8&gRQD%)tzsF54Y+v3SSYa54>kgI%)R!{K=VJp09KcX%25f>(^( z{Vt%HONIT^S|kgC54_dGE>pt!lfPY*%BTHn2N^i^STX&Qz@T-f@1{XEan*R&N&E6+ z@QVQCl`q>+`i@oUigjMwn8=@|46WuiSCt;Dox}qsxCRIyNw}w3gFG zK}l9#-oV1F>4Fq5Pa1Umxs{ReZ|?20>cO{?uOY?k?4p9~yg|_|L@R&zy8lHZeI~3Q zaOcZ2Z&@BkqWt1{GYW@X+d^~U-GMX0(`!dP@!{r)b>Z)K)-**Xnmh7t8$BWHjnS{X zcclBm$8QWJO=i}-%)(rgu%cVmzxC`T|A>F?^(DVw=X=2v5)~EBC@P6*k@fD8(qDfc zG<(z{SM+O-Roov-H=#a7B`qZPTyUpv`kh}UEV|{}9zJ_JS;=K?adweOP}tGR-V<_; zO?+nY*xlh*hfOBQtSqxCr)n0y)^+I337g{nyuDZLXU|9`r6oDp`PnUkF1P==|Lzy3 z-SE`YpRBxhV$WTq$uFK!GP8wZ*wmkEclzBs>7mDi{?Xj?8@?kc<`iZZ%rcvJPUFjk z2`Tww)>IzcaC=ZVGfB*KEoic{V-p-nlo1a-=u$egOTAnz?7c~!!_#E|T3`?Isr)YL&QFdnfkb$v- z)3b_l=Vccar_Y&{mtI^nBYpbZ+`O#x=-KI`?kLL6OV2FHMM-ICi^Q$2E@6v(M~qqc z#nxK~Jp6|OHl7S}=M=Qi97sHNc~QgZ%d$#Zj7Z5aQ=6)T?!v>myfH2KAu#RcwB zGPO24(Xrs;alc<&l3HICeWZ$S20WVz8<;gpavPtu^ z@;w{$%0kszh?tRYQlsmb&-}X`*fHs`Yw?}aPkm&V^~TYKSS zPfdw~ggWkSp z9ci)(iZL;?kVFl6^!b$MZ1J1Fd-Q)V2^#*m6qQ?0R8Z7Ha?u61`&<@YmH0xzZ9Qji z`1SLWBrhwo(4_IpOMlaQ?a~nw*Zi?WbPD}p6={kxi!-y#9Z9bmO#Lv&Z`}{LG zI}GX zJYVBBm;Zz_j^}IJ=JF%=V7vVJ$p?aMd!ujx0itIu^-Aj9Pb>zk`7}h_cU!sR)hkvxLh4UGP>pn%&z5xdJ?YkR zhh0}Vk2pkhq4?86lA*6GNBb|mQjz%I#M?zaA{6Bs$bgUx+^z%4*GRt@HrxyxV}Z65 zBCTzhjeNh{atGT&n={b14WvbgHSCjP#0{ux4q7kbBFzP7Nk0LZQXY;FYa#1-&C)PsGAC#Q18vqg?c9Xj|e zq&JUT)Vl(0Wc`)^*)HM`t1@svzLdDnLgc47c$9j{*DR+?mN$FvfhFf!{zOI7) ze3&fa@9GE<3H@k$>iO#&)n4*>5osKVd%(2s@0=DIcXV*9a(PwN6Z=G`9A)fSl4kJeQnV!S4z>9N19AeG| z8Hker)VmO|r`~12QE!%c>KzE*(0bRRoO-VZj)8iF8s%DV+L&`#+D`9t*Z|ZE18fIR z@@KzCAWyxI0!O`B9t>~-lIgn$dJa1Z{tRcD!x~Vh0=JSmhcTuM>TL(?Kt0Z3HIJ#E zj>w1d&ow-OhHrp;g6^9>va;$MCfRQcdah^+lvxqmBOI@t^c0sOyA!(bb~jy=5R5t) zQ;HB*bvpQ!*Gmx7SM0#C-*XUq_B(m7-&y9_ z?^d);_j?V>+3#x&o3q~ojdJ#T=|9vw#ePpgTCZKh{`|OuYgZiN@pX?oA`$mPyz6RrheavI-YA6^^OIUy#0T-cIEJA3WQSV zw;jAU0@lyM7&Y|83MC?-D`k?d9_8%iI>Z`uzYDB!0hsd`I4|2#k9-+(?HXY4jQBi6 zaP4Xe2{-sE9rA#8k`|%Ch|6T`6l;yTvJe-omyxF_I}mKLZEPRG1`Y&<;GW@PBV-0k z`TPNFm7^Yc^Uo)ha@>W=aj+9*aiFCyD-Nnn$-sI36vJ_o0rSwW-N9n1HQLx@@ZoK5 zKHQ*RA6O8LH50%(+7D^xD1&~p5xYRcHGs5-W|li>oa_AReecg!by=T%79x82(3hE4 zA;8DBUHNwx^d*7ybSYzF?Xl!R7DFWZjBT!h9Ll7Orva2nU|_$p&tn0r|K*fr8vh*f zk_fV>(~v969fJato~l0ViF!u?8^2PwST~>!WwGw>zI8gT-s5y^vxJK@S5Ns_BR!vR zjV08ho(^3ECNRk2T3GP~@c}+A@OB5?e>f3DhKk59ar@Qh_ye3*cYyBOXPpj>PeNJY zUW|=>?)oWvR63?1M0{;u(qdckVIaK~4b!$63>liXDNBzHs)y`*~mQArL65FIL zur)$F;rey?q#>_b*uQPacBpMR8PU^h@ zwzR``?8}Y>t>^F?*5xyen=suXCSrbrzAg{k8sIKVrd-mg&!W`;$9kI)m%|R`vIx+y zjCSCLITrb&pj&NUm!F4Q_rW#FFIk5+Asx$WP)?j|(=C)VuUjPA_|?>P`GL|e)E+Si zCFlBLKwFP%sRwP-@o1;}0Z;uX7o{?kOm{g(U_8VObvdSCz-@>8PoFB6xW0V*OSl|+ zCb%4=V~+k4XN(`^v-oieH0x21`Fg~U%JHh`D?q#UNseD7Cl+}EWsZcLowbiUzC(HB z@XCDJL;jS6F)H`v;77d>i3aS`_n;2>Fi#x_LoK4#{-m0RF8Jbg+`OM$k~cQHWX#-x z8Mq}^keWF?FFQH6xFjh%Gm90^5Ga@OsYey~>YwqDSmv0%7`s{0N1>nnrm_EBvdwy)I)hrLp*LbY6r`=or@lj6wbo@36wF-p!x^%Eo5rooJv>^9M3tVbMPR42_AFi%Xq|0K-mnW=b)AGMgdC4$p^q^0c*pnFzR(E8yMnBTJw#-|MSg!Y=I~f}Uo}|ku6Tp3)GZSF zvOji$r{8v*8xSAL>dRk5X;Ew4da~eHZaOFSFmE zvn36*^pjZthA_xAIzq7C4ucoVXn(eI_cmo$v!Ag&1oj7G8|WW~UTi!2QU>U<2j%3E z2fjT25^};4+5|+Qa(~Pygf_K_XdNObD)$#UbJfy{3scAEd%I%8|^P2u>#KX z9H^M7JyIa{aeQo&`&iv>>ZivmRpEYoKgqG zVd!`2nQIX#)QNQJQO!_M4c}p(B>wAk-BW=(lkNd1Bj~vq)2U;(p#$gUQs_~Ia>h;2 zmHMjtbD{FwL>-{FNd7Lw!g}n>66`x^zq9FH`yJb=?1wWAS#==TL@IRCU;_t27ctne z;gwhkAAda9VYA|~Gti}AP6|e2Y13~850>MRWe3rBe2}o_!=9oLgIhfsrSM=Utj1oN zF&~X$A3MRX48V|O#5=I3<_4}1`Sk#>62z?~krArEBk0Nn4%U^MJ>VO@X>SoK%=`0DocKYRIuiDVh@GHJw1YwoTiw-a8%rV5bOi{DHC56<{<= z@yGRZY?zXOUjY6ZNjmEGC~&OrU52i8daP}yV{KDSxgNX&AZvqxpe^_sfzA`nPyR9x zcP2jc1#=)DekS;XZ(NRVFH`3NeoB~g4t*jJG9v-c_u<~Ix!GLS4|wS>u&sV9oV>Z; zyZUm~2edoade&3xsFGd-8repaGuV-5@Yd(Gps|8xjX_J^%(KrKb1bkeq^kpbKDf0G zD3*cag`ooV6NVWy3MF;roTUTjp#eu#A7hIkgAG?gDu6ylzvKPIjR4v{6#|YT=HsbR zi1}G-{dsGCike}@NcEZPS&04ZLNwwTIL0hbgX8h@#{A^-PrWd|3{>>2cjR7P-GR0h z(63i@g7iZ^qOX0&+z#S+hlFimD0(fSg-&xLO*~pQ6LUrhAP;HoO}VEnLOKUH?qc~` zA9tc^51WO%`Zm-fjxSh|f}gkGYrFb2WbRhEOXh2E+!4=0J_M?HasXG#8xtiWgt~%Y!U_PJnV}fgfK? zXW0zY%m=j%IPT3ElZ)ElD;bo`y*#zxYkPc=dLU@{lDoU!=@fjyw-6NiGX~U@ulrJ> zP27!`RQ?Z!|Me+>1@Wty@Xk6h-L zE0SK9X=xi6r;nd4x2}Ja^_w7DZV5iE6=Add>A+>txs0{V(jeas9ubDU8N2R3WhIce z4zzXVtpjt50j?Dn2T_LVL)AB=v-2W!ABtVf)uNpYsfN8zf8@8xnt`hMop8>Dz3C@m zn1s?nUv22ZHjoEpvK`bdz@r_mqbo7<399!=ITq?0qocPh1zA8aq%U=c2(4F|FB;F?m?)LN$N3^Hju71HFL1nN+VM@-p= z%WvN0@Mhr{3)D8`7p2`N;a?*7ZwIS#>|zm#cnybo@Z+E6Jn! z2DwJ`4N5|sw%I4e&gvON`d3=K9os3m1m!qK{q}y&EIA8 z`IdIy)7=&Bi=QXfpiG@_6;780&~e4?FihwEe4L!;ThgPRawYJf96!*JlL^%RlmBOH7&^aJq!=WVtr$VpkIt5 z1~G$QA0p|GMM2p9ef~0iavf1`TD?2INJ$jMCMo@gWUgu_X;( zvvqY@DfUFK6pR_J{c5;O6UUG>$0c$A45f%84i1y$+l+G7+wlqRDj@7ctjmSyfmH-^ zy21C@KI48bw2cV36Nuzl%&tSi(OLxYk)nx`RC-F>^ z7lWoHP9n~5*^)C{{3A>0Y$lO*1A;nISMptXS&U;(v`gYjURoJmv1VmB>7Kv&iP5Cv z{1X7(IM)VYuHNw65XV8#+d)u2NJMtQ$Ol53CTOp-!WjN``hxN#_0sPwvI6AikC)RQ2p_Sof zh&N!(X4_e=Rf&E`+4KbYLT|P~_el#AB#2`m<$`SWdgMPqm+z%b9*TTKT7$ zFY&w4C!G^K*!~NV%*X3NZ}58V7!P0Z5V(&s=3~RUIp%{)N9H-U)a`ScL%6hEyB~F zQ`C?fL?h}Y;Cx$v6SMkY7e73zfaMu5XC&I12fkq^)tOQ2;g+MM{rCExX94az8{tdb z=QTU!9uqe)L&X1fj~5N_L;54fGUHhx@$wACbCjIFdW@F%<8KXi#DtC(C4DA{#%-~3 zKPx~_x*&0bm^N&@#HXCPw9(m4hEzfP^H>pJABd@~m41iLAx4^o3e&qQ;hc%GT zz%m=;r^KqW4sn#JLlo$4fu0S9{*hQe84e;pDSv_cd2;A=tj|>EHsCj0viL#D;r;eB z&}d$a3&D$_dC}I!rPh8QB=(cHjFzVN3qV>PIaBxWW6tjc2p7ZDWsQp(Q7)@E@-U7l)v=B`jgGgOIPf~b=l~EWfQDRlLA*fIDp8q8t`0Nv7T4g241Tw zd97KC>xv11OUt$*v221^T2?I+Czh7gBC)(|Gp`jDqU`QrOZ2O+TwnO<2;EP}iU8v? z4NRB8={5k?4=;4GsXnN1iZieraPlfeD%G2^|k8c12*y8 z64s%twQo#vQf{O1PDedHRl)vp;k8@Rlp()lt&{&lpIDDHaqLsZ)yQ9U?I%T^Wx>!{ z>w0)Zp|c)m$wtt2gCuZ1jiK0m}8=^0Ts9h(w5J-7DNY43s@jOy(4|55`9EK zpsb|NuU}$EdObe<5H)+{_w~*G-ON5?$0s7_Go&d+8c~bSq#?g9^iZ*9St)pozf$3~ zf3a>HKBYh?#Kt}g_vJDGg@DC?GT_P(F9)~)YXB91wSY>%dcX$2MnDyy8c+k+45$Tc z1#AOs2h;&}0CocE0S$oNfIWalz(K%KKoj5ufCmjLAOH{u2nK`#!T=Ef8=xN`5-3|GC79a7|N`&1)+ zKkUaoC2lo7)#1cFnl!|XDC5{8p5??dE&EiCJ^yZdUViC}V~?Nxko4@w|M2-5CJ=h; zaeVQU5_;@48vi{h^8_dSgr6}$vdzyJv^Dl>tAEcfZeDx}pQylEDqL9S!I!)#i({X> zHzNHOpUZCU-)ih7p&rMclusTAN0~v$K%QgIv&;z|9DBrTS|?}+;FAgjwu50UaMb{V zo#4E$!&cz6U8K(7$+jN^o}X|aota+~@YJ2{Da8JtZRR;3s`sJdw(O$iM4*ngOB~Wx zKplADYj@J-)FTl%vt7uWI%vDBB@a_5MPA#*T;>9PA?#I+xW`q8inVQYRknv?uJ)B+ zX)BI7mZ>qHb=ga=%%jic;nNnxX+K0t zCb{2{d!4}dzwcI%=8VOjC}~vS68?9G}q=-rgTw?j*t7fLj(*ZtA>#!L4O7Q1ihx#=_KfTvcG)h1D-xACDHmzI3z|1qw Rx8J__3ZA=D;Xl3a{~uo{hFJgr literal 0 HcmV?d00001 diff --git a/binaries/data/crashlog.txt b/binaries/data/crashlog.txt new file mode 100644 index 0000000000000000000000000000000000000000..76c3919118902b869eb9a932b84ee3adbb678bb5 GIT binary patch literal 130256 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 + PROFILE_END( "render terrain" ); MICROLOG(L"render models"); + PROFILE_START( "render models" ); RenderModels(m_pWorld->GetUnitManager()); + PROFILE_END( "render models" ); } void CGameView::RenderTerrain(CTerrain *pTerrain) diff --git a/source/graphics/MapReader.cpp b/source/graphics/MapReader.cpp index aeb56cfb0a..85ad0f3669 100755 --- a/source/graphics/MapReader.cpp +++ b/source/graphics/MapReader.cpp @@ -191,6 +191,12 @@ void CMapReader::ApplyData() // } } + // MT: Testing: + if( i == 170 ) + { + CStrW tom( "dick, harry" ); + } + CUnit* unit = g_UnitMan.CreateUnit(m_ObjectTypes.at(m_Objects[i].m_ObjectIndex), NULL); if (unit) diff --git a/source/gui/IGUIObject.cpp b/source/gui/IGUIObject.cpp index be50bf6007..583c31c158 100755 --- a/source/gui/IGUIObject.cpp +++ b/source/gui/IGUIObject.cpp @@ -453,6 +453,7 @@ void IGUIObject::ScriptEvent(const CStr& Action) paramData[0] = OBJECT_TO_JSVAL(mouseObj); jsval result; + JSBool ok = JS_CallFunction(g_ScriptingHost.getContext(), jsGuiObject, it->second, 1, paramData, &result); if (!ok) { diff --git a/source/main.cpp b/source/main.cpp index 7e7e64a093..de92d63fce 100755 --- a/source/main.cpp +++ b/source/main.cpp @@ -26,6 +26,8 @@ #endif #include "lib/res/cursor.h" +#include "ps/Profile.h" +#include "ps/ProfileViewer.h" #include "ps/Loader.h" #include "ps/Font.h" #include "ps/CConsole.h" @@ -489,7 +491,9 @@ static void Render() oglCheck(); MICROLOG(L"flush frame"); + PROFILE_START( "flush frame" ); g_Renderer.FlushFrame(); + PROFILE_END( "flush frame" ); glPushAttrib( GL_ENABLE_BIT ); glDisable( GL_LIGHTING ); @@ -498,22 +502,30 @@ static void Render() if( g_EntGraph ) { + PROFILE( "render entity overlays" ); glColor3f( 1.0f, 0.0f, 1.0f ); MICROLOG(L"render entities"); g_EntityManager.renderAll(); // <-- collision outlines, pathing routes } + PROFILE_START( "render selection" ); g_Mouseover.renderSelectionOutlines(); g_Selection.renderSelectionOutlines(); - + PROFILE_END( "render selection" ); + glPopAttrib(); } else + { + PROFILE_START( "flush frame" ); g_Renderer.FlushFrame(); + PROFILE_END( "flush frame" ); + } oglCheck(); + PROFILE_START( "render fonts" ); MICROLOG(L"render fonts"); // overlay mode glPushAttrib(GL_ENABLE_BIT); @@ -529,13 +541,17 @@ static void Render() glMatrixMode(GL_MODELVIEW); glPushMatrix(); + PROFILE_END( "render fonts" ); + oglCheck(); #ifndef NO_GUI // Temp GUI message GeeTODO glLoadIdentity(); MICROLOG(L"render GUI"); + PROFILE_START( "render gui" ); g_GUI.Draw(); + PROFILE_END( "render gui" ); #endif oglCheck(); @@ -552,6 +568,7 @@ static void Render() oglCheck(); { + PROFILE( "render console" ); glLoadIdentity(); MICROLOG(L"render console"); @@ -562,8 +579,18 @@ static void Render() oglCheck(); + + // Profile information + + PROFILE_START( "render profiling" ); + RenderProfile(); + PROFILE_END( "render profiling" ); + + oglCheck(); + if (g_Game && g_Game->IsGameStarted()) { + PROFILE( "render selection overlays" ); g_Mouseover.renderOverlays(); g_Selection.renderOverlays(); } @@ -730,7 +757,8 @@ TIMER(InitScripting) CEntity::ScriptingInit(); CBaseEntity::ScriptingInit(); JSI_Sound::ScriptingInit(); - + CProfileNode::ScriptingInit(); + #ifndef NO_GUI JSI_IGUIObject::init(); JSI_GUITypes::init(); @@ -744,7 +772,6 @@ TIMER(InitScripting) CDamageType::ScriptingInit(); CJSPropertyAccessor::ScriptingInit(); // <-- Doesn't really matter which we use, but we know CJSPropertyAccessor is already being compiled for T = CEntity. CScriptEvent::ScriptingInit(); - g_ScriptingHost.DefineConstant( "ORDER_NONE", -1 ); g_ScriptingHost.DefineConstant( "ORDER_GOTO", CEntityOrder::ORDER_GOTO ); @@ -1223,7 +1250,9 @@ TIMER(init_after_InitRenderer); in_add_handler(conInputHandler); - in_add_handler(hotkeyInputHandler); // <- Leave this one until after all the others. + in_add_handler(profilehandler); + + in_add_handler(hotkeyInputHandler); // I don't know how much this screws up, but the gui_handler needs // to be after the hotkey, so that input boxes can be typed in @@ -1279,7 +1308,10 @@ static void Frame() { MICROLOG(L"In frame"); + + PROFILE_START( "update music" ); MusicPlayer.update(); + PROFILE_END( "update music" ); static double last_time; const double time = get_time(); @@ -1289,31 +1321,47 @@ static void Frame() // first call: set last_time and return assert(TimeSinceLastFrame >= 0.0f); + PROFILE_START( "reload changed files" ); MICROLOG(L"reload files"); - res_reload_changed_files(); + res_reload_changed_files(); + PROFILE_END( "reload changed files" ); + PROFILE_START( "progressive load" ); ProgressiveLoad(); + PROFILE_END( "progressive load" ); + PROFILE_START( "input" ); MICROLOG(L"input"); in_get_events(); g_SessionManager.Poll(); - + PROFILE_END( "input" ); + + PROFILE_START( "gui tick" ); #ifndef NO_GUI g_GUI.TickObjects(); #endif + PROFILE_END( "gui tick" ); + PROFILE_START( "game logic" ); if (g_Game && g_Game->IsGameStarted()) { + PROFILE_START( "simulation update" ); g_Game->Update(TimeSinceLastFrame); + PROFILE_END( "simulation update" ); if (!g_FixedFrameTiming) + { + PROFILE( "camera update" ); g_Game->GetView()->Update(float(TimeSinceLastFrame)); + } + PROFILE_START( "selection and interaction ui" ); // TODO Where does GameView end and other things begin? g_Mouseover.update( TimeSinceLastFrame ); g_Selection.update(); + PROFILE_END( "selection and interaction ui" ); - + PROFILE_START( "sound update" ); CCamera* camera = g_Game->GetView()->GetCamera(); CMatrix3D& orientation = camera->m_Orientation; @@ -1322,6 +1370,7 @@ static void Frame() float* up = &orientation._data[4]; if(snd_update(pos, dir, up) < 0) debug_out("snd_update failed\n"); + PROFILE_END( "sound update" ); } else { @@ -1332,7 +1381,11 @@ static void Frame() debug_out("snd_update (pos=0 version) failed\n"); } + PROFILE_END( "game logic" ); + + PROFILE_START( "update console" ); g_Console->Update(TimeSinceLastFrame); + PROFILE_END( "update console" ); // ugly, but necessary. these are one-shot events, have to be reset. @@ -1349,6 +1402,7 @@ static void Frame() mouseButtons[SDL_BUTTON_WHEELUP] = false; mouseButtons[SDL_BUTTON_WHEELDOWN] = false; + PROFILE_START( "render" ); if(g_active) { MICROLOG(L"render"); @@ -1361,6 +1415,10 @@ static void Frame() else SDL_Delay(10); + PROFILE_END( "render" ); + + g_Profiler.Frame(); + calc_fps(); if (g_FixedFrameTiming && frameCount==100) quit=true; } @@ -1371,6 +1429,8 @@ static void Frame() int main(int argc, char* argv[]) { + new CProfileManager; + MICROLOG(L"In main"); MICROLOG(L"Init"); @@ -1393,6 +1453,8 @@ int main(int argc, char* argv[]) MICROLOG(L"Shutdown"); Shutdown(); + delete &g_Profiler; + exit(0); } diff --git a/source/ps/Game.cpp b/source/ps/Game.cpp index 7eede960a5..f08531a3bf 100755 --- a/source/ps/Game.cpp +++ b/source/ps/Game.cpp @@ -6,10 +6,182 @@ #include "gui/CGUI.h" #endif #include "timer.h" +#include "Profile.h" #include "Loader.h" CGame *g_Game=NULL; +/* +<<<<<<< .mine +namespace PlayerArray_JS +{ + JSBool GetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) + { + CGameAttributes *pInstance=(CGameAttributes *)JS_GetPrivate(cx, obj); + if (!JSVAL_IS_INT(id)) + return JS_FALSE; + uint index=g_ScriptingHost.ValueToInt(id); + + // Clamp to a preset upper bound. + // FIXME I guess we'll ultimately have max players as a config variable + if (pInstance->m_NumPlayers > PS_MAX_PLAYERS) + pInstance->m_NumPlayers = PS_MAX_PLAYERS; + + // Resize array according to new number of players (note that the array + // size will go up to PS_MAX_PLAYERS, but will never be made smaller - + // this to avoid losing player pointers and make sure they are all + // reclaimed in the end - it's just simpler that way ;-) ) + if (pInstance->m_NumPlayers+1 > pInstance->m_Players.size()) + { + for (size_t i=pInstance->m_Players.size();i<=index;i++) + { + CPlayer *pNewPlayer=new CPlayer((uint)i); + pNewPlayer->SetUpdateCallback(pInstance->m_PlayerUpdateCB, pInstance->m_PlayerUpdateCBData); + pInstance->m_Players.push_back(pNewPlayer); + } + } + + if (index > pInstance->m_NumPlayers) + return JS_FALSE; + + *vp=OBJECT_TO_JSVAL(pInstance->m_Players[index]->GetScript()); + return JS_TRUE; + } + + JSBool SetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) + { + return JS_FALSE; + } + + JSClass Class = { + "PlayerArray", JSCLASS_HAS_PRIVATE, + JS_PropertyStub, JS_PropertyStub, + GetProperty, SetProperty, + JS_EnumerateStub, JS_ResolveStub, + JS_ConvertStub, JS_FinalizeStub + }; + + JSBool Construct( JSContext* cx, JSObject* obj, uint argc, jsval* argv, jsval* rval ) + { + if (argc != 0) + return JS_FALSE; + + JSObject *newObj=JS_NewObject(cx, &Class, NULL, obj); + *rval=OBJECT_TO_JSVAL(newObj); + return JS_TRUE; + } +}; + +CGameAttributes::CGameAttributes(): + m_UpdateCB(NULL), + m_MapFile("test01.pmp"), + m_NumPlayers(2) +{ + ONCE( + g_ScriptingHost.DefineCustomObjectType(&PlayerArray_JS::Class, + PlayerArray_JS::Construct, 0, NULL, NULL, NULL, NULL); + + ScriptingInit(); + ); + + m_PlayerArrayJS=g_ScriptingHost.CreateCustomObject("PlayerArray"); + JS_SetPrivate(g_ScriptingHost.GetContext(), m_PlayerArrayJS, this); + + AddSynchedProperty(L"mapFile", &m_MapFile); + AddSynchedProperty(L"numPlayers", &m_NumPlayers); + + m_Players.resize(4); + for (int i=0;i<4;i++) + m_Players[i]=new CPlayer(i); + + m_Players[0]->SetName(L"Gaia"); + m_Players[0]->SetColour(SPlayerColour(0.2f, 0.7f, 0.2f)); + + m_Players[1]->SetName(L"Acumen"); + m_Players[1]->SetColour(SPlayerColour(1.0f, 0.0f, 0.0f)); + + m_Players[2]->SetName(L"Boco the Insignificant"); + m_Players[2]->SetColour(SPlayerColour(0.0f, 0.0f, 1.0f)); + + m_Players[3]->SetName(L"NoMonkey"); + m_Players[3]->SetColour(SPlayerColour(0.5f, 0.0f, 1.0f)); +} + +CGameAttributes::~CGameAttributes() +{ + std::vector::iterator it=m_Players.begin(); + while (it != m_Players.end()) + { + delete *it; + ++it; + } +} + +jsval CGameAttributes::JSGetPlayers() +{ + return OBJECT_TO_JSVAL(m_PlayerArrayJS); +} + +void CGameAttributes::SetValue(CStrW name, CStrW value) +{ + ISynchedJSProperty *prop=GetSynchedProperty(name); + if (prop) + { + prop->FromString(value); + } +} + +void CGameAttributes::Update(CStrW name, ISynchedJSProperty *attrib) +{ + if (m_UpdateCB) + m_UpdateCB(name, attrib->ToString(), m_UpdateCBData); +} + +void CGameAttributes::SetPlayerUpdateCallback(CPlayer::UpdateCallback *cb, void *userdata) +{ + m_PlayerUpdateCB=cb; + m_PlayerUpdateCBData=userdata; + + for (size_t i=0;iSetUpdateCallback(cb, userdata); + } +} + +void CGameAttributes::ScriptingInit() +{ + AddClassProperty(L"players", (GetFn)&CGameAttributes::JSGetPlayers); + CJSObject::ScriptingInit( "Game" ); + +} + +/*void CGameAttributes::CreateJSObject() +{ + CAttributeMap::CreateJSObject(); + + ONCE( + g_ScriptingHost.DefineCustomObjectType(&PlayerArray_JS::Class, + PlayerArray_JS::Construct, 0, NULL, NULL, NULL, NULL); + ); + + m_PlayerArrayJS=g_ScriptingHost.CreateCustomObject("PlayerArray"); + JS_SetPrivate(g_ScriptingHost.GetContext(), m_PlayerArrayJS, this); + int flags=JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT; + JS_DefineProperty(g_ScriptingHost.GetContext(), m_JSObject, "players", + OBJECT_TO_JSVAL(m_PlayerArrayJS), NULL, NULL, flags); +} + +JSBool CGameAttributes::GetJSProperty(jsval id, jsval *ret) +{ + CStr name=g_ScriptingHost.ValueToString(id); + if (name == CStr("players")) + return JS_TRUE; + return CAttributeMap::GetJSProperty(id, ret); +}*//* + +======= +>>>>>>> .r2037 +*/ // Disable "warning C4355: 'this' : used in base member initializer list". // "The base-class constructors and class member constructors are called before // this constructor. In effect, you've passed a pointer to an unconstructed @@ -37,6 +209,8 @@ CGame::CGame(): CGame::~CGame() { + // Again, the in-game call tree is going to be different to the main menu one. + g_Profiler.StructuralReset(); debug_out("CGame::~CGame(): Game object DESTROYED\n"); } @@ -63,14 +237,19 @@ PSRETURN CGame::ReallyStartGame() { #ifndef NO_GUI jsval rval; + JSBool ok = JS_CallFunctionName(g_ScriptingHost.getContext(), g_GUI.GetScriptObject(), "reallyStartGame", 0, NULL, &rval); + assert(ok); #endif debug_out("GAME STARTED, ALL INIT COMPLETE\n"); m_GameStarted=true; + // The call tree we've built for pregame probably isn't useful in-game. + g_Profiler.StructuralReset(); + #ifndef NO_GUI g_GUI.SendEventToAll("sessionstart"); #endif diff --git a/source/ps/Game.h b/source/ps/Game.h index e1c1fc6ca7..8f87ce7199 100755 --- a/source/ps/Game.h +++ b/source/ps/Game.h @@ -18,6 +18,59 @@ ERROR_GROUP(Game); // This may be overriden by system.cfg ("max_players") #define PS_MAX_PLAYERS 6 +/* +<<<<<<< .mine +namespace PlayerArray_JS +{ + JSBool GetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); +}; + +#define g_GameAttributes CGameAttributes::GetSingleton() +class CGameAttributes: + public CSynchedJSObject, + public Singleton +{ +public: + typedef void (UpdateCallback)(CStrW name, CStrW newValue, void *data); + +private: + friend JSBool PlayerArray_JS::GetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); + + virtual void Update(CStrW name, ISynchedJSProperty *attrib); + + UpdateCallback *m_UpdateCB; + void *m_UpdateCBData; + + CPlayer::UpdateCallback *m_PlayerUpdateCB; + void *m_PlayerUpdateCBData; + + jsval JSGetPlayers(); + +public: + CStrW m_MapFile; + uint m_NumPlayers; + + CGameAttributes(); + virtual ~CGameAttributes(); + + void SetValue(CStrW name, CStrW value); + + inline void SetUpdateCallback(UpdateCallback *cb, void *userdata) + { + m_UpdateCB=cb; + m_UpdateCBData=userdata; + } + + void SetPlayerUpdateCallback(CPlayer::UpdateCallback *cb, void *userdata); + + std::vector m_Players; + JSObject *m_PlayerArrayJS; + + static void ScriptingInit(); +}; +======= +>>>>>>> .r2037 +*/ class CGame { CWorld m_World; diff --git a/source/ps/GameAttributes.cpp b/source/ps/GameAttributes.cpp index 02bb7808ea..e158fda41c 100644 --- a/source/ps/GameAttributes.cpp +++ b/source/ps/GameAttributes.cpp @@ -21,8 +21,7 @@ CPlayerSlot::CPlayerSlot(int slotID, CPlayer *pPlayer): ); //AddProperty(L"session", (GetFn)&CPlayerSlot::JSI_GetSession); - AddReadOnlyProperty(L"session", &m_pSession); - AddProperty(L"assignment", (GetFn)&CPlayerSlot::JSI_GetAssignment); + AddReadOnlyProperty(L"session", &m_pSession); AddReadOnlyProperty(L"player", &m_pPlayer); } @@ -34,6 +33,7 @@ void CPlayerSlot::ScriptingInit() AddMethod("assignClosed", 0); AddMethod("assignToSession", 1); AddMethod("assignOpen", 0); + AddClassProperty(L"assignment", (GetFn)&CPlayerSlot::JSI_GetAssignment); // AddMethod("assignAI", ); CJSObject::ScriptingInit("PlayerSlot"); @@ -181,8 +181,6 @@ CGameAttributes::CGameAttributes(): AddSynchedProperty(L"mapFile", &m_MapFile); AddSynchedProperty(L"numSlots", &m_NumSlots, &CGameAttributes::OnNumSlotsUpdate); - - AddProperty(L"slots", (GetFn)&CGameAttributes::JSI_GetPlayerSlots); m_Players.resize(9); for (int i=0;i<9;i++) @@ -248,6 +246,7 @@ void CGameAttributes::ScriptingInit() PlayerSlotArray_JS::Construct, 0, NULL, NULL, NULL, NULL); AddMethod("getOpenSlot", 0); + AddClassProperty(L"slots", (GetFn)&CGameAttributes::JSI_GetPlayerSlots); CJSObject::ScriptingInit("GameAttributes"); } diff --git a/source/ps/Interact.cpp b/source/ps/Interact.cpp index ea074f518c..b0bcc17914 100755 --- a/source/ps/Interact.cpp +++ b/source/ps/Interact.cpp @@ -534,7 +534,8 @@ void CSelectedEntities::contextOrder( bool pushQueue ) for( it = m_selected.begin(); it < m_selected.end(); it++ ) - if( (*it)->acceptsOrder( m_contextOrder, g_Mouseover.m_target ) ) + if( ( (*it)->GetPlayer() == g_Game->GetLocalPlayer() ) && + ( (*it)->acceptsOrder( m_contextOrder, g_Mouseover.m_target ) ) ) { contextRandomized = context; do @@ -605,7 +606,7 @@ void CMouseoverEntities::update( float timestep ) std::vector::iterator it; for( it = onscreen->begin(); it < onscreen->end(); it++ ) - if( (*it)->m_extant ) + if( (*it)->m_extant && ( (*it)->GetPlayer() == g_Game->GetLocalPlayer() ) ) m_mouseover.push_back( SMouseoverFader( *it, m_fademaximum, false ) ); delete( onscreen ); @@ -634,6 +635,10 @@ void CMouseoverEntities::update( float timestep ) if( !(*it)->m_extant ) continue; + // Can only bandbox units the local player controls. + if( (*it)->GetPlayer() != g_Game->GetLocalPlayer() ) + continue; + CVector3D worldspace = (*it)->m_graphics_position; float x, y; @@ -723,6 +728,23 @@ void CMouseoverEntities::update( float timestep ) void CMouseoverEntities::addSelection() { + // Rules for shift-click selection: + + // If selecting a non-allied unit, you can only select one. You can't + // select a mix of allied and non-allied units. Therefore: + // Forbid shift-click of enemy units unless the selection is empty + // Forbid shift-click of allied units if the selection contains one + // or more enemy units. + + if( ( m_mouseover.size() != 0 ) && + ( m_mouseover.front().entity->GetPlayer() != g_Game->GetLocalPlayer() ) && + ( g_Selection.m_selected.size() != 0 ) ) + return; + + if( ( g_Selection.m_selected.size() != 0 ) && + ( g_Selection.m_selected.front()->GetPlayer() != g_Game->GetLocalPlayer() ) ) + return; + std::vector::iterator it; for( it = m_mouseover.begin(); it < m_mouseover.end(); it++ ) if( it->isActive && !g_Selection.isSelected( it->entity ) ) @@ -745,7 +767,8 @@ void CMouseoverEntities::setSelection() void CMouseoverEntities::expandAcrossScreen() { - std::vector* activeset = g_EntityManager.matches( isMouseoverType, isOnScreen ); + std::vector* activeset = g_EntityManager.matches( + CEntityManager::EntityPredicateLogicalAnd ); m_mouseover.clear(); std::vector::iterator it; for( it = activeset->begin(); it < activeset->end(); it++ ) @@ -987,7 +1010,7 @@ int interactInputHandler( const SDL_Event* ev ) return( EV_PASS ); } -bool isOnScreen( CEntity* ev ) +bool isOnScreen( CEntity* ev, void* userdata ) { CCamera *pCamera=g_Game->GetView()->GetCamera(); @@ -1000,7 +1023,7 @@ bool isOnScreen( CEntity* ev ) return( frustum.IsBoxVisible( ev->m_graphics_position, CBound() ) ); } -bool isMouseoverType( CEntity* ev ) +bool isMouseoverType( CEntity* ev, void* userdata ) { std::vector::iterator it; for( it = g_Mouseover.m_mouseover.begin(); it < g_Mouseover.m_mouseover.end(); it++ ) @@ -1009,30 +1032,4 @@ bool isMouseoverType( CEntity* ev ) return( true ); } return( false ); -} - -/* -void pushCameraTarget( const CVector3D& target ) -{ - // Save the current position - cameraTargets.push_back( g_Camera.m_Orientation.GetTranslation() ); - // And set the camera - setCameraTarget( target ); -} - -void setCameraTarget( const CVector3D& target ) -{ - // Maintain the same orientation and level of zoom, if we can - // (do this by working out the point the camera is looking at, saving - // the difference beteen that position and the camera point, and restoring - // that difference to our new target) - - cameraDelta = target - g_Camera.GetFocus(); -} - -void popCameraTarget() -{ - cameraDelta = cameraTargets.back() - g_Camera.m_Orientation.GetTranslation(); - cameraTargets.pop_back(); -} -*/ +} \ No newline at end of file diff --git a/source/ps/Interact.h b/source/ps/Interact.h index 62bc89ec87..9820498be2 100755 --- a/source/ps/Interact.h +++ b/source/ps/Interact.h @@ -118,8 +118,8 @@ struct CMouseoverEntities : public Singleton void stopBandbox(); }; -bool isMouseoverType( CEntity* ev ); -bool isOnScreen( CEntity* ev ); +bool isMouseoverType( CEntity* ev, void* userdata ); +bool isOnScreen( CEntity* ev, void* userdata ); int interactInputHandler( const SDL_Event* ev ); diff --git a/source/ps/Network/Client.cpp b/source/ps/Network/Client.cpp index 37cb262cb3..b1fcc03062 100755 --- a/source/ps/Network/Client.cpp +++ b/source/ps/Network/Client.cpp @@ -43,17 +43,6 @@ CNetClient::CNetClient(CGame *pGame, CGameAttributes *pGameAttribs): m_pGame->GetSimulation()->SetTurnManager(this); - AddProperty(L"onStartGame", &m_OnStartGame); - AddProperty(L"onChat", &m_OnChat); - AddProperty(L"onConnectComplete", &m_OnConnectComplete); - AddProperty(L"onDisconnect", &m_OnDisconnect); - AddProperty(L"onClientConnect", &m_OnClientConnect); - AddProperty(L"onClientDisconnect", &m_OnClientDisconnect); - - AddProperty(L"password", &m_Password); - AddProperty(L"playerName", &m_Name); - AddProperty(L"sessions", &m_JSI_ServerSessions); - g_ScriptingHost.SetGlobal("g_NetClient", OBJECT_TO_JSVAL(GetScript())); } @@ -66,6 +55,20 @@ void CNetClient::ScriptingInit() { AddMethod("beginConnect", 1); + + + AddClassProperty(L"onStartGame", &CNetClient::m_OnStartGame); + AddClassProperty(L"onChat", &CNetClient::m_OnChat); + AddClassProperty(L"onConnectComplete", &CNetClient::m_OnConnectComplete); + AddClassProperty(L"onDisconnect", &CNetClient::m_OnDisconnect); + AddClassProperty(L"onClientConnect", &CNetClient::m_OnClientConnect); + AddClassProperty(L"onClientDisconnect", &CNetClient::m_OnClientDisconnect); + + + AddClassProperty(L"password", &CNetClient::m_Password); + AddClassProperty(L"playerName", &CNetClient::m_Name); + + AddClassProperty(L"sessions", &CNetClient::m_JSI_ServerSessions); CJSMap::ScriptingInit("NetClient_SessionMap"); CJSObject::ScriptingInit("NetClient"); } diff --git a/source/ps/Network/Session.h b/source/ps/Network/Session.h index bd708decfe..4462ad1154 100755 --- a/source/ps/Network/Session.h +++ b/source/ps/Network/Session.h @@ -13,6 +13,7 @@ */ class CNetSession: public CMessageSocket { + friend class CNetClient; protected: /* The MessageHandler callback follows the contract of HandleMessage, see diff --git a/source/ps/Player.cpp b/source/ps/Player.cpp index b31f17e142..934f5adbe9 100755 --- a/source/ps/Player.cpp +++ b/source/ps/Player.cpp @@ -12,8 +12,6 @@ CPlayer::CPlayer(uint playerID): m_Colour(0.7f, 0.7f, 0.7f), m_UpdateCB(0) { - AddReadOnlyProperty( L"id", &m_PlayerID ); - AddProperty( L"controlled", (GetFn)&CPlayer::JSI_GetControlledEntities); AddSynchedProperty( L"name", &m_Name ); // HACK - since we have to use setColour to update this, we don't want to // expose a colour property. Meanwhile, we want to have a property "colour" @@ -22,6 +20,7 @@ CPlayer::CPlayer(uint playerID): // to CJSObject's list ISynchedJSProperty *prop=new CSynchedJSProperty(L"colour", &m_Colour, this); m_SynchedProperties[L"colour"]=prop; + } CPlayer::~CPlayer() @@ -35,6 +34,14 @@ void CPlayer::ScriptingInit() { AddMethod( "toString", 0 ); AddMethod( "setColour", 1); + + AddReadOnlyClassProperty( L"id", &CPlayer::m_PlayerID ); + // MT: Work out how this fits with the Synched stuff... + + // AddClassProperty( L"name", &CPlayer::m_Name ); + // AddClassProperty( L"colour", &CPlayer::m_Colour ); + AddClassProperty( L"controlled", (IJSObject::GetFn)JSI_GetControlledEntities ); + CJSObject::ScriptingInit( "Player" ); } diff --git a/source/ps/Profile.cpp b/source/ps/Profile.cpp new file mode 100644 index 0000000000..b95a1d188c --- /dev/null +++ b/source/ps/Profile.cpp @@ -0,0 +1,250 @@ +#include "precompiled.h" + +#include "Profile.h" + +// Note: As with the GPG profiler, name is assumed to be a pointer to a constant string; only pointer equality is checked. +CProfileNode::CProfileNode( const char* _name, CProfileNode* _parent ) +{ + name = _name; + recursion = 0; + calls_total = 0; + calls_frame_current = 0; +#ifdef PROFILE_AMORTIZE + int i; + for( i = 0; i < PROFILE_AMORTIZE_FRAMES; i++ ) + { + calls_frame_buffer[i] = 0; + time_frame_buffer[i] = 0.0; + } + calls_frame_last = calls_frame_buffer; + calls_frame_amortized = 0.0f; +#else + calls_frame_last = 0; +#endif + time_total = 0.0; + time_frame_current = 0.0; +#ifdef PROFILE_AMORTIZE + time_frame_last = time_frame_buffer; + time_frame_amortized = 0.0; +#else + time_frame_last = 0.0; +#endif + parent = _parent; + + Reset(); +} + +CProfileNode::~CProfileNode() +{ + profile_iterator it; + for( it = children.begin(); it != children.end(); it++ ) + delete( *it ); + for( it = script_children.begin(); it != script_children.end(); it++ ) + delete( *it ); +} + +const CProfileNode* CProfileNode::GetChild( const char* childName ) const +{ + const_profile_iterator it; + for( it = children.begin(); it != children.end(); it++ ) + if( (*it)->name == childName ) + return( *it ); + + return( NULL ); +} + +const CProfileNode* CProfileNode::GetScriptChild( const char* childName ) const +{ + const_profile_iterator it; + for( it = script_children.begin(); it != script_children.end(); it++ ) + if( (*it)->name == childName ) + return( *it ); + + return( NULL ); +} + +CProfileNode* CProfileNode::GetChild( const char* childName ) +{ + profile_iterator it; + for( it = children.begin(); it != children.end(); it++ ) + if( (*it)->name == childName ) + return( *it ); + + CProfileNode* newNode = new CProfileNode( childName, this ); + children.push_back( newNode ); + return( newNode ); +} + +CProfileNode* CProfileNode::GetScriptChild( const char* childName ) +{ + profile_iterator it; + for( it = script_children.begin(); it != script_children.end(); it++ ) + if( (*it)->name == childName ) + return( *it ); + + CProfileNode* newNode = new CProfileNode( childName, this ); + script_children.push_back( newNode ); + return( newNode ); +} + +bool CProfileNode::CanExpand() +{ + return( !( children.empty() && script_children.empty() ) ); +} + +void CProfileNode::Reset() +{ + calls_total = 0; + calls_frame_current = 0; +#ifdef PROFILE_AMORTIZE + int i; + for( i = 0; i < PROFILE_AMORTIZE_FRAMES; i++ ) + { + calls_frame_buffer[i] = 0; + time_frame_buffer[i] = 0.0; + } + calls_frame_last = calls_frame_buffer; + calls_frame_amortized = 0.0f; +#else + calls_frame_last = 0; +#endif + time_total = 0.0; + time_frame_current = 0.0; +#ifdef PROFILE_AMORTIZE + time_frame_last = time_frame_buffer; + time_frame_amortized = 0.0; +#else + time_frame_last = 0.0; +#endif + + profile_iterator it; + for( it = children.begin(); it != children.end(); it++ ) + (*it)->Reset(); + for( it = script_children.begin(); it != script_children.end(); it++ ) + (*it)->Reset(); +} + +void CProfileNode::Frame() +{ + calls_total += calls_frame_current; + time_total += time_frame_current; + +#ifdef PROFILE_AMORTIZE + calls_frame_amortized -= *calls_frame_last; + *calls_frame_last = calls_frame_current; + calls_frame_amortized += calls_frame_current; + time_frame_amortized -= *time_frame_last; + *time_frame_last = time_frame_current; + time_frame_amortized += time_frame_current; + if( ++calls_frame_last == ( calls_frame_buffer + PROFILE_AMORTIZE_FRAMES ) ) + calls_frame_last = calls_frame_buffer; + if( ++time_frame_last == ( time_frame_buffer + PROFILE_AMORTIZE_FRAMES ) ) + time_frame_last = time_frame_buffer; +#else + calls_frame_last = calls_frame_current; + time_frame_last = time_frame_current; +#endif + + calls_frame_current = 0; + time_frame_current = 0.0; + + profile_iterator it; + for( it = children.begin(); it != children.end(); it++ ) + (*it)->Frame(); + for( it = script_children.begin(); it != script_children.end(); it++ ) + (*it)->Frame(); +} + +void CProfileNode::Call() +{ + calls_frame_current++; + if( recursion++ == 0 ) + start = get_time(); +} + +bool CProfileNode::Return() +{ + if( !parent ) return( false ); + + if( ( --recursion == 0 ) && ( calls_frame_current != 0 ) ) + time_frame_current += ( get_time() - start ); + return( recursion == 0 ); +} + +void CProfileNode::ScriptingInit() +{ + AddClassProperty( L"name", (IJSObject::GetFn)CProfileNode::JS_GetName ); + /* + AddReadOnlyClassProperty( L"callsTotal", &CProfileNode::calls_total ); + AddReadOnlyClassProperty( L"callsPerFrame", &CProfileNode::calls_frame_last ); + AddReadOnlyClassProperty( L"timeTotal", &CProfileNode::time_total ); + AddReadOnlyClassProperty( L"timePerFrame", &CProfileNode::time_frame_last ); + */ + CJSObject::ScriptingInit( "ProfilerNode" ); +} + +CProfileManager::CProfileManager() +{ + root = new CProfileNode( "root", NULL ); + current = root; + frame_start = 0.0; +} + +CProfileManager::~CProfileManager() +{ + delete( root ); +} + +void CProfileManager::Start( const char* name ) +{ + if( name != current->GetName() ) + current = current->GetChild( name ); + current->Call(); +} + +void CProfileManager::StartScript( const char* name ) +{ + if( name != current->GetName() ) + current = current->GetScriptChild( name ); + current->Call(); +} + +void CProfileManager::Stop() +{ + if( current->Return() ) + current = current->GetParent(); +} + +void CProfileManager::Reset() +{ + root->Reset(); + start = get_time(); + frame_start = get_time(); +} + +void CProfileManager::Frame() +{ + root->time_frame_current = ( get_time() - frame_start ); + root->Frame(); + + frame_start = get_time(); +} + +void CProfileManager::StructuralReset() +{ + delete( root ); + root = new CProfileNode( "root", NULL ); + current = root; + ResetProfileViewer(); +} + +double CProfileManager::GetTime() +{ + return( get_time() - start ); +} + +double CProfileManager::GetFrameTime() +{ + return( get_time() - frame_start ); +} + diff --git a/source/ps/Profile.h b/source/ps/Profile.h new file mode 100644 index 0000000000..79240277f1 --- /dev/null +++ b/source/ps/Profile.h @@ -0,0 +1,147 @@ +// Profile.h +// +// GPG3-style hierarchical profiler +// +// Mark Thompson (mark@wildfiregames.com / mot20@cam.ac.uk) + +#include +#include "Singleton.h" +#include "scripting/ScriptableObject.h" +#include "timer.h" + +// TODO: Shouldn't depend on this. +#include "ProfileViewer.h" + +#define PROFILE_AMORTIZE +#define PROFILE_AMORTIZE_FRAMES 50 + +class CProfileManager; + +class CProfileNode : public CJSObject +{ + friend class CProfileManager; + + const char* name; + int calls_total; + int calls_frame_current; +#ifdef PROFILE_AMORTIZE + int calls_frame_buffer[PROFILE_AMORTIZE_FRAMES]; + int* calls_frame_last; + float calls_frame_amortized; +#else + int calls_frame_last; +#endif + double time_total; + double time_frame_current; +#ifdef PROFILE_AMORTIZE + double time_frame_buffer[PROFILE_AMORTIZE_FRAMES]; + double* time_frame_last; + double time_frame_amortized; +#else + double time_frame_last; +#endif + + double start; + int recursion; + + CProfileNode* parent; + std::vector children; + std::vector script_children; + +public: + typedef std::vector::iterator profile_iterator; + typedef std::vector::const_iterator const_profile_iterator; + + CProfileNode( const char* name, CProfileNode* parent ); + ~CProfileNode(); + + const char* GetName() const { return( name ); } + int GetCalls() const { return( calls_total ); } + double GetTime() const { return( time_total ); } + +#ifdef PROFILE_AMORTIZE + float GetFrameCalls() const { return( calls_frame_amortized / PROFILE_AMORTIZE_FRAMES ); } + double GetFrameTime() const { return( time_frame_amortized / PROFILE_AMORTIZE_FRAMES ); } +#else + int GetFrameCalls() const { return( calls_frame_last ); } + double GetFrameTime() const { return( time_frame_last ); } +#endif + + const CProfileNode* GetChild( const char* name ) const; + const CProfileNode* GetScriptChild( const char* name ) const; + const std::vector* GetChildren() const { return( &children ); } + const std::vector* GetScriptChildren() const { return( &script_children ); } + + bool CanExpand(); + + CProfileNode* GetChild( const char* name ); + CProfileNode* GetScriptChild( const char* name ); + CProfileNode* GetParent() const { return( parent ); } + + // Resets timing information for this node and all its children + void Reset(); + // Resets frame timings for this node and all its children + void Frame(); + // Enters the node + void Call(); + // Leaves the node. Returns true if the node has actually been left + bool Return(); + +// Javascript stuff... + + static void ScriptingInit(); + jsval JS_GetName() { return( ToJSVal( CStrW( name ) ) ); } +}; + +class CProfileManager : public Singleton +{ + CProfileNode* root; + CProfileNode* current; + double start; + double frame_start; + +public: + CProfileManager(); + ~CProfileManager(); + + // Begins timing for a named subsection + void Start( const char* name ); + void StartScript( const char* name ); + + // Ends timing for the current subsection + void Stop(); + + // Resets all timing information + void Reset(); + // Resets frame timing information + void Frame(); + // Resets absolutely everything + void StructuralReset(); + + inline const CProfileNode* GetCurrent() { return( current ); } + inline const CProfileNode* GetRoot() { return( root ); } + double GetTime(); + double GetFrameTime(); +}; + +#define g_Profiler CProfileManager::GetSingleton() + +class CProfileSample +{ +public: + CProfileSample( const char* name ) + { + g_Profiler.Start( name ); + } + ~CProfileSample() + { + g_Profiler.Stop(); + } +}; + +// Put a PROFILE( xyz ) block at the start of all code to be profiled. +// Profile blocks last until the end of the containing scope. +#define PROFILE( name ) CProfileSample __profile( name ) +// Cheat a bit to make things slightly easier on the user +#define PROFILE_START( name ) { CProfileSample __profile( name ) +#define PROFILE_END( name ) } diff --git a/source/ps/ProfileViewer.cpp b/source/ps/ProfileViewer.cpp new file mode 100644 index 0000000000..9d3763b928 --- /dev/null +++ b/source/ps/ProfileViewer.cpp @@ -0,0 +1,196 @@ +#include "precompiled.h" +#include "ProfileViewer.h" +#include "Profile.h" +#include "Renderer.h" +#include "res/unifont.h" +#include "Hotkey.h" + +bool profileVisible = true; +extern int g_xres, g_yres; + +const CProfileNode* currentNode = NULL; + +void ResetProfileViewer() +{ + currentNode = NULL; +} + +void RenderProfileNode( CProfileNode* node, int currentNodeid ) +{ + glPushMatrix(); + if( node->CanExpand() ) + { + glPushMatrix(); + glTranslatef( -15.0f, 0.0f, 0.0f ); + glwprintf( L"%d", currentNodeid ); + glPopMatrix(); + } + + glPushMatrix(); + glwprintf( L"%hs", node->GetName() ); + glPopMatrix(); + glTranslatef( 230.0f, 0.0f, 0.0f ); + glPushMatrix(); +#ifdef PROFILE_AMORTIZE + glwprintf( L"%.3f", node->GetFrameCalls() ); +#else + glwprintf( L"%d", node->GetFrameCalls() ); +#endif + glPopMatrix(); + glTranslatef( 100.0f, 0.0f, 0.0f ); + glPushMatrix(); + glwprintf( L"%.3f", node->GetFrameTime() * 1000.0f ); + glPopMatrix(); + glTranslatef( 100.0f, 0.0f, 0.0f ); + glPushMatrix(); + + glwprintf( L"%.1f", node->GetFrameTime() * 100.0 / g_Profiler.GetRoot()->GetFrameTime() ); + glPopMatrix(); + glTranslatef( 100.0f, 0.0f, 0.0f ); + glPushMatrix(); + glwprintf( L"%.1f", node->GetFrameTime() * 100.0 / currentNode->GetFrameTime() ); + glPopMatrix(); + glPopMatrix(); + + glTranslatef( 0.0f, 20.0f, 0.0f ); +} + +void RenderProfile() +{ + if( !profileVisible ) return; + if( !currentNode ) currentNode = g_Profiler.GetRoot(); + + glPushMatrix(); + glColor3f(1.0f, 1.0f, 1.0f); + + glTranslatef(2.0f, g_yres - 20.0f, 0.0f ); + glScalef(1.0f, -1.0f, 1.0f); + + glPushMatrix(); + glwprintf( L"Profiling Information for: %hs (Time in node: %.3f msec/frame)", currentNode->GetName(), currentNode->GetFrameTime() * 1000.0f ); + glPopMatrix(); + glTranslatef( 20.0f, 20.0f, 0.0f ); + glPushMatrix(); + glPushMatrix(); + glwprintf( L"Name" ); + glPopMatrix(); + glTranslatef( 230.0f, 0.0f, 0.0f ); + glPushMatrix(); + glwprintf( L"calls/frame" ); + glPopMatrix(); + glTranslatef( 100.0f, 0.0f, 0.0f ); + glPushMatrix(); + glwprintf( L"msec/frame" ); + glPopMatrix(); + glTranslatef( 100.0f, 0.0f, 0.0f ); + glPushMatrix(); + glwprintf( L"%%/frame" ); + glPopMatrix(); + glTranslatef( 100.0f, 0.0f, 0.0f ); + glPushMatrix(); + glwprintf( L"%%/parent" ); + glPopMatrix(); + glPopMatrix(); + + + CProfileNode::const_profile_iterator it; + + glTranslatef( 0.0f, 20.0f, 0.0f ); + + float unlogged = currentNode->GetFrameTime(); + + int currentNodeid = 1; + + for( it = currentNode->GetChildren()->begin(); it != currentNode->GetChildren()->end(); it++, currentNodeid++ ) + { + unlogged -= (*it)->GetFrameTime(); + RenderProfileNode( *it, currentNodeid ); + } + glColor3f( 1.0f, 0.5f, 0.5f ); + for( it = currentNode->GetScriptChildren()->begin(); it != currentNode->GetScriptChildren()->end(); it++, currentNodeid++ ) + { + unlogged -= (*it)->GetFrameTime(); + RenderProfileNode( *it, currentNodeid ); + } + glColor3f( 1.0f, 1.0f, 1.0f ); + + glTranslatef( 0.0f, 20.0f, 0.0f ); + glPushMatrix(); + + glPushMatrix(); + glwprintf( L"unlogged" ); + glPopMatrix(); + glTranslatef( 330.0f, 0.0f, 0.0f ); + glPushMatrix(); + glwprintf( L"%.3f", unlogged * 1000.0f ); + glPopMatrix(); + glTranslatef( 100.0f, 0.0f, 0.0f ); + glPushMatrix(); + glwprintf( L"%.1f", ( unlogged / g_Profiler.GetRoot()->GetFrameTime() ) * 100.0f ); + glPopMatrix(); + glTranslatef( 100.0f, 0.0f, 0.0f ); + glPushMatrix(); + glwprintf( L"%.1f", ( unlogged / currentNode->GetFrameTime() ) * 100.0f ); + glPopMatrix(); + glPopMatrix(); + + if( currentNode->GetParent() ) + { + glTranslatef( 0.0f, 20.0f, 0.0f ); + glPushMatrix(); + glPushMatrix(); + glTranslatef( -15.0f, 0.0f, 0.0f ); + glwprintf( L"0" ); + glPopMatrix(); + glwprintf( L"back to parent" ); + glPopMatrix(); + } + + glPopMatrix(); +} + +int profilehandler( const SDL_Event* ev ) +{ + switch( ev->type ) + { + case SDL_KEYDOWN: + { + if( profileVisible ) + { + int k = ev->key.keysym.sym - SDLK_0; + if( k == 0 ) + { + if( currentNode->GetParent() ) + currentNode = currentNode->GetParent(); + } + else if( ( k >= 1 ) && ( k <= 9 ) ) + { + k--; + CProfileNode::const_profile_iterator it; + for( it = currentNode->GetChildren()->begin(); it != currentNode->GetChildren()->end(); it++, k-- ) + if( (*it)->CanExpand() && !k ) + { + currentNode = (*it); + return( EV_HANDLED ); + } + for( it = currentNode->GetScriptChildren()->begin(); it != currentNode->GetScriptChildren()->end(); it++, k-- ) + if( (*it)->CanExpand() && !k ) + { + currentNode = (*it); + return( EV_HANDLED ); + } + return( EV_HANDLED ); + } + } + break; + } + case SDL_HOTKEYDOWN: + if( ev->user.code == HOTKEY_PROFILE_TOGGLE ) + { + profileVisible = !profileVisible; + return( EV_HANDLED ); + } + break; + } + return( EV_PASS ); +} \ No newline at end of file diff --git a/source/ps/ProfileViewer.h b/source/ps/ProfileViewer.h new file mode 100644 index 0000000000..d848f6c5e7 --- /dev/null +++ b/source/ps/ProfileViewer.h @@ -0,0 +1,14 @@ +// ProfileViewer.h +// +// A temporary interface for viewing profile information + +#ifndef PROFILE_VIEWER_INCLUDED +#define PROFILE_VIEWER_INCLUDED + +#include "input.h" + +void ResetProfileViewer(); +void RenderProfile(); +int profilehandler( const SDL_Event* ev ); + +#endif \ No newline at end of file diff --git a/source/ps/World.cpp b/source/ps/World.cpp index 1acc921af0..99b1c31004 100755 --- a/source/ps/World.cpp +++ b/source/ps/World.cpp @@ -32,6 +32,7 @@ void CWorld::Initialize(CGameAttributes *pAttribs) mapfilename += (CStr)pAttribs->m_MapFile; CMapReader* reader = 0; + try { reader = new CMapReader; reader->LoadMap(mapfilename, &m_Terrain, &m_UnitManager, &g_LightEnv); diff --git a/source/scripting/JSConversions.h b/source/scripting/JSConversions.h index d16195932c..19e906e3e9 100755 --- a/source/scripting/JSConversions.h +++ b/source/scripting/JSConversions.h @@ -140,6 +140,13 @@ template<> bool ToPrimitive( JSContext* cx, jsval v, bool& Storage ); template<> jsval ToJSVal( const bool& Native ); template<> jsval ToJSVal( bool& Native ); +/* +// char* +template<> bool ToPrimitive( JSContext* cx, jsval v, char*& Storage ); +template<> jsval ToJSVal( const char* Native ); +template<> jsval ToJSVal( char* Native ); +*/ + // CStrW template<> bool ToPrimitive( JSContext* cx, jsval v, CStrW& Storage ); template<> jsval ToJSVal( const CStrW& Native ); diff --git a/source/scripting/ScriptCustomTypes.cpp b/source/scripting/ScriptCustomTypes.cpp index 523feae9d0..8c32544090 100755 --- a/source/scripting/ScriptCustomTypes.cpp +++ b/source/scripting/ScriptCustomTypes.cpp @@ -42,17 +42,17 @@ JSBool Point2d_Constructor(JSContext* UNUSEDPARAM(cx), JSObject* obj, uintN argc void SColour::SColourInit( float _r, float _g, float _b, float _a ) { - AddProperty( L"r", &r ); - AddProperty( L"g", &g ); - AddProperty( L"b", &b ); - AddProperty( L"a", &a ); - r = _r; g = _g; b = _b; a = _a; } void SColour::ScriptingInit() { AddMethod( "toString", 0 ); + AddClassProperty( L"r", (float IJSObject::*)&SColour::r ); + AddClassProperty( L"g", (float IJSObject::*)&SColour::g ); + AddClassProperty( L"b", (float IJSObject::*)&SColour::b ); + AddClassProperty( L"a", (float IJSObject::*)&SColour::a ); + CJSObject::ScriptingInit( "Colour", SColour::Construct, 3 ); } diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp index 5556dbf9f7..10db4d82cf 100755 --- a/source/scripting/ScriptGlue.cpp +++ b/source/scripting/ScriptGlue.cpp @@ -95,7 +95,8 @@ JSPropertySpec ScriptGlobalTable[] = { "console", GLOBAL_CONSOLE, JSPROP_PERMANENT | JSPROP_READONLY, JSI_Console::getConsole, NULL }, { "entities", 0, JSPROP_PERMANENT | JSPROP_READONLY, GetEntitySet, NULL }, { "players", 0, JSPROP_PERMANENT | JSPROP_READONLY, GetPlayerSet, NULL }, - { "localPlayer", 0, JSPROP_PERMANENT | JSPROP_READONLY, GetLocalPlayer, NULL }, + { "localPlayer", 0, JSPROP_PERMANENT, GetLocalPlayer, SetLocalPlayer }, + { "gaiaPlayer", 0, JSPROP_PERMANENT | JSPROP_READONLY, GetGaiaPlayer, NULL }, { 0, 0, 0, 0, 0 }, }; @@ -191,7 +192,7 @@ JSBool GetEntitySet( JSContext* context, JSObject* globalObject, jsval argv, jsv return( JS_TRUE ); } -JSBool GetPlayerSet( JSContext* cx, JSObject* globalObject, jsval argv, jsval* vp ) +JSBool GetPlayerSet( JSContext* cx, JSObject* globalObject, jsval id, jsval* vp ) { std::vector* players = g_Game->GetPlayers(); @@ -200,10 +201,29 @@ JSBool GetPlayerSet( JSContext* cx, JSObject* globalObject, jsval argv, jsval* v return( JS_TRUE ); } -JSBool GetLocalPlayer( JSContext* cx, JSObject* globalObject, jsval argv, jsval* vp ) +JSBool GetLocalPlayer( JSContext* cx, JSObject* globalObject, jsval id, jsval* vp ) { *vp = OBJECT_TO_JSVAL( g_Game->GetLocalPlayer()->GetScript() ); + return( JS_TRUE ); +} +JSBool GetGaiaPlayer( JSContext* cx, JSObject* globalObject, jsval id, jsval* vp ) +{ + *vp = OBJECT_TO_JSVAL( g_Game->GetPlayer( 0 )->GetScript() ); + return( JS_TRUE ); +} + +JSBool SetLocalPlayer( JSContext* context, JSObject* obj, jsval id, jsval* vp ) +{ + CPlayer* newLocalPlayer = ToNative( *vp ); + + if( !newLocalPlayer ) + { + JS_ReportError( context, "Not a valid Player." ); + return( JS_TRUE ); + } + + g_Game->SetLocalPlayer( newLocalPlayer ); return( JS_TRUE ); } diff --git a/source/scripting/ScriptGlue.h b/source/scripting/ScriptGlue.h index 9b76a54b8f..4c76407b03 100755 --- a/source/scripting/ScriptGlue.h +++ b/source/scripting/ScriptGlue.h @@ -13,10 +13,13 @@ JSFunc WriteLog; // Entity JSFunc getEntityByHandle; JSFunc getEntityTemplate; -JSBool GetEntitySet( JSContext* context, JSObject* globalObject, jsval argv, jsval* vp ); +JSBool GetEntitySet( JSContext* context, JSObject* globalObject, jsval id, jsval* vp ); // Player -JSBool GetPlayerSet( JSContext* context, JSObject* globalObject, jsval argv, jsval* vp ); +JSBool GetPlayerSet( JSContext* context, JSObject* globalObject, jsval id, jsval* vp ); +JSBool GetLocalPlayer( JSContext* context, JSObject* globalObject, jsval id, jsval* vp ); +JSBool SetLocalPlayer( JSContext* context, JSObject* globalObject, jsval id, jsval* vp ); +JSBool GetGaiaPlayer( JSContext* context, JSObject* globalObject, jsval id, jsval* vp ); JSBool GetLocalPlayer( JSContext* context, JSObject* globalObject, jsval argv, jsval* vp ); // Camera diff --git a/source/scripting/ScriptableObject.h b/source/scripting/ScriptableObject.h index 3b29239ce4..0321e06c69 100755 --- a/source/scripting/ScriptableObject.h +++ b/source/scripting/ScriptableObject.h @@ -41,6 +41,8 @@ #ifndef SCRIPTABLE_INCLUDED #define SCRIPTABLE_INCLUDED +class IJSObject; + class IJSProperty { public: @@ -56,15 +58,15 @@ public: m_Intrinsic(true) {} - virtual jsval Get( JSContext* cx ) = 0; - virtual void Set( JSContext* cx, jsval Value ) = 0; + virtual jsval Get( JSContext* cx, IJSObject* owner ) = 0; + virtual void Set( JSContext* cx, IJSObject* owner, jsval Value ) = 0; // Copies the data directly out of a parent property // Warning: Don't use if you're not certain the properties are not of the same type. - virtual void ImmediateCopy( IJSProperty* Copy ) = 0; + virtual void ImmediateCopy( IJSObject* CopyTo, IJSObject* CopyFrom, IJSProperty* CopyProperty ) = 0; - jsval Get() { return( Get( g_ScriptingHost.GetContext() ) ); } - void Set( jsval Value ) { return( Set( g_ScriptingHost.GetContext(), Value ) ); } + jsval Get( IJSObject* owner ) { return( Get( g_ScriptingHost.GetContext(), owner ) ); } + void Set( IJSObject* owner, jsval Value ) { return( Set( g_ScriptingHost.GetContext(), owner, Value ) ); } virtual ~IJSProperty() {} }; @@ -175,7 +177,7 @@ public: Property = Target->HasProperty( Instance->m_PropertyRoot ); if( Property ) { - *rval = Property->Get( cx ); + *rval = Property->Get( cx, Target ); break; } Target = Target->m_Parent; @@ -199,7 +201,7 @@ public: Property = Target->HasProperty( Instance->m_PropertyRoot ); if( Property ) { - str = JS_ValueToString( cx, Property->Get( cx ) ); + str = JS_ValueToString( cx, Property->Get( cx, Target ) ); break; } Target = Target->m_Parent; @@ -228,11 +230,10 @@ template JSClass CJSPropertyAccessor::JSI_Class = { NULL, NULL, NULL, NULL }; -template class CJSProperty : public IJSProperty -{ - T* m_Data; - IJSObject* m_Owner; +template class CJSSharedProperty : public IJSProperty +{ + T IJSObject::*m_Data; // Function on Owner to call after value is changed IJSObject::NotifyFn m_Update; @@ -241,32 +242,71 @@ template class CJSProperty : public IJSProperty IJSObject::NotifyFn m_Freshen; public: - CJSProperty( T* Data, IJSObject* Owner = NULL, bool AllowsInheritance = false, IJSObject::NotifyFn Update = NULL, IJSObject::NotifyFn Freshen = NULL ) + CJSSharedProperty( T IJSObject::*Data, bool AllowsInheritance = false, IJSObject::NotifyFn Update = NULL, IJSObject::NotifyFn Freshen = NULL ) + { + m_Data = Data; + m_AllowsInheritance = AllowsInheritance; + m_Update = Update; + m_Freshen = Freshen; + m_Intrinsic = true; + m_Inherited = true; + } + jsval Get( JSContext* cx, IJSObject* owner ) + { + if( m_Freshen ) (owner->*m_Freshen)(); + return( ToJSVal( owner->*m_Data ) ); + } + void ImmediateCopy( IJSObject* CopyTo, IJSObject* CopyFrom, IJSProperty* CopyProperty ) + { + assert( "Inheritance not supported for CJSSharedProperties" ); + } + void Set( JSContext* cx, IJSObject* owner, jsval Value ) + { + if( !ReadOnly ) + { + if( m_Freshen ) (owner->*m_Freshen)(); + if( ToPrimitive( cx, Value, owner->*m_Data ) ) + if( m_Update ) (owner->*m_Update)(); + } + } + +}; + +template class CJSProperty : public IJSProperty +{ + T* m_Data; + + // Function on Owner to call after value is changed + IJSObject::NotifyFn m_Update; + + // Function on Owner to call before reading or writing the value + IJSObject::NotifyFn m_Freshen; + +public: + CJSProperty( T* Data, bool AllowsInheritance = false, IJSObject::NotifyFn Update = NULL, IJSObject::NotifyFn Freshen = NULL ) { - assert( !( !Owner && ( Freshen || Update ) ) ); // Bad programmer. m_Data = Data; - m_Owner = Owner; m_AllowsInheritance = AllowsInheritance; m_Update = Update; m_Freshen = Freshen; m_Intrinsic = true; } - jsval Get( JSContext* cx ) + jsval Get( JSContext* cx, IJSObject* owner ) { - if( m_Freshen ) (m_Owner->*m_Freshen)(); + if( m_Freshen ) (owner->*m_Freshen)(); return( ToJSVal( *m_Data ) ); } - void ImmediateCopy( IJSProperty* Copy ) + void ImmediateCopy( IJSObject* CopyTo, IJSObject* CopyFrom, IJSProperty* CopyProperty ) { - *m_Data = *( ((CJSProperty*)Copy)->m_Data ); + *m_Data = *( ( (CJSProperty*)CopyProperty )->m_Data ); } - void Set( JSContext* cx, jsval Value ) + void Set( JSContext* cx, IJSObject* owner, jsval Value ) { if( !ReadOnly ) { - if( m_Freshen ) (m_Owner->*m_Freshen)(); + if( m_Freshen ) (owner->*m_Freshen)(); if( ToPrimitive( cx, Value, *m_Data ) ) - if( m_Update ) (m_Owner->*m_Update)(); + if( m_Update ) (owner->*m_Update)(); } } @@ -288,6 +328,7 @@ public: { m_JSAccessor = NULL; m_Intrinsic = false; + m_Inherited = false; } }; @@ -322,28 +363,24 @@ public: if( JSVAL_IS_GCTHING( m_Data ) ) JS_RemoveRoot( g_ScriptingHost.GetContext(), (void*)&m_Data ); } - jsval Get( JSContext* cx ) + jsval Get( JSContext* cx, IJSObject* owner ) { return( m_Data ); } - void Set( JSContext* cx, jsval Value ) + void Set( JSContext* cx, IJSObject* owner, jsval Value ) { Uproot(); m_Data = Value; Root(); } - void ImmediateCopy( IJSProperty* Copy ) + void ImmediateCopy( IJSObject* CopyTo, IJSObject* CopyFrom, IJSProperty* CopyProperty ) { - Uproot(); - m_Data = ((CJSValProperty*)Copy)->m_Data; - Root(); + assert( 0 && "ImmediateCopy called on a CJSValProperty (something's gone wrong with the inheritance on this object)" ); } }; class CJSFunctionProperty : public IJSProperty { - IJSObject* m_Owner; - // Function on Owner to get the value IJSObject::GetFn m_Getter; @@ -351,28 +388,27 @@ class CJSFunctionProperty : public IJSProperty IJSObject::SetFn m_Setter; public: - CJSFunctionProperty( IJSObject* Owner, IJSObject::GetFn Getter, IJSObject::SetFn Setter ) + CJSFunctionProperty( IJSObject::GetFn Getter, IJSObject::SetFn Setter ) { m_Inherited = false; m_Intrinsic = true; - m_Owner = Owner; m_Getter = Getter; m_Setter = Setter; // Must at least be able to read - assert( m_Owner && m_Getter ); + assert( m_Getter ); } - jsval Get( JSContext* cx ) + jsval Get( JSContext* cx, IJSObject* owner ) { - return( (m_Owner->*m_Getter)() ); + return( (owner->*m_Getter)() ); } - void Set( JSContext* cx, jsval Value ) + void Set( JSContext* cx, IJSObject* owner, jsval Value ) { if( m_Setter ) - (m_Owner->*m_Setter)( Value ); + (owner->*m_Setter)( Value ); } - void ImmediateCopy( IJSProperty* Copy ) + void ImmediateCopy( IJSObject* CopyTo, IJSObject* CopyFrom, IJSProperty* CopyProperty ) { - assert( 0 && "ImmediateCopy called on a property wrapping getter/setter functions" ); + assert( 0 && "ImmediateCopy called on a property wrapping getter/setter functions (something's gone wrong with the inheritance for this object)" ); } }; @@ -419,8 +455,10 @@ public: if( prop ) { // Already exists - prop->Set( cx, *vp ); + prop->Set( cx, this, *vp ); + prop->m_Inherited = false; + // If it's a C++ property, reflect this change in objects that inherit this. if( prop->m_AllowsInheritance && prop->m_Intrinsic ) { @@ -430,11 +468,11 @@ public: { IJSObject* UpdateObj = UpdateSet.back(); UpdateSet.pop_back(); - IJSProperty* UpdateProp = UpdateObj->m_Properties[PropertyName]; + IJSProperty* UpdateProp = UpdateObj->HasProperty( PropertyName ); // Property must exist, also be a C++ property, and not have its value specified. if( UpdateProp && UpdateProp->m_Intrinsic && UpdateProp->m_Inherited ) { - UpdateProp->Set( cx, *vp ); + UpdateProp->Set( cx, this, *vp ); InheritorsList::iterator it2; for( it2 = UpdateObj->m_Inheritors.begin(); it2 != UpdateObj->m_Inheritors.end(); it2++ ) UpdateSet.push_back( *it2 ); @@ -491,7 +529,12 @@ public: delete[]( JSI_methods ); } - + static void ScriptingShutdown() + { + PropertyTable::iterator it; + for( it = m_SharedProperties.begin(); it != m_SharedProperties.end(); it++ ) + delete( it->second ); + } static void DefaultFinalize( JSContext *cx, JSObject *obj ) { T* Instance = ToNative( cx, obj ); @@ -541,6 +584,8 @@ public: private: static JSPropertySpec JSI_props[]; static std::vector m_Methods; + static PropertyTable m_IntrinsicProperties; + public: CJSObject() @@ -587,7 +632,7 @@ public: ReleaseScriptObject(); } void SetBase( IJSObject* Parent ) -{ + { if( m_Parent ) { // Remove this from the list of our parent's inheritors @@ -627,7 +672,21 @@ public: if( cp && cp->m_AllowsInheritance ) { assert( cp->m_Intrinsic ); - it->second->ImmediateCopy( cp ); + it->second->ImmediateCopy( this, m_Parent, cp ); + } + } + // Do the same for the shared properties table, too + for( it = m_IntrinsicProperties.begin(); it != m_IntrinsicProperties.end(); it++ ) + { + if( !it->second->m_Inherited ) + continue; + + IJSProperty* cp = m_Parent->HasProperty( it->first ); + + if( cp && cp->m_AllowsInheritance ) + { + assert( cp->m_Intrinsic ); + it->second->ImmediateCopy( this, m_Parent, cp ); } } @@ -640,10 +699,15 @@ public: IJSProperty* HasProperty( CStrW PropertyName ) { PropertyTable::iterator it; + it = T::m_IntrinsicProperties.find( PropertyName ); + if( it != T::m_IntrinsicProperties.end() ) + return( it->second ); + it = m_Properties.find( PropertyName ); - if( it == m_Properties.end() ) - return( NULL ); - return( it->second ); + if( it != m_Properties.end() ) + return( it->second ); + + return( NULL ); } void AddProperty( CStrW PropertyName, jsval Value ) @@ -669,9 +733,9 @@ public: { AddProperty( PropertyName, JSParseString( Value ) ); } - void AddProperty( CStrW PropertyName, GetFn Getter, SetFn Setter = NULL ) + static void AddClassProperty( CStrW PropertyName, GetFn Getter, SetFn Setter = NULL ) { - m_Properties[PropertyName] = new CJSFunctionProperty( this, Getter, Setter ); + T::m_IntrinsicProperties[PropertyName] = new CJSFunctionProperty( Getter, Setter ); } template static void AddMethod( const char* Name, uintN MinArgs ) @@ -679,13 +743,21 @@ public: JSFunctionSpec FnInfo = { Name, CNativeFunction::JSFunction, MinArgs, 0, 0 }; T::m_Methods.push_back( FnInfo ); } + template static void AddClassProperty( CStrW PropertyName, PropType T::*Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL ) + { + T::m_IntrinsicProperties[PropertyName] = new CJSSharedProperty( (PropType IJSObject::*)Native, PropAllowInheritance, Update, Refresh ); + } + template static void AddReadOnlyClassProperty( CStrW PropertyName, PropType T::*Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL ) + { + T::m_IntrinsicProperties[PropertyName] = new CJSSharedProperty( (PropType IJSObject::*)Native, PropAllowInheritance, Update, Refresh ); + } template void AddProperty( CStrW PropertyName, PropType* Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL ) { - m_Properties[PropertyName] = new CJSProperty( Native, this, PropAllowInheritance, Update, Refresh ); + m_Properties[PropertyName] = new CJSProperty( Native, PropAllowInheritance, Update, Refresh ); } template void AddReadOnlyProperty( CStrW PropertyName, PropType* Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL ) { - m_Properties[PropertyName] = new CJSProperty( Native, this, PropAllowInheritance, Update, Refresh ); + m_Properties[PropertyName] = new CJSProperty( Native, PropAllowInheritance, Update, Refresh ); } }; @@ -703,13 +775,14 @@ template JSPropertySpec CJSObject::JSI_p }; template std::vector CJSObject::m_Methods; +template typename CJSObject::PropertyTable CJSObject::m_IntrinsicProperties; template void CJSObject::GetProperty( JSContext* cx, CStrW PropertyName, jsval* vp ) { IJSProperty* Property = HasProperty( PropertyName ); if( Property && Property->m_Intrinsic ) { - *vp = Property->Get( cx ); + *vp = Property->Get( cx, this ); } else { diff --git a/source/scripting/ScriptingHost.cpp b/source/scripting/ScriptingHost.cpp index 2442c0c0f6..6cebf176ef 100755 --- a/source/scripting/ScriptingHost.cpp +++ b/source/scripting/ScriptingHost.cpp @@ -3,6 +3,7 @@ #include "ScriptingHost.h" #include "ScriptGlue.h" #include "CConsole.h" +#include "Profile.h" #include #include "res/res.h" @@ -53,6 +54,13 @@ ScriptingHost::ScriptingHost() : m_RunTime(NULL), m_Context(NULL), m_GlobalObjec m_GlobalObject = JS_NewObject(m_Context, &GlobalClass, NULL, NULL); +#ifndef NDEBUG + // Register our script and function handlers - note: docs say they don't like + // nulls passed as closures, nor should they return nulls. + JS_SetExecuteHook( m_RunTime, jshook_script, this ); + JS_SetCallHook( m_RunTime, jshook_function, this ); +#endif + if (m_GlobalObject == NULL) throw PSERROR_Scripting_GlobalObjectCreationFailed(); @@ -379,3 +387,37 @@ void ScriptingHost::_CollectGarbage() { JS_GC(m_Context); } + +#ifndef NDEBUG + +void* ScriptingHost::jshook_script( JSContext* cx, JSStackFrame* fp, JSBool before, JSBool* ok, void* closure ) +{ + if( before ) + { + g_Profiler.StartScript( "script invocation" ); + } + else + g_Profiler.Stop(); + + return( closure ); +} + +void* ScriptingHost::jshook_function( JSContext* cx, JSStackFrame* fp, JSBool before, JSBool* ok, void* closure ) +{ + JSFunction* fn = JS_GetFrameFunction( cx, fp ); + if( before ) + { + if( fn ) + { + g_Profiler.StartScript( JS_GetFunctionName( fn ) ); + } + else + g_Profiler.StartScript( "function invokation" ); + } + else + g_Profiler.Stop(); + + return( closure ); +} + +#endif diff --git a/source/scripting/ScriptingHost.h b/source/scripting/ScriptingHost.h index feb5dae004..eedfb4ecf8 100755 --- a/source/scripting/ScriptingHost.h +++ b/source/scripting/ScriptingHost.h @@ -28,6 +28,10 @@ ERROR_TYPE(Scripting_DefineType, CreationFailed); #include +#ifndef NDEBUG +#include +#endif + // Make JS debugging a little easier by automatically naming GC roots #ifndef NDEBUG // Don't simply #define NAME_ALL_GC_ROOTS, because jsapi.h is horridly broken @@ -78,7 +82,12 @@ private: std::map < std::string, CustomType > m_CustomObjectTypes; void _CollectGarbage(); - +#ifndef NDEBUG + // A hook to capture script calls + static void* jshook_script( JSContext* cx, JSStackFrame* fp, JSBool before, JSBool* ok, void* closure ); + // A hook to capture function calls + static void* jshook_function( JSContext* cx, JSStackFrame* fp, JSBool before, JSBool* ok, void* closure ); +#endif public: ScriptingHost(); diff --git a/source/scripting/SynchedJSObject.h b/source/scripting/SynchedJSObject.h index 239b6e577a..8532d14314 100644 --- a/source/scripting/SynchedJSObject.h +++ b/source/scripting/SynchedJSObject.h @@ -73,7 +73,7 @@ struct CSynchedJSObjectBase CSynchedJSObjectBase *m_Owner; UpdateFn m_Update; - virtual void Set(JSContext *cx, jsval value) + virtual void Set(JSContext *cx, IJSObject* owner, jsval value) { if (!ReadOnly) { @@ -85,12 +85,12 @@ struct CSynchedJSObjectBase } } } - virtual jsval Get(JSContext *cx) + virtual jsval Get(JSContext *cx, IJSObject* owner) { return ToJSVal(*m_Data); } - virtual void ImmediateCopy(IJSProperty *other) + virtual void ImmediateCopy(IJSObject* CopyFrom, IJSObject* CopyTo, IJSProperty *other) { *m_Data = *( ((CSynchedJSProperty*)other)->m_Data ); } diff --git a/source/simulation/BaseEntity.cpp b/source/simulation/BaseEntity.cpp index 243f5645b5..b095a839b0 100755 --- a/source/simulation/BaseEntity.cpp +++ b/source/simulation/BaseEntity.cpp @@ -11,20 +11,20 @@ CBaseEntity::CBaseEntity() { + m_base = NULL; + AddProperty( L"tag", &m_Tag, false ); - AddProperty( L"parent", (CBaseEntity**)&m_base, false ); + AddProperty( L"parent", &m_base, false ); AddProperty( L"actions.move.speed", &m_speed ); AddProperty( L"actions.move.turningradius", &m_turningRadius ); AddProperty( L"actions.attack.range", &m_meleeRange ); AddProperty( L"actions.attack.rangemin", &m_meleeRangeMin ); AddProperty( L"actor", &m_actorName ); AddProperty( L"traits.extant", &m_extant ); - AddProperty( L"traits.corpse", &m_corpse ); + AddProperty( L"traits.corpse", &m_corpse ); for( int t = 0; t < EVENT_LAST; t++ ) AddProperty( EventNames[t], &m_EventHandlers[t] ); - - m_base = NULL; // Initialize, make life a little easier on the scriptors m_speed = m_turningRadius = m_meleeRange = m_meleeRangeMin = 0.0f; @@ -193,7 +193,7 @@ void CBaseEntity::XMLLoadProperty( const CXeromyces& XeroFile, const XMBElement& { if( !Existing->m_Intrinsic ) LOG( WARNING, LOG_CATEGORY, "CBaseEntity::XMLAddProperty: %s already defined for %s. Property trees will be merged.", PropertyName.c_str(), m_Tag.c_str() ); - Existing->Set( JSParseString( Source.getText() ) ); + Existing->Set( this, JSParseString( Source.getText() ) ); Existing->m_Inherited = false; } else @@ -221,7 +221,7 @@ void CBaseEntity::XMLLoadProperty( const CXeromyces& XeroFile, const XMBElement& if( Existing ) { - Existing->Set( JSParseString( Attribute.Value ) ); + Existing->Set( this, JSParseString( Attribute.Value ) ); Existing->m_Inherited = false; } else @@ -247,6 +247,7 @@ void CBaseEntity::XMLLoadProperty( const CXeromyces& XeroFile, const XMBElement& void CBaseEntity::ScriptingInit() { AddMethod( "toString", 0 ); + CJSObject::ScriptingInit( "EntityTemplate" ); } diff --git a/source/simulation/Entity.cpp b/source/simulation/Entity.cpp index 3899dbfe27..b5e12891b8 100755 --- a/source/simulation/Entity.cpp +++ b/source/simulation/Entity.cpp @@ -2,6 +2,8 @@ #include "precompiled.h" +#include "Profile.h" + #include "Entity.h" #include "EntityManager.h" #include "BaseEntityCollection.h" @@ -25,8 +27,7 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation ) m_orientation = orientation; m_ahead.x = sin( m_orientation ); m_ahead.y = cos( m_orientation ); - - AddProperty( L"template", (CBaseEntity**)&m_base, false, (NotifyFn)&CEntity::loadBase ); + AddProperty( L"actions.move.speed", &m_speed ); AddProperty( L"selected", &m_selected, false, (NotifyFn)&CEntity::checkSelection ); AddProperty( L"group", &m_grouped, false, (NotifyFn)&CEntity::checkGroup ); @@ -172,6 +173,8 @@ void CEntity::update( size_t timestep ) // still needs to be (re-)evaluated; else 'false' to terminate the processing of // this entity in this timestep. + PROFILE_START( "state processing" ); + while( !m_orderQueue.empty() ) { CEntityOrder* current = &m_orderQueue.front(); @@ -180,6 +183,8 @@ void CEntity::update( size_t timestep ) if( m_transition ) { + PROFILE( "state transition / order" ); + CEntity* target = NULL; if( current->m_data[0].entity ) target = &( *( current->m_data[0].entity ) ); @@ -229,8 +234,11 @@ void CEntity::update( size_t timestep ) } } + PROFILE_END( "state processing" ); + if( m_actor ) { + PROFILE( "animation updates" ); if( m_extant ) { if( ( m_lastState != -1 ) || !m_actor->GetModel()->GetAnimation() ) @@ -242,6 +250,7 @@ void CEntity::update( size_t timestep ) if( m_lastState != -1 ) { + PROFILE( "state transition event" ); CEntity* d0; CVector3D d1; CEventOrderTransition evt( m_lastState, -1, d0, d1 ); @@ -313,7 +322,29 @@ void CEntity::dispatch( const CMessage* msg ) bool CEntity::DispatchEvent( CScriptEvent* evt ) { - return( m_EventHandlers[evt->m_TypeCode].DispatchEvent( GetScript(), evt ) ); + // MT: HACK. And it leaks. + static std::map evMap; + char* data; + std::map::iterator it = evMap.find( evt->m_Type ); + if( it != evMap.end() ) + { + data = it->second; + } + else + { + CStr8 short_string( evt->m_Type ); + int length = short_string.length(); + data = new char[length + 9]; + strcpy( data, "script: " ); + strcpy( data + 8, short_string.c_str() ); + data[length + 8] = 0; + evMap.insert( std::pair( evt->m_Type, data ) ); + } + + g_Profiler.StartScript( data ); + bool rval = m_EventHandlers[evt->m_TypeCode].DispatchEvent( GetScript(), evt ); + g_Profiler.Stop(); + return( rval ); } void CEntity::clearOrders() @@ -613,6 +644,10 @@ void CEntity::ScriptingInit() AddMethod( "kill", 0 ); AddMethod( "damage", 1 ); AddMethod( "isIdle", 0 ); + + + AddClassProperty( L"template", (CBaseEntity* CEntity::*)&CEntity::m_base, false, (NotifyFn)&CEntity::loadBase ); + CJSObject::ScriptingInit( "Entity", Construct, 2 ); } diff --git a/source/simulation/EntityManager.cpp b/source/simulation/EntityManager.cpp index d53e7c12cc..4af5ecbaad 100755 --- a/source/simulation/EntityManager.cpp +++ b/source/simulation/EntityManager.cpp @@ -54,17 +54,7 @@ HEntity* CEntityManager::getByHandle( u16 index ) return( new HEntity( index ) ); } -std::vector* CEntityManager::matches( EntityPredicate predicate ) -{ - std::vector* matchlist = new std::vector; - for( int i = 0; i < MAX_HANDLES; i++ ) - if( m_entities[i].m_refcount && !m_entities[i].m_entity->m_destroyed ) - if( predicate( m_entities[i].m_entity ) ) - matchlist->push_back( HEntity( i ) ); - return( matchlist ); -} - -std::vector* CEntityManager::matches( EntityPredicateUD predicate, void* userdata ) +std::vector* CEntityManager::matches( EntityPredicate predicate, void* userdata ) { std::vector* matchlist = new std::vector; for( int i = 0; i < MAX_HANDLES; i++ ) @@ -74,26 +64,6 @@ std::vector* CEntityManager::matches( EntityPredicateUD predicate, void return( matchlist ); } -std::vector* CEntityManager::matches( EntityPredicate predicate1, EntityPredicate predicate2 ) -{ - std::vector* matchlist = new std::vector; - for( int i = 0; i < MAX_HANDLES; i++ ) - if( m_entities[i].m_refcount && !m_entities[i].m_entity->m_destroyed ) - if( predicate1( m_entities[i].m_entity ) && predicate2( m_entities[i].m_entity ) ) - matchlist->push_back( HEntity( i ) ); - return( matchlist ); -} - -std::vector* CEntityManager::matches( EntityPredicateUD predicate1, EntityPredicateUD predicate2, void* userdata ) -{ - std::vector* matchlist = new std::vector; - for( int i = 0; i < MAX_HANDLES; i++ ) - if( m_entities[i].m_refcount && !m_entities[i].m_entity->m_destroyed ) - if( predicate1( m_entities[i].m_entity, userdata ) && predicate2( m_entities[i].m_entity, userdata ) ) - matchlist->push_back( HEntity( i ) ); - return( matchlist ); -} - std::vector* CEntityManager::getExtant() { std::vector* activelist = new std::vector; diff --git a/source/simulation/Scheduler.cpp b/source/simulation/Scheduler.cpp index 7e3b3ce275..95f90097f8 100755 --- a/source/simulation/Scheduler.cpp +++ b/source/simulation/Scheduler.cpp @@ -79,7 +79,9 @@ void CScheduler::update(size_t simElapsed) timeFunction.pop(); jsval rval; m_abortInterval = false; + JS_CallFunction( g_ScriptingHost.getContext(), top.operateOn, top.function, 0, NULL, &rval ); + if( top.isRecurrent && !m_abortInterval ) pushInterval( top.delay, top.delay, top.function, top.operateOn ); } @@ -90,6 +92,8 @@ void CScheduler::update(size_t simElapsed) break; frameFunction.pop(); jsval rval; + JS_CallFunction( g_ScriptingHost.getContext(), top.operateOn, top.function, 0, NULL, &rval ); + } } diff --git a/source/simulation/Simulation.cpp b/source/simulation/Simulation.cpp index 275e54fee4..54b0827464 100755 --- a/source/simulation/Simulation.cpp +++ b/source/simulation/Simulation.cpp @@ -1,6 +1,7 @@ #include "precompiled.h" #include +#include "Profile.h" #include "Simulation.h" #include "TurnManager.h" @@ -53,6 +54,7 @@ void CSimulation::Update(double frameTime) if( m_DeltaTime >= 0.0 ) { + PROFILE( "simulation turn" ); // A new simulation frame is required. MICROLOG( L"calculate simulation" ); Simulate(); @@ -65,7 +67,9 @@ void CSimulation::Update(double frameTime) } } + PROFILE_START( "simulation interpolation" ); Interpolate(frameTime, ((1000.0*m_DeltaTime) / (float)m_pTurnManager->GetTurnLength()) + 1.0); + PROFILE_END( "simulation interpolation" ); } void CSimulation::Interpolate(double frameTime, double offset) @@ -79,11 +83,18 @@ void CSimulation::Interpolate(double frameTime, double offset) void CSimulation::Simulate() { + PROFILE_START( "scheduler tick" ); g_Scheduler.update(m_pTurnManager->GetTurnLength()); - g_EntityManager.updateAll( m_pTurnManager->GetTurnLength() ); + PROFILE_END( "scheduler tick" ); + PROFILE_START( "entity updates" ); + g_EntityManager.updateAll( m_pTurnManager->GetTurnLength() ); + PROFILE_END( "entity updates" ); + + PROFILE_START( "turn manager update" ); m_pTurnManager->NewTurn(); m_pTurnManager->IterateBatch(0, TranslateMessage, this); + PROFILE_END( "turn manager update" ); } uint CSimulation::TranslateMessage(CNetMessage *pMsg, uint clientMask, void *userdata)