1414import org .bukkit .Bukkit ;
1515
1616public class PluginListSender {
17+ private static final TextColor INFO_COLOR = TextColor .color (0x00BFFF );
18+ private static final TextColor PAPER_COLOR = TextColor .color (0x00AAAA );
19+
1720 private final ConfigManager config ;
1821 private final BukkitAudiences adventure ;
19- private static final Logger logger = Bukkit .getLogger ();
20-
21- private static final TextColor BUKKIT_COLOR = TextColor .fromHexString ("#ea7f06" );
22- private static final TextColor INFO_COLOR = TextColor .fromHexString ("#339dd7" );
23- private static final TextColor LEGACY_COLOR = BUKKIT_COLOR ;
22+ private final Logger logger ;
2423
2524 public PluginListSender (ConfigManager config , BukkitAudiences adventure ) {
2625 this .config = config ;
2726 this .adventure = adventure ;
27+ this .logger = Logger .getLogger ("PluginSpoofer" );
2828 }
2929
3030 public void sendCustomPluginList (Player player ) {
@@ -33,6 +33,13 @@ public void sendCustomPluginList(Player player) {
3333 boolean serverSupportsHover = ServerCompatibility .shouldUseHoverTooltips ();
3434
3535 boolean useHover = hoverEnabled && serverSupportsHover ;
36+
37+ boolean useLegacyFormat = shouldUseLegacyFormat (player );
38+
39+ if (useLegacyFormat ) {
40+ sendLegacyPluginList (player );
41+ return ;
42+ }
3643
3744 Component title ;
3845 if (useHover ) {
@@ -57,12 +64,12 @@ public void sendCustomPluginList(Player player) {
5764 }
5865
5966 if (config .isDebugEnabled () && hoverEnabled && !serverSupportsHover ) {
60- logger .warning ("Your server doesn't support hover tooltips natively." );
61- logger .warning ("Consider using Paper 1.16.5+ for full hover support." );
67+ logger .warning ("[PluginSpoofer] Your server doesn't support hover tooltips natively." );
68+ logger .warning ("[PluginSpoofer] Consider using Paper 1.16.5+ for full hover support." );
6269 }
6370 } catch (Exception e ) {
6471 if (config .isDebugEnabled ()) {
65- logger .severe ("Failed to send message with Adventure API: " + e .getMessage ());
72+ logger .severe ("[PluginSpoofer] Failed to send message with Adventure API: " + e .getMessage ());
6673 e .printStackTrace ();
6774 }
6875 }
@@ -80,7 +87,7 @@ private void sendBukkitPlugins(Player player) {
8087 return ;
8188 }
8289
83- Component bukkitTitle = Component .text ("Bukkit Plugins:" , BUKKIT_COLOR );
90+ Component bukkitTitle = Component .text ("Bukkit Plugins:" , TextColor . color ( 0xFFD700 ) );
8491 sendMessage (player , bukkitTitle );
8592
8693 Component pluginLine = buildPluginLine (enabled , legacy , disabled );
@@ -96,7 +103,7 @@ private void sendPaperPlugins(Player player) {
96103 return ;
97104 }
98105
99- Component paperTitle = Component .text ("Paper Plugins:" , NamedTextColor . DARK_AQUA );
106+ Component paperTitle = Component .text ("Paper Plugins:" , PAPER_COLOR );
100107 sendMessage (player , paperTitle );
101108
102109 Component pluginLine = buildPluginLine (enabled , legacy , disabled );
@@ -134,8 +141,8 @@ private Component buildPluginLine(List<String> enabled, List<String> legacy, Lis
134141 break ;
135142 case LEGACY :
136143 Component legacyMarker = useHover
137- ? HoverTextBuilder .createLegacyMarker (LEGACY_COLOR )
138- : Component .text ("*" , LEGACY_COLOR );
144+ ? HoverTextBuilder .createLegacyMarker (NamedTextColor . GOLD )
145+ : Component .text ("*" , NamedTextColor . GOLD );
139146 lineComponent = lineComponent .append (legacyMarker )
140147 .append (Component .text (entry .name , NamedTextColor .GREEN ));
141148 break ;
@@ -149,6 +156,128 @@ private Component buildPluginLine(List<String> enabled, List<String> legacy, Lis
149156
150157 return lineComponent ;
151158 }
159+
160+ private boolean shouldUseLegacyFormat (Player player ) {
161+ if (config .shouldForceLegacyFormat ()) {
162+ if (config .isDebugEnabled ()) {
163+ logger .info ("[PluginSpoofer] Force legacy format enabled for " + player .getName ());
164+ }
165+ return true ;
166+ }
167+
168+ try {
169+ if (Bukkit .getPluginManager ().getPlugin ("ViaVersion" ) != null ) {
170+ Class <?> viaAPI = Class .forName ("com.viaversion.viaversion.api.Via" );
171+ Object api = viaAPI .getMethod ("getAPI" ).invoke (null );
172+ Method getPlayerVersion = api .getClass ().getMethod ("getPlayerVersion" , Object .class );
173+ int protocolVersion = (int ) getPlayerVersion .invoke (api , player );
174+
175+ if (config .isDebugEnabled ()) {
176+ logger .info ("[PluginSpoofer] Player " + player .getName () + " protocol version: " + protocolVersion );
177+ }
178+
179+ return protocolVersion < 393 ;
180+ }
181+
182+ if (Bukkit .getPluginManager ().getPlugin ("ProtocolLib" ) != null ) {
183+ try {
184+ Class <?> protocolManager = Class .forName ("com.comphenix.protocol.ProtocolLibrary" );
185+ Object manager = protocolManager .getMethod ("getProtocolManager" ).invoke (null );
186+ Method getProtocolVersion = manager .getClass ().getMethod ("getProtocolVersion" , Player .class );
187+ Object version = getProtocolVersion .invoke (manager , player );
188+ int protocolVersion = (int ) version .getClass ().getMethod ("getVersion" ).invoke (version );
189+
190+ if (config .isDebugEnabled ()) {
191+ logger .info ("[PluginSpoofer] Player " + player .getName () + " protocol version (ProtocolLib): " + protocolVersion );
192+ }
193+
194+ return protocolVersion < 393 ;
195+ } catch (Exception e ) {
196+ }
197+ }
198+ } catch (Exception e ) {
199+ if (config .isDebugEnabled ()) {
200+ logger .warning ("[PluginSpoofer] Failed to detect client version: " + e .getMessage ());
201+ }
202+ }
203+
204+ String serverVersion = Bukkit .getVersion ();
205+ if (serverVersion .contains ("1.20" ) || serverVersion .contains ("1.21" )) {
206+ if (config .isDebugEnabled ()) {
207+ logger .info ("[PluginSpoofer] High version server detected, using legacy format for safety" );
208+ }
209+ return true ;
210+ }
211+
212+ return false ;
213+ }
214+
215+ private void sendLegacyPluginList (Player player ) {
216+ int totalPlugins = getTotalPluginCount ();
217+
218+ player .sendMessage ("§3ℹ§f Server Plugins (" + totalPlugins + "):" );
219+
220+ List <String > bukkitEnabled = config .getBukkitEnabledPlugins ();
221+ List <String > bukkitLegacy = config .getBukkitLegacyPlugins ();
222+ List <String > bukkitDisabled = config .getBukkitDisabledPlugins ();
223+
224+ if (!bukkitEnabled .isEmpty () || !bukkitLegacy .isEmpty () || !bukkitDisabled .isEmpty ()) {
225+ player .sendMessage ("§6Bukkit Plugins:" );
226+ String pluginLine = buildLegacyPluginLine (bukkitEnabled , bukkitLegacy , bukkitDisabled );
227+ player .sendMessage (pluginLine );
228+ }
229+
230+ List <String > paperEnabled = config .getPaperEnabledPlugins ();
231+ List <String > paperLegacy = config .getPaperLegacyPlugins ();
232+ List <String > paperDisabled = config .getPaperDisabledPlugins ();
233+
234+ if (!paperEnabled .isEmpty () || !paperLegacy .isEmpty () || !paperDisabled .isEmpty ()) {
235+ player .sendMessage ("§3Paper Plugins:" );
236+ String pluginLine = buildLegacyPluginLine (paperEnabled , paperLegacy , paperDisabled );
237+ player .sendMessage (pluginLine );
238+ }
239+ }
240+
241+ private String buildLegacyPluginLine (List <String > enabled , List <String > legacy , List <String > disabled ) {
242+ List <PluginEntry > allPlugins = new ArrayList <>();
243+
244+ for (String plugin : enabled ) {
245+ allPlugins .add (new PluginEntry (plugin , PluginType .ENABLED ));
246+ }
247+ for (String plugin : legacy ) {
248+ allPlugins .add (new PluginEntry (plugin , PluginType .LEGACY ));
249+ }
250+ for (String plugin : disabled ) {
251+ allPlugins .add (new PluginEntry (plugin , PluginType .DISABLED ));
252+ }
253+
254+ allPlugins .sort ((a , b ) -> a .name .compareToIgnoreCase (b .name ));
255+
256+ StringBuilder line = new StringBuilder ("§7 - " );
257+ boolean first = true ;
258+
259+ for (PluginEntry entry : allPlugins ) {
260+ if (!first ) {
261+ line .append ("§f, " );
262+ }
263+
264+ switch (entry .type ) {
265+ case ENABLED :
266+ line .append ("§a" ).append (entry .name );
267+ break ;
268+ case LEGACY :
269+ line .append ("§6*§a" ).append (entry .name );
270+ break ;
271+ case DISABLED :
272+ line .append ("§c" ).append (entry .name );
273+ break ;
274+ }
275+
276+ first = false ;
277+ }
278+
279+ return line .toString ();
280+ }
152281
153282 private static class PluginEntry {
154283 final String name ;
@@ -174,21 +303,30 @@ private int getTotalPluginCount() {
174303 }
175304
176305 private void sendMessage (Player player , Component message ) {
177- if (ServerCompatibility .isPaper () && adventure == null ) {
178- try {
179- Method sendMessageMethod = player .getClass ().getMethod ("sendMessage" , Component .class );
180- sendMessageMethod .invoke (player , message );
181- } catch (Exception e ) {
182- if (adventure != null ) {
183- adventure .player (player ).sendMessage (message );
184- } else {
185- player .sendMessage (LegacyComponentSerializer .legacySection ().serialize (message ));
306+ try {
307+ if (ServerCompatibility .isPaper () && adventure == null ) {
308+ try {
309+ Method sendMessageMethod = player .getClass ().getMethod ("sendMessage" , Component .class );
310+ sendMessageMethod .invoke (player , message );
311+ } catch (Exception e ) {
312+ sendLegacyMessage (player , message );
186313 }
314+ } else if (adventure != null ) {
315+ adventure .player (player ).sendMessage (message );
316+ } else {
317+ sendLegacyMessage (player , message );
187318 }
188- } else if (adventure != null ) {
189- adventure .player (player ).sendMessage (message );
190- } else {
191- player .sendMessage (LegacyComponentSerializer .legacySection ().serialize (message ));
319+ } catch (Exception e ) {
320+ sendLegacyMessage (player , message );
321+ }
322+ }
323+
324+ private void sendLegacyMessage (Player player , Component message ) {
325+ try {
326+ String legacyText = LegacyComponentSerializer .legacySection ().serialize (message );
327+ player .sendMessage (legacyText );
328+ } catch (Exception e ) {
329+ player .sendMessage (message .toString ());
192330 }
193331 }
194332}
0 commit comments