2828import com .velocitypowered .api .proxy .Player ;
2929import net .kyori .adventure .text .Component ;
3030import net .kyori .adventure .text .format .TextColor ;
31+ import net .kyori .adventure .text .minimessage .MiniMessage ;
3132import net .kyori .adventure .text .serializer .plain .PlainTextComponentSerializer ;
3233import net .william278 .desertwell .about .AboutMenu ;
3334import net .william278 .velocitab .Velocitab ;
35+ import net .william278 .velocitab .config .Group ;
36+ import net .william278 .velocitab .config .Settings ;
37+ import net .william278 .velocitab .config .TabGroups ;
3438import net .william278 .velocitab .player .TabPlayer ;
3539import org .jetbrains .annotations .NotNull ;
40+ import org .slf4j .event .Level ;
3641
37- import java .util .Optional ;
38- import java .util .UUID ;
42+ import java .util .*;
3943
4044public final class VelocitabCommand {
4145
@@ -146,24 +150,126 @@ public BrigadierCommand command() {
146150 .then (LiteralArgumentBuilder .<CommandSource >literal ("reload" )
147151 .requires (src -> hasPermission (src , "reload" ))
148152 .executes (ctx -> {
149- plugin .loadConfigs ();
153+ final Settings settings = plugin .getSettings ();
154+ try {
155+ plugin .loadSettings ();
156+ } catch (Throwable e ) {
157+ plugin .setSettings (settings );
158+ ctx .getSource ().sendRichMessage ("<red>An error occurred while reloading the settings file" );
159+ plugin .log (Level .ERROR , "An error occurred while reloading the settings file" , e );
160+ return Command .SINGLE_SUCCESS ;
161+ }
162+
163+ final Map <String , Group > groups = Map .copyOf (plugin .getTabGroupsManager ().getGroupsMap ());
164+ final Map <TabGroups , String > groupsFiles = Map .copyOf (plugin .getTabGroupsManager ().getGroupsFilesMap ());
165+
166+ try {
167+ plugin .getTabGroupsManager ().loadGroups ();
168+ } catch (Throwable e ) {
169+ plugin .getTabGroupsManager ().loadGroupsBackup (groups , groupsFiles );
170+ ctx .getSource ().sendRichMessage ("<red>An error occurred while reloading the tab groups file" );
171+ plugin .log (Level .ERROR , "An error occurred while reloading the tab groups file" , e );
172+ return Command .SINGLE_SUCCESS ;
173+ }
174+
150175 plugin .getTabList ().reloadUpdate ();
151176 ctx .getSource ().sendRichMessage (systemReloaded );
152177 return Command .SINGLE_SUCCESS ;
153178 })
154179 )
155180 .then (LiteralArgumentBuilder .<CommandSource >literal ("debug" )
156181 .requires (src -> hasPermission (src , "debug" ))
182+ .then (LiteralArgumentBuilder .<CommandSource >literal ("tabgroups" )
183+ .then (RequiredArgumentBuilder .<CommandSource , String >argument ("group" , StringArgumentType .string ())
184+ .suggests ((ctx , builder1 ) -> {
185+ final String input = builder1 .getRemainingLowerCase ();
186+ plugin .getTabGroupsManager ().getGroups ().stream ()
187+ .map (Group ::name )
188+ .filter (s -> input .isEmpty () || s .toLowerCase ().contains (input ))
189+ .forEach (builder1 ::suggest );
190+ return builder1 .buildFuture ();
191+ })
192+ // players - headers - footers
193+ .then (LiteralArgumentBuilder .<CommandSource >literal ("players" )
194+ .executes (ctx -> {
195+ final String input = ctx .getArgument ("group" , String .class );
196+ final Optional <Group > optionalGroup = plugin .getTabGroupsManager ().getGroup (input );
197+ if (optionalGroup .isEmpty ()) {
198+ ctx .getSource ().sendRichMessage (errorTabNameChangeUntracked );
199+ return Command .SINGLE_SUCCESS ;
200+ }
201+
202+ //send group info: players count(hover with player list sorted by their team name)
203+
204+ final List <TabPlayer > players = optionalGroup .get ().getTabPlayers (plugin )
205+ .stream ()
206+ .sorted (Comparator .comparing (t -> -plugin .getScoreboardManager ().getPosition (t .getTeamName ())))
207+ .toList ();
208+
209+ Component playersCount = MiniMessage .miniMessage ().deserialize ("<yellow>Players:</yellow> <gray>%s" .formatted (players .size ()));
210+ final String join = joinPlayersName (players );
211+ Component playersCountHover = MiniMessage .miniMessage ().deserialize ("<yellow>Players:</yellow> <gray>%s" .formatted (join ));
212+ playersCount = playersCount .hoverEvent (playersCountHover );
213+
214+ ctx .getSource ().sendMessage (playersCount );
215+ return Command .SINGLE_SUCCESS ;
216+ })
217+ )
218+ .then (LiteralArgumentBuilder .<CommandSource >literal ("header" )
219+ .executes (ctx -> {
220+ final String input = ctx .getArgument ("group" , String .class );
221+ final Optional <Group > optionalGroup = plugin .getTabGroupsManager ().getGroup (input );
222+ if (optionalGroup .isEmpty ()) {
223+ ctx .getSource ().sendRichMessage (errorTabNameChangeUntracked );
224+ return Command .SINGLE_SUCCESS ;
225+ }
226+
227+ final Group group = optionalGroup .get ();
228+
229+ for (int i = 0 ; i < group .headers ().size (); i ++) {
230+ final String header = group .getHeader (i );
231+
232+ Component headerComponent = MiniMessage .miniMessage ().deserialize ("<yellow>Header:</yellow> <gray>%s" .formatted ((i + 1 )));
233+ Component headerHover = plugin .getFormatter ().deserialize (header );
234+ headerComponent = headerComponent .hoverEvent (headerHover );
235+ ctx .getSource ().sendMessage (headerComponent );
236+ }
237+
238+ return Command .SINGLE_SUCCESS ;
239+ })
240+ )
241+ .then (LiteralArgumentBuilder .<CommandSource >literal ("footer" )
242+ .executes (ctx -> {
243+ final String input = ctx .getArgument ("group" , String .class );
244+ final Optional <Group > optionalGroup = plugin .getTabGroupsManager ().getGroup (input );
245+ if (optionalGroup .isEmpty ()) {
246+ ctx .getSource ().sendRichMessage (errorTabNameChangeUntracked );
247+ return Command .SINGLE_SUCCESS ;
248+ }
249+
250+ final Group group = optionalGroup .get ();
251+
252+ for (int i = 0 ; i < group .footers ().size (); i ++) {
253+ final String footer = group .getFooter (i );
254+
255+ Component footerComponent = MiniMessage .miniMessage ().deserialize ("<yellow>Footer:</yellow> <gray>%s" .formatted ((i + 1 )));
256+ Component footerHover = plugin .getFormatter ().deserialize (footer );
257+ footerComponent = footerComponent .hoverEvent (footerHover );
258+ ctx .getSource ().sendMessage (footerComponent );
259+ }
260+
261+ return Command .SINGLE_SUCCESS ;
262+ })
263+ )
264+ )
265+ )
157266 .then (LiteralArgumentBuilder .<CommandSource >literal ("tablist" )
158267 .then (RequiredArgumentBuilder .<CommandSource , String >argument ("player" , StringArgumentType .string ())
159268 .suggests ((ctx , builder1 ) -> {
160- final String input = ctx .getInput ();
161- if (input .isEmpty ()) {
162- return builder1 .buildFuture ();
163- }
269+ final String input = builder1 .getRemainingLowerCase ();
164270 plugin .getServer ().getAllPlayers ().stream ()
165271 .map (Player ::getUsername )
166- .filter (s -> s .toLowerCase ().startsWith (input . toLowerCase () ))
272+ .filter (s -> input . isEmpty () || s .toLowerCase ().contains (input ))
167273 .forEach (builder1 ::suggest );
168274 return builder1 .buildFuture ();
169275 })
@@ -183,9 +289,14 @@ public BrigadierCommand command() {
183289 .map (c -> PlainTextComponentSerializer .plainText ().serialize (c ))
184290 .orElse ("empty" );
185291
186- ctx .getSource ().sendMessage (Component .text (
187- "Name: %s, UUID: %s, Unformatted display name: %s"
188- .formatted (name , uuid , unformattedDisplayName )));
292+ final Component hover = MiniMessage .miniMessage ().deserialize ("<yellow>UUID:</yellow> <gray>%s<gray>" .formatted (uuid ))
293+ .appendNewline ()
294+ .append (MiniMessage .miniMessage ().deserialize ("<yellow>Format</yellow>: " ).append (entry .getDisplayNameComponent ().orElse (Component .empty ())));
295+
296+ final Component component = MiniMessage .miniMessage ().deserialize ("<gray>%s<gray> <yellow>-</yellow> <gray>%s"
297+ .formatted (name , unformattedDisplayName ))
298+ .hoverEvent (hover );
299+ ctx .getSource ().sendMessage (component );
189300 });
190301
191302 return Command .SINGLE_SUCCESS ;
@@ -228,6 +339,22 @@ public BrigadierCommand command() {
228339 return new BrigadierCommand (builder );
229340 }
230341
342+ @ NotNull
343+ private static String joinPlayersName (@ NotNull List <TabPlayer > players ) {
344+ final StringBuilder join = new StringBuilder ();
345+ for (int i = 0 ; i < players .size (); i ++) {
346+ join .append ("<yellow>%s</yellow>" .formatted (players .get (i ).getPlayer ().getUsername ()));
347+ if (i != players .size () - 1 ) {
348+ join .append ("<gray>,</gray> " );
349+ }
350+ if (i % 4 == 0 ) {
351+ join .append ("<br>" );
352+ }
353+ }
354+
355+ return join .toString ();
356+ }
357+
231358 private boolean hasPermission (@ NotNull CommandSource source , @ NotNull String command ) {
232359 return source .hasPermission (String .join ("." , "velocitab" , "command" , command ));
233360 }
0 commit comments