Skip to content

Commit 9cf88cc

Browse files
Merge pull request #76 from Dans-Plugins/copilot/show-player-activity-ranking
Show player activity ranking in info command output and unify command formatting
2 parents 343781f + cafbf4b commit 9cf88cc

File tree

11 files changed

+564
-52
lines changed

11 files changed

+564
-52
lines changed

COMMAND_OUTPUT_STYLE.md

Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
# Command Output Formatting Style Guide
2+
3+
This document describes the command output formatting conventions used in this project. Follow this guide to maintain consistency across all commands, or to reproduce this style in other Bukkit/Spigot plugin projects.
4+
5+
## Overview
6+
7+
All command output uses Unicode box-drawing characters for structure, Minecraft `ChatColor` codes for color, and Unicode block characters for visual progress bars.
8+
9+
```
10+
┌─ Title ─ Subtitle
11+
│ Label: Value
12+
│ Label: Value [██████░░░░]
13+
└─────────────────────────
14+
```
15+
16+
## Structure
17+
18+
### Layout
19+
20+
Every command output block follows this structure:
21+
22+
1. **Empty line** — send an empty `""` message for visual separation from prior chat
23+
2. **Header** — top border with title using `┌─`
24+
3. **Body lines** — content rows prefixed with ``
25+
4. **Footer** — bottom border using `└─────────────────────────`
26+
27+
### Box-Drawing Characters
28+
29+
| Character | Unicode | Usage |
30+
|-----------|---------|-------|
31+
| `` | U+250C | Top-left corner (header start) |
32+
| `` | U+2502 | Left border (body lines) |
33+
| `` | U+2514 | Bottom-left corner (footer start) |
34+
| `` | U+2500 | Horizontal line (header/footer fill) |
35+
36+
## Color Scheme
37+
38+
All colors use Bukkit's `org.bukkit.ChatColor` enum.
39+
40+
### Borders and Structure
41+
42+
| Element | Color | ChatColor |
43+
|---------|-------|-----------|
44+
| Box-drawing borders (`┌│└─`) | Gold | `ChatColor.GOLD` |
45+
46+
### Header
47+
48+
| Element | Color | ChatColor |
49+
|---------|-------|-----------|
50+
| Plugin/player name | Yellow + Bold | `ChatColor.YELLOW` + `ChatColor.BOLD` |
51+
| Subtitle text | Gold | `ChatColor.GOLD` |
52+
53+
**Important:** After using `ChatColor.BOLD`, always insert `ChatColor.RESET` before continuing with other colors to prevent bold from bleeding into subsequent text.
54+
55+
### Body Content
56+
57+
| Element | Color | ChatColor |
58+
|---------|-------|-----------|
59+
| Labels (e.g., "Logins:", "Status:") | Gray | `ChatColor.GRAY` |
60+
| General data values | White | `ChatColor.WHITE` |
61+
| Positive numeric values (hours, counts) | Green | `ChatColor.GREEN` |
62+
| Averages, rankings, commands | Aqua | `ChatColor.AQUA` |
63+
| Negative states (Offline, Ended) | Red | `ChatColor.RED` |
64+
| Positive states (Online, Active) | Green | `ChatColor.GREEN` |
65+
| Visual bars | Dark Gray | `ChatColor.DARK_GRAY` |
66+
67+
### Error Messages
68+
69+
| Element | Color | ChatColor |
70+
|---------|-------|-----------|
71+
| Error messages | Red | `ChatColor.RED` |
72+
73+
## Visual Progress Bars
74+
75+
Use Unicode block characters to create visual indicators for metrics:
76+
77+
| Character | Unicode | Usage |
78+
|-----------|---------|-------|
79+
| `` | U+2588 | Filled portion |
80+
| `` | U+2591 | Empty portion |
81+
82+
### Bar Format
83+
84+
```
85+
[██████░░░░]
86+
```
87+
88+
- Default bar length: **10 characters**
89+
- Enclosed in square brackets `[` and `]`
90+
- Colored with `ChatColor.DARK_GRAY`
91+
92+
### Scaling
93+
94+
Calculate the filled portion based on the value relative to its maximum:
95+
96+
```java
97+
private String createBar(double value, double max) {
98+
int barLength = 10;
99+
int filled = (int) Math.min(barLength, (value / max) * barLength);
100+
StringBuilder bar = new StringBuilder("[");
101+
for (int i = 0; i < barLength; i++) {
102+
bar.append(i < filled ? "\u2588" : "\u2591");
103+
}
104+
bar.append("]");
105+
return bar.toString();
106+
}
107+
```
108+
109+
For ranking bars (where rank 1 = best), invert the scale:
110+
111+
```java
112+
private String createRankBar(int rank, int totalPlayers) {
113+
int barLength = 10;
114+
int filled = (int) Math.round(((double)(totalPlayers - rank + 1) / totalPlayers) * barLength);
115+
filled = Math.max(0, Math.min(barLength, filled));
116+
StringBuilder bar = new StringBuilder("[");
117+
for (int i = 0; i < barLength; i++) {
118+
bar.append(i < filled ? "\u2588" : "\u2591");
119+
}
120+
bar.append("]");
121+
return bar.toString();
122+
}
123+
```
124+
125+
## Code Patterns
126+
127+
### Header Pattern
128+
129+
```java
130+
sender.sendMessage("");
131+
sender.sendMessage(ChatColor.GOLD + "┌─ " + ChatColor.YELLOW + ChatColor.BOLD + "Title" +
132+
ChatColor.RESET + ChatColor.GOLD + " ─ Subtitle");
133+
```
134+
135+
### Label-Value Line Pattern
136+
137+
```java
138+
// Simple value
139+
sender.sendMessage(ChatColor.GOLD + "" + ChatColor.GRAY + "Label: " +
140+
ChatColor.WHITE + value);
141+
142+
// Numeric value (positive)
143+
sender.sendMessage(ChatColor.GOLD + "" + ChatColor.GRAY + "Hours: " +
144+
ChatColor.GREEN + String.format("%.2f", hours) + "h");
145+
146+
// Value with visual bar
147+
sender.sendMessage(ChatColor.GOLD + "" + ChatColor.GRAY + "Progress: " +
148+
ChatColor.GREEN + String.format("%.2f", value) + "h " +
149+
ChatColor.DARK_GRAY + createBar(value, maxValue));
150+
```
151+
152+
### Numbered List Entry Pattern
153+
154+
```java
155+
sender.sendMessage(ChatColor.GOLD + "" + ChatColor.AQUA + "#" + count + " " +
156+
ChatColor.WHITE + itemName + " " +
157+
ChatColor.GREEN + String.format("%.2f", value) + "h " +
158+
ChatColor.DARK_GRAY + createBar(value, maxValue));
159+
```
160+
161+
### Command List Entry Pattern
162+
163+
```java
164+
sender.sendMessage(ChatColor.GOLD + "" + ChatColor.AQUA + "/command args " +
165+
ChatColor.GRAY + "- Description text.");
166+
```
167+
168+
### Status Indicator Pattern
169+
170+
```java
171+
// Online/Active status
172+
String status = isActive ? ChatColor.GREEN + "Active" : ChatColor.RED + "Ended";
173+
```
174+
175+
### Footer Pattern
176+
177+
```java
178+
sender.sendMessage(ChatColor.GOLD + "└─────────────────────────");
179+
```
180+
181+
The footer uses 25 horizontal line characters (``) after the corner character.
182+
183+
## Command Output Examples
184+
185+
### Info/Detail View
186+
187+
```
188+
┌─ PlayerName ─ Activity Info
189+
│ Logins: 42
190+
│ Play Time: 156.30h
191+
│ Ranking: 3/15 [███████░░░]
192+
│ Status: Online
193+
│ Session: 1.25h since login
194+
│ First Login: 2025-01-15T10:30:00
195+
└─────────────────────────
196+
```
197+
198+
### Statistics View
199+
200+
```
201+
┌─ Activity Tracker ─ Statistics
202+
│ Unique Players: 42
203+
│ Total Logins: 156
204+
└─────────────────────────
205+
```
206+
207+
### Leaderboard View
208+
209+
```
210+
┌─ Activity Tracker ─ Top Players
211+
│ #1 PlayerA 156.30h [██████████]
212+
│ #2 PlayerB 98.50h [██████░░░░]
213+
│ #3 PlayerC 45.20h [██░░░░░░░░]
214+
└─────────────────────────
215+
```
216+
217+
### Help/Command List View
218+
219+
```
220+
┌─ Activity Tracker ─ Commands
221+
│ /at help - View a list of helpful commands.
222+
│ /at info - View your activity record.
223+
│ /at top - View the most active players.
224+
└─────────────────────────
225+
```
226+
227+
### Config View
228+
229+
```
230+
┌─ Activity Tracker ─ Config
231+
│ version: 1.3.0
232+
│ debugMode: false
233+
│ restApiEnabled: false
234+
│ restApiPort: 8080
235+
└─────────────────────────
236+
```
237+
238+
### Session List View
239+
240+
```
241+
┌─ Activity Tracker ─ Recent Sessions (5)
242+
│ #1 PlayerA - 2025-03-07 10:30:00 (Active)
243+
│ #2 PlayerB - 2025-03-07 09:15:00 (Ended - 45.0 min)
244+
└─────────────────────────
245+
```
246+
247+
## Label Alignment
248+
249+
When multiple labels appear in a block, right-pad shorter labels with spaces to align values:
250+
251+
```
252+
│ Logins: 42
253+
│ Play Time: 156.30h
254+
│ Ranking: 3/15
255+
│ Status: Online
256+
```
257+
258+
For config options, use consistent padding:
259+
260+
```
261+
│ version: 1.3.0
262+
│ debugMode: false
263+
│ restApiEnabled: false
264+
│ restApiPort: 8080
265+
```
266+
267+
## Adapting for Other Projects
268+
269+
To use this style in another Bukkit/Spigot project:
270+
271+
1. Copy the color scheme table above as your reference
272+
2. Use the code patterns section as templates for building output
273+
3. Include the `createBar()` helper method in any command that displays metrics
274+
4. Keep the footer length consistent at 25 `` characters
275+
5. Always prefix output with an empty line for visual separation from chat
276+
6. Always use `ChatColor.RESET` after `ChatColor.BOLD` to prevent bleed

