Skip to content

Commit a3fff41

Browse files
authored
Merge pull request #155 from BentoBoxWorld/133-permission-recheck
Revoke permission-gated generators when island owner loses permission (#133)
2 parents a214bb5 + 92cc9a2 commit a3fff41

2 files changed

Lines changed: 104 additions & 0 deletions

File tree

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,47 @@ public void checkGeneratorUnlockStatus(Island island, @Nullable User user, @Null
872872
.
873873
// Now process each generator.
874874
forEach(generator -> this.unlockGenerator(dataObject, user, island, generator));
875+
876+
// Revoke permission based generators that the current owner no longer qualifies for.
877+
// This handles ownership transfer to a player without the required permission (#133).
878+
this.revokePermissionGenerators(island, dataObject, owner);
879+
}
880+
881+
/**
882+
* This method revokes access to permission based generators that the current island owner no longer holds the
883+
* required permissions for. Only the unlocked and active status is revoked; any purchase record is preserved so the
884+
* generator becomes available again if the permission is regained.
885+
* <p>
886+
* Permissions can only be checked reliably for an online owner, so nothing is revoked while the owner is offline.
887+
*
888+
* @param island Island which is targeted for the check.
889+
* @param dataObject Data object that stores island generators.
890+
* @param owner The island owner, or null (e.g. spawn islands).
891+
*/
892+
private void revokePermissionGenerators(@NotNull Island island, @NotNull GeneratorDataObject dataObject,
893+
@Nullable User owner) {
894+
if (owner == null || !owner.isOnline()) {
895+
// Cannot reliably check permissions of an offline owner. Do not revoke anything.
896+
return;
897+
}
898+
899+
List<GeneratorTierObject> revokeList = this.getIslandGeneratorTiers(island.getWorld(), dataObject).stream()
900+
// Only permission gated generators can be revoked this way.
901+
.filter(generator -> !generator.getRequiredPermissions().isEmpty())
902+
// That are currently unlocked.
903+
.filter(generator -> dataObject.getUnlockedTiers().contains(generator.getUniqueId()))
904+
// But whose required permissions the current owner does not have.
905+
.filter(generator -> !Utils.matchAllPermissions(owner, generator.getRequiredPermissions()))
906+
.collect(Collectors.toList());
907+
908+
if (!revokeList.isEmpty()) {
909+
revokeList.forEach(generator -> {
910+
dataObject.getUnlockedTiers().remove(generator.getUniqueId());
911+
dataObject.getActiveGeneratorList().remove(generator.getUniqueId());
912+
});
913+
914+
this.saveGeneratorData(dataObject);
915+
}
875916
}
876917

877918
/**

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

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,69 @@ void testCheckGeneratorUnlockStatus() {
328328
verify(island, times(2)).isSpawn();
329329
}
330330

331+
/**
332+
* Seeds a deployed, permission-gated generator tier into the cache and returns the freshly created island data with
333+
* that tier already unlocked and active, simulating a generator that a previous owner had unlocked.
334+
*/
335+
private GeneratorDataObject seedPermissionGeneratorAndData() {
336+
sgm.addWorld(world);
337+
when(island.getUniqueId()).thenReturn("island-133");
338+
when(island.getWorld()).thenReturn(world);
339+
when(island.isSpawn()).thenReturn(false);
340+
341+
when(generatorTier.getUniqueId()).thenReturn("magiccobblegenerator_perm");
342+
when(generatorTier.isDeployed()).thenReturn(true);
343+
when(generatorTier.isDefaultGenerator()).thenReturn(false);
344+
when(generatorTier.getGeneratorType()).thenReturn(GeneratorType.COBBLESTONE);
345+
when(generatorTier.getRequiredMinIslandLevel()).thenReturn(0L);
346+
when(generatorTier.getRequiredPermissions())
347+
.thenReturn(java.util.Set.of("magiccobblegenerator.gen.perm"));
348+
sgm.loadGeneratorTier(generatorTier, true, null);
349+
350+
GeneratorDataObject data = sgm.getGeneratorData(island);
351+
assertNotNull(data);
352+
data.getUnlockedTiers().add("magiccobblegenerator_perm");
353+
data.getActiveGeneratorList().add("magiccobblegenerator_perm");
354+
return data;
355+
}
356+
357+
@Test
358+
void testCheckGeneratorUnlockStatusRevokesPermissionGeneratorWhenOwnerLacksPermission() {
359+
GeneratorDataObject data = seedPermissionGeneratorAndData();
360+
// Owner is online but does not have the required permission (new owner scenario, #133).
361+
when(mockPlayer.isOnline()).thenReturn(true);
362+
363+
sgm.checkGeneratorUnlockStatus(island, null, null);
364+
365+
assertFalse(data.getUnlockedTiers().contains("magiccobblegenerator_perm"));
366+
assertFalse(data.getActiveGeneratorList().contains("magiccobblegenerator_perm"));
367+
}
368+
369+
@Test
370+
void testCheckGeneratorUnlockStatusKeepsPermissionGeneratorWhenOwnerHasPermission() {
371+
GeneratorDataObject data = seedPermissionGeneratorAndData();
372+
when(mockPlayer.isOnline()).thenReturn(true);
373+
// Owner still has the required permission.
374+
when(mockPlayer.hasPermission(anyString())).thenReturn(true);
375+
376+
sgm.checkGeneratorUnlockStatus(island, null, null);
377+
378+
assertTrue(data.getUnlockedTiers().contains("magiccobblegenerator_perm"));
379+
assertTrue(data.getActiveGeneratorList().contains("magiccobblegenerator_perm"));
380+
}
381+
382+
@Test
383+
void testCheckGeneratorUnlockStatusDoesNotRevokeWhenOwnerOffline() {
384+
GeneratorDataObject data = seedPermissionGeneratorAndData();
385+
// Owner is offline, so permissions cannot be checked reliably and nothing is revoked.
386+
when(mockPlayer.isOnline()).thenReturn(false);
387+
388+
sgm.checkGeneratorUnlockStatus(island, null, null);
389+
390+
assertTrue(data.getUnlockedTiers().contains("magiccobblegenerator_perm"));
391+
assertTrue(data.getActiveGeneratorList().contains("magiccobblegenerator_perm"));
392+
}
393+
331394
@Test
332395
void testGetGeneratorDataIsland() {
333396
assertNotNull(sgm.getGeneratorData(island));

0 commit comments

Comments
 (0)