Skip to content

Commit 5477a0c

Browse files
tastybentoclaude
andcommitted
Add option to lose level-gated tiers when island level drops (#118)
Adds a lose-tiers-on-level-loss config option (default false). When enabled, generators that were unlocked purely by reaching an island level are locked again if the island level later drops below their required level. - Settings.loseTiersOnLevelLoss (lose-tiers-on-level-loss, default false). - checkGeneratorUnlockStatus now calls revokeLevelLockedGenerators, which removes level-gated tiers from the unlocked and active lists when the island level is below their requirement. Runs on the existing IslandLevelCalculatedEvent -> checkGeneratorUnlockStatus path. - Purchased tiers are always kept, so players never lose generators they actually paid for. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
1 parent afe8fec commit 5477a0c

3 files changed

Lines changed: 139 additions & 0 deletions

File tree

src/main/java/world/bentobox/magiccobblestonegenerator/config/Settings.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,28 @@ public void setBuyConfirmation(boolean buyConfirmation)
328328
}
329329

330330

331+
/**
332+
* Is lose tiers on level loss boolean.
333+
*
334+
* @return the boolean
335+
*/
336+
public boolean isLoseTiersOnLevelLoss()
337+
{
338+
return loseTiersOnLevelLoss;
339+
}
340+
341+
342+
/**
343+
* Sets lose tiers on level loss.
344+
*
345+
* @param loseTiersOnLevelLoss the lose tiers on level loss
346+
*/
347+
public void setLoseTiersOnLevelLoss(boolean loseTiersOnLevelLoss)
348+
{
349+
this.loseTiersOnLevelLoss = loseTiersOnLevelLoss;
350+
}
351+
352+
331353
/**
332354
* Is use bank account boolean.
333355
*
@@ -514,6 +536,13 @@ public enum GuiAction
514536
@ConfigEntry(path = "buy-confirmation")
515537
private boolean buyConfirmation = true;
516538

539+
@ConfigComment("")
540+
@ConfigComment("If enabled, generators unlocked purely by reaching an island level are locked again")
541+
@ConfigComment("when the island level drops back below their required level. Purchased generators are")
542+
@ConfigComment("always kept. Requires the Level addon.")
543+
@ConfigEntry(path = "lose-tiers-on-level-loss")
544+
private boolean loseTiersOnLevelLoss = false;
545+
517546
@ConfigComment("")
518547
@ConfigComment("Send a notification message when player unlocks a new generator.")
519548
@ConfigComment("3 messages that will be showed:")

src/main/java/world/bentobox/magiccobblestonegenerator/managers/StoneGeneratorManager.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,46 @@ public void checkGeneratorUnlockStatus(Island island, @Nullable User user, @Null
883883
// Revoke permission based generators that the current owner no longer qualifies for.
884884
// This handles ownership transfer to a player without the required permission (#133).
885885
this.revokePermissionGenerators(island, dataObject, owner);
886+
887+
// Revoke level based generators when the island level dropped below their requirement (#118).
888+
this.revokeLevelLockedGenerators(island, dataObject, islandLevel);
889+
}
890+
891+
/**
892+
* This method locks level based generators again when the island level has dropped below their required level. It
893+
* only runs when the {@code lose-tiers-on-level-loss} setting is enabled, and never revokes purchased generators, so
894+
* paid tiers are kept even if the level drops (#118).
895+
*
896+
* @param island Island which is targeted for the check.
897+
* @param dataObject Data object that stores island generators.
898+
* @param islandLevel The current island level.
899+
*/
900+
private void revokeLevelLockedGenerators(@NotNull Island island, @NotNull GeneratorDataObject dataObject,
901+
long islandLevel) {
902+
if (!this.addon.getSettings().isLoseTiersOnLevelLoss()) {
903+
// Feature disabled: unlocked generators stay unlocked regardless of level.
904+
return;
905+
}
906+
907+
List<GeneratorTierObject> revokeList = this.getIslandGeneratorTiers(island.getWorld(), dataObject).stream()
908+
// Only level gated generators can be revoked this way.
909+
.filter(generator -> generator.getRequiredMinIslandLevel() > 0)
910+
// Whose required level is now above the current island level.
911+
.filter(generator -> generator.getRequiredMinIslandLevel() > islandLevel)
912+
// That are currently unlocked.
913+
.filter(generator -> dataObject.getUnlockedTiers().contains(generator.getUniqueId()))
914+
// But that were not purchased. Paid tiers are kept even when the level drops.
915+
.filter(generator -> !dataObject.getPurchasedTiers().contains(generator.getUniqueId()))
916+
.collect(Collectors.toList());
917+
918+
if (!revokeList.isEmpty()) {
919+
revokeList.forEach(generator -> {
920+
dataObject.getUnlockedTiers().remove(generator.getUniqueId());
921+
dataObject.getActiveGeneratorList().remove(generator.getUniqueId());
922+
});
923+
924+
this.saveGeneratorData(dataObject);
925+
}
886926
}
887927