src/main/java/dansplugins/activitytracker/commands/DefaultCommand.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,14 @@ public DefaultCommand(ActivityTracker activityTracker) {
2222

2323
@Override
2424
public boolean execute(CommandSender commandSender) {
25-
commandSender.sendMessage(ChatColor.AQUA + "Activity Tracker " + activityTracker.getVersion());
26-
commandSender.sendMessage(ChatColor.AQUA + "Developed by: Daniel McCoy Stephenson");
27-
commandSender.sendMessage(ChatColor.AQUA + "Wiki: https://github.com/Dans-Plugins/Activity-Tracker/wiki");
25+
commandSender.sendMessage("");
26+
commandSender.sendMessage(ChatColor.GOLD + "┌─ " + ChatColor.YELLOW + "" + ChatColor.BOLD + "Activity Tracker" +
27+
ChatColor.RESET + ChatColor.GOLD + " ─ v" + activityTracker.getVersion());
28+
commandSender.sendMessage(ChatColor.GOLD + "│ " + ChatColor.GRAY + "Author: " +
29+
ChatColor.WHITE + "Daniel McCoy Stephenson");
30+
commandSender.sendMessage(ChatColor.GOLD + "│ " + ChatColor.GRAY + "Wiki: " +
31+
ChatColor.AQUA + "github.com/Dans-Plugins/Activity-Tracker/wiki");
32+
commandSender.sendMessage(ChatColor.GOLD + "└─────────────────────────");
2833
return true;
2934
}
3035

src/main/java/dansplugins/activitytracker/commands/HelpCommand.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,18 @@ public HelpCommand() {
1919

2020
@Override
2121
public boolean execute(CommandSender sender) {
22-
sender.sendMessage(ChatColor.AQUA + "/at help - View a list of helpful commands.");
23-
sender.sendMessage(ChatColor.AQUA + "/at info - View your activity record.");
24-
sender.sendMessage(ChatColor.AQUA + "/at info (playerName) - View a player's activity record.");
25-
sender.sendMessage(ChatColor.AQUA + "/at list - View the 10 most recent sessions (admin only).");
26-
sender.sendMessage(ChatColor.AQUA + "/at top - View a list of the most active players on the server.");
27-
sender.sendMessage(ChatColor.AQUA + "/at stats - View activity stats for the server.");
28-
sender.sendMessage(ChatColor.AQUA + "/at average [playerName] [days] - View average daily activity (default: 7 days).");
29-
sender.sendMessage(ChatColor.AQUA + "/at config - Show or set config options.");
22+
sender.sendMessage("");
23+
sender.sendMessage(ChatColor.GOLD + "┌─ " + ChatColor.YELLOW + "" + ChatColor.BOLD + "Activity Tracker" +
24+
ChatColor.RESET + ChatColor.GOLD + " ─ Commands");
25+
sender.sendMessage(ChatColor.GOLD + "│ " + ChatColor.AQUA + "/at help " + ChatColor.GRAY + "- View a list of helpful commands.");
26+
sender.sendMessage(ChatColor.GOLD + "│ " + ChatColor.AQUA + "/at info " + ChatColor.GRAY + "- View your activity record.");
27+
sender.sendMessage(ChatColor.GOLD + "│ " + ChatColor.AQUA + "/at info (playerName) " + ChatColor.GRAY + "- View a player's activity record.");
28+
sender.sendMessage(ChatColor.GOLD + "│ " + ChatColor.AQUA + "/at list " + ChatColor.GRAY + "- View the 10 most recent sessions (admin only).");
29+
sender.sendMessage(ChatColor.GOLD + "│ " + ChatColor.AQUA + "/at top " + ChatColor.GRAY + "- View the most active players.");
30+
sender.sendMessage(ChatColor.GOLD + "│ " + ChatColor.AQUA + "/at stats " + ChatColor.GRAY + "- View activity stats for the server.");
31+
sender.sendMessage(ChatColor.GOLD + "│ " + ChatColor.AQUA + "/at average [player] [days] " + ChatColor.GRAY + "- Avg daily activity (default: 7 days).");
32+
sender.sendMessage(ChatColor.GOLD + "│ " + ChatColor.AQUA + "/at config " + ChatColor.GRAY + "- Show or set config options.");
33+
sender.sendMessage(ChatColor.GOLD + "└─────────────────────────");
3034
return true;
3135
}
3236

src/main/java/dansplugins/activitytracker/commands/InfoCommand.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ public boolean execute(CommandSender sender) {
3737
return false;
3838
}
3939

40-
record.sendInfoToSender(sender);
40+
int rank = persistentData.getPlayerRank(player.getUniqueId());
41+
int totalPlayers = persistentData.getActivityRecords().size();
42+
record.sendInfoToSender(sender, rank, totalPlayers);
4143
return true;
4244
}
4345

@@ -57,7 +59,9 @@ public boolean execute(CommandSender sender, String[] args) {
5759
return false;
5860
}
5961

60-
record.sendInfoToSender(sender);
62+
int rank = persistentData.getPlayerRank(playerUUID);
63+
int totalPlayers = persistentData.getActivityRecords().size();
64+
record.sendInfoToSender(sender, rank, totalPlayers);
6165
return true;
6266
}
6367
}

