@@ -25,8 +25,18 @@ public class CLVTabComplete implements TabCompleter {
2525
2626 private static final String PLAYER_PREFIX = "CyberLevels.player." ;
2727 private static final String ADMIN_PREFIX = "CyberLevels.admin." ;
28-
29- private static final Map <String , String > COMMAND_PERMISSIONS = new HashMap <>();
28+ private static final long PLAYER_NAME_CACHE_MILLIS = 5000L ;
29+
30+ private static final List <String > EXP_AMOUNT_SUGGESTIONS = Collections .unmodifiableList (
31+ Arrays .asList ("<amount>" , "5" , "100" , "250" , "1000" )
32+ );
33+ private static final List <String > LEVEL_AMOUNT_SUGGESTIONS = Collections .unmodifiableList (
34+ Arrays .asList ("<amount>" , "1" , "2" , "5" )
35+ );
36+ private static final Set <String > MUTATION_COMMANDS = Collections .unmodifiableSet (new HashSet <>(
37+ Arrays .asList ("addexp" , "setexp" , "removeexp" , "addlevel" , "setlevel" , "removelevel" )
38+ ));
39+ private static final Map <String , String > COMMAND_PERMISSIONS = new LinkedHashMap <>();
3040
3141 static {
3242 COMMAND_PERMISSIONS .put ("about" , PLAYER_PREFIX + "about" );
@@ -48,6 +58,9 @@ public class CLVTabComplete implements TabCompleter {
4858 }
4959
5060 private final CyberLevels main ;
61+ private long playerNamesCachedAt = 0L ;
62+ private boolean playerNamesCachedOfflineMode = false ;
63+ private List <String > cachedPlayerNames = Collections .emptyList ();
5164
5265 /**
5366 * Produces context-aware tab completions for the CyberLevels command set.
@@ -84,16 +97,14 @@ public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Comman
8497 break ;
8598
8699 case "addexp" : case "setexp" : case "removeexp" :
87- return partialMatch (args [1 ], Arrays . asList ( "<amount>" , "5" , "100" , "250" , "1000" ) );
100+ return partialMatch (args [1 ], EXP_AMOUNT_SUGGESTIONS );
88101
89102 case "addlevel" : case "setlevel" : case "removelevel" :
90- return partialMatch (args [1 ], Arrays . asList ( "<amount>" , "1" , "2" , "5" ) );
103+ return partialMatch (args [1 ], LEVEL_AMOUNT_SUGGESTIONS );
91104 }
92105 }
93106
94- if (args .length == 3 &&
95- Arrays .asList ("addexp" , "setexp" , "removeexp" , "addlevel" , "setlevel" , "removelevel" )
96- .contains (args [0 ].toLowerCase ()))
107+ if (args .length == 3 && MUTATION_COMMANDS .contains (args [0 ].toLowerCase (Locale .ENGLISH )))
97108 {
98109 List <String > suggestions = new ArrayList <>();
99110 suggestions .add ("[<player>]" );
@@ -105,9 +116,16 @@ public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Comman
105116 }
106117
107118 private List <String > getPlayerNames () {
108- List <String > players = new ArrayList <>();
119+ boolean offlineMode = main .cache ().config ().isTabCompleteLoadOfflineUsers ();
120+ long now = System .currentTimeMillis ();
121+
122+ if (offlineMode == playerNamesCachedOfflineMode &&
123+ now - playerNamesCachedAt <= PLAYER_NAME_CACHE_MILLIS )
124+ return cachedPlayerNames ;
125+
126+ LinkedHashSet <String > players = new LinkedHashSet <>();
109127
110- if (main . cache (). config (). isTabCompleteLoadOfflineUsers () ) {
128+ if (offlineMode ) {
111129 for (OfflinePlayer p : Bukkit .getOfflinePlayers ()) {
112130 String name = p .getName ();
113131 if (name != null ) players .add (name );
@@ -118,13 +136,18 @@ private List<String> getPlayerNames() {
118136 }
119137 }
120138
121- return players ;
139+ List <String > snapshot = new ArrayList <>(players );
140+ snapshot .sort (String .CASE_INSENSITIVE_ORDER );
141+ cachedPlayerNames = snapshot ;
142+ playerNamesCachedOfflineMode = offlineMode ;
143+ playerNamesCachedAt = now ;
144+ return cachedPlayerNames ;
122145 }
123146
124147 private List <String > partialMatch (String input , List <String > options ) {
125148 List <String > matches = new ArrayList <>();
126149 StringUtil .copyPartialMatches (input , options , matches );
127- Collections .sort (matches );
150+ matches .sort (String . CASE_INSENSITIVE_ORDER );
128151 return matches ;
129152 }
130153}
0 commit comments