Skip to content

Commit 23683dd

Browse files
authored
feat(gui): adopt Marketblock GUI styling (#12)
Gray pane filler in empty slots, hex palette and label/value lore conventions lifted from the Marketblock plugin so both GUIs read as one family. Filler name and every string stay in messages.yml.
1 parent 81c27fb commit 23683dd

4 files changed

Lines changed: 172 additions & 21 deletions

File tree

‎src/main/java/tfmc/justin/activity/gui/ActivityGui.java‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,25 @@ public Inventory build(Player player) {
8585

8686
inventory.setItem(REWARD_SLOT, rewardItem(config, messages, data));
8787

88+
fillEmptySlots(inventory, messages);
89+
8890
return inventory;
8991
}
9092

93+
// ====================================
94+
// Marketblock's filler: every slot the loops above left null gets a gray
95+
// pane instead, so the window reads as intentionally designed rather than
96+
// half-empty. Clicks on it are already cancelled by onClick.
97+
// ====================================
98+
private void fillEmptySlots(Inventory inventory, Messages messages) {
99+
ItemStack filler = item(Material.GRAY_STAINED_GLASS_PANE, messages.get("gui.filler-name"), List.of());
100+
for (int slot = 0; slot < SIZE; slot++) {
101+
if (inventory.getItem(slot) == null) {
102+
inventory.setItem(slot, filler);
103+
}
104+
}
105+
}
106+
91107
private ItemStack barItem(ActivityConfiguration config, Messages messages, PlayerData data) {
92108
String bar = Bar.render(data.points(), config.barMax(), config.barLength(), config.barFilledChar(),
93109
config.barEmptyChar(), config.barFilledColor(), config.barEmptyColor());
@@ -117,6 +133,7 @@ private ItemStack rewardItem(ActivityConfiguration config, Messages messages, Pl
117133
lore.addAll(Messages.colorize(config.rewardDisplay()));
118134
lore.add(messages.get("gui.reward-lore-claimed", "%claimed%", data.claimedPoints() / config.rewardEvery(),
119135
"%total%", config.barMax() / config.rewardEvery()));
136+
lore.add(" ");
120137
lore.add(due > 0
121138
? messages.get("gui.reward-click", "%count%", due)
122139
: messages.get("gui.reward-nothing"));

‎src/main/resources/config.yml‎

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,51 +38,51 @@ reset:
3838
# profession XP is unbounded, unlike the one-per-action activities.
3939
activities:
4040
vote:
41-
display: "&aVoting"
41+
display: "#e6ca40&lVoting"
4242
material: PAPER
4343
every: 1
4444
points: 1
4545
daily-cap: 5
4646
quest:
47-
display: "&bDaily Quests"
47+
display: "#e6ca40&lDaily Quests"
4848
material: BOOK
4949
every: 1
5050
points: 1
5151
daily-cap: 5
5252
geiger:
53-
display: "&eRadioactive Sources"
53+
display: "#e6ca40&lRadioactive Sources"
5454
material: SPYGLASS
5555
every: 3
5656
points: 1
5757
daily-cap: 1
5858
instrument:
59-
display: "&dMusical Instruments"
59+
display: "#e6ca40&lMusical Instruments"
6060
material: NOTE_BLOCK
6161
every: 20
6262
points: 1
6363
daily-cap: 1
6464
playtime:
65-
display: "&6Time Played"
65+
display: "#e6ca40&lTime Played"
6666
material: CLOCK
6767
every: 60 # 60 counted minutes => 1 point
6868
points: 1
6969
daily-cap: 3
7070
craft_diamond_block:
71-
display: "&bCraft Diamond Blocks"
71+
display: "#e6ca40&lCraft Diamond Blocks"
7272
material: DIAMOND_BLOCK
7373
every: 3
7474
points: 1
7575
daily-cap: 1
7676
craft: DIAMOND_BLOCK
7777
craft_golden_carrot:
78-
display: "&6Craft Golden Carrots"
78+
display: "#e6ca40&lCraft Golden Carrots"
7979
material: GOLDEN_CARROT
8080
every: 16
8181
points: 1
8282
daily-cap: 1
8383
craft: GOLDEN_CARROT
8484
craft_anvil:
85-
display: "&7Craft Anvils"
85+
display: "#e6ca40&lCraft Anvils"
8686
material: ANVIL
8787
every: 1
8888
points: 1
@@ -91,21 +91,21 @@ activities:
9191
# MMOCore professions - uncomment to enable. They need MMOCore installed;
9292
# without it they show in /activity but can never be filled.
9393
#profession_crafter:
94-
# display: "&6Crafter XP"
94+
# display: "#e6ca40&lCrafter XP"
9595
# material: CRAFTING_TABLE
9696
# every: 500 # 500 profession XP → 1 point
9797
# points: 1
9898
# daily-cap: 2
9999
# profession: crafter
100100
#profession_forager:
101-
# display: "&2Forager XP"
101+
# display: "#e6ca40&lForager XP"
102102
# material: WHEAT
103103
# every: 500
104104
# points: 1
105105
# daily-cap: 2
106106
# profession: forager
107107
#profession_herborist:
108-
# display: "&aHerborist XP"
108+
# display: "#e6ca40&lHerborist XP"
109109
# material: FERN
110110
# every: 500
111111
# points: 1
@@ -127,7 +127,7 @@ rewards:
127127
commands:
128128
- "give %player% diamond 3"
129129
display: # shown in GUI reward item
130-
- "&f3x Diamond"
130+
- "#50d990x3 #b8906eDiamond"
131131

132132
gui:
133133
title: "&8Weekly Activity"
@@ -139,7 +139,7 @@ bar:
139139
length: 20 # glyphs
140140
filled-char: "░"
141141
empty-char: "░"
142-
filled-color: "&a"
142+
filled-color: "#50d990"
143143
empty-color: "&7"
144144

145145
sounds: # Bukkit Sound names, "" disables

‎src/main/resources/messages.yml‎

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@ reward-nothing: "&7Nothing to claim yet."
55
reward-failed: "&cYour rewards could not be handed over - tell an admin."
66
reward-unconfigured: "&cRewards are not configured - tell an admin."
77
gui:
8-
bar-name: "&fWeekly Activity: &a%points%&7/%max%"
9-
reward-name: "&6Rewards"
10-
reward-lore-header: "&7Every %every% points:"
11-
reward-lore-claimed: "&7Claimed: &f%claimed%&7/&f%total%"
12-
reward-click: "&a▶ Click to claim %count% reward(s)"
8+
bar-name: "#e6ca40&lWeekly Activity&e: #50d990%points%&7/&f%max%"
9+
reward-name: "#e6ca40&lRewards"
10+
reward-lore-header: "#af97bdEvery&e: #50d990%every% #b8906epoints"
11+
reward-lore-claimed: "#d97b66Claimed&e: &6%claimed%&7/&f%total%"
12+
reward-click: "#6b9c68[#fafa16Click to claim %count% reward(s)#6b9c68]"
1313
reward-nothing: "&8Nothing to claim yet"
14-
activity-lore-points: "&7Worth: &a%points% &7per &f%every%"
15-
activity-lore-today: "&7Today: &f%today%"
16-
activity-lore-today-capped: "&7Today: &f%today%&7/&f%cap%"
14+
activity-lore-points: "#af97bdWorth&e: #50d990%points% #b8906eper %every%"
15+
activity-lore-today: "#d97b66Today&e: &6%today%"
16+
activity-lore-today-capped: "#d97b66Today&e: &6%today%&7/&f%cap%"
17+
filler-name: "&8 "
1718
placeholder: { done: "&a✔", not-done: "&c✘" }
1819
admin:
1920
usage: "&eUsage: /activity <reload|reset <player>|add <player> <activity> <count>>"
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package tfmc.justin.activity.config;
2+
3+
import org.bukkit.configuration.ConfigurationSection;
4+
import org.bukkit.configuration.file.YamlConfiguration;
5+
import org.junit.jupiter.api.Test;
6+
import tfmc.justin.activity.utils.Utils;
7+
8+
import java.io.File;
9+
import java.util.List;
10+
import java.util.Map;
11+
import java.util.regex.Matcher;
12+
import java.util.regex.Pattern;
13+
14+
import static org.junit.jupiter.api.Assertions.assertEquals;
15+
import static org.junit.jupiter.api.Assertions.assertFalse;
16+
import static org.junit.jupiter.api.Assertions.assertTrue;
17+
18+
// ====================================
19+
// The shipped default messages.yml/config.yml now mix inline #rrggbb hex
20+
// with legacy &-codes (see the diff that introduced fillEmptySlots and the
21+
// hex accents). YamlConfiguration.loadConfiguration works headless (pure
22+
// SnakeYAML under the hood, no live server needed) - these tests just load
23+
// the real resources exactly as the plugin ships them and check the hex
24+
// strings survived as values, not as swallowed YAML comments, and that every
25+
// placeholder callers substitute into is still present.
26+
// ====================================
27+
class DefaultResourcesTest {
28+
29+
private static YamlConfiguration load(String resource) {
30+
File file = new File("src/main/resources/" + resource);
31+
assertTrue(file.exists(), resource + " should exist");
32+
return YamlConfiguration.loadConfiguration(file);
33+
}
34+
35+
@Test
36+
void everyGuiMessageIsNonEmpty() {
37+
YamlConfiguration messages = load("messages.yml");
38+
ConfigurationSection gui = messages.getConfigurationSection("gui");
39+
40+
assertTrue(gui != null && !gui.getKeys(false).isEmpty());
41+
for (String key : gui.getKeys(false)) {
42+
String value = gui.getString(key);
43+
assertFalse(value == null || value.isBlank(), "gui." + key + " should not be blank");
44+
}
45+
}
46+
47+
@Test
48+
void guiMessagesKeepTheirPlaceholders() {
49+
YamlConfiguration messages = load("messages.yml");
50+
51+
assertTrue(messages.getString("gui.bar-name").contains("%points%"));
52+
assertTrue(messages.getString("gui.bar-name").contains("%max%"));
53+
assertTrue(messages.getString("gui.reward-click").contains("%count%"));
54+
assertTrue(messages.getString("gui.activity-lore-points").contains("%points%"));
55+
assertTrue(messages.getString("gui.activity-lore-points").contains("%every%"));
56+
assertTrue(messages.getString("gui.activity-lore-today").contains("%today%"));
57+
assertTrue(messages.getString("gui.activity-lore-today-capped").contains("%today%"));
58+
assertTrue(messages.getString("gui.activity-lore-today-capped").contains("%cap%"));
59+
assertTrue(messages.getString("gui.reward-lore-claimed").contains("%claimed%"));
60+
assertTrue(messages.getString("gui.reward-lore-claimed").contains("%total%"));
61+
}
62+
63+
private static final Pattern HEX_MARKER = Pattern.compile("#[0-9a-fA-F]{6}");
64+
65+
private static void assertEveryHexMarkerIsValid(String value, String where) {
66+
int index = 0;
67+
while ((index = value.indexOf('#', index)) != -1) {
68+
Matcher m = HEX_MARKER.matcher(value);
69+
assertTrue(m.find(index) && m.start() == index,
70+
where + ": '#' at index " + index + " is not followed by exactly 6 hex digits: " + value);
71+
index++;
72+
}
73+
}
74+
75+
@Test
76+
void everyHexMarkerInGuiAndConfigIsSixDigits() {
77+
YamlConfiguration messages = load("messages.yml");
78+
ConfigurationSection gui = messages.getConfigurationSection("gui");
79+
assertTrue(gui != null && !gui.getKeys(false).isEmpty());
80+
for (String key : gui.getKeys(false)) {
81+
String value = gui.getString(key);
82+
if (value != null) {
83+
assertEveryHexMarkerIsValid(value, "gui." + key);
84+
}
85+
}
86+
87+
YamlConfiguration config = load("config.yml");
88+
ConfigurationSection activities = config.getConfigurationSection("activities");
89+
assertTrue(activities != null && !activities.getKeys(false).isEmpty());
90+
for (String key : activities.getKeys(false)) {
91+
String display = activities.getString(key + ".display");
92+
if (display != null) {
93+
assertEveryHexMarkerIsValid(display, "activities." + key + ".display");
94+
}
95+
}
96+
97+
List<String> rewardDisplay = config.getStringList("rewards.display");
98+
for (int i = 0; i < rewardDisplay.size(); i++) {
99+
assertEveryHexMarkerIsValid(rewardDisplay.get(i), "rewards.display[" + i + "]");
100+
}
101+
}
102+
103+
@Test
104+
void everyActivityDisplayIsNonEmpty() {
105+
YamlConfiguration config = load("config.yml");
106+
ConfigurationSection activities = config.getConfigurationSection("activities");
107+
108+
assertTrue(activities != null && !activities.getKeys(false).isEmpty());
109+
for (String key : activities.getKeys(false)) {
110+
String display = activities.getString(key + ".display");
111+
assertFalse(display == null || display.isBlank(), "activities." + key + ".display should not be blank");
112+
}
113+
}
114+
115+
@Test
116+
void everyRewardDisplayLineIsNonEmpty() {
117+
YamlConfiguration config = load("config.yml");
118+
var display = config.getStringList("rewards.display");
119+
120+
assertFalse(display.isEmpty());
121+
for (String line : display) {
122+
assertFalse(line == null || line.isBlank(), "rewards.display entries should not be blank");
123+
}
124+
}
125+
126+
@Test
127+
void colorizeStripsHexAndLegacyCodes() {
128+
String result = Utils.colorize("#e6ca40&lX");
129+
130+
assertFalse(result.contains("#e6ca40"), "hex marker should be translated away: " + result);
131+
assertFalse(result.contains("&l"), "legacy code should be translated away: " + result);
132+
}
133+
}

0 commit comments

Comments
 (0)