Skip to content

Commit 3d8c323

Browse files
committed
Added natural spawner interaction config
1 parent 114228f commit 3d8c323

11 files changed

Lines changed: 224 additions & 249 deletions

File tree

src/main/java/me/nighter/smartSpawner/hooks/shops/api/economyshopgui/EconomyShopGUI.java

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ public class EconomyShopGUI implements IShopIntegration {
3030
private final ConfigManager configManager;
3131
private final SpawnerGuiViewManager spawnerGuiViewManager;
3232

33-
// Cooldown system
34-
private final Map<UUID, Long> sellCooldowns = new ConcurrentHashMap<>();
35-
private static final long SELL_COOLDOWN_MS = 1000;
36-
3733
// Transaction timeout
3834
private static final long TRANSACTION_TIMEOUT_MS = 5000; // 5 seconds timeout
3935

@@ -48,22 +44,6 @@ public EconomyShopGUI(SmartSpawner plugin) {
4844
this.spawnerGuiViewManager = plugin.getSpawnerGuiManager();
4945
}
5046

51-
private boolean isOnCooldown(Player player) {
52-
long lastSellTime = sellCooldowns.getOrDefault(player.getUniqueId(), 0L);
53-
long currentTime = System.currentTimeMillis();
54-
return (currentTime - lastSellTime) < SELL_COOLDOWN_MS;
55-
}
56-
57-
private void updateCooldown(Player player) {
58-
sellCooldowns.put(player.getUniqueId(), System.currentTimeMillis());
59-
}
60-
61-
private void clearOldCooldowns() {
62-
long currentTime = System.currentTimeMillis();
63-
sellCooldowns.entrySet().removeIf(entry ->
64-
(currentTime - entry.getValue()) > SELL_COOLDOWN_MS * 10);
65-
}
66-
6747
@Override
6848
public boolean sellAllItems(Player player, SpawnerData spawner) {
6949
// Prevent multiple concurrent sales for the same player
@@ -72,12 +52,6 @@ public boolean sellAllItems(Player player, SpawnerData spawner) {
7252
return false;
7353
}
7454

75-
// Check cooldown
76-
if (isOnCooldown(player)) {
77-
languageManager.sendMessage(player, "messages.sell-cooldown");
78-
return false;
79-
}
80-
8155
// Get lock with timeout
8256
ReentrantLock lock = spawner.getLock();
8357
if (!lock.tryLock()) {
@@ -96,7 +70,6 @@ public boolean sellAllItems(Player player, SpawnerData spawner) {
9670
saleFuture.whenComplete((success, error) -> {
9771
pendingSales.remove(player.getUniqueId());
9872
lock.unlock();
99-
updateCooldown(player);
10073

10174
if (error != null) {
10275
plugin.getLogger().log(Level.SEVERE, "Error processing sale", error);

src/main/java/me/nighter/smartSpawner/hooks/shops/api/shopguiplus/ShopGuiPlus.java

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@ public class ShopGuiPlus implements IShopIntegration {
3131
private final SpawnerGuiViewManager spawnerGuiViewManager;
3232
private final boolean isLoggingEnabled;
3333

34-
// Cooldown system
35-
private final Map<UUID, Long> sellCooldowns = new ConcurrentHashMap<>();
36-
private static final long SELL_COOLDOWN_MS = 1000;
37-
3834
// Transaction timeout
3935
private static final long TRANSACTION_TIMEOUT_MS = 5000; // 5 seconds timeout
4036

@@ -50,22 +46,6 @@ public ShopGuiPlus(SmartSpawner plugin) {
5046
this.isLoggingEnabled = configManager.isLoggingEnabled();
5147
}
5248

53-
private boolean isOnCooldown(Player player) {
54-
long lastSellTime = sellCooldowns.getOrDefault(player.getUniqueId(), 0L);
55-
long currentTime = System.currentTimeMillis();
56-
return (currentTime - lastSellTime) < SELL_COOLDOWN_MS;
57-
}
58-
59-
private void updateCooldown(Player player) {
60-
sellCooldowns.put(player.getUniqueId(), System.currentTimeMillis());
61-
}
62-
63-
private void clearOldCooldowns() {
64-
long currentTime = System.currentTimeMillis();
65-
sellCooldowns.entrySet().removeIf(entry ->
66-
(currentTime - entry.getValue()) > SELL_COOLDOWN_MS * 10);
67-
}
68-
6949
@Override
7050
public boolean sellAllItems(Player player, SpawnerData spawner) {
7151
// Check if shop system is enabled
@@ -79,12 +59,6 @@ public boolean sellAllItems(Player player, SpawnerData spawner) {
7959
return false;
8060
}
8161

82-
// Check cooldown
83-
if (isOnCooldown(player)) {
84-
languageManager.sendMessage(player, "messages.sell-cooldown");
85-
return false;
86-
}
87-
8862
// Get lock with timeout
8963
ReentrantLock lock = spawner.getLock();
9064
if (!lock.tryLock()) {
@@ -103,7 +77,6 @@ public boolean sellAllItems(Player player, SpawnerData spawner) {
10377
saleFuture.whenComplete((success, error) -> {
10478
pendingSales.remove(player.getUniqueId());
10579
lock.unlock();
106-
updateCooldown(player);
10780

10881
if (error != null) {
10982
plugin.getLogger().log(Level.SEVERE, "Error processing sale", error);

src/main/java/me/nighter/smartSpawner/hooks/shops/api/zshop/ZShop.java

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ public class ZShop implements IShopIntegration {
3030
private final SpawnerGuiViewManager spawnerGuiViewManager;
3131
private Economy vaultEconomy;
3232

33-
// Cooldown system
34-
private final Map<UUID, Long> sellCooldowns = new ConcurrentHashMap<>();
35-
private static final long SELL_COOLDOWN_MS = 1000; // 2000ms cooldown
36-
3733
// Transaction timeout
3834
private static final long TRANSACTION_TIMEOUT_MS = 5000; // 5 seconds timeout
3935

@@ -77,22 +73,6 @@ public ShopManager getShopManager() {
7773
.getRegistration(ShopManager.class).getProvider();
7874
}
7975

80-
private boolean isOnCooldown(Player player) {
81-
long lastSellTime = sellCooldowns.getOrDefault(player.getUniqueId(), 0L);
82-
long currentTime = System.currentTimeMillis();
83-
return (currentTime - lastSellTime) < SELL_COOLDOWN_MS;
84-
}
85-
86-
private void updateCooldown(Player player) {
87-
sellCooldowns.put(player.getUniqueId(), System.currentTimeMillis());
88-
}
89-
90-
private void clearOldCooldowns() {
91-
long currentTime = System.currentTimeMillis();
92-
sellCooldowns.entrySet().removeIf(entry ->
93-
(currentTime - entry.getValue()) > SELL_COOLDOWN_MS * 10);
94-
}
95-
9676
private double calculateNetAmount(double grossAmount, double taxPercentage) {
9777
if (taxPercentage <= 0) {
9878
return grossAmount;
@@ -113,12 +93,6 @@ public boolean sellAllItems(Player player, SpawnerData spawner) {
11393
return false;
11494
}
11595

116-
// Check cooldown
117-
if (isOnCooldown(player)) {
118-
languageManager.sendMessage(player, "messages.sell-cooldown");
119-
return false;
120-
}
121-
12296
// Get lock with timeout
12397
ReentrantLock lock = spawner.getLock();
12498
if (!lock.tryLock()) {
@@ -137,7 +111,6 @@ public boolean sellAllItems(Player player, SpawnerData spawner) {
137111
saleFuture.whenComplete((success, error) -> {
138112
pendingSales.remove(player.getUniqueId());
139113
lock.unlock();
140-
updateCooldown(player);
141114

142115
if (error != null) {
143116
plugin.getLogger().log(Level.SEVERE, "Error processing sale", error);

src/main/java/me/nighter/smartSpawner/spawner/gui/storage/SpawnerStorageAction.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ public class SpawnerStorageAction implements Listener {
4040
private static final Set<Integer> CONTROL_SLOTS = Set.of(45, 46, 48, 49, 50, 53);
4141

4242
// Add cooldown system properties
43-
private static final long SELL_COOLDOWN_MS = 5000; // 5 second cooldown
4443
private final Map<UUID, Long> sellCooldowns = new ConcurrentHashMap<>();
4544

4645
private final Map<ClickType, ItemClickHandler> clickHandlers;
@@ -226,10 +225,20 @@ private void updateInventoryTitle(Player player, Inventory inventory, SpawnerDat
226225
}
227226
}
228227

228+
private long getSellCooldownMs() {
229+
return configManager.getInt("sell-cooldown") * 1000L;
230+
}
231+
229232
private boolean isOnCooldown(Player player) {
233+
long cooldownMs = getSellCooldownMs();
234+
// If cooldown is disabled (set to 0), always return false
235+
if (cooldownMs <= 0) {
236+
return false;
237+
}
238+
230239
long lastSellTime = sellCooldowns.getOrDefault(player.getUniqueId(), 0L);
231240
long currentTime = System.currentTimeMillis();
232-
boolean onCooldown = (currentTime - lastSellTime) < SELL_COOLDOWN_MS;
241+
boolean onCooldown = (currentTime - lastSellTime) < cooldownMs;
233242

234243
// Debug information if needed
235244
if (onCooldown) {
@@ -245,9 +254,16 @@ private void updateCooldown(Player player) {
245254

246255
// Method to periodically clean up old cooldowns to prevent memory leaks
247256
private void clearOldCooldowns() {
257+
long cooldownMs = getSellCooldownMs();
258+
if (cooldownMs <= 0) {
259+
// If cooldown is disabled, clear all entries
260+
sellCooldowns.clear();
261+
return;
262+
}
263+
248264
long currentTime = System.currentTimeMillis();
249265
sellCooldowns.entrySet().removeIf(entry ->
250-
(currentTime - entry.getValue()) > SELL_COOLDOWN_MS * 10);
266+
(currentTime - entry.getValue()) > cooldownMs * 10);
251267
}
252268

253269
private void handleSellAllItems(Player player, SpawnerData spawner, StoragePageHolder holder) {
@@ -264,7 +280,9 @@ private void handleSellAllItems(Player player, SpawnerData spawner, StoragePageH
264280

265281
// Anti-spam cooldown check
266282
if (isOnCooldown(player)) {
267-
languageManager.sendMessage(player, "messages.sell-cooldown");
283+
int cooldownSeconds = configManager.getInt("sell-cooldown");
284+
languageManager.sendMessage(player, "messages.sell-cooldown",
285+
"%seconds%", String.valueOf(cooldownSeconds));
268286
return;
269287
}
270288

src/main/java/me/nighter/smartSpawner/spawner/interactions/SpawnerClickManager.java

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import org.bukkit.Location;
1414
import org.bukkit.Material;
1515
import org.bukkit.block.Block;
16+
import org.bukkit.block.BlockFace;
17+
import org.bukkit.block.BlockState;
1618
import org.bukkit.block.CreatureSpawner;
1719
import org.bukkit.entity.EntityType;
1820
import org.bukkit.entity.Player;
@@ -61,6 +63,78 @@ public SpawnerClickManager(SmartSpawner plugin) {
6163
initCleanupTask();
6264
}
6365

66+
/**
67+
* Checks if a spawner is likely to be naturally generated based on surrounding blocks
68+
* and efficient contextual analysis.
69+
*
70+
* @param spawnerBlock The spawner block to check
71+
* @return true if it appears to be a natural spawner
72+
*/
73+
private boolean isNaturalDungeonSpawner(Block spawnerBlock) {
74+
// Check the block below first (most efficient check)
75+
Block blockBelow = spawnerBlock.getRelative(BlockFace.DOWN);
76+
Material belowMaterial = blockBelow.getType();
77+
78+
// Check common dungeon floor materials
79+
if (belowMaterial == Material.COBBLESTONE ||
80+
belowMaterial == Material.MOSSY_COBBLESTONE) {
81+
return true;
82+
}
83+
84+
// Check mineshaft materials (for cave spider spawners)
85+
if (belowMaterial == Material.COBWEB ||
86+
belowMaterial == Material.OAK_PLANKS ||
87+
belowMaterial == Material.OAK_FENCE ||
88+
belowMaterial == Material.RAIL ||
89+
belowMaterial == Material.DEEPSLATE) {
90+
return true;
91+
}
92+
93+
// For floating spawners, check if there's no block below
94+
if (belowMaterial == Material.AIR || belowMaterial == Material.CAVE_AIR) {
95+
// Quick surroundings check for natural cave features
96+
int naturalBlockCount = 0;
97+
int cobwebCount = 0;
98+
99+
// Only check immediate surroundings (6 adjacent blocks) for better performance
100+
for (BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.EAST,
101+
BlockFace.SOUTH, BlockFace.WEST,
102+
BlockFace.UP}) {
103+
Block adjacentBlock = spawnerBlock.getRelative(face);
104+
Material material = adjacentBlock.getType();
105+
106+
// Count natural blocks and cobwebs
107+
if (material.toString().contains("STONE") ||
108+
material.toString().contains("DEEPSLATE") ||
109+
material == Material.DIRT ||
110+
material == Material.GRAVEL) {
111+
naturalBlockCount++;
112+
} else if (material == Material.COBWEB) {
113+
cobwebCount++;
114+
}
115+
}
116+
117+
// If surrounded by natural blocks or has cobwebs, likely natural
118+
if (naturalBlockCount >= 3 || cobwebCount >= 1) {
119+
return true;
120+
}
121+
}
122+
123+
// As a last check, examine the spawner type (lightweight operation)
124+
BlockState state = spawnerBlock.getState();
125+
if (state instanceof CreatureSpawner) {
126+
CreatureSpawner cs = (CreatureSpawner) state;
127+
EntityType entityType = cs.getSpawnedType();
128+
129+
// Cave spiders are almost always from natural mineshaft spawners
130+
if (entityType == EntityType.CAVE_SPIDER) {
131+
return true;
132+
}
133+
}
134+
135+
return false;
136+
}
137+
64138
@EventHandler(priority = EventPriority.HIGH)
65139
public void onSpawnerClick(PlayerInteractEvent event) {
66140
// Quick validation checks
@@ -71,6 +145,12 @@ public void onSpawnerClick(PlayerInteractEvent event) {
71145
Player player = event.getPlayer();
72146
Block block = event.getClickedBlock();
73147

148+
if (!configManager.getBoolean("natural-spawner-interaction")) {
149+
if (isNaturalDungeonSpawner(block)) {
150+
return;
151+
}
152+
}
153+
74154
// Apply interaction cooldown
75155
if (!isInteractionAllowed(player)) {
76156
event.setCancelled(true);
@@ -149,6 +229,7 @@ private boolean isBedrockPlayerUsingTool(Player player, Material itemType) {
149229
* Main handler for spawner interactions
150230
*/
151231
private void handleSpawnerInteraction(Player player, Block block, ItemStack heldItem, Material itemType) {
232+
152233
// Get or create spawner data
153234
SpawnerData spawner = getOrCreateSpawnerData(block, player);
154235

0 commit comments

Comments
 (0)