From f89578f45c618bd515b9311c09e53dc833a568eb Mon Sep 17 00:00:00 2001 From: sam-k0 <56673835+sam-k0@users.noreply.github.com> Date: Fri, 22 Mar 2024 13:10:17 +0100 Subject: [PATCH] Add project files. --- Export/2018-LC_API/LC_API.dll | Bin 0 -> 130560 bytes Export/2018-LC_API/README.md | 127 ++++ Export/2018-LC_API/manifest.json | 11 + Gfe/NvidiaHighlights.cs | 1045 ++++++++++++++++++++++++++++++ Highlight.cs | 57 ++ LC_Highlights.csproj | 40 ++ LC_Highlights.sln | 25 + Patches/PlayerKillPatch.cs | 67 ++ Plugin.cs | 74 +++ PluginMeta.cs | 13 + README.md | 11 + 11 files changed, 1470 insertions(+) create mode 100644 Export/2018-LC_API/LC_API.dll create mode 100644 Export/2018-LC_API/README.md create mode 100644 Export/2018-LC_API/manifest.json create mode 100644 Gfe/NvidiaHighlights.cs create mode 100644 Highlight.cs create mode 100644 LC_Highlights.csproj create mode 100644 LC_Highlights.sln create mode 100644 Patches/PlayerKillPatch.cs create mode 100644 Plugin.cs create mode 100644 PluginMeta.cs create mode 100644 README.md diff --git a/Export/2018-LC_API/LC_API.dll b/Export/2018-LC_API/LC_API.dll new file mode 100644 index 0000000000000000000000000000000000000000..4b9044ca520d8652e0f13fc01edc7e016ac870e6 GIT binary patch literal 130560 zcmdqK2b>$l**`v7=~m@*XX}b|#lAb2JFg|(`P>Wc6&qJvuuU-?494q7rUW5zU^>PW zg8|cw=_PamF(q^eEk{CtP>czL&_f6zgmV19&oi^qu5@P`L*C!}fA3?@&hyMOGtWHp z%rnoF)y`Uao^T5xJox{^4?^6JC;g4*aQi_Ul1uBil!|-&FZ8jD3l3kNY*>{r z4@(?yRKr0BtXyfXZaDCehQ!e;8s9P(72+$G5W2)ZT%ifkU{Q>haiEBA`m>&5e<1OX{@h~!Q-$cx|8h?SN)oXG z<<6magC-s%LFE69*F+GwD$tF{Pum{cAcW7B?gPBL4Q^R|$Z@LyKk+5nh%|1i;@ctv zdjFP0GI0!1N<1_9l>Ll@UO^d5AYLAq({LCJxI2HQvOzS)jz5c+vvmMMga|3FQ`3 z30G|`EfXDK^meTYc?I4Cb1tZfCTheXCyG*PX?d$p>_ZX!Wx$Om@gYhxOF(WM=n{Hj zic73YEJ4s)h)v_e;c((!0Ooq6*$AHOlpyiGhStmjOHrz42I@dBgf!!7Mj~a-udvphW@; zYAXcgvI{CP5gh5%zp<>$!lG%klvzu%44Ju8qcs`ys0Yf>#?P7z`j$a{l6<`)2IkQD zXm7(OprGwx|QIF1{OWJF*)cfVoO*ZriIdr+F{m5*c*W2(#HWqD_mg}}! zAGFbX+k0fI{ltd%+3=o{Y@5pcHhh&0A0WJvLDYsXZtvMCKA0gf`}|3?I#7W>6Zr#8 zjMcrJVMCsZicpbCu~CQgQ0Mf%icqmtke%M&1wK#_3OebHJuxzvB?HEsjVlJT9>w^P zIRq4qZIog_a8<-rh16Ef>zYJJQ^bP?Fg;V9f zVlT49UgY+2o#vLMqg{b`xfV8OBBDk3K|@=QzHcu#sDN3ZQpGL;8~MzzFyJS7ga*HZ z{xWdpJQ>&!D1LcUMTZU(p(kgfn8r538gmd`4fU^WBT81Qa0U#>fzl6=4jp4!PtN5$ zltMN%#{C@5pg21v2EIi}DUy^yEA)lTyeY$5;u%8Q3j5B`k%WME`+f zN-9TQrm?7l5)2BhjOfFeOqnEDD8$ zQP7hMiLxO_345R?7ZI{o4hhqsC-)*GRK~-GzK!%Xx=7koc=wBus(I2&@QAh~2OvWm z@e|!ILu`0bOOfD7?TygfhiER~?vwcXfHazm8fO)PUV5d z71l$@?bMUYW2>hiPYbuf_?CQ$mJB7!IO`MoSp=w^&|^=9VFHRzZb#QhugX{jL?B!o zi|XEuL7({xfQf6#a3B-Rxz9}C+3fSRQT|xK8(CcJ)z>W_)XoJ;pCwxdM!+uD5l0=A z-%$r4qU>`(i3Nsp$iR%In@KQbVyIwc8N~|lXvB(*V+eUH0x#*6?rrSwLYegBafJUR z0#F{0NAnAEtq9jJf34VE44)=28flKw1O^JNy;YqlD&_Xsn7h2{u7EBMby z=EY)(hJ6~8p_!+GbmT06no-93Id%pB>b7Mp|G1m39V}ae=SfwStM2Y5EAZ>54{QN3aM*BDm zgM29PY*1;&T7>2~2sWGR5H>~a{CUchzKuK$oYQ=*{}>h~SQT2$u(8l(_4T98bHPY3 zTr$FkN`3x~<(`nolHfler;x`y4;0PCiB|BJJRkAnfx7_Db;~1z_u45wL!R~>vS+SG zkxDKxtBS}*^FpA@iyR#kD%!aoLbcoP7%GT*#$LBSvbeXk<0c^cO>=va8vq5^d}z9PF#z&v^?1*m z-O%&`lfga;)e+jMIxrdOKfaEq+|4DDG3Fnu7;r^)PBSl|_H?(gXkH2oI)~;X>KhDs z)%G%BZX{|$Ke`?!sMs6#dEMq^M4sqZPCnQ?gzOMXp`dMUwngOyW%SdJu7ssP8D6i6 zxmE9~2-Xpj5B+6^!Cdp|Xb2)5`d-MGbZJ6wY@-wdmO;O3QWS;X9C?DMr>ZX;6GIvKMQe1x8P>b<$ zJXVbUg^AL=20RcwSmyCnhG{1&R#jN;@Fm6E67)%Gl7m`4{j9Jr+BT3cPD6!eI-Q@)he-+~_;_EdrxX{0jfWQLU1*Y2oxlkc_~X6k6{Wo_~H! z66t|7hMGr{H~3R!)XvwB-eqvrka!wl8_c4s-M{4FzgRv?h5csy#j@ zvPpy`+g>ETL(`?q2nm^y=(~~`kw9k9p+cEWrnE?!NLXe}n<7#vGm2>p+hlelT5W5| z4rNA#)ORW~uD;4y{SIYD%Q-10%1-jS2ZEyKz3TaEdghD+CBrySDvSdsLVjc)Ud3~} z_Mu$b2e)w_GIwDh+-v)wG`0}Q3&Gm|I$LqDIQW^ItvC^F-bq_=f3DHHW-ES!0;H|* znsAYI0~N>2Ex<+>g_9593A6DaJ>2Ps2n*}+u*CjWVjrQ0C;ccT=7z#!1fm_5{itU9 zL0F6h%GuReAQFs)$MGnzA5TzPBuykd7MM0gq;f1!Ok>zK7JjV#ph7wy3tWAbv-%y5 z1uaDa(o!U!oc*ApY|?s?K$aElr%7264*5v-UCD|_AgibFD3I0Dlom-73CoIUQ$#9d zMKO(Go2-7U-Jn7`mlaoE<*a@uWJM}wJcEF(EEPglVmNhCCoBb`qp}|? zi{>^iMK)A)8RhQXO&FN^^ymyN^(>m8rQqcRl9v7HI6l3EG8!8ZCSM?` z7ZIeXXhryYz$Amct?D@f#6A{+Bj9IW=EsoyTusG#jBBV);^zj6?1{)rC=ZW6P+iv& z5*$%Z~A4Ba+Y?&0YG$A z_LnTec_J2Xp+}Jc2SIX*IaQAysHI*-HCpO54*!fWi8)@6ekKbsUI(VRH{=JG5ZuDg zL3k^|j#wem=dWsU%`!a{Hah@&h7M}SyqAvl6onm}|^#$_viM-_XF=jc&n zV0dvWF`{HEq4C_xPf@>?`i#TBbND&JWIH9({FQ4Xm2Uh4iQL9#s6gXc4xi`nMTE&O zDDyuNq={UzWPAyj+PKPMm?J>^!a{Hah=hgU2oOmN!4b4^H4q(@&9aRcozzB*7HT5~ z3bzr1K(-N@$Zh-=>eo_VarkczzeY&oB)^SRy73<*avNW!0u2m#gcyqmG4k}}HfrDP4soq1kc7(Sw~`7=Q>d;t)dP^(3a^K+=sM zP2`d#!vmPwc)Z0hM}SCK2###fPB;OGj>-YD1$Ur81A0cy;5hV5G7m+OhPenO!*u9W z>*s{*kYyNNV49mSral4IxE+CJKv`upiN#qU=|_;J3RRW>VB#`uF~t!eG8Td(;POP~ zvQ=_dM^sa9wZb4g_wCBQJ3Ujl1ffj~2$ZZeuICHig% z(nKt)HM#?a8G+y97IUQ;5$;G!I5EEx$F^(tr%j*`Xt3W%VX7QqVm;DiG*toEtVF;& zg=qriqVGD;@M(AiUPId`+z^UHH)yFa(MKq#LXdcssK!H2;$AxV$ATpiJ(Q2i)z(8X zuXF=OPbA_L>LijKE>H2ZCUdd^`N?hQhc?u}&&{kslI=|DFf=51A|Y{BR0aP!?@TH$ z&q}bgdZ+T7(pf!(+)h2YJhpmvkmuCS>LKKI>dED?)w6>Fr?2;b+CUZJ+b?6u)da@4awl=^S3ff4MWQ-V; zG2%nUs5b0)VzB9LR0hs%&%i_8ILMrdsJwMR>kVB%nfWhs77`4cJO!4tQIzwT4S>TP z8YlK9x(?5>_yWW>jb|#O7YHhh-U#FU7~p*JmI2o#qt;E#J|I*SeJM)ZgiVS@7xBf2 zHeyxAC=H|TYBu}^8L`rT3V|b5W3DM)XNZ2W%dUl_UWT|P?DZ4Ax0&T9mBY#J+YA7HM|-_ zxj7=^ng}BTK2j5HVYTg%K1YDzwx901eu_Yz#sHD3&ti6^(1o0VkIu(KN~45TuRjW%+j!_0Uh490cDz{XjyW8~MW-rY z1ORg+VNfrfu`R%p{<_qg0pXn9kbYxF9oc1Z?(}ZixJgC3&C!H#8&GrU`@ks`bv7L# zkqS#k#Ex}jZ{(*OrcFlxZ6X~RhcxKOYd2mnq9ceNB~a-IR1uCr2mBFZ3^<}LcZod8 zF1sA%+qzuUmhJML6oOOaxGfyOvYai1lGHdt-PWbtQ#rZ24QQAebM0v3e_5XY^j7b^ z9eIw=$Yw~m(FmAe2S`!MTHF5jWdciI&m>OCp^7#56kk@}s+-=i#D7mjSN%^Ir^}JQt8qFDX&9$RPyNrgUCXJX z#GN(ZZfU^PsCDMsHK{pfIF^|;Ax|a&ZtYTl)sZ~&XX0fK65UX#WMsqtgy#L1$7J;l zsrNgP9cEdY*o>**NlD8|xr@?b8^v1MU(n``8Gee3Bbvys0mT^xio=;Fk4uNYe>PbETU;x39X zD+8LAZ4HkOQ*);|9dgM*GaS$!1U;+f_F5&qGg)rr^fvo6@|pFxhOU)jUYZ!%K^$AnFG9v&PCLmhu}y_wI`xWmm8Sq z^eFZW*n7z%H|BRv-Zj(ys_f`<8<>-!HkdYvY0{JX;Dt5VY!hriw0+6mwJLCZSI7sz~N4q3m_Qy_cicZ<3}jr zEdnmSuMJoipCd)R7p1gXE+Wz8@OJv;=3=C6G?yTZmD}mV5~);&Yj>Gge#GL-RRK$> zj(u#vy7=r|E%5=k_sU&NbUC~Yxz4J6Z%{<-fdAtw6)V>Jx4jm2FllviVzXVnwO_fhhK>^rKS`A21Rd&@!V27{tl0v$C0x zdCceuke9SFMKcdWg|t4`#9*|y505SCW_n2=hMll;(HL4-Fm5@BWkx+si(Z`iQF`=1 zTao4wNNB<>8Y-Cj8;uZsQLdzc&aXg9T!YP!e4);mC3CEKI;X9O4wL!aoZX^FxuTK! z2Jlq@MqxZFY^l^c|D2u4`4d=WC92yi9jaN3I$0phXqOGLL&** zv>=JRMI^z-79^2Nge2J9f+U*%kpxp)kVNwuk}%v0lE{=HX`v&@lIuxmBlah-Hv!iZ z>-_Dk;b_Grm*fs_4!shqkQ)S+fo4KllOKaJF(cE~Kzab;+UhtNShzN3AF!h}AVH=` ze&oAu#*g6#9@4Q?a;KHhQq@@r>Hi{B+W$w^aa@;m(E6?OI)1)(Kz0RnxW&O}2jsT% zeW&`5FAdUkYEa*GE;(8~*jr`EEw+>O`Kd1S%`dx@8#&qb8swhE6toFCvNLTeV4Su? z@`_}8_mj#bpTy2)P2xY82crAAQ|NfP$)=@f!s2cJJUmSh5eh&7q@ zh|ne^KWj1<64+uaLv>~fl+lL`Ol^ARTHyJ5=rxp4{~K`06Oi86Mk(}$WsF{|q*q!l zq9RZtKWj1@6sVr5iwUMJO^#rX^AZce5g;&OOA3wvahZkS2oRSO0?VsI!A2@WY%Y}( z^@-Ft1J+eH+X!vZoJ7DnnSo~kmG@-eQ)>`}H}aMiUftnBWof4%L87N>#?dIW8BPX_ ziH_qGtK?IuWD7XW4xCN^^oZu9ZFn}bJ`v0AG^HsP&Op>{!toBsO3y+pbvC7U=(mA5 zi4_fAP(TpSD_f@J5$WbSq`1@PBD5u)2T&heBQfU#NVuzU@WiJ{vaSPBw8`?j0LiKK z2zctzH>NH`Tyd0hmel3pP4J%LJ}j!BMwn6EcwxWtRQL{F8e(!kuENFlCULcE~Ul$dwk=Z0*^;{L2GA=i0;$7tt0TiUPfbdsoshUOf2qCpnh zo-H=;oJDUy(bk@=i!<%$GT>kzcRi#_chH3)A1e>@1XqkAJ7w4HsNo)}@)@rP_6 zWkAoTX=KRt?etY_oc1F0h-HqrvZ$=E>~rT#b`E zLw$7sRf#`YUUMJG*Ctp&Yb8w<5$Aw6b>3&!p&(lx``ai%#hZD3LG{?}QR~GF*S-_= z`)iy7(RLbQYgjjzaRbUWx5HMMB)2G;IcuuFk@)I*Q}=*89^7fl0AqleU+ss(r4s}H zyLxI2+d97!J;iCKV^0@)>ZJU+^fX0{R{E(VATxPx$lt)^>GDRxVe?ibWUceB2)Iq1k@PH0&7kS-Sf*9e$tSEV*-E|4;EV$#2cxEFdp+M>h+|OVundRnFrWza@J1EK3*k za~E)IiP9sFY9t*lER=Y&bY697f&AV8vX}U>Nj{b2_e$RUNG0Cr8OTxvtXmI$>(&F+ z=(TuLj)YTaU7C{ZITD@pIQdTj@gllqF#6o45t^3Th~XKex2!1QOMVR%39xO^&Ce0n z%`Z6o5}|nyl$gDf!wI^Vpc2g>KsSF)3N8T|a(ZNmc^?vV^FJU8w{}Jywo?o$m6`F5 z`u({Ab@Mj>ioM|hZttPk-=rG7ih|na6Z6qF`cq?Ow;wrX)QG{-!#-jRtU`Fac*QHw z>7O!QmLPvuXI|LKrt$J>_cvyfLNri2{@0He9tSk~x)>rfdO8^*`i~zXdfpIm%IPN# z5!J;!K7I|k50T@e0k8O-D9x!FBE@*Cn1_gWCx^%p(4F`Y&7i0GDFS$%kBl4MTVkk_ z+suCht@K?HlG5W>xsF5v55m+IAds_docRD^Ib331Ev~6PNaV()pjK<7Qqm>-$>K0p zIfp8o#wHnxXjY&=(=K4APBc#jSkzPQi zew$1A*h*0)5gYMgwx*mzO?d@md1TW=c|HXcX3Nj8UtA_dS{t|tm|k&W<* zze6rV(Z9C!QnSsc?!|{Cfz*@8j_o73Bzp2G#Oe3UV#Z+ru^>2cOdkp zpGBw}M^P;ry*eK=&fywYB5X`OM}>9hSiI=T=MgvNU`k#+2KN=yltg}wThQ8h7|-`f z(6J4tUK@Ee@VTBaUqA-P8?=LS*s%E`(DXAazo+Cw4?T3;@QPeA)3bKU{%vG!mv=_Z z&rpf#b~Ogj2Ll|Lx2M`tA7uf}a2>PrPIzEn$bvvQeX!nIh<324M#UCBHR?=CD;-i& zM_{ZcccT5nA*ESw7`CEYXE~( zm%oQl5%p0y^1b|G(GcUKL>@0?iVqw^VtubS2Ig679qDgiGgOQs8E2g-8qTzts~cGK zlR0KxngM&f8`16fY);+5B?F%Gv+pM;Xt{gN{akG1li%?BVej9Y^Bc1Jx$MwlKV>RJ zAst%U*~S0d(UIKIB{vi|x|ptWFW7Nb$eBu{7o6R!afv)Oc4_ao)SJKg+v2hf%S8{c-v1{&* zTrt~anQW)m7fwPz^MjAxE$&jEZ}^|p=VRNBIP8CcK0Dd?ujuoQ|D*bRiu?QP{uk)8 zlZ~HEpC2K8K3VB=fNZYPXFju)dmz$tD=m`GW>5Htn76dZ#M&-E+a@^+elvGWd8=RG z6jQ*J+GYFw8Cjh!?Drp#2K)WX-~9WE4!>VC5STlUv+T^PJFwquieYE4iVSqIi_wK~ z!q!Kwa4h3!Go>?ogk@ae+Z$@X!pZ!ujS~NMt$wMu)Mwm69YS^r=M`e?kLnMn-Ou(% zCw5=;NB8QLeYZ1Caw4Pov{1A=(I16!=FTqYkHS}GxNzzZ#|9Qn9jZT^%>UHU#aFQ8 z*lBiG#Bdo1v!(eOG%fXK9yI3b^gs_KucYyJ293YFwB#GWrs+lk-@0hyb+cA^L^zy$ zlTzpgLiRS-TfnsO%?aGc*a|=`n?@ii?+@(hW}j4g^6aGI@&(3<8|#|A@Z`H+@?Jwl zhby3u#CQ`TaSK+J@)yx?2+dWRZ=+0s1wBEDvwC1DyNxlacc@-Qn}1=9b&-tjk-@d( zKY3Y<&bVuzXd{yj1}-bE62$qJI_fDlR8GAl@;Q!XU^x|1Y2SU}Q!og~plA(F6P zP*5OkkRSE$%7fqGWmYQw1~-)f^HAM=;s%zk5t*90el z_v)n5hYKae**Uvd-UXCNK_r!AlS=GK-H_Bho77zOCGYA&eNBPCFSf9YHW1#EC}`Oa)PUkctZl^TL8I;PuAA=!1#>|LX(p zt%7qM>Q*Us^hOC9ue_+BUF?uY2}G}w@LLH=8PH3Rl}#B+^2OeLXT*-0gH%*^VP2dk za`Kz#9jHk=DQ{LZb?;L)tJ47>6%s2~7|VbJ@MbRqEG9Z6a~uxj#Do*GW0A?S#Qv@< zG3tdiroqw?L~%h33h0FsuTJhN zTYDq4XRQ{#PRd={h;UpzX2F|iEN?+u&E|H$0lw>gRJ)yf5ZQKk}+z5dq!o4i>`S=9;93ExhYX1qA-HtP_JSMfD@Xtv8sM_~}2%V!Ql zirbt9##AQiDLQw=-TQjV)s2241?#4O@dCiuY)`z0t@!-p0k*cKXtd~q^9m@*miIi$ zi$ud}Je9(ZP2agTW6L8ez!Z(* z>SZ>#E%N*uXX63)Mz2|mT&ceUpbJ;(4unjLnEwFAYgU88rY8IquQYCFsH8Bzt1ijH z=8P=fmL=Ukiw&p$nT;!oGf;jS7d%vXk#s-AWm+S>BZHp}XD0szbZ@$ju>>K%aN97! z_zK9y=D9f*sg2D&3%E}G8-(ev5yWZ>6aQl++L-21;+C|V>71%a41iAU@!!>{{{H?4 z?1D}?v+bHrVPlGQYO_tJu=MUsr_i64P8|vgB_+1r1;X8)zR13oS+=Jcwr)|%U{H^J zgP<_!TT1%QnG{KXpGEAdQuQckT285=g=txxl6PQmUz~lPF1#ChF$*_G_{A(()lH%cc7KNj0eR7wn~yOEdz;;pg*}B$RqtH6cWlR{zXL*> z9S5`t-jDSgQTnGJo=VI722^R?eWZmy{$l}?{rwb=XmCn3S$Ou z+qx@vTZ5S8(5yuln@=FX*?~sa%yjogGTk?j%j;5Vg_kUN@+R9BSGUlljSedt&2C3` zY1unawZ!Z3D#j7h2J#{^8oTn{|46xv(7{~ ze-ws!?D@hxMffV%=6b{QCI>#@LvIl2`1}jaDJczgn$3uHF(!)Tj~tjyAVGOFE#TqK za=LQ^d5L{?AZsNJd&TDHS-8ZNZHL4%V+O`*%y}P58y8+hkuodHeB&DcdTXSZ| zPp)mlkG5zAF6+h&+#f^%+xv}xYe?bnC(m|h5rK1wSCK9MY=``8B)!&25;-AA`g12q zG$|nI^-hv#03+#*PLfE+k%Y4{8ynJw(fi`FY-3Tbpww8zHK7*tkWzEGMWFWatVO)$ zT*O1n>d*te&Qqw*zAXLO_T#Nu=qjY62DxrH3~idd3vH4Ogl9*48;(`DRUvzi^Ng*(?0{`;KM=dkr;-uV~YvCHXcI+GsxlFV3r*71nD*ZuzoM z_QiQj0QBN~7A8Lja7*%iD&ra|qt0!v1^^m)=$pDu(qMDsdQR6;FwFFheCkH^yosLl zQaneHaI;Fd#Y*4^5^l8+90B527J?%{+-4y-Li(BecC*HxjZYJ)^~r!V@q{mw5KH(% z32}s9qW+9TRq9C-9~xd;f)fu|H~z^_uK_n2u+M-)Y}q#hW1uI-fZN1E0KPtjO9Fa$ zfL0mR!vi&ZtAQMCENUrS5~aJ3xPK_-(72)Nyk-%MGJQL%FTS0%8r$HtL7&^yf!tbJ z!aslPHz#05+bXi3$9e^}mF_;$7is*xMCl}e)}6|^1?Bdka(9Ehz|Zht+R(c!_Ei*{ zE!Wo|%OyGP3H&^iyA$6>?1#!wj~DDG!aZ?2+=p1aMDv+g$py>+f~IUc{ute0`&c`4 zPcyD0QPIVP) zSevNJPLU8;ztHv0a+iXISgYMza!%%LrL1c4a)9BqWH74sj z23Kh*8nHZf2N#10E;|tOhS@gYXQ}98RGu_8COwFgg`f{ldFbOW28JFCHm!+pBG32K zZH5O%nC%W;cH>ooE2{IWpKOAp1zOh$xujW#l8sZic$Dwwcl#HBZ(D|}VS`+6gU4e` zfsrfLz1bV+d30r*cH{tW=XRGWg1&FZ@Y+pnb!ISXag6R7hh?rUw8cGa zc7AhX&&&{%V4K7AI+)R+z$r6YCr!-wteq`1-LS=W+pP?5sK{Yo3M?W`qLs zUBc!&q&rF}b=K6)33hjaAt$IzY_7^UHPt?2lxK#a;hmb;T&@}UxhgZm^E&}1Hm`Yy z=jV!WUCv3MDnHk0`MIh&m!re$Yw~m5m7lAYIrN(&z^85gDEEbYK4UP}y%ejp+yI^& zymqm7HaCQd>}I{np;Xm7QmUHH8OrjK<0|W%>?BwE_P82__RAS=b7M_rH$XPUf03kS zQ+&rnr8tv@Amj=8)O00>YX~1pw$E2yIbX5WAY!CO7T1{4z}T`x7FSt9r*T}+L2$Y{ z#oH>+JmfS=P-n|1Q3`v4FiL*A=}}frS}2&roKXtaXSKlY3^L39?HQ%fHpy0J#@L{p zut#HUN|M`8*aFnu-j~tCj-SSLSCZurc9IY)m9SSAmVG>cqxW=jST0F+&)qoy&=pK(+k^=}D|q{-o8kD5I%`pl!Jyi^O7!lS0R z%puL9-J_=5B^tiU4u)I_V>x(x1k1K#y+h z%*S=Jcboh(2pWx3cSLp=Ck!ESB5 z)@_?PKCxyFx#$l^PgeBfv-ClCqDMXEmkGe&DnQN$eir2`ANYBy3NrKIDd;@~tU)MQ z`M{65l@H8WwA2eolKTQLA*Q7$%shjDePH6d13xF8oee03XM_4~v@!5|0?9>%|C^0N zIkRzW3Lt6XyXsXM&cWvzmoV_Yq3WzYQ% z^tPVEddZr{DMj{N$6~BzZC!+KO6U5^X9xUUcV0+$PUJtW_YU8w-U~V0$(`)JkfYC4 z|2g^;3y;E0i;&lDzu^h+T;t5wSqFyf9bXO~iTW(0hXTq@TcEQK{npmRA3)7p6GW$_ z2$WkB&k-C+)2L-b%EOn_%Zs&8F$^iu${ey%yCJ3A{CjX1Fan!h$|guVN){t$N4a3O zqh!v=j*>k~lbt}Ej9Qwsh4&>eNcHITHalwVMc8%qgo(mr7Pno}oS@SpA-F}g^q)wa#m8m)>!aGdu8!R+-7~Aj50u@FL zR^OIAwd^l>R9X9bghia#OqLanZUea)WNB6pl14oSZWDbILzzMMx;b0fdYY%Aw_YZq@8 zrE2N-!6ydp2Y6uM&H%FQZHilis|)AmE*f04EVc$?ZgBkt+122Bk4oaPrFn(en`KJL zYHU5OtFgsd_;bK&Y<);&q$td6L%?H;*y_;t0Eg;KgHm{G@tMZo2vV*~HV%c)#^Jj3 zwKO}Yq_UR05xBiGje=7Qd9YDy+d;v>22u5}qk1r^ryZphwbQdB{gHxMvtUu{SZd0n z499#}uhz8tWDCuAf^fP)$0p91@24$k9ZaeHv>XF}vFxyQ0wa$soW~>T$Rd~P^ZZ=$ z$ilfZruNfvxeAU)BApy`C<~O!Rd75~&AA+1YVD`xa&_c$Sj)K_yYSUxL{ z*mpp08?iHUBbHLsY)CF^ZfL?~%>lmp?1n)8IL-G`{~rz1iiZ5fNx?v+G3NAd3wNI! z<7TH09dmkAFh1m=qjP+yL&sdMg7F~_9i2PJ1tYj%e8>^(93KTExL|z95$qfv1tYj% ze8>^(93NFuvz?Z&x)aTIc>T29NeT+@-LJfN3v_C;&+^_s0yVoDM5m<)l&;3R1V_>| zZ?UVv6Bwssi4Y3Fdna0%Lsn|{-YGZxoN^xo-2?xfijckr&6+u1gNtTggJx{q4@G(3(afZ9H$_*7ZkDJWB3|A~&u-jn#024>I3Bg#mcGH^$7&J^*+f+&u~wcam0|NNNb zufV>fuIidv-S%vL&MS{@bua&>pEvmj)NP!IfDe|bQYF_T!7}~rOh4h*{OCT4>>R$; z#62WsEn${^PdkRX0M{68UBLTqSTh#(CpPR@2jKLdh=|98I~a%$=HlchKDc}1z3dn` zWPv7~IZM7w&1^%!eYHR8z-Ely-^F?|MID?+&gGeyDAeaOhz+`fRDtU|jp6iZ0K@51 z5oYh|yw5-4W@1Rt@1lF@`%&`u-VTI>0{D%!8_-{ITzA5^2Yb`^r0EimiR;bifm-Mh zx>JBZCvTb0so!U#O#Fa)D{Q>{*$>Seg2OOQ3>$duLr<(lnmH6moY4=%qe(Z1)1y&0 z=ODLk?1zd{a}iC=LtySn0S0HFIM(Df7a$V!r4|x$1hPqOk6WldRFYTz%-kQg2E1{+ zH4#K>-h|4i-uK|J|1i?qGHkAfp8w2SxhMyZvhiSA&__v zjYxcnz`%$Mv{Bp1cDVV@K;Ak9{bue1s`w!M_@A)}t!p;qFZGQCw~h9n<}3JFKGubP z;O_vE_ZO(f_U-!FbiwRILgE|jqfl1fx9jurtb`m^?7jEl;?1&=ReMR7IHm=L_HG<>&eT*_3S9ma;oPWXFZF!9zvp?iG}s# z<>7jEl;;Sl=UZnzdvQI4L_IJ#`Ffp~hwJGg&mgt|nlTxrLYYb zdj6oE!iDs^G-F>FJ=_Q;a$L_PYFy7HV!D@0#JHE6W?~fPqD**d>giTb4?XE(F-Jg9 zWFa^Lgl-`?0)*E>a0CdSh2RJfc%MZU$`LwKL#z1@{tV%=%oAH+p11<@#1xn})?=Ec zOT`!QQ#UT=r`NcYpFZOnh908)lLU06#QVYQmAi7xyj=Ts) zDUxNBs=_yduO<$PjBA(?k8vG8i;No-L*1zm6c(cAqHJbDqm_(BYMG)cSI-K168juU zplXU_a}zmoThx^*S6DqG^rYMzLGe`!S}2RBqZ1o3Mni2Icww(wIo9^|Ljco`|hm&(TqK#f2Kfo^o783ekC(0Jm_B7WkfLfJx&P z9=XxQsy<_X(3l5Mum%|OK*Z89)NObOEMlq-{as{F9)vVwHjGtyQK+c7 zOkKQ(UIgUr`_@bp8L=sTFco(Qg4Ly9!*AwDvKREnEySS0vvJFT`FR_+fEy>@KM0FZzg*iMK`V|b zXxp{fw(U)A^O#5E8h7N6Y21o}#vS#uH*P*P&T3nkk!#zZ(F#nmA#E*I<+T;YN>q)P z3?*p2!!d$ZIjp1C5fzitue!&~RUmItJ^Bm8ce+OtAa?d>5}2R2M`uWNRquW@iP{OW z-AA;CptbT%fu$H%#%fgEM&lrQnp+Npqk+i{E{(p+=`jKrSY1*aLk-$4#j!i2I4(

%KOYmo4($o#iI(jAyFQVCNG@z?u^Nl(@;xjXN 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 + + + F:/SteamLibrary/steamapps/common/Lethal Company + $(APPDATA)/r2modmanPlus-local/LethalCompany/profiles/Test LC API + $(SolutionDir)NetcodeWeaver + + + + + + + + +``` + +It is vital that you change the `NETCODE_PATCHER_DIR` property to the location of your local NetcodeWeaver installation. + +Ensure your Assembly CSharp is set `Publicize="true"` in the .csproj file to ensure it gets publicized. + +Once you have completed these steps, you will be able to properly build the solution. + +## Making a PR +Your [pull request](https://github.com/steven4547466/LC-API/pulls) should target the [dev branch](https://github.com/steven4547466/LC-API/tree/dev). This is because the `main` branch is reserved for tested features that are ready for release. Basically if someone were to clone the repo, they should be able to build `main` and use it without any fear of broken things. + +The `dev` branch, however, may contain untested features and is used to build release candidates. Before releases, the `dev` branch will be frozen and tested for issues, when it passes its testing then it will be merged into `main` and a release will be made. Pre-releases may come from the `dev` branch for release candidates and testing. These will be generally stable, but may still contain broken features before testing is done. + +Pull requests targeting the `main` branch will not be merged in most circumstances. Most merges to `main` will be directly from the frozen `dev` branch after testing. + +# Features +AssetBundle loading - Put asset bundles in BepInEx > Bundles and load them using BundleAPI.BundleLoader.GetLoadedAsset + +ServerAPI - Utilities relating to the network and server. This includes: + +ModdedServer - Automatically alerts other users when you host a server that your server is modded. +It also lets mod authors make their mods put users in special matchmaking where they can only play with other modded users + +Networking - Easily send data across the network to sync data between clients + +# Installation + +## R2ModMan or Thunderstore Manager (highly recommended) + +### R2ModMan +1. Go to the [thunderstore page](https://thunderstore.io/c/lethal-company/p/2018/LC_API) +2. Click `Install with Mod Manager` + +### Thunderstore Manager +(if the above doesn't work for you, open up the Thunderstore App to do the following) +1. Click `Get mods`/`Online` (whatever it happens to be called) +2. Search for LC API +3. Download it + +## Manual +1. Go to the [thunderstore page](https://thunderstore.io/c/lethal-company/p/2018/LC_API) +2. Click `Manual Download` +3. Unzip files +4. Navigate to `2018-LC_API-VERSION/BepinEx/plugins` and copy the contents +5. Find your BepinEx installation's plugin folder, by default it would be in steamapps: `steamapps\common\Lethal Company\BepInEx\plugins` +6. Create a folder titled `2018-LC_API` +7. Paste the contents into that folder + +**DO NOT PLACE THE BUNDLES FOLDER IN THE PREMADE `BepinEx/Bundles` FOLDER!** It must be in the `2018-LC_API` folder. + +If you did all of this correctly, it should load properly. + +The resulting file structure should look like this: +``` +BepinEx +├───Bundles +├───cache +├───config +├───core +├───patchers +└───plugins + └───2018-LC_API + ├───Bundles + │ └───networking + └───LC_API.dll +``` + +# TODO +- Picking up and dropping item events + - Including `Player.StartGrabbingItem`, `Player.GrabbingItem`, `Player.GrabbedItem`, `Player.DroppingItem`, and `Player.DroppedItem` + - The present-tense versions are cancellable, `StartGrabbingItem`, `GrabbingItem` and `DroppingItem`. + - `StartGrabbingItem` exists for items that take time to pickup. +- Using item events + - For shovels, that's hitting + - For boomboxes, that's activating music + - etc. though this would all fall under one event probably just `Item.Using` or `Item.Activating` +- Player begin and end moving events +- Player crouch and jump events +- Changing item event +- Selling items event + - Probably one for selling many items on the counter which will also call an event for each individual item being sold +- Item spawning event +- Enemy stuff is a bit further out, but here's some events that will be useful for them (as well as their past tense versions): + - Spawning + - Hurting + - Dying + - Attacking (when the enemy attacks a player) + - There may be ones specific to some kind of enemy as well +- `Player.EnteringFacility` and `Player.LeavingFacility` + - With a bool for using fire escape \ No newline at end of file diff --git a/Export/2018-LC_API/manifest.json b/Export/2018-LC_API/manifest.json new file mode 100644 index 0000000..2ce178c --- /dev/null +++ b/Export/2018-LC_API/manifest.json @@ -0,0 +1,11 @@ +{ + "namespace": "2018", + "name": "LC_API", + "description": "Multipurpose modding API for Lethal Company", + "version_number": "3.4.5", + "dependencies": [ + "BepInEx-BepInExPack-5.4.2100" + ], + "website_url": "https://github.com/steven4547466/LC-API", + "FullName": "2018-LC_API" +} \ No newline at end of file diff --git a/Gfe/NvidiaHighlights.cs b/Gfe/NvidiaHighlights.cs new file mode 100644 index 0000000..32c9a79 --- /dev/null +++ b/Gfe/NvidiaHighlights.cs @@ -0,0 +1,1045 @@ +/* +* Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +* +* NVIDIA CORPORATION and its licensors retain all intellectual property +* and proprietary rights in and to this software, related documentation +* and any modifications thereto. Any use, reproduction, disclosure or +* distribution of this software and related documentation without an express +* license agreement from NVIDIA CORPORATION is strictly prohibited. +*/ + +using System.Collections; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using UnityEngine; +using System.Text; +using System; + +namespace NVIDIA +{ + public class Highlights + { + + public static bool instanceCreated = false; + + public enum HighlightScope + { + Highlights = 0x00, + HighlightsRecordVideo = 0x01, + HighlightsRecordScreenshot = 0x02, + Ops = 0x03, + MAX + } + + public enum HighlightType + { + None = 0x00, + Milestone = 0x01, + Achievement = 0x02, + Incident = 0x04, + StateChange = 0x08, + Unannounced = 0x10, + MAX = 0x20 + }; + + public enum HighlightSignificance + { + None = 0x00, + ExtremelyBad = 0x01, + VeryBad = 0x02, + Bad = 0x04, + Neutral = 0x10, + Good = 0x100, + VeryGood = 0x200, + ExtremelyGood = 0x400, + MAX = 0x800 + }; + + public enum Permission + { + Granted = 0, + Denied = 1, + MustAsk = 2, + Unknown = 3, + MAX = 4, + }; + + public enum LogLevel + { + None = 0, + Error = 1, + Info = 2, + Debug = 3, + Verbose = 4, + MAX = 5 + }; + + public enum ReturnCode + { + SUCCESS = 0, + SUCCESS_VERSION_OLD_SDK = 1001, + SUCCESS_VERSION_OLD_GFE = 1002, + SUCCESS_PENDING = 1003, + SUCCESS_USER_NOT_INTERESTED = 1004, + SUCCESS_PERMISSION_GRANTED = 1005, + + ERR_GENERIC = -1001, + ERR_GFE_VERSION = -1002, + ERR_SDK_VERSION = -1003, + ERR_NOT_IMPLEMENTED = -1004, + ERR_INVALID_PARAMETER = -1005, + ERR_NOT_SET = -1006, + ERR_SHADOWPLAY_IR_DISABLED = -1007, + ERR_SDK_IN_USE = -1008, + ERR_GROUP_NOT_FOUND = -1009, + ERR_FILE_NOT_FOUND = -1010, + ERR_HIGHLIGHTS_SETUP_FAILED = -1011, + ERR_HIGHLIGHTS_NOT_CONFIGURED = -1012, + ERR_HIGHLIGHTS_SAVE_FAILED = -1013, + ERR_UNEXPECTED_EXCEPTION = -1014, + ERR_NO_HIGHLIGHTS = -1015, + ERR_NO_CONNECTION = -1016, + ERR_PERMISSION_NOT_GRANTED = -1017, + ERR_PERMISSION_DENIED = -1018, + ERR_INVALID_HANDLE = -1019, + ERR_UNHANDLED_EXCEPTION = -1020, + ERR_OUT_OF_MEMORY = -1021, + ERR_LOAD_LIBRARY = -1022, + ERR_LIB_CALL_FAILED = -1023, + ERR_IPC_FAILED = -1024, + ERR_CONNECTION = -1025, + ERR_MODULE_NOT_LOADED = -1026, + ERR_LIB_CALL_TIMEOUT = -1027, + ERR_APPLICATION_LOOKUP_FAILED = -1028, + ERR_APPLICATION_NOT_KNOWN = -1029, + ERR_FEATURE_DISABLED = -1030, + ERR_APP_NO_OPTIMIZATION = -1031, + ERR_APP_SETTINGS_READ = -1032, + ERR_APP_SETTINGS_WRITE = -1033, + }; + + public struct TranslationEntry + { + public TranslationEntry(string _Language, string _Translation) + { + Language = _Language; + Translation = _Translation; + } + public string Language; + public string Translation; + }; + + [StructLayout(LayoutKind.Sequential), Serializable] + private struct Scope + { + [MarshalAsAttribute(UnmanagedType.SysInt)] + public int value; + }; + + [StructLayout(LayoutKind.Sequential), Serializable] + private struct HighlightDefinitionInternal + { + [MarshalAsAttribute(UnmanagedType.LPStr)] + public string id; + [MarshalAsAttribute(UnmanagedType.I1)] + public bool userDefaultInterest; + [MarshalAsAttribute(UnmanagedType.SysInt)] + public int highlightTags; + [MarshalAsAttribute(UnmanagedType.SysInt)] + public int significance; + [MarshalAsAttribute(UnmanagedType.LPStr)] + public string languageTranslationStrings; + }; + + public struct HighlightDefinition + { + public string Id; + public bool UserDefaultInterest; + public HighlightType HighlightTags; + public HighlightSignificance Significance; + public TranslationEntry[] NameTranslationTable; + }; + + [StructLayout(LayoutKind.Sequential), Serializable] + private struct OpenGroupParamsInternal + { + [MarshalAsAttribute(UnmanagedType.LPStr)] + public string id; + [MarshalAsAttribute(UnmanagedType.LPStr)] + public string groupDescriptionTable; + }; + + public struct OpenGroupParams + { + public string Id; + public TranslationEntry[] GroupDescriptionTable; + }; + + [StructLayout(LayoutKind.Sequential), Serializable] + public struct CloseGroupParams + { + [MarshalAsAttribute(UnmanagedType.LPStr)] + public string id; + [MarshalAsAttribute(UnmanagedType.I1)] + public bool destroyHighlights; + }; + + [StructLayout(LayoutKind.Sequential), Serializable] + public struct ScreenshotHighlightParams + { + [MarshalAsAttribute(UnmanagedType.LPStr)] + public string groupId; + [MarshalAsAttribute(UnmanagedType.LPStr)] + public string highlightId; + }; + + [StructLayout(LayoutKind.Sequential), Serializable] + public struct VideoHighlightParams + { + [MarshalAsAttribute(UnmanagedType.LPStr)] + public string groupId; + [MarshalAsAttribute(UnmanagedType.LPStr)] + public string highlightId; + [MarshalAsAttribute(UnmanagedType.SysInt)] + public int startDelta; + [MarshalAsAttribute(UnmanagedType.SysInt)] + public int endDelta; + }; + + [StructLayout(LayoutKind.Sequential), Serializable] + private struct GroupViewInternal + { + [MarshalAsAttribute(UnmanagedType.LPStr)] + public string groupId; + [MarshalAsAttribute(UnmanagedType.SysInt)] + public int tagFilter; + [MarshalAsAttribute(UnmanagedType.SysInt)] + public int significanceFilter; + }; + + public struct GroupView + { + public string GroupId; + public HighlightType TagFilter; + public HighlightSignificance SignificanceFilter; + }; + + public struct RequestPermissionsParams + { + public HighlightScope ScopesFlags; + }; + + [StructLayout(LayoutKind.Sequential), Serializable] + private struct RequestPermissionsParamsInternal + { + [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 1)] + public int scopesFlags; + }; + + [StructLayout(LayoutKind.Sequential), Serializable] + private struct EmptyCallbackId + { + [MarshalAsAttribute(UnmanagedType.SysInt)] + public int id; + [MarshalAsAttribute(UnmanagedType.FunctionPtr)] + public EmptyCallbackDelegate callback; + }; + + [StructLayout(LayoutKind.Sequential), Serializable] + private struct GetNumberOfHighlightsCallbackId + { + [MarshalAsAttribute(UnmanagedType.SysInt)] + public int id; + [MarshalAsAttribute(UnmanagedType.FunctionPtr)] + public GetNumberOfHighlightsCallbackDelegate callback; + }; + + [StructLayout(LayoutKind.Sequential), Serializable] + private struct UserSettingsInternal + { + [MarshalAsAttribute(UnmanagedType.SysInt)] + public IntPtr highlightSettingTable; + [MarshalAsAttribute(UnmanagedType.SysInt)] + public int highlightSettingTableSize; + }; + + public struct UserSettings + { + public List highlightSettingTable; + }; + + [StructLayout(LayoutKind.Sequential), Serializable] + private struct UserSettingInternal + { + [MarshalAsAttribute(UnmanagedType.LPStr)] + public string id; + [MarshalAsAttribute(UnmanagedType.I1)] + public bool enabled; + }; + + public struct UserSetting + { + public string id; + public bool enabled; + }; + + [StructLayout(LayoutKind.Sequential), Serializable] + private struct GetUserSettingsCallbackId + { + [MarshalAsAttribute(UnmanagedType.SysInt)] + public int id; + [MarshalAsAttribute(UnmanagedType.FunctionPtr)] + public GetUserSettingsCallbackDelegate callback; + [MarshalAsAttribute(UnmanagedType.FunctionPtr)] + public IntermediateCallbackDelegateInternal intermediateCallback; + }; + + [StructLayout(LayoutKind.Sequential), Serializable] + private struct UILanguageInternal + { + [MarshalAsAttribute(UnmanagedType.LPStr)] + public string cultureCode; + }; + + public struct UILanguage + { + public string cultureCode; + }; + + [StructLayout(LayoutKind.Sequential), Serializable] + private struct GetUILanguageCallbackId + { + [MarshalAsAttribute(UnmanagedType.SysInt)] + public int id; + [MarshalAsAttribute(UnmanagedType.FunctionPtr)] + public GetUILanguageCallbackDelegate callback; + [MarshalAsAttribute(UnmanagedType.FunctionPtr)] + public IntermediateCallbackDelegateInternal intermediateCallback; + }; + + const string DLL64Name = "HighlightsPlugin64"; + + [DllImport(DLL64Name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + private static extern int Create([MarshalAs(UnmanagedType.LPStr)] string appName, int n, IntPtr scopes); + + [DllImport(DLL64Name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + private static extern bool Release(); + + [DllImport(DLL64Name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + private static extern void Highlights_RequestPermissionsAsync(IntPtr asyncOp); + + [DllImport(DLL64Name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + private static extern void Highlights_GetUILanguageAsync(IntPtr asyncOp); + + [DllImport(DLL64Name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + private static extern void SetDefaultLocale([MarshalAs(UnmanagedType.LPStr)] string defaultLocale); + + [DllImport(DLL64Name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + private static extern void Highlights_ConfigureAsync(int n, IntPtr highlightDefinitions, IntPtr asyncOp); + + [DllImport(DLL64Name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + private static extern void Highlights_GetUserSettingsAsync(IntPtr asyncOp); + + [DllImport(DLL64Name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + private static extern void Highlights_OpenGroupAsync(IntPtr openGroupParams, IntPtr asyncOp); + + [DllImport(DLL64Name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + private static extern void Highlights_CloseGroupAsync(IntPtr closeGroupParams, IntPtr asyncOp); + + [DllImport(DLL64Name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + private static extern void Highlights_SetScreenshotHighlightAsync(IntPtr screenshotHighlightParams, IntPtr asyncOp); + + [DllImport(DLL64Name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + private static extern void Highlights_SetVideoHighlightAsync(IntPtr videoHighlightParams, IntPtr asyncOp); + + [DllImport(DLL64Name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + private static extern void Highlights_OpenSummaryAsync(int n, IntPtr summaryParams, IntPtr asyncOp); + + [DllImport(DLL64Name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + private static extern void Highlights_GetNumberOfHighlightsAsync(IntPtr groupView, IntPtr ayncOp); + + [DllImport(DLL64Name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.BStr)] + public static extern string GetInfoLog(); + + [DllImport(DLL64Name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.BStr)] + public static extern string GetErrorLog(); + + [DllImport(DLL64Name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + private static extern int Log_SetLevel(int level); + + [DllImport(DLL64Name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + private static extern int Log_AttachListener([MarshalAs(UnmanagedType.FunctionPtr)] LogListenerDelegate listener); + + [DllImport(DLL64Name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + private static extern int Log_SetListenerLevel(int level); + + private static int CallbackId = 0; + // For public use right before requesting an async operation, if CallbackId needs to be used to map a caller and a callback. + public static int PeekCallbackId() + { + return CallbackId; + } + // Use privately once for one async operation request. + private static int GetCallbackId() + { + return CallbackId++; + } + + // Local functions + //Constructs the main SDK interface. Also performs the version check. + public static ReturnCode CreateHighlightsSDK(string AppName, HighlightScope[] RequiredScopes) + { + + List allocatedMemory = new List(); + + IntPtr nativeArray = Marshal.AllocHGlobal(RequiredScopes.Length * Marshal.SizeOf(typeof(IntPtr))); + + for (int i = 0; i < RequiredScopes.Length; ++i) + { + IntPtr nativeScope = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Scope))); + allocatedMemory.Add(nativeScope); + Scope scope = new Scope(); + scope.value = (int)RequiredScopes[i]; + Marshal.StructureToPtr(scope, nativeScope, false); + Marshal.WriteIntPtr(nativeArray, i * Marshal.SizeOf(typeof(IntPtr)), nativeScope); + } + + ReturnCode ret = (ReturnCode)Create(AppName, RequiredScopes.Length, nativeArray); + + if (ret == ReturnCode.SUCCESS) + { + Debug.Log("Highlights SDK initialized successfully"); + instanceCreated = true; + } + else + { + Debug.LogError("Failed to initialize Highlights SDK"); + } + + Marshal.FreeHGlobal(nativeArray); + + foreach (IntPtr ptr in allocatedMemory) + { + Marshal.FreeHGlobal(ptr); + } + + return ret; + } + + //Release the main SDK interface after create. + public static void ReleaseHighlightsSDK() + { + if (!instanceCreated) + { + Debug.LogError("Highlights release failed as no running instance was found"); + return; + } + + if (Release()) + Debug.Log("Highlights SDK released successfully"); + else + Debug.LogError("Failed to release Highlights SDK"); + + instanceCreated = false; + + } + + // Updates the unity log with info and error messages passed from the highlights sdk + public static void UpdateLog() + { + string infoLog = GetInfoLog(); + if (infoLog != "") + { + Debug.Log(infoLog); + } + + string errorLog = GetErrorLog(); + if (errorLog != "") + { + Debug.LogError(errorLog); + } + } + + // Configure Highlights. Takes an array of highlight definition objects to define highlights in the game + public static void ConfigureHighlights(HighlightDefinition[] highlightDefinitions, string defaultLocale, EmptyCallbackDelegate callback) + { + if (!instanceCreated) + { + Debug.LogError("ERROR: Cannot configure Highlights. The SDK has not been initialized."); + return; + } + + SetDefaultLocale(defaultLocale); + + var allocatedMemory = new List(); + + IntPtr nativeArray = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)) * highlightDefinitions.Length); + + EmptyCallbackId cid = new EmptyCallbackId(); + cid.id = GetCallbackId(); + cid.callback = callback; + + IntPtr asyncOp = Marshal.AllocHGlobal(Marshal.SizeOf(cid)); + + try + { + + for (int i = 0; i < highlightDefinitions.Length; ++i) + { + IntPtr nativeHighlightsDefinition = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(HighlightDefinitionInternal))); + HighlightDefinitionInternal hd = new HighlightDefinitionInternal(); + hd.id = highlightDefinitions[i].Id; + hd.highlightTags = (int)(highlightDefinitions[i]).HighlightTags; + hd.significance = (int)(highlightDefinitions[i]).Significance; + hd.userDefaultInterest = (highlightDefinitions[i]).UserDefaultInterest; + StringBuilder sb = new StringBuilder(); + foreach (TranslationEntry te in (highlightDefinitions[i]).NameTranslationTable) + { + sb.Append(te.Language).Append("\a").Append(te.Translation).Append("\a"); + } + hd.languageTranslationStrings = sb.ToString(); + allocatedMemory.Add(nativeHighlightsDefinition); + Marshal.StructureToPtr(hd, nativeHighlightsDefinition, false); + Marshal.WriteIntPtr(nativeArray, i * Marshal.SizeOf(typeof(IntPtr)), nativeHighlightsDefinition); + } + + Marshal.StructureToPtr(cid, asyncOp, false); + + Highlights_ConfigureAsync(highlightDefinitions.Length, nativeArray, asyncOp); + } + finally + { + Marshal.FreeHGlobal(nativeArray); + Marshal.FreeHGlobal(asyncOp); + + foreach (IntPtr ptr in allocatedMemory) + { + Marshal.FreeHGlobal(ptr); + } + } + } + + // Begins a "group" which groups several Highlights together. + public static void OpenGroup(OpenGroupParams openGroupParams, EmptyCallbackDelegate callback) + { + if (!instanceCreated) + { + Debug.LogError("ERROR: Cannot open a group. The SDK has not been initialized."); + return; + } + + OpenGroupParamsInternal ogp = new OpenGroupParamsInternal(); + ogp.id = openGroupParams.Id; + + StringBuilder sb = new StringBuilder(); + foreach (TranslationEntry te in openGroupParams.GroupDescriptionTable) + { + sb.Append(te.Language).Append("\a").Append(te.Translation).Append("\a"); + } + + ogp.groupDescriptionTable = sb.ToString(); + + IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(ogp)); + + EmptyCallbackId cid = new EmptyCallbackId(); + cid.id = GetCallbackId(); + cid.callback = callback; + + IntPtr asyncOp = Marshal.AllocHGlobal(Marshal.SizeOf(cid)); + + try + { + Marshal.StructureToPtr(ogp, pnt, false); + Marshal.StructureToPtr(cid, asyncOp, false); + + Highlights_OpenGroupAsync(pnt, asyncOp); + } + finally + { + Marshal.FreeHGlobal(pnt); + Marshal.FreeHGlobal(asyncOp); + } + + } + + // Closes out a group and purges the unsaved contents. + public static void CloseGroup(CloseGroupParams closeGroupParams, EmptyCallbackDelegate callback) + { + if (!instanceCreated) + { + Debug.LogError("ERROR: Cannot close a group. The SDK has not been initialized."); + return; + } + + IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(closeGroupParams)); + + EmptyCallbackId cid = new EmptyCallbackId(); + cid.id = GetCallbackId(); + cid.callback = callback; + + IntPtr asyncOp = Marshal.AllocHGlobal(Marshal.SizeOf(cid)); + + try + { + Marshal.StructureToPtr(closeGroupParams, pnt, false); + Marshal.StructureToPtr(cid, asyncOp, false); + + Highlights_CloseGroupAsync(pnt, asyncOp); + } + finally + { + Marshal.FreeHGlobal(pnt); + Marshal.FreeHGlobal(asyncOp); + } + } + + // Records a screenshot highlight for the given group. Attached metadata to it to make the Highlight more interesting. + public static void SetScreenshotHighlight(ScreenshotHighlightParams screenshotHighlightParams, EmptyCallbackDelegate callback) + { + if (!instanceCreated) + { + Debug.LogError("ERROR: Cannot take a screenshot. The SDK has not been initialized."); + return; + } + + IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(screenshotHighlightParams)); + + EmptyCallbackId cid = new EmptyCallbackId(); + cid.id = GetCallbackId(); + cid.callback = callback; + + IntPtr asyncOp = Marshal.AllocHGlobal(Marshal.SizeOf(cid)); + + try + { + Marshal.StructureToPtr(screenshotHighlightParams, pnt, false); + Marshal.StructureToPtr(cid, asyncOp, false); + + Highlights_SetScreenshotHighlightAsync(pnt, asyncOp); + } + finally + { + Marshal.FreeHGlobal(pnt); + Marshal.FreeHGlobal(asyncOp); + } + } + + // Records a video highlight for the given group. Attached metadata to it to make the Highlight more interesting. + // Set the start and end delta to change the length of the video clip. + public static void SetVideoHighlight(VideoHighlightParams videoHighlightParams, EmptyCallbackDelegate callback) + { + if (!instanceCreated) + { + Debug.LogError("ERROR: Cannot record a video. The SDK has not been initialized."); + return; + } + + IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(videoHighlightParams)); + + EmptyCallbackId cid = new EmptyCallbackId(); + cid.id = GetCallbackId(); + cid.callback = callback; + + IntPtr asyncOp = Marshal.AllocHGlobal(Marshal.SizeOf(cid)); + + try + { + Marshal.StructureToPtr(videoHighlightParams, pnt, false); + Marshal.StructureToPtr(cid, asyncOp, false); + + Highlights_SetVideoHighlightAsync(pnt, asyncOp); + } + finally + { + Marshal.FreeHGlobal(pnt); + Marshal.FreeHGlobal(asyncOp); + } + } + + // Opens up Summary Dialog for one or more groups + public static void OpenSummary(GroupView[] summaryParams, EmptyCallbackDelegate callback) + { + if (!instanceCreated) + { + Debug.LogError("ERROR: Cannot open summary. The SDK has not been initialized."); + return; + } + + List allocatedMemory = new List(); + IntPtr nativeArray = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)) * summaryParams.Length); + + EmptyCallbackId cid = new EmptyCallbackId(); + cid.id = GetCallbackId(); + cid.callback = callback; + + IntPtr asyncOp = Marshal.AllocHGlobal(Marshal.SizeOf(cid)); + + try + { + + for (int i = 0; i < summaryParams.Length; ++i) + { + GroupViewInternal gvi = new GroupViewInternal(); + gvi.groupId = summaryParams[i].GroupId; + gvi.significanceFilter = (int)(summaryParams[i]).SignificanceFilter; + gvi.tagFilter = (int)(summaryParams[i]).TagFilter; + + IntPtr nativeSummaryParams = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(GroupViewInternal))); + allocatedMemory.Add(nativeSummaryParams); + Marshal.StructureToPtr(gvi, nativeSummaryParams, false); + Marshal.WriteIntPtr(nativeArray, Marshal.SizeOf(typeof(IntPtr)) * i, nativeSummaryParams); + } + + Marshal.StructureToPtr(cid, asyncOp, false); + + Highlights_OpenSummaryAsync(summaryParams.Length, nativeArray, asyncOp); + } + finally + { + Marshal.FreeHGlobal(nativeArray); + Marshal.FreeHGlobal(asyncOp); + + foreach (IntPtr ptr in allocatedMemory) + { + Marshal.FreeHGlobal(ptr); + } + } + } + + // Retrieves the number of highlights given the group ID and filtering params + public static void GetNumberOfHighlights(GroupView groupView, GetNumberOfHighlightsCallbackDelegate callback) + { + if (!instanceCreated) + { + Debug.LogError("ERROR: Cannot get number of highlights. The SDK has not been initialized."); + return; + } + + GroupViewInternal spi = new GroupViewInternal(); + spi.groupId = groupView.GroupId; + spi.significanceFilter = (int)groupView.SignificanceFilter; + spi.tagFilter = (int)groupView.TagFilter; + + IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(spi)); + + GetNumberOfHighlightsCallbackId cid = new GetNumberOfHighlightsCallbackId(); + cid.id = GetCallbackId(); + cid.callback = callback; + + IntPtr pntid = Marshal.AllocHGlobal(Marshal.SizeOf(cid)); + + try + { + Marshal.StructureToPtr(spi, pnt, false); + Marshal.StructureToPtr(cid, pntid, false); + Highlights_GetNumberOfHighlightsAsync(pnt, pntid); + } + finally + { + Marshal.FreeHGlobal(pnt); + Marshal.FreeHGlobal(pntid); + } + } + + public delegate void GetNumberOfHighlightsCallbackDelegate(ReturnCode ret, int number, int id); + + private delegate void IntermediateCallbackDelegateInternal(ReturnCode ret, IntPtr blob, IntPtr callbackWithId); + + public delegate void EmptyCallbackDelegate(ReturnCode ret, int id); + + public static void GetUserSettings(GetUserSettingsCallbackDelegate callback) + { + if (!instanceCreated) + { + Debug.LogError("ERROR: Cannot get highlights user setting. The SDK has not been initialized."); + return; + } + + GetUserSettingsCallbackId cid = new GetUserSettingsCallbackId(); + cid.id = GetCallbackId(); + cid.callback = callback; + cid.intermediateCallback = GetUserSettingsCallbackInternal; + + IntPtr asyncOp = Marshal.AllocHGlobal(Marshal.SizeOf(cid)); + + try + { + Marshal.StructureToPtr(cid, asyncOp, false); + Highlights_GetUserSettingsAsync(asyncOp); + } + finally + { + Marshal.FreeHGlobal(asyncOp); + } + } + + private static void GetUserSettingsCallbackInternal(ReturnCode ret, IntPtr blob, IntPtr callbackId) + { + UserSettings uss = new UserSettings(); + uss.highlightSettingTable = new List(); + + // read from blob when possible + if (ret == ReturnCode.SUCCESS) + { + UserSettingsInternal ussi = new UserSettingsInternal(); + ussi = (UserSettingsInternal)Marshal.PtrToStructure(blob, typeof(UserSettingsInternal)); + for (int i = 0; i < ussi.highlightSettingTableSize; i++) + { + // read usi + UserSettingInternal usi = new UserSettingInternal(); + IntPtr ptrOfOneSetting = new IntPtr(ussi.highlightSettingTable.ToInt64() + i * Marshal.SizeOf(usi)); + usi = (UserSettingInternal)Marshal.PtrToStructure(ptrOfOneSetting, typeof(UserSettingInternal)); + + // copy usi to us + UserSetting us = new UserSetting(); + us.enabled = usi.enabled; + us.id = usi.id; + + // pack us into uss + uss.highlightSettingTable.Add(us); + } + } + + // read cid + GetUserSettingsCallbackId cid = new GetUserSettingsCallbackId(); + + cid = (GetUserSettingsCallbackId)Marshal.PtrToStructure(callbackId, typeof(GetUserSettingsCallbackId)); + GetUserSettingsCallbackDelegate nextCall = cid.callback; + int id = cid.id; + + // call user provided function + nextCall(ret, uss, id); + } + + public delegate void GetUserSettingsCallbackDelegate(ReturnCode ret, UserSettings settings, int id); + + public static void GetUILanguage(GetUILanguageCallbackDelegate callback) + { + if (!instanceCreated) + { + Debug.LogError("ERROR: Cannot get highlights UI language. The SDK has not been initialized."); + return; + } + + GetUILanguageCallbackId cid = new GetUILanguageCallbackId(); + cid.id = GetCallbackId(); + cid.callback = callback; + cid.intermediateCallback = GetUILanguageCallbackInternal; + + IntPtr asyncOp = Marshal.AllocHGlobal(Marshal.SizeOf(cid)); + + try + { + Marshal.StructureToPtr(cid, asyncOp, false); + Highlights_GetUILanguageAsync(asyncOp); + } + finally + { + Marshal.FreeHGlobal(asyncOp); + } + } + + private static void GetUILanguageCallbackInternal(ReturnCode ret, IntPtr blob, IntPtr callbackId) + { + UILanguage ul = new UILanguage(); + + // read from blob when possible + if (ret == ReturnCode.SUCCESS) + { + // copy blob into uli + UILanguageInternal uli = new UILanguageInternal(); + uli = (UILanguageInternal)Marshal.PtrToStructure(blob, typeof(UILanguageInternal)); + + // read ul from uli + ul.cultureCode = uli.cultureCode; + } + + // read from cid + GetUILanguageCallbackId cid = new GetUILanguageCallbackId(); + cid = (GetUILanguageCallbackId)Marshal.PtrToStructure(callbackId, typeof(GetUILanguageCallbackId)); + GetUILanguageCallbackDelegate nextCall = cid.callback; + int id = cid.id; + + // call user provided function + nextCall(ret, ul.cultureCode, id); + } + + public delegate void GetUILanguageCallbackDelegate(ReturnCode ret, string cultureCode, int id); + + // Request permissions from the user (if not already granted to provide permissions for highlight capture) + public static void RequestPermissions(EmptyCallbackDelegate callback) + { + if (!instanceCreated) + { + Debug.LogError("ERROR: Cannot request permissions. The SDK has not been initialized."); + return; + } + + EmptyCallbackId cid = new EmptyCallbackId(); + cid.id = GetCallbackId(); + cid.callback = callback; + + IntPtr asyncOp = Marshal.AllocHGlobal(Marshal.SizeOf(cid)); + + try + { + Marshal.StructureToPtr(cid, asyncOp, false); + Highlights_RequestPermissionsAsync(asyncOp); + } + finally + { + Marshal.FreeHGlobal(asyncOp); + } + } + + public static ReturnCode SetLogLevel(LogLevel level) + { + return (ReturnCode)Log_SetLevel((int)level); + } + + public static ReturnCode AttachLogListener(LogListenerDelegate listener) + { + return (ReturnCode)Log_AttachListener(listener); + } + + public static ReturnCode SetListenerLogLevel(LogLevel level) + { + return (ReturnCode)Log_SetListenerLevel((int)level); + } + + public delegate void LogListenerDelegate(LogLevel level, string message); + public static void DefaultLogListener(LogLevel level, string message) + { + string[] levelString = { "None", "Error", "Info", "Debug", "Verbose" }; + Debug.Log("Highlights LogListener " + levelString[(int)level] + ": " + message); + } + + + public static void DefaultGetNumberOfHighlightsCallback(ReturnCode ret, int number, int id) + { + if (ret == ReturnCode.SUCCESS) + { + Debug.Log("GetNumberOfHighlightsCallback " + id + " returns " + number); + } + else + { + Debug.LogError("GetNumberOfHighlightsCallback " + id + " returns unsuccess"); + } + } + + public static void DefaultGetUserSettingsCallback(ReturnCode ret, UserSettings settings, int id) + { + if (ret == ReturnCode.SUCCESS) + { + Debug.Log("GetUserSettingsCallback " + id + " returns table count " + settings.highlightSettingTable.Count); + foreach (var setting in settings.highlightSettingTable) + { + Debug.Log("GetUserSettingsCallback " + id + " " + setting.id + " " + setting.enabled); + } + } + else + { + Debug.LogError("GetUserSettingsCallback " + id + " returns unsuccess"); + } + } + + public static void DefaultGetUILanguageCallback(ReturnCode ret, string langueage, int id) + { + if (ret == ReturnCode.SUCCESS) + { + Debug.Log("GetUILanguageCallback " + id + " returns " + langueage); + } + else + { + Debug.LogError("GetUILanguageCallback " + id + " returns unsuccess"); + } + } + + public static void DefaultRequestPermissionsCallback(ReturnCode ret, int id) + { + if (ret == ReturnCode.SUCCESS) + { + Debug.Log("RequestPermissionsCallback " + id + " returns success"); + } + else + { + Debug.LogError("RequestPermissionsCallback " + id + " returns unsuccess"); + } + } + + public static void DefaultConfigureCallback(ReturnCode ret, int id) + { + if (ret == ReturnCode.SUCCESS) + { + Debug.Log("ConfigureCallback " + id + " returns success"); + } + else + { + Debug.LogError("ConfigureCallback " + id + " returns unsuccess"); + } + } + + public static void DefaultSetScreenshotCallback(ReturnCode ret, int id) + { + if (ret == ReturnCode.SUCCESS) + { + Debug.Log("SetScreenshotCallback " + id + " returns success"); + } + else + { + Debug.LogError("SetScreenshotCallback " + id + " returns unsuccess"); + } + } + + public static void DefaultSetVideoCallback(ReturnCode ret, int id) + { + if (ret == ReturnCode.SUCCESS) + { + Debug.Log("SetVideoCallback " + id + " returns success"); + } + else + { + Debug.LogError("SetVideoCallback " + id + " returns unsuccess"); + } + } + + public static void DefaultOpenSummaryCallback(ReturnCode ret, int id) + { + if (ret == ReturnCode.SUCCESS) + { + Debug.Log("OpenSummaryCallback " + id + " returns success"); + } + else + { + Debug.LogError("OpenSummaryCallback " + id + " returns unsuccess"); + } + } + + public static void DefaultOpenGroupCallback(ReturnCode ret, int id) + { + if (ret == ReturnCode.SUCCESS) + { + Debug.Log("OpenGroupCallback " + id + " returns success"); + } + else + { + Debug.LogError("OpenGroupCallback " + id + " returns unsuccess"); + } + } + + public static void DefaultCloseGroupCallback(ReturnCode ret, int id) + { + if (ret == ReturnCode.SUCCESS) + { + Debug.Log("CloseGroupCallback " + id + " returns success"); + } + else + { + Debug.LogError("CloseGroupCallback " + id + " returns unsuccess"); + } + } + + } +} \ No newline at end of file diff --git a/Highlight.cs b/Highlight.cs new file mode 100644 index 0000000..71c8b05 --- /dev/null +++ b/Highlight.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Text; +using NVIDIA; + +namespace LC_Highlights +{ + internal class Highlight + { + private static DateTime _startTime; + private static string _lastName; + + public static void LogCallback(Highlights.ReturnCode ret, int id) + { + Plugin.Log.LogDebug($"Callback from NVIDIA SDK with code {ret} for ID {id}."); + } + + + public static void SaveRecording(string name) + { + _lastName = name; + + if (!Plugin.cfgEnabled.Value) + return; + + DateTime currentTime = DateTime.Now; + DateTime timeBefore = currentTime.AddSeconds(-15); + TimeSpan difference = DateTime.Now - timeBefore; + + Highlights.VideoHighlightParams vhp = new Highlights.VideoHighlightParams(); + vhp.highlightId = "MAP_PLAY"; + vhp.groupId = "MAP_PLAY_GROUP"; + vhp.startDelta = (int)-difference.TotalMilliseconds; + vhp.endDelta = 0; + + vhp.startDelta += 0; + vhp.endDelta += Plugin.cfgAfterDeathDelta.Value; + + Highlights.SetVideoHighlight(vhp, LogCallback); + } + + public static void ShowSummary() + { + if (!Plugin.cfgEnabled.Value) + return; + + Highlights.GroupView[] groupViews = new Highlights.GroupView[1]; + Highlights.GroupView gv1 = new Highlights.GroupView(); + gv1.GroupId = "MAP_PLAY_GROUP"; + gv1.SignificanceFilter = Highlights.HighlightSignificance.Good; + gv1.TagFilter = Highlights.HighlightType.Achievement; + groupViews[0] = gv1; + + Highlights.OpenSummary(groupViews, LogCallback); + } + } +} diff --git a/LC_Highlights.csproj b/LC_Highlights.csproj new file mode 100644 index 0000000..8123797 --- /dev/null +++ b/LC_Highlights.csproj @@ -0,0 +1,40 @@ + + + + netstandard2.1 + LC_Highlights + Source moment + 1.0.0 + true + latest + + https://api.nuget.org/v3/index.json; + https://nuget.bepinex.dev/v3/index.json; + https://nuget.samboy.dev/v3/index.json + + LC_Highlights + + + + + + + + + + + + + + + + ..\..\..\SteamLibrary\steamapps\common\Lethal Company\Lethal Company_Data\Managed\Assembly-CSharp.dll + + + ..\..\..\SteamLibrary\steamapps\common\Lethal Company\Lethal Company_Data\Managed\Unity.Netcode.Runtime.dll + + + ..\..\..\SteamLibrary\steamapps\common\Lethal Company\Lethal Company_Data\Managed\UnityEngine.CoreModule.dll + + + diff --git a/LC_Highlights.sln b/LC_Highlights.sln new file mode 100644 index 0000000..c5fcb02 --- /dev/null +++ b/LC_Highlights.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.32228.343 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LC_Highlights", "LC_Highlights.csproj", "{C448EE58-3487-467F-BB3C-9DFD73648468}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C448EE58-3487-467F-BB3C-9DFD73648468}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C448EE58-3487-467F-BB3C-9DFD73648468}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C448EE58-3487-467F-BB3C-9DFD73648468}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C448EE58-3487-467F-BB3C-9DFD73648468}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5DF3688D-81D0-4E65-92D8-14E91F3B5BD3} + EndGlobalSection +EndGlobal diff --git a/Patches/PlayerKillPatch.cs b/Patches/PlayerKillPatch.cs new file mode 100644 index 0000000..752c173 --- /dev/null +++ b/Patches/PlayerKillPatch.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Text; +using HarmonyLib; +using UnityEngine; +using GameNetcodeStuff; + + +namespace LC_Highlights +{ + + public static class Convert + { + public static string GetCauseOfDeathString(int causeOfDeathValue) + { + switch ((CauseOfDeath)causeOfDeathValue) + { + case CauseOfDeath.Unknown: + return "Unknown"; + case CauseOfDeath.Bludgeoning: + return "Bludgeoning"; + case CauseOfDeath.Gravity: + return "Gravity"; + case CauseOfDeath.Blast: + return "Blast"; + case CauseOfDeath.Strangulation: + return "Strangulation"; + case CauseOfDeath.Suffocation: + return "Suffocation"; + case CauseOfDeath.Mauling: + return "Mauling"; + case CauseOfDeath.Gunshots: + return "Gunshots"; + case CauseOfDeath.Crushing: + return "Crushing"; + case CauseOfDeath.Drowning: + return "Drowning"; + case CauseOfDeath.Abandoned: + return "Abandoned"; + case CauseOfDeath.Electrocution: + return "Electrocution"; + case CauseOfDeath.Kicking: + return "Kicking"; + default: + return "Unknown"; + } + } + } + + + // Catches player killed event + [HarmonyPatch(typeof(PlayerControllerB))] + [HarmonyPatch("KillPlayer")] + class PlayerKillPatch + { + + + public static void Prefix(PlayerControllerB __instance, ref CauseOfDeath causeOfDeath) + { + string hname = DateTime.Now.ToString("yyyyMMdd_HHmmss")+ "_"+ Convert.GetCauseOfDeathString((int)causeOfDeath); + Highlight.SaveRecording(hname); + Plugin.Log.LogMessage($"Saved recording {hname} because player died!"); + Highlight.ShowSummary(); + } + } + +} diff --git a/Plugin.cs b/Plugin.cs new file mode 100644 index 0000000..0819591 --- /dev/null +++ b/Plugin.cs @@ -0,0 +1,74 @@ +using BepInEx; +using BepInEx.Logging; +using HarmonyLib; +using UnityEngine; +using NVIDIA; +using BepInEx.Configuration; + + +namespace LC_Highlights +{ + [BepInPlugin(PluginMeta.PLUGIN_GUID, PluginMeta.PLUGIN_NAME, PluginMeta.PLUGIN_VERSION)] + public class Plugin : BaseUnityPlugin + { + private Harmony thisHarmony; + public static ManualLogSource Log; + public static ConfigEntry cfgEnabled; + public static ConfigEntry cfgAfterDeathDelta; + private void Awake() + { + // configs + cfgEnabled = Config.Bind("General", "Enable this plugin (Will take a video)", true, "Enables this mod to take videos using NVIDIA Highlights."); + cfgAfterDeathDelta = Config.Bind("General", "Time after death (millis)", 2000, "This setting determines the length, in milliseconds, of the video segment captured after the player's character has died."); + + Log = Logger; + // Setup highlights SDK + Highlights.HighlightScope[] reqScopes = new Highlights.HighlightScope[2] + { + Highlights.HighlightScope.Highlights, + Highlights.HighlightScope.HighlightsRecordVideo, + }; + + var status = Highlights.CreateHighlightsSDK("LethalCompany Highlights", reqScopes); + if (status != Highlights.ReturnCode.SUCCESS) + { + Log.LogError($"Failed to set up Highlights (Are you using NVIDIA GeForce?) - CODE: {status}"); + Highlights.UpdateLog(); + return; + } + + Highlights.RequestPermissions(Highlight.LogCallback); + + Highlights.HighlightDefinition[] highlightDefinitions = new Highlights.HighlightDefinition[1]; + + highlightDefinitions[0].Id = "MAP_PLAY"; + highlightDefinitions[0].HighlightTags = Highlights.HighlightType.Achievement; + + highlightDefinitions[0].Significance = Highlights.HighlightSignificance.Good; + + highlightDefinitions[0].UserDefaultInterest = true; + highlightDefinitions[0].NameTranslationTable = new Highlights.TranslationEntry[] + { + new Highlights.TranslationEntry ("en-US", "Player Death"), + }; + + Highlights.ConfigureHighlights(highlightDefinitions, "en-US", Highlight.LogCallback); + + Highlights.OpenGroupParams ogp1 = new Highlights.OpenGroupParams(); + ogp1.Id = "MAP_PLAY_GROUP"; + ogp1.GroupDescriptionTable = new Highlights.TranslationEntry[] + { + new Highlights.TranslationEntry ("en-US", "Player Death group"), + }; + + Highlights.OpenGroup(ogp1, Highlight.LogCallback); + Log.LogInfo("Success."); + + // Register a callback for player death I guess? + thisHarmony = new Harmony(PluginMeta.PLUGIN_GUID); + thisHarmony.PatchAll(); + + } + + } +} \ No newline at end of file diff --git a/PluginMeta.cs b/PluginMeta.cs new file mode 100644 index 0000000..4f8255e --- /dev/null +++ b/PluginMeta.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LC_Highlights +{ + class PluginMeta + { + public const string PLUGIN_GUID = "mnc.highlights"; + public const string PLUGIN_NAME = "GeForce Highlights"; + public const string PLUGIN_VERSION = "2024.03.22"; + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..4679751 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# Movement-Company +Bhop mod for Lethal Company + +# Installation +First, install BepInEx 5 into your game +(https://github.com/BepInEx/BepInEx) + +Then, install the LC API into your game +(https://thunderstore.io/c/lethal-company/p/2018/LC_API/) + +Then, drop the MovementCompany.dll file in Lethal Company\BepInEx\plugins