1+ package cqb13 .NumbyHack .modules .general ;
2+
3+ import cqb13 .NumbyHack .NumbyHack ;
4+ import cqb13 .NumbyHack .utils .TimerUtils ;
5+ import meteordevelopment .meteorclient .events .entity .EntityAddedEvent ;
6+ import meteordevelopment .meteorclient .events .render .Render2DEvent ;
7+ import meteordevelopment .meteorclient .events .render .Render3DEvent ;
8+ import meteordevelopment .meteorclient .events .world .TickEvent ;
9+ import meteordevelopment .meteorclient .renderer .Renderer2D ;
10+ import meteordevelopment .meteorclient .renderer .ShapeMode ;
11+ import meteordevelopment .meteorclient .renderer .text .TextRenderer ;
12+ import meteordevelopment .meteorclient .settings .*;
13+ import meteordevelopment .meteorclient .systems .modules .Module ;
14+ import meteordevelopment .meteorclient .utils .player .PlayerUtils ;
15+ import meteordevelopment .meteorclient .utils .render .NametagUtils ;
16+ import meteordevelopment .meteorclient .utils .render .WireframeEntityRenderer ;
17+ import meteordevelopment .meteorclient .utils .render .color .SettingColor ;
18+ import meteordevelopment .meteorclient .utils .world .Dimension ;
19+ import meteordevelopment .orbit .EventHandler ;
20+ import net .minecraft .client .network .PlayerListEntry ;
21+ import net .minecraft .entity .Entity ;
22+ import net .minecraft .entity .player .PlayerEntity ;
23+ import net .minecraft .item .ItemStack ;
24+ import org .joml .Vector3d ;
25+
26+ import java .util .ArrayList ;
27+ import java .util .List ;
28+ import java .util .UUID ;
29+
30+ public class LogOutSpots extends Module {
31+
32+ private final SettingGroup sgGeneral = settings .getDefaultGroup ();
33+ private final SettingGroup sgRender = settings .createGroup ("Render" );
34+
35+ // General
36+ private final Setting <Boolean > nameRender = sgGeneral .add (new BoolSetting .Builder ()
37+ .name ("name" )
38+ .description ("Shows the name of the player." )
39+ .defaultValue (true )
40+ .build ()
41+ );
42+
43+ private final Setting <Boolean > healthRender = sgGeneral .add (new BoolSetting .Builder ()
44+ .name ("health" )
45+ .description ("Shows the health of the player." )
46+ .defaultValue (true )
47+ .build ()
48+ );
49+
50+ private final Setting <Boolean > coordRender = sgGeneral .add (new BoolSetting .Builder ()
51+ .name ("coordinates" )
52+ .description ("Shows the coordinates of the player." )
53+ .defaultValue (false )
54+ .build ()
55+ );
56+
57+ private final Setting <Boolean > armorCheck = sgGeneral .add (new BoolSetting .Builder ()
58+ .name ("armor-check" )
59+ .description ("Checks if the player has armor on." )
60+ .defaultValue (true )
61+ .build ()
62+ );
63+
64+ private final Setting <Double > scale = sgGeneral .add (new DoubleSetting .Builder ()
65+ .name ("scale" )
66+ .description ("The scale of the text." )
67+ .defaultValue (1 )
68+ .min (0.2 )
69+ .sliderRange (0.2 , 2 )
70+ .build ()
71+ );
72+
73+ private final Setting <Boolean > notification = sgGeneral .add (new BoolSetting .Builder ()
74+ .name ("notification" )
75+ .description ("Notifies you when a player logs out." )
76+ .defaultValue (true )
77+ .build ()
78+ );
79+
80+ // Render
81+ private final Setting <ShapeMode > shapeMode = sgRender .add (new EnumSetting .Builder <ShapeMode >()
82+ .name ("shape-mode" )
83+ .description ("The shape." )
84+ .defaultValue (ShapeMode .Both )
85+ .build ()
86+ );
87+
88+ private final Setting <SettingColor > sideColor = sgRender .add (new ColorSetting .Builder ()
89+ .name ("side-color" )
90+ .description ("The side color." )
91+ .defaultValue (new SettingColor (146 ,188 ,98 , 10 )).
92+ build ()
93+ );
94+
95+ private final Setting <SettingColor > lineColor = sgRender .add (new ColorSetting .Builder ()
96+ .name ("line-color" )
97+ .description ("The line color." )
98+ .defaultValue (new SettingColor (146 ,188 ,98 , 255 ))
99+ .build ()
100+ );
101+
102+ private final Setting <SettingColor > nameColor = sgRender .add (new ColorSetting .Builder ()
103+ .name ("name-color" )
104+ .description ("The name color." )
105+ .defaultValue (new SettingColor (255 , 255 , 255 ))
106+ .build ()
107+ );
108+
109+ private final Setting <SettingColor > nameBackgroundColor = sgRender .add (new ColorSetting .Builder ()
110+ .name ("name-background-color" )
111+ .description ("The name background color." )
112+ .defaultValue (new SettingColor (0 , 0 , 0 , 75 ))
113+ .build ()
114+ );
115+
116+ private final List <Entry > players = new ArrayList <>();
117+
118+ private final List <PlayerListEntry > lastPlayerList = new ArrayList <>();
119+ private final List <PlayerEntity > lastPlayers = new ArrayList <>();
120+
121+ private int timer ;
122+ private Dimension lastDimension ;
123+
124+ public LogOutSpots () {
125+ super (NumbyHack .CATEGORY , "log-spots-+" , "Displays a box where another player has logged out at." );
126+ lineColor .onChanged ();
127+ }
128+
129+ @ Override
130+ public void onActivate () {
131+ lastPlayerList .addAll (mc .getNetworkHandler ().getPlayerList ());
132+ updateLastPlayers ();
133+
134+ timer = 10 ;
135+ lastDimension = PlayerUtils .getDimension ();
136+ }
137+
138+ @ Override
139+ public void onDeactivate () {
140+ players .clear ();
141+ lastPlayerList .clear ();
142+ }
143+
144+ private void updateLastPlayers () {
145+ lastPlayers .clear ();
146+ for (Entity entity : mc .world .getEntities ()) {
147+ if (entity instanceof PlayerEntity ) lastPlayers .add ((PlayerEntity ) entity );
148+ }
149+ }
150+
151+ @ EventHandler
152+ private void onEntityAdded (EntityAddedEvent event ) {
153+ if (event .entity instanceof PlayerEntity ) {
154+ int toRemove = -1 ;
155+
156+ for (int i = 0 ; i < players .size (); i ++) {
157+ if (players .get (i ).uuid .equals (event .entity .getUuid ())) {
158+ toRemove = i ;
159+ break ;
160+ }
161+ }
162+
163+ if (toRemove != -1 ) {
164+ players .remove (toRemove );
165+ }
166+ }
167+ }
168+
169+ @ EventHandler
170+ private void onTick (TickEvent .Post event ) {
171+ if (mc .getNetworkHandler ().getPlayerList ().size () != lastPlayerList .size ()) {
172+ for (PlayerListEntry entry : lastPlayerList ) {
173+ if (mc .getNetworkHandler ().getPlayerList ().stream ().anyMatch (playerListEntry -> playerListEntry .getProfile ().equals (entry .getProfile ()))) continue ;
174+
175+ for (PlayerEntity player : lastPlayers ) {
176+ if (player .getUuid ().equals (entry .getProfile ().getId ())) {
177+ if (armorCheck .get ()) {
178+ for (int position = 3 ; position >= 0 ; position --) {
179+ ItemStack itemStack = getItem (position , player );
180+
181+ if (itemStack .isEmpty ()) return ;
182+ }
183+ }
184+ add (new Entry (player ));
185+ }
186+ }
187+ }
188+
189+ lastPlayerList .clear ();
190+ lastPlayerList .addAll (mc .getNetworkHandler ().getPlayerList ());
191+ updateLastPlayers ();
192+ }
193+
194+ if (timer <= 0 ) {
195+ updateLastPlayers ();
196+ timer = 10 ;
197+ } else {
198+ timer --;
199+ }
200+
201+ Dimension dimension = PlayerUtils .getDimension ();
202+ if (dimension != lastDimension ) players .clear ();
203+ lastDimension = dimension ;
204+ }
205+
206+ private void add (Entry entry ) {
207+ players .removeIf (player -> player .uuid .equals (entry .uuid ));
208+ players .add (entry );
209+ }
210+
211+ private ItemStack getItem (int i , PlayerEntity playerEntity ) {
212+ if (playerEntity == null ) return ItemStack .EMPTY ;
213+
214+ return switch (i ) {
215+ case 4 -> playerEntity .getOffHandStack ();
216+ case 5 -> playerEntity .getMainHandStack ();
217+ default -> playerEntity .getInventory ().getArmorStack (i );
218+ };
219+ }
220+
221+ @ EventHandler
222+ private void onRender3D (Render3DEvent event ) {
223+ for (Entry player : players ) player .render3D (event );
224+ }
225+
226+ @ EventHandler
227+ private void onRender2D (Render2DEvent event ) {
228+ for (Entry player : players ) player .render2D ();
229+ }
230+
231+ private static final Vector3d pos = new Vector3d ();
232+
233+ private class Entry {
234+ public final double x , y , z ;
235+ public final double xWidth , zWidth , halfWidth , height ;
236+
237+ public final TimerUtils passed = new TimerUtils ();
238+
239+ public final UUID uuid ;
240+ public final String name ;
241+ public final int health , maxHealth ;
242+ public final String healthText ;
243+ PlayerEntity entity ;
244+
245+ public Entry (PlayerEntity entity ) {
246+
247+ passed .reset ();
248+ halfWidth = entity .getWidth () / 2 ;
249+ x = entity .getX () - halfWidth ;
250+ y = entity .getY ();
251+ z = entity .getZ () - halfWidth ;
252+
253+ xWidth = entity .getBoundingBox ().getXLength ();
254+ zWidth = entity .getBoundingBox ().getZLength ();
255+ height = entity .getBoundingBox ().getYLength ();
256+
257+ this .entity = entity ;
258+
259+ uuid = entity .getUuid ();
260+ name = entity .getEntityName ();
261+ health = Math .round (entity .getHealth () + entity .getAbsorptionAmount ());
262+ maxHealth = Math .round (entity .getMaxHealth () + entity .getAbsorptionAmount ());
263+
264+ healthText = " " + health ;
265+ }
266+
267+ public void render3D (Render3DEvent event ) {
268+ WireframeEntityRenderer .render (event , entity , scale .get (), sideColor .get (), lineColor .get (), shapeMode .get ());
269+ }
270+
271+ public void render2D () {
272+ if (PlayerUtils .distanceToCamera (x , y , z ) > mc .options .getViewDistance ().getValue () * 16 ) return ;
273+
274+ TextRenderer text = TextRenderer .get ();
275+ double s = scale .get ();
276+ pos .set (x + halfWidth , y + height + 0.5 , z + halfWidth );
277+
278+ if (!NametagUtils .to2D (pos , s )) return ;
279+
280+ NametagUtils .begin (pos );
281+
282+ String content = "" ;
283+ if (nameRender .get ()) content = content + name ;
284+ if (healthRender .get ()) content = content + " " + healthText + "HP" ;
285+ if (coordRender .get ()) content = content + " (" + Math .round (entity .getX ()) + " " + Math .round (entity .getY ()) + " " + Math .round (entity .getZ ()) + ")" ;
286+
287+ // Render background
288+ double i = text .getWidth (content )/2 ;
289+ Renderer2D .COLOR .begin ();
290+ Renderer2D .COLOR .quad (-i , 0 , i * 2 , text .getHeight (), nameBackgroundColor .get ());
291+ Renderer2D .COLOR .render (null );
292+
293+ // Render name and health texts
294+ text .beginBig ();
295+ if (nameRender .get ())text .render (content , -i , 0 , nameColor .get ());
296+ text .end ();
297+
298+ NametagUtils .end ();
299+ }
300+ }
301+ }
0 commit comments