Show player activity ranking in info command output and unify command formatting#76
Conversation
Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds an activity ranking line to /at info output so players can see their position among all tracked players by total hours played.
Changes:
- Added
PersistentData.getPlayerRank(UUID)to compute a 1-based rank by total hours played. - Updated
/at infoflow to compute(rank, totalPlayers)and displayActivity Ranking: X/Y. - Added unit tests covering rank behavior (single player, ordering, missing player, null UUID).
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/main/java/dansplugins/activitytracker/data/PersistentData.java |
Adds getPlayerRank(UUID) based on sorting records by total hours. |
src/main/java/dansplugins/activitytracker/objects/ActivityRecord.java |
Extends sendInfoToSender to accept (rank, totalPlayers) and prints the ranking line. |
src/main/java/dansplugins/activitytracker/commands/InfoCommand.java |
Computes rank + total player count and passes them into sendInfoToSender. |
src/test/java/dansplugins/activitytracker/data/PersistentDataTest.java |
Adds tests validating rank calculation and edge cases. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Collections.sort(sortedRecords, new Comparator<ActivityRecord>() { | ||
| @Override | ||
| public int compare(ActivityRecord r1, ActivityRecord r2) { | ||
| return Double.compare(r2.getTotalHoursSpent(), r1.getTotalHoursSpent()); |
There was a problem hiding this comment.
getPlayerRank sorts by total hours only; when multiple players have identical getTotalHoursSpent() values, the returned rank depends on the existing insertion/load order (which can change across restarts). Consider adding a deterministic tie-breaker (e.g., secondary compare on UUID) or explicitly defining tie behavior (shared rank vs. sequential).
| return Double.compare(r2.getTotalHoursSpent(), r1.getTotalHoursSpent()); | |
| int hoursComparison = Double.compare(r2.getTotalHoursSpent(), r1.getTotalHoursSpent()); | |
| if (hoursComparison != 0) { | |
| return hoursComparison; | |
| } | |
| // Deterministic tie-breaker: order by UUID when total hours are equal | |
| return r1.getPlayerUUID().compareTo(r2.getPlayerUUID()); |
| ArrayList<ActivityRecord> sortedRecords = new ArrayList<>(activityRecords); | ||
| Collections.sort(sortedRecords, new Comparator<ActivityRecord>() { | ||
| @Override | ||
| public int compare(ActivityRecord r1, ActivityRecord r2) { | ||
| return Double.compare(r2.getTotalHoursSpent(), r1.getTotalHoursSpent()); | ||
| } | ||
| }); | ||
|
|
||
| for (int i = 0; i < sortedRecords.size(); i++) { | ||
| if (sortedRecords.get(i).getPlayerUUID().equals(playerUUID)) { | ||
| return i + 1; | ||
| } | ||
| } | ||
| return -1; |
There was a problem hiding this comment.
getPlayerRank copies and sorts the entire activityRecords list on each call (O(n log n)). Since /at info may be run often on larger servers, consider computing rank in a single pass (count how many records have strictly greater hours) to avoid allocating/copying/sorting.
| ArrayList<ActivityRecord> sortedRecords = new ArrayList<>(activityRecords); | |
| Collections.sort(sortedRecords, new Comparator<ActivityRecord>() { | |
| @Override | |
| public int compare(ActivityRecord r1, ActivityRecord r2) { | |
| return Double.compare(r2.getTotalHoursSpent(), r1.getTotalHoursSpent()); | |
| } | |
| }); | |
| for (int i = 0; i < sortedRecords.size(); i++) { | |
| if (sortedRecords.get(i).getPlayerUUID().equals(playerUUID)) { | |
| return i + 1; | |
| } | |
| } | |
| return -1; | |
| // First, find the target player's total hours | |
| double targetTotalHours = -1.0; | |
| for (ActivityRecord record : activityRecords) { | |
| if (record.getPlayerUUID().equals(playerUUID)) { | |
| targetTotalHours = record.getTotalHoursSpent(); | |
| break; | |
| } | |
| } | |
| // If the player does not have an activity record, return -1 | |
| if (targetTotalHours < 0.0) { | |
| return -1; | |
| } | |
| // Count how many players have strictly greater total hours | |
| int countGreater = 0; | |
| for (ActivityRecord record : activityRecords) { | |
| if (record.getTotalHoursSpent() > targetTotalHours) { | |
| countGreater++; | |
| } | |
| } | |
| // Rank is 1 plus the number of players with more hours | |
| return countGreater + 1; |
|
@copilot address comments |
Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Addressed both review comments in
|
|
@copilot That works! However, the output is ugly. Update formatting for the |
…x-drawing chars, colors, and rank bar Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Updated in
Example output: Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot Go ahead and update the formatting for the rest of the commands to be like the output of |
…ox-drawing borders and colors Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
…y note, average params Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Updated all remaining commands in
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot Document command output formatting style so that it can be reproduced in other projects |
Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Added
|
Adds activity ranking (e.g.,
Ranking: 3/15) to/at infooutput, showing where a player stands relative to all tracked players by total hours played. Updates formatting across all commands to use a consistent style with GOLD box-drawing borders, colored labels, and visual indicators. Adds a style guide documenting the formatting conventions for reuse in other projects.Changes
PersistentData: AddedgetPlayerRank(UUID)— uses an O(n) single-pass algorithm that counts players with strictly greater hours, so tied players share the same rankActivityRecord.sendInfoToSender(): Now acceptsrankandtotalPlayersparams; displays ranking line with a visual bar indicator. Formatting updated to use GOLD box-drawing borders (┌│└), YELLOW+BOLD player names, GRAY labels, and colored values (GREEN for play time, AQUA for ranking, GREEN/RED for online/offline status)InfoCommand: Computes rank and total count before delegating tosendInfoToSenderHelpCommand: Updated to use GOLD box-drawing borders with AQUA commands and GRAY descriptionsDefaultCommand: Updated to use GOLD box-drawing borders with version in header, GRAY labels, and colored valuesStatsCommand: Updated to use GOLD box-drawing borders with GRAY labels and GREEN valuesTopCommand: Updated to use GOLD box-drawing borders with numbered entries and visual progress bars scaled to the top playerListCommand: Updated to use GOLD box-drawing borders with numbered session entries and GREEN/RED Active/Ended status indicatorsConfigService.sendConfigList(): Updated to use GOLD box-drawing borders with each config option on its own lineCOMMAND_OUTPUT_STYLE.md: Added style guide documenting the color scheme, box-drawing structure, visual progress bars, code patterns, and examples for reproducing the formatting in other projectsPersistentDataTest: 5 new tests covering single player, multi-player ordering, tied ranks, missing player, and null UUIDExample output
/at info/at top/at statsOriginal prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.