From da592f98605acc03e6f05ff7aeee15023b076e30 Mon Sep 17 00:00:00 2001 From: SuspiciousActivity <38253929+SuspiciousActivity@users.noreply.github.com> Date: Wed, 21 Jan 2026 14:24:25 +0100 Subject: [PATCH] update 14 --- Data/goat.png | Bin 19708 -> 0 bytes SamplePlugin/Configuration.cs | 19 ---- SamplePlugin/Plugin.cs | 86 --------------- SamplePlugin/SamplePlugin.json | 12 --- SamplePlugin/Windows/ConfigWindow.cs | 59 ---------- SamplePlugin/Windows/MainWindow.cs | 102 ------------------ SamplePlugin.sln => Waypoints.sln | 2 +- Waypoints/Configuration.cs | 28 +++++ Waypoints/MainWindow.cs | 58 ++++++++++ Waypoints/Plugin.cs | 37 +++++++ Waypoints/Utils.cs | 29 +++++ .../Waypoints.csproj | 7 -- Waypoints/Waypoints.json | 11 ++ Waypoints/WotsitIpc.cs | 97 +++++++++++++++++ .../packages.lock.json | 0 15 files changed, 261 insertions(+), 286 deletions(-) delete mode 100644 Data/goat.png delete mode 100644 SamplePlugin/Configuration.cs delete mode 100644 SamplePlugin/Plugin.cs delete mode 100644 SamplePlugin/SamplePlugin.json delete mode 100644 SamplePlugin/Windows/ConfigWindow.cs delete mode 100644 SamplePlugin/Windows/MainWindow.cs rename SamplePlugin.sln => Waypoints.sln (89%) create mode 100644 Waypoints/Configuration.cs create mode 100644 Waypoints/MainWindow.cs create mode 100644 Waypoints/Plugin.cs create mode 100644 Waypoints/Utils.cs rename SamplePlugin/SamplePlugin.csproj => Waypoints/Waypoints.csproj (65%) create mode 100644 Waypoints/Waypoints.json create mode 100644 Waypoints/WotsitIpc.cs rename {SamplePlugin => Waypoints}/packages.lock.json (100%) diff --git a/Data/goat.png b/Data/goat.png deleted file mode 100644 index 4ca06ace488f9503cff0e9e56117a7db559ae80a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19708 zcmXtAV{jzh0*$e;oou}E#x^ImZQHhOC!3AUjcwbuZNK?`yc%>>*Hlg4se8{o>WPq- z6-W4i`vU|71OXr+q6j?B0bk=VP{4OQfk_nL0m@KHTm1Jzv%HA~_Hdy*68L}%?JDrV(mN}J8 z0R5Kj8(2|@qWO3+zu5S%cvP4y2p9;|dNih-6^D-J)TYOeFOGke;)yn+QuRsGE~oWP zafQdeQ=HE)TlSGk*?Z_E9D`J{4v`Ll=%=6%y$};nM<8ecU_S{YK=wWet-#m(O?OJC z53%jRZlcG+ViLmIA3UBac zzTt^yow)u3rV0`Vf)Ebgu^lyAnl?Y5co^6reNE0urMqOw0?ya`u88yj$B}lz5s+<& zzw0MZ1+@gm=-a#uZso5d?A;yG)6}CPAX^K4aA;hsf5j4MDr35q4EE!WX>@$F$CwGi zM=(yjxV$(wabG2wu%__99YZ`eM}IvQ+}YXnku?@|XZ1?z6`6mYO7_ohGH`j&LXdQ6 zs0Hej>)w?gw9sAf_q-I~%PxAwZ`)yyJ-ZuLILf)|J--~Bv2egWHHVWEdHat?}nRuXBTHK5rZZ`QgWer~(BBif&rdce>2 z<_<4_>Vf`yxX;8Lm~cY0XRICh2Bl6JIE6EH94tDvKMkRg0LWs8#?A3x5@3F{f063C zAM$Qb&j&%*1$Uw`YUS*q8|+$1xPf;=xL@6FJKbiQ_;Y|TwCt%O;!{8R=t9~TzR#_G za(M_48!p}I;e!3P8X~KH8*A0}y%hs_}sm%G`Bvb&#Kd$zE(cY2_I(7>8ZIA-6E0e5Nb3)N z0#+V?n~%-`av}Obp%7I=TqV*H@%pxC_44k+ufj8P`E)aVtb6>LwtYBK=Xl{NK7%ze zAz`o-4WQ+Aq94bcHkqmvBBN@{F|M*9__(Y~^VrK+u2rw>a_fZh&Qoeo;wTMZMj4*h z=s68v*^%c&^oH<;>40WI?6*S1>k@ClbikAV&NS=o2in(G9KpPU+Yx2u#o4*FcG@{h z7W4xXLpD5d=N?jki3%_O+v}(I!>R0c7G6LWvTTGBgm}!&i!Vk?vTc}(pE--A;RHp9 z()g+4Yu?CPUqm=k7fdDi+Pk0oiZ;XtR06y`{0pVw=(ZXDoL~71sXcU0lUn6b0< z=NTJt-;O|-&6ao10*29WDi+m5vakDx%}TE0XyRzA3q=K$;W%Gcej+>7;HiILY9J~J zI4TRjv0h;9Sq;heMJr}&jTKOibG#_Vv8IjQ76J`4)|wk#Z&sH&tv}qk?K?gdA zZ+}nb5qcvwuV?*R2GK^ej@=j`8A19Z+%Bk?F2kq?x^g5>!Z!gPD@z^Y!l<#N+b^CecuRw9luGrTU`?lN zrJDHXgwM!=^uhx+KZm41FsHJnvT8msI%V+={!l{ad3R-fzxL{|ur)nx7>mgqHnAQ0KWVLC(GgF*-F zT}g41$j}ivIHrS>J@UL%Z+qtvc|ZTSPD;!1BYj8m?2m#PxUR{s;dBGLfsFrQKWIYZ zaZ%%zuUgUf8oeKxxh7WKefoT{aw+2lORITl=2x6dQ5jfcx|jAjN+ z4{-6=To8kJiolDccdd?UkS%EEpV6nY(7pj;%=i(jMriGuy_5W}%-=ryq}y57AYUxf zb_PNajU~={6yO%&g}W>Ry_Ki?t@H!+4TQTsRl@Gskv?CpPq!QT=p>FP(-*D1)@+XB zF=}`Hcr}rp*VZyNq(r{;L2`WClS?-5WtG+E^R?0x;AXjOS=_emxgqyvzpg4O>{2H*YFiM6LY1KHa*Y`KJ9zP+r` zLsyx9Gj}>B$~)*4*E?%H1DO(sfPW_?N)YY-fl?byR0kR=Mrp|3fwC)94U#L=;sH7` zC3$G)_eFI~i_|tuxV*5y#^m?c7#1fm`J+s!T| zx2NqJG>HxEuU%TwJ7mGp8i@9J{h6e!95Gcf>Im4nfuT(K3eRUHAhNm}XFNU0YTL5s zYiW5N0d=h32DV121WjrHxvv_gqJisU{=*<K-qjbQUi;aHVCS>@&Zyba?fv#w=dmU8Z@9W=_%VIoB1jm!MU0p1PO-!Y z$W`t8MHOwYL66UBGt%CKzm)2}Uojln^vF^j!^l#9`R3Qje=^VZBug_VF-sp5VKbhI z4M!L`d6t^jD=MywI>dyGnO5}GGBGQ@ETg&A>t8i0;K;GujUKnR-r>1Dd=&pwMPqn= z&i-RWSy6;tYbJ{Ke@f_rP$h1xz+)r=d!_^=KJ!RQ$!`@s+MqUEX;OdXbpKnl$w^A z2H7S&@#y!NIY;JH>$2s=D6p?4NT{D(^XX*WStY6B!}){Dg2sWM{sWzAOQd4A7?1u~ zjsKI)v(q-6U+4v&Ut#jYWE;kFJD3Fxj&g{Zh5>W_*Cf}US_ePU>nn>J-R`e7xR&oL zqQ8qGTRo(Mz~8IoATv*KduGFFUL1x}@kSAvsGz;;PugnFV^8x9Ec{e1XGRIptBo=T zS22Cd+&eh7izTLP^l@|_#N7TP3ZceNZprnR>Eq6+lB{kg$p0`$LGOwwv7_ApZoBq=xG4iUYBGW) z5mU7BcVaYgzV={gTC^v&pI@vWSAN}iy9%PQ{evbO?>!A2w^Jp&ug*V3d{xoJ74H-O`l7d zpQ7W?r|EfP%6;xHQ!Yv$xO%PJn=odvT^sHfUs|s|6@9yX6WSy6HWT_VsbUS7z%<|S z`{S8t94&DZf`o@NzM67MPyXONA_1T#In9sA${3Ds{aw-NO@t4Pi$h}bh$%HcGX8S- zp8h)*Zmdz}6)- zO~S7C{`S|CNpW%Vt;XHIHrn5v+g{*fQYGXGxLBE34oijFH7KBk6ho+HY;%N~WiBiD zOB7uQnYU2&{Uk7{ng*51ZZiw~`d)G_zx~)UfQoHk5_Z!$HCs z&qk+D-UXgUFVC<5i4syjI>G*q&sKmYA`>Y?xGA4pTwhbaDTGi$Wy?E=dQ?|Qhx<%4kKgK*FPHq9l_1| zAA3g8wDg(Mx?(4TDU6;m&pzjPT0*{C_H$bXyOHPLX>{uyyx430_x|6c?hd=@hCH}) zwj%N|ZEqC1n(w{&dZmq(k>l0xI882nHu!dPH=8LQ+KoR6s<=8r)HMz9sbIelpi`Wk zAL&LhjTV%Y(}(vsLk5P^?OTQ2SS%J$VJV1pl{8gZseASGfE4^_{d)k5`{{Y(K+ss( z?&4j;DC*W+0tD&d<9_We4*C&{Ei0$S=eSw-FnMK>ZOzgK&AFHz$x7!njN9h(ci<)~w0qj_ zEMy$V{$e~&Pu5S|Sewl*KmRbA)qnRuaYy>pMGe?{JLF792%-rXkp%o?_u2WBHcLYQ z!Vv>$1_oR)v!5j>z`;yB1OI)( zn$7CR)j)Bm|Krb4IgPaNoR!MNRc^`}H|@vgtuGv3ScqA!-t?7^IEX~#tm9^)bypL~ zF#nb-ET7bE-IzODp`7Q}Y9r^vQnR1e134lAC!&C6M{Y_36qehp1q*Gus=pY)+9=zS z@jyP3G+=yeQ_n``8<%J<8B4OL-TC?1fw;uH(&Q=_ABSN0|<&j1Y05=D(;x%-~_Zpx7L1} z`kC?aRjRF`#rbbtIS-RddjzT8ez~r_Prt!v0gTc`Cq=3;wP0}g9?fJXNTbkOeF@GU zoA4C{v>QZ{U+t&~BQQO1H66=lA0nwHzAp{$9YUuOjGFY>+ip+pirE<$_azQbffmve zvPxvb6vKn^>1liiNQ*>Qzgeq%0I`b>L&m!<|G2X^oW7a+S;}=?ues;`rpTxk1W*ZD zHj?d>GcyB}QumHYC2@!FjTYlkQTDEgKq-;478f5#k^VVN8!UA;QSG<_M|t`Ep3iP0 zT9w#h3vlheQ)i|;)@M6o#C?#a8F?5AU!cZlfO8V>P?u#5KP+ZA#w>D|+SLQ9oS?8c zq~Y3*O23lk{mGArTc0E3Ggj)ZRubq=RR?U{fSDs~rD)dXeRz@n6EkF9&mSkG%k%jv z2}#!Z{YOt{|9l=sWfM{NC8Pj_)qg@Buf4~R{9O6*__m-n8Jr*YXa_yFh;n56AG}ST zT!o?|=-ZQ$gVmXo#B@W{|0*gdY~!oC1~GWX{7BO(ZtQ~7z@+1^>9BrbI=pWCwkWp> zHXXq*Gk)??WIA6Qz-huSRc_gz7Ht_6pTc9B5YfwVuvZ1+7nh)fCTNgM9Fb!D%}Ntm zreW%s7~Rp)lu1BtL);mlN$#*}fkR7u!M~D=Y-Q-6V9;}^!v<}c!eZ%DNPU+1QeUVz zyQo~HO6+CKLtF^5noW46;|3q4bJ4t|@s1oNo5gzI0EC|(raFQBrzBKj#IXe*93i&a039rDpJ<7y#J3GC zW3rQ0Lj{UgDsaj_mha|P%!-65J(u)ac$$gtI0d!mYZ z)ahbX)ArA5!g-CYt?JDNETWv?(o3+`m;Ocp1OiU?Nt&br*7tYyEikGGb}?ct7f`XL z>tB>b?3UM|c=HuVGT~1h zMVh0uzqx-X##H7em5+3|w((s2ve}>SpJZu#COAyG3`uOGKf}v>-JQNVULE#jFD2LY5oRWGX%=KWTQDXI*5mR6&MN$>I(;Wk z0xEuimI0)&Ps6_wEbfK8Fja>&Q|q}ohM12fNVuU$r=$@iSEd(I5I6k%+8z9Sjb^017+M}>XwLYM#39? zwlLdMy8I`REOV`I+7Wt0inXq@5CQ1XzNm9LIGD=bTY=*IX#Tvb@%9iH*t=7bK4C?b z$&t;rMM@NrIBW2%`Tg)kJs!^X=Z_gt98*GO0!vRPi~?Uxw??AAf&tjJX2N(d zOVV;US0(+DuR_08`#HuN_|J_k(N_oUx?f2L*aXltUejYyKY)|oVP~~}KVjBlf$T}? zA4maQC}*Sy28Kj@0=}G731kJ`NAOam2zU+~dx{Jjkh@Givni=4O+S>ONrWRwyE(RQ zSZ}+;4}Z0$X4!TwXBpVdl-ob<5`H&|gk}UeuiIELO2@xr-xNrVQXD zp>cSbGQpbC5o#QDv3pJ%0#7n@Gi9_OzayWzXin*J_{ ziD>xMNeM&hUnk|->vM_9)_IAX?9P~Ih5>@@Qz5=1b3wzTDF+8WJ=-xHt<&RPbr z<&awiv6xww!U~i!-YsvAPO(81Gt)OSP^ERt<5igyP_IA9>I7+dxq=3!JE#|S*U1XA zWXh7{u)dzNBHzIypb>G5b;h##OMU8v{f3A4KEw82P-$Yub*--t_RLB`AKBBpv z(1?WGgs;Gp>SGgGU;JhIQN@KzEdpEJ741obZke+IXS8kgRGH{Mc3y66CSP`!3fG!k zq=M6O^qCwdpy!Ras<~{W)bCKQ`w1qoYOMAJ#VA=u_V0fZL{bghH1PEBt%@qUqV%VD z5{kClMIJVvxpW9!3GK}8cTLaM-q5GLVI86oe9j2KNIe=q2ott;O>UD#=(*{H6HI0- z9qtZ>9M3-M(Nd*l4)!2V!GFxZ5AlQ0>&8#r5l={fM48HvPzBC){h6_?tA8JXrR~i! z70p(SO2Xo=DQ=|axi+w^Pas!9%g{nz&VqshLi)|_mzZQ=w=Vad`a3j=q76YA$DEwM zm$w~osX7Xj%L2`|VZL7_qh>Od3R2pwzoMK>i-Hd#eVxpBCpV|nD#)re5?K$vsx+%o z7f@(1h^QYYFRl6A@x8(|cmK-BROEzhGyLtM`*2rnUmX03MC{^NiX;OVQ{u>1kR=+q z&}Jw11S_KC(uLyW>;J^yM;gZapH3jCb4yI+Qa>v>IQu8LJ=*+}Z zJ7VOeY+UUzbZW5ms&bQ4NyZxP^98HLZIYHu%sCL@W~5-ZZ4REtFn2~QNeZl-@g#_0 zd!)O(;L*lReCI%I;bn^J@)NpkeeH&~S>iR@@iHFp&V=|mF>-yL0KTQ63{`C5I28Vq}F}tp8*`PcDaVT`z=+i|d zCcg-s3uedo`77lIVD_SMZM8GRJ+UKV^;DgI`TBQ7|Du^3J9Ww&nf{lrLbF*JGwJz+ zL0NlkPeR{}?V2_jFlZUqMhg|SIJLERr?7m57`AD08Cfgp7@caDn<8aeyWP|-lQem{ zDG-=vw{(NPp?GpzY~hLfSoa2=hEU2L5B`l63UbY=HY975bjg9L&F zx-C))h~enxBs~PV2Hy%l0)DJoEAy|pm*STB;V8mkWQ(9-bn11@7$xgO%k;XJXPOI; z=8R8|$kRfz;%3~ZF4f*ma3$^$l&SQ zZe4ZFC!@~!(bdu1+?y4XuL{^`q~>oydCgalGA74O=O@l>g}ik)24W+PY+{uT{XYV$ z!OMhT=h)RdC5 zjk&qo&A^ajWvni#B#_^Is=Sg71*;X<)U|6gS50xdP1A&%x$0hbiB&w=FG3zlXIh6| z5DE6J>hptE?*MYdIY=S|32}8n)ouc%nk0*VcL((s-8#FD zN{1)3H#>CRS{0t|hi8|pifbGP1(ufjAIm&dwqm1du-Yqe=aHlP^K!B7+=VCk7ox3rjip!j(10yTVke0p0T!jV)W55zUB`aOzOb@Nd>XcPD zj-@(Id36qEb?!o>gLl2xf<&Ir3*xqDd;dPuZEP=k(LE4X8xxyk5;vW9Zjg{{qzbLS?*m&B-4I zm~-gSD95IUcB69zDu+px6g7xW4T7WnMkU)_+|6d)lR~d6CyXXHSVVd13r5F;?TC)u zJDJqmtu;}%xoC#FQzmG4n18b5)FR_V5}W*d659(QbHKcjp{A?4Htg@(T1kh{ZYGQB zAeMa|WR*-n+P1#wpmosmq50VDI`;Tl6?bUg1cqq)ar{$#Qh7(^+`E-p24n0!9Z<60 zxtR=4w8N*7gbV}%D#A_+UZ>s>%ogZ`YnbCVaXLbcYpuH%+M?B_VUvUVcw?)c%B|ly zxdi<&H1{8()b}W@oaYg3y0zxD~;-%M@4W(h{>rNzbdo#-?|Rh*9E(b05tuuV8$tP52~ zrKhfc@-B*bM{~%xS6Y^zNhhlg?AVLRhGD6m3e?NK1Y3{>< zv_Kt^O$JVhTjjjEc|eBuvNm@?td`%l!F2v_*(1o6x!wrF_BumpO(N3Geuu;Qx>~bt z{gMN}cV1;GJ9Vn2T9?C`TDV_S#|iJSsgv+`ljPAufhj$2b7Dq_jd6(<0MM9}Ximwz zIFt-aFp;wrC`+THW7kJ2egwYQ#QDn(-K&khJ&Rl^=_5_GKNL`7+FR&;wvHdEJ!#aW z!?DQ}lF{iI!U%;hUvIRcwG}&m$lFdy9Q;cUBs95^LtVHHDSh4PFcI=pa2y}is1djc zqBKeFb#RuYzmM)Arrc5B>AkpzV#>)pv-SSlMDUDJcI&MYQH5 zs|@P9MR$>f&6Cpq*v@EssZ?gpi7Iat~l!)p%mQP+4{!yV7Hj<{VZaoQBACmDRRP3fEG|q%7 zKCSh^92v{ZX*9-D%hj8LJBK@|kEv$FFwF#N9_>xrGluc?_eno|L}gTMUoi^Lm`E8u zhf2CZI$$tTt($$g*=|CK^D;HYL%1y;+tBR(z#}48l?U$%AM~2)heUhTT3`OlWd@-Y zs=ruxa?4^PU&Y}zFxuZ_wUTP=0x|_cWAt|e$W%6!X?epD?##GU{NLIJ84VdU85;r# zRBsa%NQ+U|8M3|yvlOI-;&6}#W_t#cnRY<5n|+J3b5TFgk&L9MV3#Q^>mS7lf&Hq| z3MGI|Ps9i!14JrD0httLdzQs2Bc|G3asXXO@6K7ZNxSJV>X=1L>S2Gp_Hcq_j5 z22iJ%NXzk4kR8{)YlZG1cheH{1}+|uHv#!pb~r0-?cYU({W!u>9a##GX&B0)O^ctK!fU!5Tj|2eWqUrDnuyO;!sm? z3o6&dy&$hM%X3Wq2FlnKj+f>ntpjjbHBmz@pmJiyHXx(Jd_ouV+K zmYa8r5d^>Nii}rK&eM&_A3}PPso~wd-HufVaYxKpAXu7XJ_59*@>tR_S~WqA9rvXe z2h^D2>9fD1fhuZjt*0|EYF9n z`}5My!n&@`mRbABD*c1i{YJ(9g&fU%k#NsYjK9?DC|P9i?yQ0IZ*#}_ZUN-!MBdE# z36KcgrQ(XtL;jVWWR9O zd)m}~B9v9;V8z2TL-rWG-%+o0<*M9c9!d`p#df~=`m}$o|H{)+g=^-8zwZLiyHeW1 zGQ#x{mW)`W%KS}Kb6wEL=l!_+XJ-D!qh1aRt$n`#KC7ZbR}^`%eLUrmP&3$GZY0=9 zV);!sL+kfj6IT--v!Z1-ed$mRgKTpo65sgFD?1#AJuRV>8vZ2#sE$!V=+KfbL!#`w zRs)7zXp^7+<8#je=o}qVu73)DfSL~`Meo?Dco1{Rue9mwO9B@vNFcb|(N0s$mJsWx zG{msGEm9G>0d-?yGOGg?2o@^IAK!jY@3!Nj;dAIpPkdNhpW=h$mKiOXr3E|>GbPNd z<{ZJsDKUR`SBRNaj1z^96KReQ{0?9CN==EpRcu)-?RUSKBy5z6Cb1wK&bmlmYYQN2 zY)@6_FH~~M(NmQPTdcD8H(yZnuZAfw<}GAkP!`qIN-E6Ecl9^!YkyOl{{>uV>LLDnoMlGs$Y9R{sa~*$f^M6SCJi`j#CXrF6ufi2Vn)dB6m`AeHw3*M zFB8wFlQdkG*U=ScoQxUSx6~UH;n(PrFB;Jj_sDq7K`p+a{&z@sbcacy!uvsU0iXi*mv6s zzgYW-=ksnP7cs7y<2>x3&#sWP1WdvYZaX=ALRyuzQc_L6mtuU$m z6_1~uPr+&Q6Y?z{TieSV`rq3Uj8vNkdGMX6#9P~xf3WB7a{b8UUk=34^d5oMe4 zmVYOyTeZh7^Nk#SPBTHXM#ZpL9TibM{nComD#h)kUi%}TjCG#p=py46M|2WCA$E}f zGHXh%*!WI+DRc>E#dIPe6W!%W>bFJ*UID@S@5JMAlSeVhT6&}|KGnG2+iv&`Y9Y?0QUk@dRraeUh=edKWiXF? zQpJRHrc4*{E_dUT#xOexP78p90>1y{A5sY6vp;`U1%&TUykx?nOy(0;6z0yVsA%jO z>mSXf1TaNdewX~5T8>xlQ3?NP0|HKWDSO|^L`=s-M{I-GY*>aW`OE3UN@ys-J{ z7iz1^PvxK`TNPJU7IWy_1jo6*+oK>eCJ5a)%kDdgA*Ye4#bFiPtGY~YqT%4XYA+>1 zEG%&O{K8`(9n^QEWf1dNbUCtwzBRP@n|~bqaR4QY@wwQm3+eKw3O~43f1fURA3B>P zo&X(9^d_O%o`nezxl@l`!sTrg&f(`Vb5-_04q@JxsoQ*#pdrvFiPf?Qg&ehGsbzqr z#7{0-%){s0n+tlR?=NKy8gvWP3C-`tl~;%|+Ux1~;&)vDQJ|_D2ZuJH?zY14_j_r< z^vJUSLgsK}5~%DJPFWbu)QJ4T50&N>cOP*b{%LHVV(JEuME}>XxYOx)^sI91{SjzG zsq;4XovM9nzKshad1Z;7hh=Ndp+d?f9@mY2%5%apXy6vJoJuW)`;X8jqFlS<=Xg8D z7kjX+#9M-tul2d(EpQ_ueBTifNM)}jd`Y@S_>_^*pqj;sJBds35d#~MV|Dz(H&JSK zS+~N_ktPB7mXGq2)8*fE^9$dZdY(0v$2+a}^e&h-S=xHc`legw?C3yb#we%|`Ik=yf{F_I~q2LxMOT}cIeQEgHr3Gl%MQBJ2|q_ zDr>$!32*FgU(#_}bbPQ}xADn#d`I`4{j2<175&zl&NOcg!Tu&Mg7X>}Q!cPVjDmA4 z-tY7IP5q&-=bY&N~#AWdw5f0Dhrv954?9Z@q{)M#gG?CQxBbUdBh&# zSGaq3e}TeqT+8xhzs<ok&eKcTVB#e32%x| zl2X=m0*ZB8C!++J(B|Cn?j;lrB`4!fDdtNf%gLwa!Aydj_q$O`r#DsabMDZ-0Z8b& zJC%mEx2TM~09Lgx{siu*yO!TnzfWfV>Ha02LeJ3dk+(Q+^n4a=N6O1Dw7h6+!k0-j zYTR(P%{7#oojW}sx=!)%Vu)dbs)`gTk_{)BTH8J{bDQR`haa}21CPvAx3-O4aIUZE z2C7X|qPxk~?ywNP>gyv-?!%bNbH zK~$QsE2dDW2i#iV!e?oJe*l|y>ZjK~bt7kJgLOJpuBrsL!&vgSNYc@s;vgAiHjP$K zhg1?~Lo(Pz3N?{tVua++PoJOpwR|F^Yj7X%v%A+k1MuwXq>3z{ju5x58St}JY+sI>k-@spF@FZ-`AZfl~&xpXh{Qm!~9f3-)VkuoH>W!tm{YQt&+}nhvuIh zc1{8B0p;@0Ye4vVxz5O}iKp%_&eCvWR6#g6+1)#N}N&J+{|zT zY_H`r7V1XJ(Pxn>8RY1#`Ibc4Z5lT5odL5Z(PNx#!zQI|@3Bb&dP*<^i;C?>wjDoY z9YxufEd!Sp4>LJlx9{g)*B50-se;VrALR|5r-(*_@#rPaQf@hk(WQEv^0R_EQqIOd z-kll?5IHkh>kH7kKT!nq5L&l{As+lzewnZg*VlI?btesCT|Ohq)lgo@=vZgT7G{0r#9ZknmVL!NNT$!IW~uWh@!ZFEs3 zfKL;;5c0x=0P;T0z2YkE;eW-kCLk(I*;>|LBeS)z25=CitGd(~83C?u=T_wjh6%%| z0hYp_{Nd}Q4b3ed3)UX^ zE11JC=bEp~reQy=(y8S*@0VP;f;^-#=m7;@MyAQp{T`+$=i6LH2G3IvMt|`d)i_gF zteTSQJWP1Y;JX(d$JWeYOv`cMfc?8kg9a!2@_C?JJMRUrrmT&UmL7vor0>ggs-LziEW@>y0=71n!cMVdZ_V@Rfh}<_)VhB0KedofV z)0uLWMi)-1>L&dKc^lUdcvY?}6+Av-?f{6BfsfIk3T$-DJl zg2CwmS>qnsUldXs~ib%PIo54EO+->cU#o6aO z9&*)T7pVpfHeRX|-Ba}4+tFUrZ)`=Jo1NcXqO8E0P;EPgfpVEZ>7X^@j#|%t7key* z8TdthQ*dn<-!0QJ<~nJm6-M%5slGOO#3 z1NTX-vqMXH%<{iw$P~zNStk3#0%>3bp%m_rZTRA0rRF1_yR9V#%5$82A06} zt%8gK)@Dgx$v#o#`}ULP7K z^Nx(b2)B7^Y}X7+&hRVvMG1;U$lJ9rLuYs$EbT9g46tZE|rU8%7;ZG`jC@RsS z!e?N<7he6`Ubq~pc$&P4HTYK+NvP==XkKIfV)6A*H0N$Vh$kW`iikT~D`HipYS3?i z1^fFSd!Ow~$FY6C!zR>O$dJ8?#J#G4w@sMwRl@^9n1?9Cxw2D|N?-=g?C<-IsB7fS zHGHnG8-Qs;mAIFbL8E0v#ngmIqR3n+lE+_`4Pr)BV8fbZAB$HFNZ#dq)CD#4O^U#_ z5$sr+)bXPhnz?^fA;IfD-<)AJHNH%66g}$vN2eAw)!#$vqh4Q~<~wBnLNox&8-q1? z02ZcHgi%E8Xt~3}#oeO_p#N=|4*D|Y+WMBN%qPmWe)Sh zSl8U0?qb$htzRYpuUSQ&Rof59J-w|&W1I1d!+wUc*!?mhLKq4n4nP)Pz4kK_ZVwXQ zV%YCqx9sF^95w^|;W7ab*EKZ8@YgUHhy%1{(sSkycRxFYPELb-Vj`9EL>f|wYBG>_ za3&>L?C(7wdquD!Sj|6p-JHM)(M_V8CPKSjU<;x-Kr}*u9#~>6%FvXPl=U=U*Sc zPs=jRY*oblhWm4c*Q5h8q&R1(Hz5*U;l)2*Zvi07Y+7h~^t~q3NM^j|**a1Q%*ZAl zpqKqKaGLshB7nwVUHwCS2&a*nUNe4bF{)wad;#4JF9ROG^g?+;{dhuhw-ErlwalZu zI(l~s&~`CZ?QxtU;*ZP6{X;_}$xs#kn-KmK;4SiNDm}YLO?Eo}7k}&o1o-fIJ38)M zS8UrG8#fb)tpWbes1M`+V(Mw@@`Ld^M88ui)59Uh{#6ekGf5yD0Wj5`yKB{|76YpQ zz>%h^antt}{`t8$FlPZEJ{?`nA$n4I{^m#HWvM?p})A6XwN447RI*G96 zc!DY-{QjD%{KTPY$yedQviM`=(W6T*Q9$Of6j97?5311l#p{3Sk$Abp~-ZQ)5 zW5sAByG5(317<~}BF4Buiez7@8niN+)dK1^FQr`F_pF6-;b7R7C*@G7K~nv~cEre6 zoaE3O;VF|hK84j$F{Cl}ISaL_wA|iAAH+ZO=9}373R+k8#NYxvZK;wZf*c!NUe+p2 z5}=FgS`aWH!ixh7Rge0(Z+m2UW`Fb5CFYve1nE4i1V9De@=)LQt7-akA~53ig4RZ< z(7Y-mOUx4)$KM{P6wdmr9k$}-})K5$~>oK&@?dMO*B^>j${4}Ksx5sIMnwv z$A+lt8cZN1`P*t#dM0VnMjwcub9>H4vLHppi&JKs%nr4>-AQvY-iHtHbHeGOnp`Lfb6V>Vf-j$y1aFWp@j>b!X*6z;S|4MA->>PjS#=exnxyt zI(9d-AuRRR22dHg3u7%#vRP_g0_&V%$t%==c;h8cv#JAi0stddqEQoYvj1g@0=8Iz zJF#PaK~Vod}@I8-o6a(;5M*m ziXDWTq#FY$87ftJ#PcCh zte`ekujg;qOfI1`nx~N&LkCv|%6ESH1!~wFu@DGsm%dVGTnzfS=*iRGqlX=MV)Eg% z2nz~eVrQ&sYpr~J4a5!~gwb&Itxk+q6iBnmUssSyARzFe|NSoj-kfaPeeK!$#Y%Rr z!l){+_)?FGU`$T!)VD#H5$X#4XyXc8Itwn}+cSh~@Jm>>aThv?kV$ZGDL`q>>}dF3 z*LGsyyunf6#s!>Drvx7E0AQ%?-xS1=>kpf8 zkBf}vf)7eI*IoGHWH**5hPVC_5Cl;Y;Toq=TSNZ~nG0t0aua}Q_%!*72FB*M+lw7| z4$(-8R*RGO_cn0Rf`PT}Mw?EX%bOwHjT_OX5kxn-YKAwLZ0Rt*Rz#VSY4$ZF5X-x$ zGNkA_bq|ieAlhOALNxL~aOvBK^2Uxj|NTu#_hqC|{I+AcWMoQKjK4$V!bpv!FUEr* zl_7eD0wN3f`OVe7o}P$vprV7_WdUW^xs0s%p+d%LESHQJv?>Zx6}sz-i839BvHR^R zxf`DfS*OdxlLKfsj22CuPX4o{CfHp@;DQl+>v3a908_IRcB2Q*j?hqoGPb|nUfc*x z@FP7pINdVOZK~wWopm9VJ&y!E`Vqd_1oP)i^?k^dBlz};93O*rY$w}J%?g;j*F<6* zeKB4P34{>JIrx;E%fO~X&D^)Xl-*_RLux`AE_RoPr#`Bnx}~@5Ix{1M7oWbHob0ro zo7N!Ct|NhRM$(P#pE@(q;9q{;Uss<|XKa7Ffm9=U%_;(RtrjOQY_8(IH%i!ixH)Jc z+HhjAyLoD3xgs%Cr`7QEBflXnC6Q%kdL;;A7&$$HakaFQK#^SnOaclcGnzog_Iw{4 z8}K5~h}e{R(+|4rZjMx2`20u=A!LYxgga7wog+k9jr`7P!hkwI4 z%NGJrSzXVDkGJ>Sy$jeeYy;@!a=M#W1FSAe9oEko37l@3FUuAC-lM>_2n|QUSdSz1 zg$(=yQBk=bQODxN?((qfcpJNpx1o|G3Q~>ar5edeGLW5QAUP(ql8hd#4mSrXI{Cb~ zB|zU=uh;Rf$A8bNbI$PIHfPop--pZ(_rryVcSe#VLP~s%cBW>Uk-&F}z8v^_q{idR zcr~OR8WHU>0nljFxLnFyHIFP)THmFR-c_q45=cbbvPn-% z<`=hJ&#q7Z#kP;0=FVT<$XQG06B}b1mN%0miF1}OZq-6#%>R2Sq}&&LUvXfMKdRJ`ofu9bpBHEaxy|1SW0pNrDatBI>hV| zdbhOD@EWMuFpg%Vw1Cd?OA*Px5oNp^k{3@u^+1v&F=;|JlO|*byawBH zYS3xL*A^cagEUCZu7vnl->YVZ*N{xz7jb2r?2$lps)#jc=;)OISQ5$c^f2BH$=igd zr7f_UCxan*v%)uT-5beqaPaVP@BePMBAzweY3hl-SH_e38wgeb9bj3b&Bbi{)8->1rsI^UDJHzdcaGuY!slas-aw$L50 z+qL%yM@z~hGKki;PPT5}&x^0V-+kR{NG?WrMlz0r^dMhay8@)wDkCutU&hxr92^<= zSI?ElpI#S{LA10Aui@|Rd4krq4q95hw$s|@lLn8X7HK@>+4)l5sK{rmLbN}PDC6rJ z?wiNy?)LWl%kNU(&^+n`Xl)a#kH)4}e)gNc)7;{9$DbJW!Hi*QTI`f5WdznoYAn8- zEQVAAJPTm6*?H*E|BU_sYI|Ek`t8+@j=MWe0;;9 zaWCCk;s1Q@b;>Ji2YC4KQdLvm*Igs-lXr(Gqa5vgdZ^jkYO|aDz$XzJj)IfPkd6b7 z0@xi+?!5P@QGN6Mhx$xV9tnN6Hs32FT@gGQd~vLmw|3R}-~7J_O~8nAG8q!UU34F0 zudV->FLvx7;Nio^?!8C)x@&u1cMO3R-z#1AsBCf<5^j&o`ki&Wy0yl?=Ifupn~@n+ zASat4H3I(!A`$g}fB%R#t}~KUR@L`pdIzI;1m03%wfbeU|6jm}h#PIkXUX$rdB>bD%YfHu#BFaL#3u#maz>-Cce7n7!YeOnKcX)N}CbsqLc6M8UPY}D^9;9xllu@S+ zU`@U|=FX`iQ8$NqwQ=fds;Txk4aH(HpATMbE?2K6UPV<^jCgen%d+ztzGN+nlxbs_ zSq#%+)W|S$Im4)tFCIgZRbQ{vcD2}YvR)_LJg^2-gA_11NXGl)~8|Xtmmo6mzXGRdkV1t(p z-ksk5Q?#yY3+>6@YwL1E1kj0y2;|pxeP}OK7#mrG-2;3{nX5?iU;!tPtdnNoR%E8| zE;C3(pjRZw6E*AH{1#0sre-aDr0-`QeX`YA8(l(dqrxtim@Er{`w+v-JCP27Hy}x_ zbH_PvDvTjk(*GcNg#$>`bO1O`_?hozL4_o(C(k1Oa$5mzxoIIs_jeZ^d@wT^9$Nki z$4>?p39_Tb@T zv~{@Jw2`jsM&UD**?Oudny_;u#rD@l5>A=U8sLh?GERuA-t8U>$zZcsC2F*1WlFqf?X_LI*(sWsqpx(lU-qQDzi%z>h!{ s>16RXdIeIHqNoMtmwOP3q9~E#KhG+%-}Pf=XaE2J07*qoM6N<$f(aDRSpWb4 diff --git a/SamplePlugin/Configuration.cs b/SamplePlugin/Configuration.cs deleted file mode 100644 index de783a4..0000000 --- a/SamplePlugin/Configuration.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Dalamud.Configuration; -using System; - -namespace SamplePlugin; - -[Serializable] -public class Configuration : IPluginConfiguration -{ - public int Version { get; set; } = 0; - - public bool IsConfigWindowMovable { get; set; } = true; - public bool SomePropertyToBeSavedAndWithADefault { get; set; } = true; - - // The below exists just to make saving less cumbersome - public void Save() - { - Plugin.PluginInterface.SavePluginConfig(this); - } -} diff --git a/SamplePlugin/Plugin.cs b/SamplePlugin/Plugin.cs deleted file mode 100644 index d00c733..0000000 --- a/SamplePlugin/Plugin.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Dalamud.Game.Command; -using Dalamud.IoC; -using Dalamud.Plugin; -using System.IO; -using Dalamud.Interface.Windowing; -using Dalamud.Plugin.Services; -using SamplePlugin.Windows; - -namespace SamplePlugin; - -public sealed class Plugin : IDalamudPlugin -{ - [PluginService] internal static IDalamudPluginInterface PluginInterface { get; private set; } = null!; - [PluginService] internal static ITextureProvider TextureProvider { get; private set; } = null!; - [PluginService] internal static ICommandManager CommandManager { get; private set; } = null!; - [PluginService] internal static IClientState ClientState { get; private set; } = null!; - [PluginService] internal static IPlayerState PlayerState { get; private set; } = null!; - [PluginService] internal static IDataManager DataManager { get; private set; } = null!; - [PluginService] internal static IPluginLog Log { get; private set; } = null!; - - private const string CommandName = "/pmycommand"; - - public Configuration Configuration { get; init; } - - public readonly WindowSystem WindowSystem = new("SamplePlugin"); - private ConfigWindow ConfigWindow { get; init; } - private MainWindow MainWindow { get; init; } - - public Plugin() - { - Configuration = PluginInterface.GetPluginConfig() as Configuration ?? new Configuration(); - - // You might normally want to embed resources and load them from the manifest stream - var goatImagePath = Path.Combine(PluginInterface.AssemblyLocation.Directory?.FullName!, "goat.png"); - - ConfigWindow = new ConfigWindow(this); - MainWindow = new MainWindow(this, goatImagePath); - - WindowSystem.AddWindow(ConfigWindow); - WindowSystem.AddWindow(MainWindow); - - CommandManager.AddHandler(CommandName, new CommandInfo(OnCommand) - { - HelpMessage = "A useful message to display in /xlhelp" - }); - - // Tell the UI system that we want our windows to be drawn through the window system - PluginInterface.UiBuilder.Draw += WindowSystem.Draw; - - // This adds a button to the plugin installer entry of this plugin which allows - // toggling the display status of the configuration ui - PluginInterface.UiBuilder.OpenConfigUi += ToggleConfigUi; - - // Adds another button doing the same but for the main ui of the plugin - PluginInterface.UiBuilder.OpenMainUi += ToggleMainUi; - - // Add a simple message to the log with level set to information - // Use /xllog to open the log window in-game - // Example Output: 00:57:54.959 | INF | [SamplePlugin] ===A cool log message from Sample Plugin=== - Log.Information($"===A cool log message from {PluginInterface.Manifest.Name}==="); - } - - public void Dispose() - { - // Unregister all actions to not leak anything during disposal of plugin - PluginInterface.UiBuilder.Draw -= WindowSystem.Draw; - PluginInterface.UiBuilder.OpenConfigUi -= ToggleConfigUi; - PluginInterface.UiBuilder.OpenMainUi -= ToggleMainUi; - - WindowSystem.RemoveAllWindows(); - - ConfigWindow.Dispose(); - MainWindow.Dispose(); - - CommandManager.RemoveHandler(CommandName); - } - - private void OnCommand(string command, string args) - { - // In response to the slash command, toggle the display status of our main ui - MainWindow.Toggle(); - } - - public void ToggleConfigUi() => ConfigWindow.Toggle(); - public void ToggleMainUi() => MainWindow.Toggle(); -} diff --git a/SamplePlugin/SamplePlugin.json b/SamplePlugin/SamplePlugin.json deleted file mode 100644 index c806554..0000000 --- a/SamplePlugin/SamplePlugin.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "Author": "your name here", - "Name": "Sample Plugin", - "Punchline": "A short one-liner that shows up in /xlplugins.", - "Description": "A description that shows up in /xlplugins. List any major slash-command(s).", - "ApplicableVersion": "any", - "Tags": [ - "sample", - "plugin", - "goats" - ] -} diff --git a/SamplePlugin/Windows/ConfigWindow.cs b/SamplePlugin/Windows/ConfigWindow.cs deleted file mode 100644 index 5a43c5f..0000000 --- a/SamplePlugin/Windows/ConfigWindow.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Numerics; -using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Windowing; - -namespace SamplePlugin.Windows; - -public class ConfigWindow : Window, IDisposable -{ - private readonly Configuration configuration; - - // We give this window a constant ID using ###. - // This allows for labels to be dynamic, like "{FPS Counter}fps###XYZ counter window", - // and the window ID will always be "###XYZ counter window" for ImGui - public ConfigWindow(Plugin plugin) : base("A Wonderful Configuration Window###With a constant ID") - { - Flags = ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoScrollbar | - ImGuiWindowFlags.NoScrollWithMouse; - - Size = new Vector2(232, 90); - SizeCondition = ImGuiCond.Always; - - configuration = plugin.Configuration; - } - - public void Dispose() { } - - public override void PreDraw() - { - // Flags must be added or removed before Draw() is being called, or they won't apply - if (configuration.IsConfigWindowMovable) - { - Flags &= ~ImGuiWindowFlags.NoMove; - } - else - { - Flags |= ImGuiWindowFlags.NoMove; - } - } - - public override void Draw() - { - // Can't ref a property, so use a local copy - var configValue = configuration.SomePropertyToBeSavedAndWithADefault; - if (ImGui.Checkbox("Random Config Bool", ref configValue)) - { - configuration.SomePropertyToBeSavedAndWithADefault = configValue; - // Can save immediately on change if you don't want to provide a "Save and Close" button - configuration.Save(); - } - - var movable = configuration.IsConfigWindowMovable; - if (ImGui.Checkbox("Movable Config Window", ref movable)) - { - configuration.IsConfigWindowMovable = movable; - configuration.Save(); - } - } -} diff --git a/SamplePlugin/Windows/MainWindow.cs b/SamplePlugin/Windows/MainWindow.cs deleted file mode 100644 index d1e12ad..0000000 --- a/SamplePlugin/Windows/MainWindow.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using System.Numerics; -using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Utility; -using Dalamud.Interface.Utility.Raii; -using Dalamud.Interface.Windowing; -using Lumina.Excel.Sheets; - -namespace SamplePlugin.Windows; - -public class MainWindow : Window, IDisposable -{ - private readonly string goatImagePath; - private readonly Plugin plugin; - - // We give this window a hidden ID using ##. - // The user will see "My Amazing Window" as window title, - // but for ImGui the ID is "My Amazing Window##With a hidden ID" - public MainWindow(Plugin plugin, string goatImagePath) - : base("My Amazing Window##With a hidden ID", ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse) - { - SizeConstraints = new WindowSizeConstraints - { - MinimumSize = new Vector2(375, 330), - MaximumSize = new Vector2(float.MaxValue, float.MaxValue) - }; - - this.goatImagePath = goatImagePath; - this.plugin = plugin; - } - - public void Dispose() { } - - public override void Draw() - { - ImGui.Text($"The random config bool is {plugin.Configuration.SomePropertyToBeSavedAndWithADefault}"); - - if (ImGui.Button("Show Settings")) - { - plugin.ToggleConfigUi(); - } - - ImGui.Spacing(); - - // Normally a BeginChild() would have to be followed by an unconditional EndChild(), - // ImRaii takes care of this after the scope ends. - // This works for all ImGui functions that require specific handling, examples are BeginTable() or Indent(). - using (var child = ImRaii.Child("SomeChildWithAScrollbar", Vector2.Zero, true)) - { - // Check if this child is drawing - if (child.Success) - { - ImGui.Text("Have a goat:"); - var goatImage = Plugin.TextureProvider.GetFromFile(goatImagePath).GetWrapOrDefault(); - if (goatImage != null) - { - using (ImRaii.PushIndent(55f)) - { - ImGui.Image(goatImage.Handle, goatImage.Size); - } - } - else - { - ImGui.Text("Image not found."); - } - - ImGuiHelpers.ScaledDummy(20.0f); - - // Example for other services that Dalamud provides. - // PlayerState provides a wrapper filled with information about the player character. - - var playerState = Plugin.PlayerState; - if (!playerState.IsLoaded) - { - ImGui.Text("Our local player is currently not logged in."); - return; - } - - if (!playerState.ClassJob.IsValid) - { - ImGui.Text("Our current job is currently not valid."); - return; - } - - // If you want to see the Macro representation of this SeString use `.ToMacroString()` - // More info about SeStrings: https://dalamud.dev/plugin-development/sestring/ - ImGui.Text($"Our current job is ({playerState.ClassJob.RowId}) '{playerState.ClassJob.Value.Abbreviation}' with level {playerState.Level}"); - - // Example for querying Lumina, getting the name of our current area. - var territoryId = Plugin.ClientState.TerritoryType; - if (Plugin.DataManager.GetExcelSheet().TryGetRow(territoryId, out var territoryRow)) - { - ImGui.Text($"We are currently in ({territoryId}) '{territoryRow.PlaceName.Value.Name}'"); - } - else - { - ImGui.Text("Invalid territory."); - } - } - } - } -} diff --git a/SamplePlugin.sln b/Waypoints.sln similarity index 89% rename from SamplePlugin.sln rename to Waypoints.sln index 31c0066..ae963d1 100644 --- a/SamplePlugin.sln +++ b/Waypoints.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29709.97 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamplePlugin", "SamplePlugin\SamplePlugin.csproj", "{13C812E9-0D42-4B95-8646-40EEBF30636F}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Waypoints", "Waypoints\Waypoints.csproj", "{13C812E9-0D42-4B95-8646-40EEBF30636F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/Waypoints/Configuration.cs b/Waypoints/Configuration.cs new file mode 100644 index 0000000..011a6f5 --- /dev/null +++ b/Waypoints/Configuration.cs @@ -0,0 +1,28 @@ +using Dalamud.Configuration; +using Dalamud.Plugin; +using System; +using System.Collections.Generic; +using System.Numerics; + +namespace Waypoints; + +[Serializable] +public class Configuration : IPluginConfiguration +{ + public int Version { get; set; } = 0; + + public Dictionary Waypoints = new(); + + [NonSerialized] + private IDalamudPluginInterface? PluginInterface; + + public void Initialize(IDalamudPluginInterface pluginInterface) + { + PluginInterface = pluginInterface; + } + + public void Save() + { + PluginInterface!.SavePluginConfig(this); + } +} diff --git a/Waypoints/MainWindow.cs b/Waypoints/MainWindow.cs new file mode 100644 index 0000000..c3cfad6 --- /dev/null +++ b/Waypoints/MainWindow.cs @@ -0,0 +1,58 @@ +using Dalamud.Bindings.ImGui; +using Dalamud.Interface.Windowing; +using System; +using System.Numerics; + +namespace Waypoints; + +public class MainWindow : Window, IDisposable +{ + private string newName = string.Empty; + + public MainWindow() + : base("Waypoints") + { + SizeConstraints = new WindowSizeConstraints + { + MinimumSize = new Vector2(375, 330), + MaximumSize = new Vector2(float.MaxValue, float.MaxValue) + }; + } + + public void Dispose() { } + + public override void Draw() + { + ImGui.InputText("", ref newName, 128); + ImGui.SameLine(); + if (ImGui.Button("Add Waypoint")) + { + if (newName.Length == 0) + { + return; + } + Plugin.Configuration.Waypoints.Add(newName, (Utils.CurrentTerritoryId(), Utils.CurrentMapId(), Utils.CurrentPosition() ?? Vector3.Zero)); + Plugin.Configuration.Save(); + Plugin.WotsitIpc.Update(); + newName = string.Empty; + } + + ImGui.Spacing(); + + ImGui.Text("Waypoints"); + foreach (var kvp in Plugin.Configuration.Waypoints) + { + if (ImGui.Button(kvp.Key)) + { + Utils.OpenMapAt(kvp.Value.Item1, kvp.Value.Item2, kvp.Value.Item3); + } + ImGui.SameLine(); + if (ImGui.Button($"Delete##{kvp.Key}")) + { + Plugin.Configuration.Waypoints.Remove(kvp.Key); + Plugin.Configuration.Save(); + Plugin.WotsitIpc.Update(); + } + } + } +} diff --git a/Waypoints/Plugin.cs b/Waypoints/Plugin.cs new file mode 100644 index 0000000..b8d574a --- /dev/null +++ b/Waypoints/Plugin.cs @@ -0,0 +1,37 @@ +using Dalamud.Interface.Windowing; +using Dalamud.IoC; +using Dalamud.Plugin; +using Dalamud.Plugin.Services; + +namespace Waypoints; + +public sealed class Plugin : IDalamudPlugin +{ + [PluginService] public static IDalamudPluginInterface PluginInterface { get; private set; } = null!; + [PluginService] public static IClientState ClientState { get; private set; } = null!; + [PluginService] public static IObjectTable ObjectTable { get; private set; } = null!; + public static Configuration Configuration { get; private set; } = null!; + public readonly WindowSystem WindowSystem = new("Waypoints"); + public static WotsitIpc WotsitIpc { get; private set; } = null!; + public static MainWindow MainWindow { get; private set; } = null!; + + public Plugin() + { + Configuration = PluginInterface.GetPluginConfig() as Configuration ?? new Configuration(); + Configuration.Initialize(PluginInterface); + + WotsitIpc = new(); + + MainWindow = new(); + WindowSystem.AddWindow(MainWindow); + PluginInterface.UiBuilder.Draw += WindowSystem.Draw; + PluginInterface.UiBuilder.OpenMainUi += MainWindow.Toggle; + } + + public void Dispose() + { + Configuration.Save(); + WindowSystem.RemoveAllWindows(); + WotsitIpc.Dispose(); + } +} diff --git a/Waypoints/Utils.cs b/Waypoints/Utils.cs new file mode 100644 index 0000000..5685886 --- /dev/null +++ b/Waypoints/Utils.cs @@ -0,0 +1,29 @@ +using FFXIVClientStructs.FFXIV.Client.UI.Agent; +using System.Numerics; + +namespace Waypoints +{ + public static class Utils + { + public static unsafe uint CurrentTerritoryId() + { + return AgentMap.Instance()->CurrentTerritoryId; + } + + public static unsafe uint CurrentMapId() + { + return AgentMap.Instance()->CurrentMapId; + } + + public static Vector3? CurrentPosition() + { + return Plugin.ObjectTable.LocalPlayer?.Position; + } + + public static unsafe void OpenMapAt(uint territoryId, uint mapId, Vector3 position) + { + AgentMap.Instance()->SetFlagMapMarker(territoryId, mapId, position); + AgentMap.Instance()->OpenMap(mapId); + } + } +} diff --git a/SamplePlugin/SamplePlugin.csproj b/Waypoints/Waypoints.csproj similarity index 65% rename from SamplePlugin/SamplePlugin.csproj rename to Waypoints/Waypoints.csproj index 5cad3cb..3f60da8 100644 --- a/SamplePlugin/SamplePlugin.csproj +++ b/Waypoints/Waypoints.csproj @@ -6,11 +6,4 @@ AGPL-3.0-or-later false - - - - PreserveNewest - false - - diff --git a/Waypoints/Waypoints.json b/Waypoints/Waypoints.json new file mode 100644 index 0000000..0ecdfeb --- /dev/null +++ b/Waypoints/Waypoints.json @@ -0,0 +1,11 @@ +{ + "Author": "SuspiciousActivity", + "Name": "Waypoints", + "Punchline": "Save Waypoints and access them using Wotsit.", + "Description": "Save Waypoints and access them using Wotsit.", + "ApplicableVersion": "any", + "Tags": [ + "waypoint", + "wotsit" + ] +} diff --git a/Waypoints/WotsitIpc.cs b/Waypoints/WotsitIpc.cs new file mode 100644 index 0000000..4fbb063 --- /dev/null +++ b/Waypoints/WotsitIpc.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Numerics; +using System.Timers; +using Dalamud.Plugin.Ipc; + +namespace Waypoints +{ + public class WotsitIpc + { + private ICallGateSubscriber _registerWithSearch; + private ICallGateSubscriber _invoke; + private ICallGateSubscriber _unregisterAll; + private Timer _timer; + + private Dictionary _map = new(); + + public WotsitIpc() + { + _registerWithSearch = Plugin.PluginInterface.GetIpcSubscriber("FA.RegisterWithSearch"); + _unregisterAll = Plugin.PluginInterface.GetIpcSubscriber("FA.UnregisterAll"); + + _invoke = Plugin.PluginInterface.GetIpcSubscriber("FA.Invoke"); + _invoke.Subscribe(Invoke); + _timer = new Timer(5000); + _timer.Elapsed += (sender, e) => RetryInit(); + if (!Update()) + { + _timer.Start(); + } + } + + private void RetryInit() + { + _registerWithSearch = Plugin.PluginInterface.GetIpcSubscriber("FA.RegisterWithSearch"); + _unregisterAll = Plugin.PluginInterface.GetIpcSubscriber("FA.UnregisterAll"); + + _invoke = Plugin.PluginInterface.GetIpcSubscriber("FA.Invoke"); + _invoke.Subscribe(Invoke); + if (Update()) + { + _timer.Stop(); + } + } + + public void Dispose() + { + GC.SuppressFinalize(this); + + UnregisterAll(); + } + + public bool Update() + { + _map.Clear(); + if (!UnregisterAll()) + { + return false; + } + + foreach (var kvp in Plugin.Configuration.Waypoints) + { + string guid = _registerWithSearch.InvokeFunc( + Plugin.PluginInterface.InternalName, + $"Waypoint: {kvp.Key}", + $"Waypoint: {kvp.Key}", + 66472 + ); + + _map.Add(guid, (kvp.Value.Item1, kvp.Value.Item2, kvp.Value.Item3)); + } + return true; + } + + public void Invoke(string guid) + { + if (!_map.TryGetValue(guid, out var value)) + { + return; + } + Utils.OpenMapAt(value.Item1, value.Item2, value.Item3); + } + + public bool UnregisterAll() + { + try + { + _unregisterAll.InvokeFunc(Plugin.PluginInterface.InternalName); + return true; + } + catch + { + return false; + } + } + } +} diff --git a/SamplePlugin/packages.lock.json b/Waypoints/packages.lock.json similarity index 100% rename from SamplePlugin/packages.lock.json rename to Waypoints/packages.lock.json