Skip to content

Commit 8992d6e

Browse files
authored
Merge pull request #37 from ez-plugins/35-rotation-items
fix: not in rotation check
2 parents 68b85a6 + 43bb520 commit 8992d6e

File tree

12 files changed

+259
-4
lines changed

12 files changed

+259
-4
lines changed

pom.xml

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

66
<groupId>com.skyblockexp</groupId>
77
<artifactId>ezshops</artifactId>
8-
<version>2.2.2</version>
8+
<version>2.2.3</version>
99
<name>EzShops Plugin</name>
1010
<description>Standalone plugin providing the Skyblock shop command and sign shops.</description>
1111
<packaging>jar</packaging>

src/main/java/com/skyblockexp/ezshops/bootstrap/CoreShopComponent.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public void enable(EzShopsPlugin plugin) {
124124

125125
shopCommand = new ShopCommand(pricingManager, transactionService, shopMenu, commandMessages.shop(),
126126
transactionMessages.errors(), transactionMessages.restrictions(), plugin.isDebugMode());
127-
sellHandCommand = new SellHandCommand(transactionService, commandMessages.sellHand());
127+
sellHandCommand = new SellHandCommand(transactionService, pricingManager, commandMessages.sellHand());
128128
sellInventoryCommand = new SellInventoryCommand(transactionService, commandMessages.sellInventory());
129129
priceCommand = new PriceCommand(pricingManager, transactionService, commandMessages.price());
130130

src/main/java/com/skyblockexp/ezshops/config/ShopMessageConfiguration.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,10 @@ public String invalidAmount(String amount) {
288288
public String amountMustBePositive() {
289289
return string("commands.shop.amount-positive", "&cAmount must be positive.");
290290
}
291+
292+
public String notInRotation() {
293+
return string("commands.shop.not-in-rotation", "&cThat item is not available in the current shop rotation.");
294+
}
291295
}
292296

293297
public final class SellHandCommandMessages {
@@ -299,13 +303,21 @@ public String playersOnly() {
299303
public String mustHoldItem() {
300304
return string("commands.sell-hand.must-hold-item", "&cYou must hold an item to use this command.");
301305
}
306+
307+
public String notInRotation() {
308+
return string("commands.sell-hand.not-in-rotation", "&cThat item is not available in the current shop rotation.");
309+
}
302310
}
303311

304312
public final class SellInventoryCommandMessages {
305313

306314
public String playersOnly() {
307315
return string("commands.sell-inventory.players-only", "&cOnly players can sell items.");
308316
}
317+
318+
public String notInRotation() {
319+
return string("commands.sell-inventory.not-in-rotation", "&cNo sellable items are available in the current shop rotation.");
320+
}
309321
}
310322

311323
public final class PriceCommandMessages {
@@ -525,6 +537,10 @@ public String notSellable() {
525537
return string("transactions.errors.not-sellable", "&cThat item cannot be sold to the shop.");
526538
}
527539

540+
public String notInRotation() {
541+
return string("transactions.errors.not-in-rotation", "&cThat item is not available in the current shop rotation.");
542+
}
543+
528544
public String invalidBuyPrice() {
529545
return string("transactions.errors.invalid-buy-price", "&cThis item does not have a valid buy price.");
530546
}

src/main/java/com/skyblockexp/ezshops/shop/ShopPricingManager.java

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,83 @@ public ShopMenuLayout getMenuLayout() {
162162
return menuLayout;
163163
}
164164

165+
/**
166+
* Returns true if the given material is present in the active shop menu layout (current rotation).
167+
*/
168+
public boolean isVisibleInMenu(Material material) {
169+
if (material == null) return false;
170+
ShopMenuLayout layout = getMenuLayout();
171+
if (layout == null) return false;
172+
for (ShopMenuLayout.Category category : layout.categories()) {
173+
for (ShopMenuLayout.Item item : category.items()) {
174+
if (item == null) continue;
175+
if (item.material() == material) return true;
176+
if (item.priceId() != null && item.priceId().equalsIgnoreCase(material.name())) return true;
177+
if (item.id() != null && item.id().equalsIgnoreCase(material.name())) return true;
178+
}
179+
}
180+
return false;
181+
}
182+
183+
/**
184+
* Returns true if the given price key / identifier is present in the active shop menu layout (current rotation).
185+
*/
186+
public boolean isVisibleInMenu(String priceKey) {
187+
if (priceKey == null || priceKey.isBlank()) return false;
188+
ShopMenuLayout layout = getMenuLayout();
189+
if (layout == null) return false;
190+
String lower = priceKey.toLowerCase(Locale.ENGLISH);
191+
for (ShopMenuLayout.Category category : layout.categories()) {
192+
for (ShopMenuLayout.Item item : category.items()) {
193+
if (item == null) continue;
194+
if (item.id() != null && item.id().equalsIgnoreCase(priceKey)) return true;
195+
if (item.priceId() != null && item.priceId().equalsIgnoreCase(priceKey)) return true;
196+
if (item.material() != null && item.material().name().equalsIgnoreCase(priceKey)) return true;
197+
if (item.display() != null && item.display().displayName() != null
198+
&& item.display().displayName().toLowerCase(Locale.ENGLISH).startsWith(lower)) return true;
199+
}
200+
}
201+
return false;
202+
}
203+
204+
/**
205+
* Returns true if the given material is declared in any rotation option (regardless of active option).
206+
*/
207+
public boolean isPartOfRotation(Material material) {
208+
if (material == null) return false;
209+
String name = material.name();
210+
return isPartOfRotation(name);
211+
}
212+
213+
/**
214+
* Returns true if the given price key / identifier is declared in any rotation option (regardless of active option).
215+
*/
216+
public boolean isPartOfRotation(String priceKey) {
217+
if (priceKey == null || priceKey.isBlank()) return false;
218+
if (categoryTemplates == null || categoryTemplates.isEmpty()) return false;
219+
String lower = priceKey.toLowerCase(Locale.ENGLISH);
220+
for (CategoryTemplate template : categoryTemplates) {
221+
if (template == null || !template.isRotating()) continue;
222+
RotationBinding binding = template.rotation;
223+
if (binding == null) continue;
224+
ShopRotationDefinition def = rotationDefinitions.get(binding.groupId());
225+
if (def == null) continue;
226+
for (ShopRotationOption option : def.options()) {
227+
java.util.List<ShopMenuLayout.Item> items = binding.itemsFor(option.id());
228+
if (items == null) continue;
229+
for (ShopMenuLayout.Item item : items) {
230+
if (item == null) continue;
231+
if (item.id() != null && item.id().equalsIgnoreCase(priceKey)) return true;
232+
if (item.priceId() != null && item.priceId().equalsIgnoreCase(priceKey)) return true;
233+
if (item.material() != null && item.material().name().equalsIgnoreCase(priceKey)) return true;
234+
if (item.display() != null && item.display().displayName() != null
235+
&& item.display().displayName().toLowerCase(Locale.ENGLISH).startsWith(lower)) return true;
236+
}
237+
}
238+
}
239+
return false;
240+
}
241+
165242
public Map<String, ShopRotationDefinition> getRotationDefinitions() {
166243
return Collections.unmodifiableMap(rotationDefinitions);
167244
}

src/main/java/com/skyblockexp/ezshops/shop/ShopTransactionService.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ public ShopTransactionResult buy(Player player, Material material, int amount) {
203203
return ShopTransactionResult.failure(errorMessages.amountPositive());
204204
}
205205

206+
// If the material is part of a rotation but not currently visible, reject the trade.
207+
if (!pricingManager.isVisibleInMenu(material) && pricingManager.isPartOfRotation(material)) {
208+
return ShopTransactionResult.failure(errorMessages.notInRotation());
209+
}
210+
206211
ShopPrice price = pricingManager.getPrice(material).orElse(null);
207212
if (price == null) {
208213
return ShopTransactionResult.failure(errorMessages.notConfigured());
@@ -328,6 +333,11 @@ public ShopTransactionResult sell(Player player, Material material, int amount)
328333
return ShopTransactionResult.failure(errorMessages.amountPositive());
329334
}
330335

336+
// If the material is part of a rotation but not currently visible, reject the trade.
337+
if (!pricingManager.isVisibleInMenu(material) && pricingManager.isPartOfRotation(material)) {
338+
return ShopTransactionResult.failure(errorMessages.notInRotation());
339+
}
340+
331341
ShopPrice price = pricingManager.getPrice(material).orElse(null);
332342
if (price == null) {
333343
return ShopTransactionResult.failure(errorMessages.notConfigured());
@@ -446,6 +456,10 @@ public ShopTransactionResult sellInventory(Player player) {
446456
}
447457

448458
Material material = stack.getType();
459+
// Skip materials that are part of a rotation but not visible in the current menu rotation
460+
if (!pricingManager.isVisibleInMenu(material) && pricingManager.isPartOfRotation(material)) {
461+
continue;
462+
}
449463
ShopPrice price = pricingManager.getPrice(material).orElse(null);
450464
if (price == null || !price.canSell()) {
451465
continue;

src/main/java/com/skyblockexp/ezshops/shop/command/SellHandCommand.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.skyblockexp.ezshops.shop.command;
22

33
import com.skyblockexp.ezshops.config.ShopMessageConfiguration;
4+
import com.skyblockexp.ezshops.shop.ShopPricingManager;
45
import com.skyblockexp.ezshops.shop.ShopTransactionResult;
56
import com.skyblockexp.ezshops.shop.ShopTransactionService;
67
import org.bukkit.Material;
@@ -16,11 +17,13 @@
1617
public class SellHandCommand implements CommandExecutor {
1718

1819
private final ShopTransactionService transactionService;
20+
private final ShopPricingManager pricingManager;
1921
private final ShopMessageConfiguration.CommandMessages.SellHandCommandMessages messages;
2022

21-
public SellHandCommand(ShopTransactionService transactionService,
23+
public SellHandCommand(ShopTransactionService transactionService, ShopPricingManager pricingManager,
2224
ShopMessageConfiguration.CommandMessages.SellHandCommandMessages messages) {
2325
this.transactionService = transactionService;
26+
this.pricingManager = pricingManager;
2427
this.messages = messages;
2528
}
2629

@@ -37,6 +40,12 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
3740
return true;
3841
}
3942

43+
// If the held item is part of a rotation but not visible in the current rotation, show message
44+
if (!pricingManager.isVisibleInMenu(handItem.getType()) && pricingManager.isPartOfRotation(handItem.getType())) {
45+
player.sendMessage(messages.notInRotation());
46+
return true;
47+
}
48+
4049
ShopTransactionResult result = transactionService.sell(player, handItem.getType(), handItem.getAmount());
4150
player.sendMessage(result.message());
4251
return true;

src/main/java/com/skyblockexp/ezshops/shop/command/ShopCommand.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,13 @@ private ShopTransactionResult handleBuy(Player player, Material material, int am
148148
case MATERIAL -> {
149149
// Try to find a configured ShopMenuLayout.Item for this material so hooks (on-buy) execute.
150150
ShopMenuLayout.Item item = findItemForMaterial(material);
151-
if (item != null) yield transactionService.buy(player, item, amount);
151+
if (item != null) {
152+
yield transactionService.buy(player, item, amount);
153+
}
154+
// If the material is part of a rotation but not present in the active menu rotation, reject the command
155+
if (!pricingManager.isVisibleInMenu(material) && pricingManager.isPartOfRotation(material)) {
156+
yield ShopTransactionResult.failure(messages.notInRotation());
157+
}
152158
yield transactionService.buy(player, material, amount);
153159
}
154160
case MINION_CRATE_KEY -> executeCrateKeyPurchase(player, material, amount,
@@ -184,6 +190,10 @@ private ShopTransactionResult handleSell(Player player, Material material, int a
184190
if (debug) {
185191
org.bukkit.Bukkit.getLogger().info("ShopCommand: falling back to material-only sell for " + material.name());
186192
}
193+
// Prevent selling items via command that are part of a rotation but not visible in the active menu rotation
194+
if (!pricingManager.isVisibleInMenu(material) && pricingManager.isPartOfRotation(material)) {
195+
yield ShopTransactionResult.failure(messages.notInRotation());
196+
}
187197
yield transactionService.sell(player, material, amount);
188198
}
189199
case MINION_CRATE_KEY, VOTE_CRATE_KEY -> ShopTransactionResult.failure(restrictionMessages.enchantedBookMenuOnly());

src/main/resources/messages/messages_en.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ commands:
1212
sell-hand:
1313
players-only: "&cOnly players can sell items."
1414
must-hold-item: "&cYou must hold an item to use this command."
15+
not-in-rotation: "&cThat item is not available in the current shop rotation."
1516
sell-inventory:
1617
players-only: "&cOnly players can sell items."
18+
not-in-rotation: "&cNo sellable items are available in the current shop rotation."
1719
price:
1820
usage: "&eUsage: /{label} <item>"
1921
unknown-item: "&cUnknown item: {item}"
@@ -54,6 +56,7 @@ transactions:
5456
not-configured: "&cThat item is not configured in the shop."
5557
not-buyable: "&cThat item cannot be purchased from the shop."
5658
not-sellable: "&cThat item cannot be sold to the shop."
59+
not-in-rotation: "&cThat item is not available in the current shop rotation."
5760
invalid-buy-price: "&cThis item does not have a valid buy price."
5861
invalid-sell-price: "&cThis item does not have a valid sell price."
5962
invalid-spawner: "&cThis spawner is not configured correctly."

src/main/resources/messages/messages_es.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ commands:
1212
sell-hand:
1313
players-only: "&cSolo los jugadores pueden vender artículos."
1414
must-hold-item: "&cDebes tener un artículo en la mano para usar este comando."
15+
not-in-rotation: "&cEse artículo no está disponible en la rotación actual de la tienda."
1516
sell-inventory:
1617
players-only: "&cSolo los jugadores pueden vender artículos."
18+
not-in-rotation: "&cNo hay artículos vendibles disponibles en la rotación actual de la tienda."
1719
price:
1820
usage: "&eUso: /{label} <artículo>"
1921
unknown-item: "&cArtículo desconocido: {item}"
@@ -54,6 +56,7 @@ transactions:
5456
not-configured: "&cEse artículo no está configurado en la tienda."
5557
not-buyable: "&cEse artículo no se puede comprar en la tienda."
5658
not-sellable: "&cEse artículo no se puede vender a la tienda."
59+
not-in-rotation: "&cEse artículo no está disponible en la rotación actual de la tienda."
5760
invalid-buy-price: "&cEste artículo no tiene un precio de compra válido."
5861
invalid-sell-price: "&cEste artículo no tiene un precio de venta válido."
5962
invalid-spawner: "&cEste generador no está configurado correctamente."

src/main/resources/messages/messages_nl.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ commands:
1212
sell-hand:
1313
players-only: "&cAlleen spelers kunnen items verkopen."
1414
must-hold-item: "&cJe moet een item vasthouden om dit commando te gebruiken."
15+
not-in-rotation: "&cDit item is niet beschikbaar in de huidige winkelrotatie."
1516
sell-inventory:
1617
players-only: "&cAlleen spelers kunnen items verkopen."
18+
not-in-rotation: "&cEr zijn geen verkoopbare items beschikbaar in de huidige winkelrotatie."
1719
price:
1820
usage: "&eGebruik: /{label} <item>"
1921
unknown-item: "&cOnbekend item: {item}"
@@ -54,6 +56,7 @@ transactions:
5456
not-configured: "&cDat item is niet geconfigureerd in de winkel."
5557
not-buyable: "&cDat item kan niet in de winkel worden gekocht."
5658
not-sellable: "&cDat item kan niet aan de winkel worden verkocht."
59+
not-in-rotation: "&cDit item is niet beschikbaar in de huidige winkelrotatie."
5760
invalid-buy-price: "&cDit item heeft geen geldige aankoopprijs."
5861
invalid-sell-price: "&cDit item heeft geen geldige verkoopprijs."
5962
invalid-spawner: "&cDeze spawner is niet correct geconfigureerd."

0 commit comments

Comments
 (0)