888928
/**

src/test/java/world/bentobox/magiccobblestonegenerator/managers/StoneGeneratorManagerTest.java

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,76 @@ void testCheckGeneratorUnlockStatusDoesNotRevokeWhenOwnerOffline() {
430430
assertTrue(data.getActiveGeneratorList().contains("magiccobblegenerator_perm"));
431431
}
432432

433+
/**
434+
* Seeds a deployed, level-gated (required level 100) generator that is already unlocked and active, for
435+
* lose-tiers-on-level-loss tests (#118).
436+
*/
437+
private GeneratorDataObject seedLevelGeneratorAndData() {
438+
sgm.addWorld(world);
439+
when(island.getUniqueId()).thenReturn("island-118");
440+
when(island.getWorld()).thenReturn(world);
441+
when(island.isSpawn()).thenReturn(false);
442+
443+
when(generatorTier.getUniqueId()).thenReturn("magiccobblegenerator_level");
444+
when(generatorTier.isDeployed()).thenReturn(true);
445+
when(generatorTier.isDefaultGenerator()).thenReturn(false);
446+
when(generatorTier.getGeneratorType()).thenReturn(GeneratorType.COBBLESTONE);
447+
when(generatorTier.getRequiredMinIslandLevel()).thenReturn(100L);
448+
when(generatorTier.getRequiredPermissions()).thenReturn(java.util.Collections.emptySet());
449+
sgm.loadGeneratorTier(generatorTier, true, null);
450+
451+
GeneratorDataObject data = sgm.getGeneratorData(island);
452+
assertNotNull(data);
453+
data.getUnlockedTiers().add("magiccobblegenerator_level");
454+
data.getActiveGeneratorList().add("magiccobblegenerator_level");
455+
return data;
456+
}
457+
458+
@Test
459+
void testRevokesLevelGeneratorWhenLevelDropped() {
460+
GeneratorDataObject data = seedLevelGeneratorAndData();
461+
s.setLoseTiersOnLevelLoss(true);
462+
463+
// Island level dropped to 10, below the generator's required level of 100.
464+
sgm.checkGeneratorUnlockStatus(island, null, 10L);
465+
466+
assertFalse(data.getUnlockedTiers().contains("magiccobblegenerator_level"));
467+
assertFalse(data.getActiveGeneratorList().contains("magiccobblegenerator_level"));
468+
}
469+
470+
@Test
471+
void testKeepsPurchasedLevelGeneratorWhenLevelDropped() {
472+
GeneratorDataObject data = seedLevelGeneratorAndData();
473+
data.getPurchasedTiers().add("magiccobblegenerator_level");
474+
s.setLoseTiersOnLevelLoss(true);
475+
476+
sgm.checkGeneratorUnlockStatus(island, null, 10L);
477+
478+
// Purchased tiers are kept even when the level drops.
479+
assertTrue(data.getUnlockedTiers().contains("magiccobblegenerator_level"));
480+
}
481+
482+
@Test
483+
void testDoesNotRevokeLevelGeneratorWhenFeatureDisabled() {
484+
GeneratorDataObject data = seedLevelGeneratorAndData();
485+
// Feature is off by default.
486+
487+
sgm.checkGeneratorUnlockStatus(island, null, 10L);
488+
489+
assertTrue(data.getUnlockedTiers().contains("magiccobblegenerator_level"));
490+
}
491+
492+
@Test
493+
void testKeepsLevelGeneratorWhenLevelSufficient() {
494+
GeneratorDataObject data = seedLevelGeneratorAndData();
495+
s.setLoseTiersOnLevelLoss(true);
496+
497+
// Island level is still at or above the requirement.
498+
sgm.checkGeneratorUnlockStatus(island, null, 200L);
499+
500+
assertTrue(data.getUnlockedTiers().contains("magiccobblegenerator_level"));
501+
}
502+
433503
/**
434504
* Builds a deployed, non-default cobblestone generator tier mock with no permission/level requirements, for
435505
* prerequisite-generator tests.

0 commit comments

Comments
 (0)