Skip to content

Commit 8311c85

Browse files
committed
bumped version to 1.1.1 + Fixed Permission related bugs
1 parent 97f2c0f commit 8311c85

9 files changed

Lines changed: 95 additions & 41 deletions

File tree

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ Modules are documented by category (config keys, permissions, and previews where
5858
| `/mint help` / `about` | Show plugin info ||
5959
| `/mint admin reload` | Reload configuration | `mint.admin`, `mint.reload` |
6060
| `/mint admin modules` | List all module states | `mint.admin` |
61-
| `/mint admin toggle <mod> [player]` | Toggle a module | `mint.toggle`; `mint.toggle.others` when `[player]` is set |
61+
| `/mint admin toggle <mod> [player]` | Toggle a module (self or another player) | `mint.admin`, `mint.toggle` |
6262
| `/mint admin global <mod> <on/off>` | Globally toggle a module in config | `mint.admin.global` |
6363
| `/mint admin profile list` | List saved module presets | `mint.admin.profile` |
6464
| `/mint admin profile save <name> [player]` | Snapshot a player's enabled modules | `mint.admin.profile` |
@@ -68,6 +68,16 @@ Modules are documented by category (config keys, permissions, and previews where
6868

6969
*Bypass protection checks in supported plugins with permission `mint.bypass.protection`.*
7070

71+
### Module permissions
72+
73+
Personal modules use two optional permission layers (configured per module in `config.yml`):
74+
75+
| Layer | Default node | Config key | Purpose |
76+
| --- | --- | --- | --- |
77+
| **Use** | `mint.module.<module-key>` | `permission` | Whether the module's features apply for the player |
78+
| **Toggle** | `mint.toggle.<module-key>` | `toggle-permission` | Whether the player can enable or disable the module (GUI and `/mint admin toggle` for themselves) |
79+
80+
7181
## Technical details
7282

7383
- **Storage:** YAML (default), H2, MySQL, MariaDB, MongoDB.

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
<groupId>ir.buddy</groupId>
77
<artifactId>Mint</artifactId>
8-
<version>1.1.0</version>
8+
<version>1.1.1</version>
99
<packaging>jar</packaging>
1010

1111
<name>Mint</name>

src/main/java/ir/buddy/mint/command/MintCommand.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,6 @@ private void handleToggle(CommandSender sender, String label, String[] args, Min
163163

164164
Player targetPlayer;
165165
if (args.length >= 4) {
166-
if (!sender.hasPermission("mint.toggle.others")) {
167-
lang.send(sender, "errors.no-permission", Map.of("label", label));
168-
return;
169-
}
170166
targetPlayer = plugin.getServer().getPlayerExact(args[3]);
171167
if (targetPlayer == null) {
172168
lang.send(sender, "errors.player-not-found", Map.of("label", label, "player", args[3]));
@@ -185,7 +181,17 @@ private void handleToggle(CommandSender sender, String label, String[] args, Min
185181
return;
186182
}
187183

188-
boolean enabledAfterToggle = plugin.getPlayerModulePreferences().toggleFor(targetPlayer, module);
184+
boolean togglingOther = args.length >= 4;
185+
boolean bypassTogglePermission = togglingOther;
186+
if (!bypassTogglePermission
187+
&& sender instanceof Player self
188+
&& self.getUniqueId().equals(targetPlayer.getUniqueId())
189+
&& !plugin.getPlayerModulePreferences().hasTogglePermission(self, module)) {
190+
lang.send(sender, "errors.no-module-toggle-permission", Map.of("label", label, "module", module.getName()));
191+
return;
192+
}
193+
194+
boolean enabledAfterToggle = plugin.getPlayerModulePreferences().toggleFor(targetPlayer, module, bypassTogglePermission);
189195

190196
Map<String, String> ph = new HashMap<>();
191197
ph.put("label", label);
@@ -430,7 +436,7 @@ public List<String> onTabComplete(CommandSender sender, Command command, String
430436
}
431437
}
432438
if (args.length == 4 && args[0].equalsIgnoreCase("admin") && args[1].equalsIgnoreCase("toggle")
433-
&& sender.hasPermission("mint.toggle.others")) {
439+
&& sender.hasPermission("mint.admin")) {
434440
return filterPrefix(
435441
plugin.getServer().getOnlinePlayers().stream()
436442
.map(Player::getName)

src/main/java/ir/buddy/mint/gui/ModuleToggleGui.java

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ private void handleModuleGuiClick(InventoryClickEvent event, Player player) {
249249
}
250250

251251
if (rawSlot == nextSlot) {
252-
List<Module> modules = getModulesForCategory(guiHolder.categoryKey);
252+
List<Module> modules = getModulesForCategory(player, guiHolder.categoryKey);
253253
List<Integer> moduleSlots = layout.moduleSlots();
254254
int pageSize = Math.max(1, moduleSlots.size());
255255
int maxPage = Math.max(0, (int) Math.ceil((double) modules.size() / pageSize) - 1);
@@ -284,7 +284,7 @@ private void handleModuleGuiClick(InventoryClickEvent event, Player player) {
284284
if (isSinglePage) {
285285
int catIdx = layout.categorySlots().indexOf(rawSlot);
286286
if (catIdx >= 0) {
287-
List<CategoryEntry> categories = getVisibleCategories();
287+
List<CategoryEntry> categories = getVisibleCategories(player);
288288

289289
if (catIdx < categories.size()) {
290290
openGui(player, categories.get(catIdx).key(), 0, GuiView.MODULES);
@@ -302,7 +302,7 @@ private void handleModuleGuiClick(InventoryClickEvent event, Player player) {
302302
syncInventory(player);
303303
return;
304304
}
305-
List<CategoryEntry> categories = getVisibleCategories();
305+
List<CategoryEntry> categories = getVisibleCategories(player);
306306
int categoryIndex = guiHolder.page * contentSlots.size() + idxInPage;
307307
if (categoryIndex < 0 || categoryIndex >= categories.size()) {
308308
syncInventory(player);
@@ -314,14 +314,20 @@ private void handleModuleGuiClick(InventoryClickEvent event, Player player) {
314314
}
315315

316316
if (guiHolder.view == GuiView.MODULES) {
317-
List<Module> modules = getModulesForCategory(guiHolder.categoryKey);
317+
List<Module> modules = getModulesForCategory(player, guiHolder.categoryKey);
318318
Integer globalIdx = guiHolder.slotToGlobalModuleIndex.get(rawSlot);
319319
if (globalIdx == null || globalIdx < 0 || globalIdx >= modules.size()) {
320320
syncInventory(player);
321321
return;
322322
}
323323

324324
Module module = modules.get(globalIdx);
325+
if (!plugin.getPlayerModulePreferences().hasTogglePermission(player, module)) {
326+
player.sendMessage(color(getString("messages.no-module-toggle-permission", "&cYou do not have permission to toggle this module.")));
327+
syncInventory(player);
328+
return;
329+
}
330+
325331
boolean enabled = plugin.getPlayerModulePreferences().toggleFor(player, module);
326332

327333
String msg = color(getString("messages.toggle", "&e%module% &7-> %state%"))
@@ -459,13 +465,13 @@ private void openGui(Player player, String categoryKey, int requestedPage, GuiVi
459465
String activeCategory = categoryKey;
460466
if (view == GuiView.MODULES && isCategoriesEnabled()) {
461467
if (activeCategory == null || activeCategory.isBlank() || "all".equalsIgnoreCase(activeCategory)) {
462-
activeCategory = resolveDefaultCategoryKey();
468+
activeCategory = resolveDefaultCategoryKey(player);
463469
}
464470
}
465471

466472
int entryCount = (view == GuiView.CATEGORIES && !isSinglePage)
467-
? getVisibleCategories().size()
468-
: getModulesForCategory(activeCategory).size();
473+
? getVisibleCategories(player).size()
474+
: getModulesForCategory(player, activeCategory).size();
469475
int totalPages = Math.max(1, (int) Math.ceil((double) entryCount / pageSize));
470476
int page = Math.max(0, Math.min(requestedPage, totalPages - 1));
471477

@@ -480,7 +486,7 @@ private void openGui(Player player, String categoryKey, int requestedPage, GuiVi
480486
int start = page * pageSize;
481487

482488
List<Module> modulesForView = view == GuiView.MODULES
483-
? getModulesForCategory(activeCategory)
489+
? getModulesForCategory(player, activeCategory)
484490
: List.of();
485491
Map<Integer, Integer> moduleSlotIndexMap = view == GuiView.MODULES
486492
? computeModulePlacements(modulesForView, start, pageSize, contentSlots, readModuleSlotOverrides())
@@ -495,7 +501,7 @@ private void openGui(Player player, String categoryKey, int requestedPage, GuiVi
495501
}
496502

497503
if (isSinglePage) {
498-
List<CategoryEntry> categories = getVisibleCategories();
504+
List<CategoryEntry> categories = getVisibleCategories(player);
499505

500506
for (int i = 0; i < layout.categorySlots().size(); i++) {
501507
if (i >= categories.size()) {
@@ -521,7 +527,7 @@ private void openGui(Player player, String categoryKey, int requestedPage, GuiVi
521527
inv.setItem(invSlot, buildModuleItem(player, modulesForView.get(modIdx)));
522528
}
523529
} else if (view == GuiView.CATEGORIES) {
524-
List<CategoryEntry> categories = getVisibleCategories();
530+
List<CategoryEntry> categories = getVisibleCategories(player);
525531
for (int i = 0; i < pageSize; i++) {
526532
int categoryIndex = start + i;
527533
if (categoryIndex >= categories.size()) {
@@ -982,29 +988,30 @@ private boolean isModuleGui(Inventory inventory) {
982988
return inventory != null && inventory.getHolder() instanceof ModuleGuiHolder;
983989
}
984990

985-
private List<Module> getModules() {
991+
private List<Module> getModules(Player player) {
986992
return plugin.getModuleManager().getPlayerScopedModules().stream()
987993
.filter(module -> module.isEnabledByConfig(plugin.getConfig()))
994+
.filter(module -> plugin.getPlayerModulePreferences().hasTogglePermission(player, module))
988995
.sorted(Comparator.comparing(Module::getName, String.CASE_INSENSITIVE_ORDER))
989996
.collect(Collectors.toList());
990997
}
991998

992-
public List<Module> getModulesForCategory(String categoryKey) {
999+
public List<Module> getModulesForCategory(Player player, String categoryKey) {
9931000
if (!isCategoriesEnabled()) {
9941001
if (categoryKey == null || categoryKey.isBlank() || "all".equalsIgnoreCase(categoryKey)) {
995-
return getModules();
1002+
return getModules(player);
9961003
}
9971004
} else {
9981005
if (categoryKey == null || categoryKey.isBlank() || "all".equalsIgnoreCase(categoryKey)) {
999-
String def = resolveDefaultCategoryKey();
1006+
String def = resolveDefaultCategoryKey(player);
10001007
if (def == null) {
10011008
return List.of();
10021009
}
10031010
categoryKey = def;
10041011
}
10051012
}
10061013
final String resolvedKey = categoryKey;
1007-
return getModules().stream()
1014+
return getModules(player).stream()
10081015
.filter(module -> resolveModuleCategoryKey(module).equalsIgnoreCase(resolvedKey))
10091016
.collect(Collectors.toList());
10101017
}
@@ -1018,17 +1025,13 @@ public String getCategoryDisplayName(String categoryKey) {
10181025
if (!isCategoriesEnabled()) {
10191026
return color(getString("gui.modules-aggregate-display", "&fModules"));
10201027
}
1021-
String def = resolveDefaultCategoryKey();
1022-
if (def != null) {
1023-
return color(getString("gui.categories.items." + def + ".display-name", toTitleCase(def.replace('-', ' '))));
1024-
}
10251028
return color(getString("gui.modules-empty-display", "&fModules"));
10261029
}
10271030
return color(getString("gui.categories.items." + categoryKey + ".display-name", toTitleCase(categoryKey.replace('-', ' '))));
10281031
}
10291032

1030-
private String resolveDefaultCategoryKey() {
1031-
List<CategoryEntry> visible = getVisibleCategories();
1033+
private String resolveDefaultCategoryKey(Player player) {
1034+
List<CategoryEntry> visible = getVisibleCategories(player);
10321035
return visible.isEmpty() ? null : visible.get(0).key();
10331036
}
10341037

@@ -1055,9 +1058,9 @@ private String normalizeCategoryKey(String value) {
10551058
return value.toLowerCase(Locale.ROOT).replaceAll("[^a-z0-9-]", "-");
10561059
}
10571060

1058-
public List<CategoryEntry> getVisibleCategories() {
1061+
public List<CategoryEntry> getVisibleCategories(Player player) {
10591062
Map<String, Long> counts = new HashMap<>();
1060-
for (Module module : getModules()) {
1063+
for (Module module : getModules(player)) {
10611064
counts.merge(resolveModuleCategoryKey(module), 1L, Long::sum);
10621065
}
10631066

src/main/java/ir/buddy/mint/player/PlayerModulePreferences.java

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public boolean isPersonalModuleEnabled(Player player, Module module) {
6767
if (!isToggleEnabledFor(player, module)) {
6868
return false;
6969
}
70-
if (!hasModulePermission(player, module)) {
70+
if (!hasModulePermissionInternal(player, module)) {
7171
return false;
7272
}
7373
if (!isAllowedInWorld(player, module)) {
@@ -108,14 +108,35 @@ public boolean setEnabledFor(Player player, Module module, boolean enabled) {
108108
}
109109

110110
public boolean toggleFor(Player player, Module module) {
111+
return toggleFor(player, module, false);
112+
}
113+
114+
public boolean toggleFor(Player player, Module module, boolean bypassTogglePermission) {
111115
if (module.isServerScoped()) {
112116
return module.isEnabledByConfig(plugin.getConfig());
113117
}
114-
boolean next = !isPersonalModuleEnabled(player, module);
118+
if (!bypassTogglePermission && !hasTogglePermission(player, module)) {
119+
return isToggleEnabledFor(player, module);
120+
}
121+
boolean next = !isToggleEnabledFor(player, module);
115122
setEnabledFor(player, module, next);
116123
return next;
117124
}
118125

126+
public boolean hasModulePermission(Player player, Module module) {
127+
if (player == null) {
128+
return true;
129+
}
130+
return hasModulePermissionInternal(player, module);
131+
}
132+
133+
public boolean hasTogglePermission(Player player, Module module) {
134+
if (player == null) {
135+
return true;
136+
}
137+
return hasTogglePermissionInternal(player, module);
138+
}
139+
119140
public void clearCachedToggles(UUID playerUuid) {
120141
toggleCache.remove(playerUuid);
121142
}
@@ -147,17 +168,26 @@ private String getModuleKey(Module module) {
147168
return module.getConfigPath().replaceFirst("^modules\\.", "");
148169
}
149170

150-
private boolean hasModulePermission(Player player, Module module) {
171+
private boolean hasModulePermissionInternal(Player player, Module module) {
172+
return resolvesPermission(player, module, "permission", "mint.module.");
173+
}
174+
175+
private boolean hasTogglePermissionInternal(Player player, Module module) {
176+
return resolvesPermission(player, module, "toggle-permission", "mint.toggle.");
177+
}
178+
179+
private boolean resolvesPermission(Player player, Module module, String configKey, String defaultPrefix) {
151180
String moduleKey = getModuleKey(module);
152-
String path = module.getConfigPath() + ".permission";
181+
String path = module.getConfigPath() + "." + configKey;
153182
String configured = plugin.getConfig().getString(path, "");
154183
String permission = (configured == null || configured.isBlank())
155-
? "mint.module." + moduleKey
184+
? defaultPrefix + moduleKey
156185
: configured.trim();
157186
if (permission.equalsIgnoreCase("none") || permission.equalsIgnoreCase("disabled")) {
158187
return true;
159188
}
160-
return player.hasPermission(permission) || player.hasPermission("mint.module.*");
189+
String wildcard = defaultPrefix + "*";
190+
return player.hasPermission(permission) || player.hasPermission(wildcard);
161191
}
162192

163193
private boolean isAllowedInWorld(Player player, Module module) {

src/main/resources/config.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,10 @@ modules:
4949
brightness:
5050
block: 15
5151
sky: 15
52-
# Permission defaults to mint.module.<module-key> when omitted.
52+
# Use permission defaults to mint.module.<module-key> when omitted.
5353
permission: mint.module.reacharound-placement
54+
# Toggle permission defaults to mint.toggle.<module-key> when omitted.
55+
# toggle-permission: mint.toggle.reacharound-placement
5456
# Per-world controls:
5557
# mode: all | whitelist | blacklist
5658
worlds:

src/main/resources/gui.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,5 @@ messages:
160160
state-enabled: "&aEnabled"
161161
state-disabled: "&cDisabled"
162162
toggle: "&e%module% &7-> %state%"
163+
no-module-permission: "&cYou do not have permission to use this module."
164+
no-module-toggle-permission: "&cYou do not have permission to toggle this module."

src/main/resources/lang.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ prefix: "<gradient:#00AA55:#55FF88><bold>Mint</bold></gradient><gray> » </gray>
77

88
errors:
99
no-permission: "<mint_prefix><red>You do not have permission.</red>"
10+
no-module-toggle-permission: "<mint_prefix><red>You do not have permission to toggle </red><yellow><module></yellow><red>.</red>"
1011
players-only: "<mint_prefix><red>Only players can open the module GUI.</red>"
1112
no-gui-permission: "<mint_prefix><red>You cannot open the module GUI.</red>"
1213
unknown-subcommand: "<mint_prefix><gray>Unknown. Try </gray><yellow>/<label> help</yellow><gray>.</gray>"

src/main/resources/plugin.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ permissions:
2424
description: Allows reloading Mint
2525
default: op
2626
mint.toggle:
27-
description: Allows toggling personal Mint modules
27+
description: Allows using /mint admin toggle for your own modules
2828
default: op
29-
mint.toggle.others:
30-
description: Allows toggling Mint modules for other players
29+
mint.toggle.*:
30+
description: Allows toggling any personal Mint module for yourself (GUI and per-module nodes)
3131
default: op
3232
mint.bypass.protection:
3333
description: Bypass protection plugin checks for Mint features

0 commit comments

Comments
 (0)