3636import net .wurstclient .util .ChatUtils ;
3737import net .wurstclient .util .FakePlayerEntity ;
3838
39- @ SearchTags ({"spectator monitor" , "spectator detector" , "gamemode monitor" ,
40- "spec detector" , "hidden player detector" , "vanish detector" })
41- public final class SpectatorMonitorHack extends Hack implements UpdateListener
39+ @ SearchTags ({"staff monitor" , "spectator monitor" , "spectator detector" ,
40+ "gamemode monitor" , "creative monitor" , "spec detector" ,
41+ "hidden player detector" , "vanish detector" , "staff detector" })
42+ public final class StaffMonitorHack extends Hack implements UpdateListener
4243{
4344 private enum AlertSound
4445 {
@@ -86,6 +87,11 @@ public String toString()
8687 new EnumSetting <>("Sound" , AlertSound .values (), AlertSound .CHIME );
8788 private final SliderSetting volume = new SliderSetting ("Volume" , 100 , 0 ,
8889 200 , 1 , ValueDisplay .INTEGER .withSuffix ("%" ));
90+ private final CheckboxSetting monitorModeSwitching = new CheckboxSetting (
91+ "Monitor mode switching" ,
92+ "Alert when players switch gamemodes (survival \u2194 creative \u2194 "
93+ + " adventure \u2194 spectator)." ,
94+ true );
8995 private final CheckboxSetting ignoreSelf =
9096 new CheckboxSetting ("Ignore self" , true );
9197 private final CheckboxSetting hiddenPlayerAlerts = new CheckboxSetting (
@@ -94,38 +100,39 @@ public String toString()
94100 + " the tab list.\n \n "
95101 + "This can reveal vanished players, but some servers also use"
96102 + " off-tab player entities for NPCs." ,
97- false );
98- private final CheckboxSetting staffAlerts = new CheckboxSetting (
99- "Staff alerts" ,
103+ true );
104+ private final CheckboxSetting hiddenStaffAlerts = new CheckboxSetting (
105+ "Hidden staff alerts" ,
100106 "Alerts when a player from the local staff list appears in tab.\n \n "
101107 + "Staff names are loaded from .minecraft/wurst/staff/<server>.txt"
102108 + " and .minecraft/wurst/staff/global.txt, one name per line." ,
103- false );
109+ true );
104110
105- private final Map <UUID , Boolean > spectatorStates = new HashMap <>();
111+ private final Map <UUID , GameType > gamemodeStates = new HashMap <>();
106112 private final Map <UUID , String > hiddenPlayers = new HashMap <>();
107113 private final Set <String > staffNames = new HashSet <>();
108114 private final Set <UUID > alertedStaff = new HashSet <>();
109115 private String lastServerKey = "unknown" ;
110116 private boolean hiddenPlayerAlertsActive ;
111117
112- public SpectatorMonitorHack ()
118+ public StaffMonitorHack ()
113119 {
114- super ("SpectatorMonitor " );
120+ super ("StaffMonitor " );
115121 setCategory (Category .INTEL );
116122 addSetting (chatAlert );
117123 addSetting (soundAlert );
118124 addSetting (sound );
119125 addSetting (volume );
126+ addSetting (monitorModeSwitching );
120127 addSetting (ignoreSelf );
121128 addSetting (hiddenPlayerAlerts );
122- addSetting (staffAlerts );
129+ addSetting (hiddenStaffAlerts );
123130 }
124131
125132 @ Override
126133 protected void onEnable ()
127134 {
128- spectatorStates .clear ();
135+ gamemodeStates .clear ();
129136 hiddenPlayers .clear ();
130137 alertedStaff .clear ();
131138 lastServerKey = resolveServerKey ();
@@ -141,7 +148,7 @@ protected void onEnable()
141148 protected void onDisable ()
142149 {
143150 EVENTS .remove (UpdateListener .class , this );
144- spectatorStates .clear ();
151+ gamemodeStates .clear ();
145152 hiddenPlayers .clear ();
146153 alertedStaff .clear ();
147154 staffNames .clear ();
@@ -153,7 +160,7 @@ public void onUpdate()
153160 {
154161 if (MC .getConnection () == null )
155162 {
156- spectatorStates .clear ();
163+ gamemodeStates .clear ();
157164 hiddenPlayers .clear ();
158165 hiddenPlayerAlertsActive = false ;
159166 return ;
@@ -162,7 +169,7 @@ public void onUpdate()
162169 String serverKeyNow = resolveServerKey ();
163170 if (!serverKeyNow .equals (lastServerKey ))
164171 {
165- spectatorStates .clear ();
172+ gamemodeStates .clear ();
166173 hiddenPlayers .clear ();
167174 alertedStaff .clear ();
168175 lastServerKey = serverKeyNow ;
@@ -174,36 +181,43 @@ public void onUpdate()
174181 return ;
175182 }
176183
184+ boolean modeSwitching = monitorModeSwitching .isChecked ();
185+
177186 updateHiddenPlayers ();
178187
179- HashMap <UUID , Boolean > nextStates = new HashMap <>();
188+ HashMap <UUID , GameType > nextStates = new HashMap <>();
180189 for (PlayerInfo info : MC .getConnection ().getOnlinePlayers ())
181190 {
182191 UUID id = info .getProfile ().id ();
183192 if (ignoreSelf .isChecked () && MC .player != null
184193 && id .equals (MC .player .getUUID ()))
185194 continue ;
186195
187- boolean isSpectator = info .getGameMode () == GameType .SPECTATOR ;
188- nextStates .put (id , isSpectator );
189- if (staffAlerts .isChecked () && isStaffName (info .getProfile ().name ())
196+ GameType currentMode = info .getGameMode ();
197+ nextStates .put (id , currentMode );
198+
199+ // Hidden staff alert
200+ if (hiddenStaffAlerts .isChecked ()
201+ && isStaffName (info .getProfile ().name ())
190202 && alertedStaff .add (id ))
191203 alertStaff (info );
192204
193- Boolean previous = spectatorStates .get (id );
205+ GameType previous = gamemodeStates .get (id );
194206 if (previous == null )
195207 {
196- if (isSpectator )
197- alert (info , true );
208+ // First time seeing this player — alert their initial mode
209+ if (modeSwitching )
210+ alert (info , currentMode , true );
198211 continue ;
199212 }
200213
201- if (previous .booleanValue () != isSpectator )
202- alert (info , isSpectator );
214+ // Gamemode changed — alert on any transition
215+ if (modeSwitching && previous != currentMode )
216+ alert (info , currentMode , true );
203217 }
204218
205- spectatorStates .clear ();
206- spectatorStates .putAll (nextStates );
219+ gamemodeStates .clear ();
220+ gamemodeStates .putAll (nextStates );
207221 }
208222
209223 private void updateHiddenPlayers ()
@@ -264,7 +278,7 @@ private void snapshotCurrentStates()
264278 && id .equals (MC .player .getUUID ()))
265279 continue ;
266280
267- spectatorStates .put (id , info .getGameMode () == GameType . SPECTATOR );
281+ gamemodeStates .put (id , info .getGameMode ());
268282 }
269283 }
270284
@@ -296,14 +310,16 @@ private boolean shouldIgnorePlayerEntity(Player player)
296310 && player .getUUID ().equals (MC .player .getUUID ());
297311 }
298312
299- private void alert (PlayerInfo info , boolean enteredSpectator )
313+ private void alert (PlayerInfo info , GameType mode , boolean entered )
300314 {
301315 String name = info .getProfile ().name ();
316+ String modeLabel = mode .getName (); // "survival", "creative",
317+ // "spectator", "adventure"
302318 if (chatAlert .isChecked ())
303319 {
304- String action = enteredSpectator ? "entered" : "left" ;
320+ String action = entered ? "entered" : "left" ;
305321 ChatUtils .component (Component .literal (String .format (Locale .ROOT ,
306- "[SpectatorMonitor ] %s %s spectator mode." , name , action )));
322+ "[StaffMonitor ] %s %s %s mode." , name , action , modeLabel )));
307323 }
308324
309325 if (soundAlert .isChecked () && MC .level != null && MC .player != null )
@@ -320,10 +336,10 @@ private void alert(PlayerInfo info, boolean enteredSpectator)
320336 double z = MC .player .getZ ();
321337 for (int i = 0 ; i < whole ; i ++)
322338 MC .level .playLocalSound (x , y , z , event , SoundSource .PLAYERS , 1F ,
323- enteredSpectator ? 1.2F : 0.85F , false );
339+ entered ? 1.2F : 0.85F , false );
324340 if (remainder > 0F )
325341 MC .level .playLocalSound (x , y , z , event , SoundSource .PLAYERS ,
326- remainder , enteredSpectator ? 1.2F : 0.85F , false );
342+ remainder , entered ? 1.2F : 0.85F , false );
327343 }
328344 }
329345
@@ -332,7 +348,7 @@ private void alertStaff(PlayerInfo info)
332348 String name = info .getProfile ().name ();
333349 if (chatAlert .isChecked ())
334350 ChatUtils .component (Component .literal (String .format (Locale .ROOT ,
335- "[SpectatorMonitor ] Staff member %s is online." , name )));
351+ "[StaffMonitor ] Staff member %s is online." , name )));
336352
337353 if (soundAlert .isChecked () && MC .level != null && MC .player != null )
338354 {
@@ -353,7 +369,7 @@ private void alertHiddenPlayer(String name, boolean appeared)
353369 {
354370 String action = appeared ? "appeared off-tab" : "disappeared" ;
355371 ChatUtils .component (Component .literal (String .format (Locale .ROOT ,
356- "[SpectatorMonitor ] %s %s." , name , action )));
372+ "[StaffMonitor ] %s %s." , name , action )));
357373 }
358374
359375 if (soundAlert .isChecked () && MC .level != null && MC .player != null )
@@ -372,7 +388,7 @@ private void alertHiddenPlayer(String name, boolean appeared)
372388 private void loadStaffNames ()
373389 {
374390 staffNames .clear ();
375- if (!staffAlerts .isChecked ())
391+ if (!hiddenStaffAlerts .isChecked ())
376392 return ;
377393
378394 Path folder = WURST .getWurstFolder ().resolve ("staff" );
@@ -397,7 +413,7 @@ private void loadStaffFile(Path file)
397413 }catch (IOException e )
398414 {
399415 ChatUtils
400- .error ("SpectatorMonitor staff list failed: " + e .getMessage ());
416+ .error ("StaffMonitor staff list failed: " + e .getMessage ());
401417 }
402418 }
403419
0 commit comments