src/main/java/dansplugins/activitytracker/commands/ListCommand.java

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,18 @@ public boolean execute(CommandSender sender) {
4444
.limit(10)
4545
.collect(Collectors.toList());
4646

47+
int displayedCount = sortedSessions.size();
48+
49+
sender.sendMessage("");
50+
sender.sendMessage(ChatColor.GOLD + "┌─ " + ChatColor.YELLOW + "" + ChatColor.BOLD + "Activity Tracker" +
51+
ChatColor.RESET + ChatColor.GOLD + " ─ Recent Sessions (" + displayedCount + ")");
52+
4753
if (sortedSessions.isEmpty()) {
48-
sender.sendMessage(ChatColor.RED + "No sessions found.");
54+
sender.sendMessage(ChatColor.GOLD + "│ " + ChatColor.GRAY + "No sessions found.");
55+
sender.sendMessage(ChatColor.GOLD + "└─────────────────────────");
4956
return true;
5057
}
5158

52-
int displayedCount = sortedSessions.size();
53-
sender.sendMessage(ChatColor.AQUA + " === Most Recent Sessions (" + displayedCount + "/10) ===");
54-
5559
UUIDChecker uuidChecker = new UUIDChecker();
5660
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
5761

@@ -63,20 +67,23 @@ public boolean execute(CommandSender sender) {
6367
}
6468

6569
String loginTime = session.getLoginDate().format(formatter);
66-
String status = session.isActive() ? ChatColor.GREEN + "Active" : ChatColor.RED + "Ended";
70+
String status = session.isActive()
71+
? ChatColor.GREEN + "Active"
72+
: ChatColor.RED + "Ended";
6773

68-
String sessionInfo;
6974
if (session.isActive()) {
70-
sessionInfo = String.format("%d. %s - Login: %s (%s%s)",
71-
count, playerName, loginTime, status, ChatColor.AQUA);
75+
sender.sendMessage(ChatColor.GOLD + "│ " + ChatColor.AQUA + "#" + count + " " +
76+
ChatColor.WHITE + playerName + ChatColor.GRAY + " - " +
77+
ChatColor.WHITE + loginTime + " (" + status + ChatColor.GRAY + ")");
7278
} else {
73-
sessionInfo = String.format("%d. %s - Login: %s (%s%s - Duration: %.1f min)",
74-
count, playerName, loginTime, status, ChatColor.AQUA, session.getMinutesSpent());
79+
sender.sendMessage(ChatColor.GOLD + "│ " + ChatColor.AQUA + "#" + count + " " +
80+
ChatColor.WHITE + playerName + ChatColor.GRAY + " - " +
81+
ChatColor.WHITE + loginTime + " (" + status + ChatColor.GRAY +
82+
" - " + ChatColor.WHITE + String.format("%.1f", session.getMinutesSpent()) + " min" + ChatColor.GRAY + ")");
7583
}
76-
77-
sender.sendMessage(ChatColor.AQUA + sessionInfo);
7884
count++;
7985
}
86+
sender.sendMessage(ChatColor.GOLD + "└─────────────────────────");
8087

8188
return true;
8289
}

0 commit comments

Comments
 (0)