Be able to delete multiple islands, e.g. when joining a team

This is not fully tested.
This commit is contained in:
tastybento 2023-08-26 17:45:23 -07:00
parent 9e4e5a8c14
commit 6e80c5bdd8
10 changed files with 115 additions and 72 deletions

View File

@ -197,6 +197,12 @@ public class Settings implements ConfigObject {
/*
* Island
*/
// Number of islands
@ConfigComment("The default number of concurrent islands a player may have.")
@ConfigComment("This may be overridden by individual game mode config settings.")
@ConfigEntry(path = "island.cooldown.time.invite")
private int islandNumber = 1;
// Cooldowns
@ConfigComment("How long a player must wait until they can rejoin a team island after being kicked in minutes.")
@ConfigComment("This slows the effectiveness of players repeating challenges")
@ -983,8 +989,8 @@ public class Settings implements ConfigObject {
{
return maximumPoolSize;
}
/**
* Gets safe spot search range.
*
@ -1038,4 +1044,20 @@ public class Settings implements ConfigObject {
{
this.safeSpotSearchRange = safeSpotSearchRange;
}
/**
* @return the islandNumber
* @since 2.0.0
*/
public int getIslandNumber() {
return islandNumber;
}
/**
* @param islandNumber the islandNumber to set
* @since 2.0.0
*/
public void setIslandNumber(int islandNumber) {
this.islandNumber = islandNumber;
}
}

View File

@ -5,8 +5,6 @@ import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.bukkit.util.Vector;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.events.island.IslandEvent;
@ -66,10 +64,7 @@ public class AdminDeleteCommand extends ConfirmableCommand {
private void deletePlayer(User user, UUID targetUUID) {
// Delete player and island
// Get the target's island
Island oldIsland = getIslands().getIsland(getWorld(), targetUUID);
Vector vector = null;
if (oldIsland != null) {
for (Island oldIsland : getIslands().getIslands(getWorld(), targetUUID)) {
// Fire island preclear event
IslandEvent.builder()
.involvedPlayer(user.getUniqueId())
@ -78,21 +73,17 @@ public class AdminDeleteCommand extends ConfirmableCommand {
.oldIsland(oldIsland)
.location(oldIsland.getCenter())
.build();
// Check if player is online and on the island
User target = User.getInstance(targetUUID);
// Remove them from this island (it still exists and will be deleted later)
getIslands().removePlayer(getWorld(), targetUUID);
if (target.isPlayer() && target.isOnline()) {
cleanUp(target);
}
vector = oldIsland.getCenter().toVector();
user.sendMessage("commands.admin.delete.deleted-island", TextVariables.XYZ, Util.xyz(oldIsland.getCenter().toVector()));
getIslands().deleteIsland(oldIsland, true, targetUUID);
}
if (vector == null) {
user.sendMessage("general.success");
} else {
user.sendMessage("commands.admin.delete.deleted-island", TextVariables.XYZ, Util.xyz(vector));
// Check if player is online and on the island
User target = User.getInstance(targetUUID);
// Remove them from this island (it still exists and will be deleted later)
getIslands().removePlayer(getWorld(), targetUUID);
if (target.isPlayer() && target.isOnline()) {
cleanUp(target);
}
user.sendMessage("general.success");
}
private void cleanUp(User target) {

View File

@ -2,8 +2,10 @@ package world.bentobox.bentobox.api.commands.island;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
@ -123,10 +125,9 @@ public class IslandResetCommand extends ConfirmableCommand {
*/
private boolean resetIsland(User user, String name) {
// Get the player's old island
Island oldIsland = getIslands().getIsland(getWorld(), user);
if (oldIsland != null) {
deleteOldIsland(user, oldIsland);
}
Set<Island> oldIslands = getIslands().getIslands(getWorld(), user);
oldIslands.forEach(oldIsland -> deleteOldIsland(user, oldIsland));
user.sendMessage("commands.island.create.creating-island");
// Create new island and then delete the old one
try {
@ -134,7 +135,7 @@ public class IslandResetCommand extends ConfirmableCommand {
.player(user)
.reason(Reason.RESET)
.addon(getAddon())
.oldIsland(oldIsland)
.oldIslands(oldIslands)
.name(name);
if (noPaste) builder.noPaste();
builder.build();

View File

@ -1,6 +1,7 @@
package world.bentobox.bentobox.api.commands.island.team;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import world.bentobox.bentobox.api.commands.CompositeCommand;
@ -150,7 +151,7 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
// Remove the invite
itc.removeInvite(playerUUID);
// Get the player's island - may be null if the player has no island
Island island = getIslands().getIsland(getWorld(), playerUUID);
Set<Island> islands = getIslands().getIslands(getWorld(), playerUUID);
// Get the team's island
Island teamIsland = getIslands().getIsland(getWorld(), prospectiveOwnerUUID);
if (teamIsland == null) {
@ -169,10 +170,9 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
getIslands().setJoinTeam(teamIsland, playerUUID);
// Move player to team's island
getIslands().homeTeleportAsync(getWorld(), user.getPlayer()).thenRun(() -> {
// Delete the old island
if (island != null) {
getIslands().deleteIsland(island, true, user.getUniqueId());
}
// Delete the old islands
islands.forEach(island -> getIslands().deleteIsland(island, true, user.getUniqueId()));
// Put player back into normal mode
user.setGameMode(getIWM().getDefaultGameMode(getWorld()));

View File

@ -13,6 +13,7 @@ import org.bukkit.GameMode;
import org.bukkit.entity.EntityType;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.lists.Flags;
@ -638,9 +639,9 @@ public interface WorldSettings extends ConfigObject {
/**
* Get the number of concurrent islands a player can have in the world
* @return 1 by default
* @since 1.24.2
* @since 2.0.0
*/
default int getConcurrentIslands() {
return 5;
return BentoBox.getInstance().getSettings().getIslandNumber();
}
}

View File

@ -1,5 +1,7 @@
package world.bentobox.bentobox.api.events.island;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
@ -176,7 +178,7 @@ public class IslandEvent extends IslandBaseEvent {
* Event that will fire when an island is named or renamed
* @since 1.24.0
*/
NAME,
NAME,
/**
* Event that will fire when the info command is executed. Allows addons to add to it
* @since 1.24.0
@ -216,6 +218,12 @@ public class IslandEvent extends IslandBaseEvent {
*/
private Island oldIsland;
/**
* Store old islands
* @since 2.0.0
*/
private Set<Island> oldIslands;
/**
* @since 1.13.0
*/
@ -301,6 +309,14 @@ public class IslandEvent extends IslandBaseEvent {
return this;
}
/**
* @param oldIslands2 set of old islands
* @since 2.0.0
*/
public IslandEventBuilder oldIslands(Set<Island> oldIslands2) {
this.oldIslands = new HashSet<>(oldIslands2);
return this;
}
/**
* Allows to set new and old protection range.
@ -334,7 +350,7 @@ public class IslandEvent extends IslandBaseEvent {
this.previousName = previousName;
return this;
}
/**
* Addon that triggered this event, e.g. BSkyBlock
* @param addon Addon.
@ -358,7 +374,7 @@ public class IslandEvent extends IslandBaseEvent {
case ENTER -> new IslandEnterEvent(island, player, admin, location, oldIsland, rawEvent);
case EXIT -> new IslandExitEvent(island, player, admin, location, oldIsland, rawEvent);
case LOCK -> new IslandLockEvent(island, player, admin, location);
case RESET -> new IslandResetEvent(island, player, admin, location, blueprintBundle, oldIsland);
case RESET -> new IslandResetEvent(island, player, admin, location, blueprintBundle, oldIslands);
case RESETTED -> new IslandResettedEvent(island, player, admin, location, oldIsland);
case UNBAN -> new IslandUnbanEvent(island, player, admin, location);
case UNLOCK -> new IslandUnlockEvent(island, player, admin, location);

View File

@ -1,5 +1,7 @@
package world.bentobox.bentobox.api.events.island;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Location;
@ -16,7 +18,7 @@ import world.bentobox.bentobox.database.objects.Island;
*/
public class IslandResetEvent extends IslandBaseEvent {
private final @NonNull Island oldIsland;
private final @NonNull Set<Island> oldIslands;
private @NonNull BlueprintBundle blueprintBundle;
private static final HandlerList handlers = new HandlerList();
@ -29,20 +31,19 @@ public class IslandResetEvent extends IslandBaseEvent {
return handlers;
}
public IslandResetEvent(Island island, UUID player, boolean admin, Location location, @NonNull BlueprintBundle blueprintBundle, @NonNull Island oldIsland) {
public IslandResetEvent(Island island, UUID player, boolean admin, Location location, @NonNull BlueprintBundle blueprintBundle, Set<Island> oldIslands) {
// Final variables have to be declared in the constructor
super(island, player, admin, location);
this.blueprintBundle = blueprintBundle;
// Create a copy of the old island
this.oldIsland = new Island(oldIsland);
this.oldIslands = oldIslands != null ? new HashSet<>(oldIslands) : null;
}
/**
* @since 1.12.0
* @since 2.0.0
*/
@NonNull
public Island getOldIsland() {
return oldIsland;
public Set<Island> getOldIslands() {
return oldIslands;
}
/**

View File

@ -1,6 +1,8 @@
package world.bentobox.bentobox.managers.island;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@ -59,7 +61,7 @@ public class NewIsland {
// Do nothing
return;
}
newIsland(builder.oldIsland2);
newIsland(builder.oldIslands);
}
/**
@ -82,7 +84,7 @@ public class NewIsland {
* @author tastybento
*/
public static class Builder {
private Island oldIsland2;
private Set<Island> oldIslands = new HashSet<>();
private User user2;
private Reason reason2;
private World world2;
@ -91,12 +93,6 @@ public class NewIsland {
private GameModeAddon addon2;
private NewIslandLocationStrategy locationStrategy2;
public Builder oldIsland(Island oldIsland) {
this.oldIsland2 = oldIsland;
this.world2 = oldIsland.getWorld();
return this;
}
public Builder player(User player) {
this.user2 = player;
@ -161,14 +157,22 @@ public class NewIsland {
}
throw new IOException("Insufficient parameters. Must have a user!");
}
/**
* @param oldIslands2 old islands
*/
public Builder oldIslands(Set<Island> oldIslands2) {
oldIslands = new HashSet<>(oldIslands2);
return this;
}
}
/**
* Makes an island.
* @param oldIsland old island that is being replaced, if any
* @param oldIslands old island that is being replaced, if any
* @throws IOException - if an island cannot be made. Message is the tag to show the user.
*/
public void newIsland(Island oldIsland) throws IOException {
public void newIsland(Set<Island> oldIslands) throws IOException {
// Find the new island location
Location next = checkReservedIsland();
if (next == null) {
@ -183,7 +187,7 @@ public class NewIsland {
.island(island)
.location(island.getCenter())
.blueprintBundle(plugin.getBlueprintsManager().getBlueprintBundles(addon).get(name))
.oldIsland(oldIsland)
.oldIslands(oldIslands)
.build();
if (event.getNewEvent().map(IslandBaseEvent::isCancelled).orElse(event.isCancelled())) {
// Do nothing
@ -201,10 +205,10 @@ public class NewIsland {
// Run task to run after creating the island in one tick if island is not being pasted
if (noPaste) {
Bukkit.getScheduler().runTask(plugin, () -> postCreationTask(oldIsland));
Bukkit.getScheduler().runTask(plugin, () -> postCreationTask(oldIslands));
} else {
// Create islands, then run task
plugin.getBlueprintsManager().paste(addon, island, name, () -> postCreationTask(oldIsland));
plugin.getBlueprintsManager().paste(addon, island, name, () -> postCreationTask(oldIslands));
}
// Set default settings
island.setFlagsDefaults();
@ -216,9 +220,9 @@ public class NewIsland {
/**
* Tasks to run after the new island has been created
* @param oldIsland - old island that will be deleted
* @param oldIslands - old island that will be deleted
*/
private void postCreationTask(Island oldIsland) {
private void postCreationTask(Set<Island> oldIslands) {
plugin.getIslands().setPrimaryIsland(user.getPlayer().getUniqueId(), island);
// Set initial spawn point if one exists
if (island.getSpawnPoint(Environment.NORMAL) != null) {
@ -230,7 +234,7 @@ public class NewIsland {
user.getPlayer().setVelocity(new Vector(0, 0, 0));
user.getPlayer().setFallDistance(0F);
// Teleport player after this island is built
plugin.getIslands().homeTeleportAsync(world, user.getPlayer(), true).thenRun(() -> tidyUp(oldIsland));
plugin.getIslands().homeTeleportAsync(world, user.getPlayer(), true).thenRun(() -> tidyUp(oldIslands));
return;
} else {
// let's send him a message so that he knows he can teleport to his island!
@ -240,7 +244,7 @@ public class NewIsland {
// Remove the player again to completely clear the data
User.removePlayer(user.getPlayer());
}
tidyUp(oldIsland);
tidyUp(oldIslands);
}
/**
@ -303,11 +307,10 @@ public class NewIsland {
return null;
}
private void tidyUp(Island oldIsland) {
private void tidyUp(Set<Island> oldIslands) {
// Delete old island
if (oldIsland != null && !plugin.getSettings().isKeepPreviousIslandOnReset()) {
// Delete the old island
plugin.getIslands().deleteIsland(oldIsland, true, user.getUniqueId());
if (!plugin.getSettings().isKeepPreviousIslandOnReset()) {
oldIslands.forEach(old -> plugin.getIslands().deleteIsland(old, true, user.getUniqueId()));
}
// Fire exit event
@ -316,7 +319,7 @@ public class NewIsland {
.reason(reason == Reason.RESET ? Reason.RESETTED : Reason.CREATED)
.island(island)
.location(island.getCenter())
.oldIsland(oldIsland)
.oldIslands(oldIslands)
.build();
}

View File

@ -14,6 +14,7 @@ import static org.mockito.Mockito.when;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
@ -177,6 +178,7 @@ public class IslandResetCommandTest {
when(island.getCenter()).thenReturn(location);
when(island.getHistory()).thenReturn(Collections.emptyList());
when(island.getSpawnPoint()).thenReturn(Collections.emptyMap());
when(im.getIslands(world, user)).thenReturn(Set.of(island));
// Addon
GameModeAddon addon1 = mock(GameModeAddon.class);
@ -244,7 +246,7 @@ public class IslandResetCommandTest {
// Mock up NewIsland builder
NewIsland.Builder builder = mock(NewIsland.Builder.class);
when(builder.player(any())).thenReturn(builder);
when(builder.oldIsland(any())).thenReturn(builder);
when(builder.oldIslands(any())).thenReturn(builder);
when(builder.reason(any())).thenReturn(builder);
when(builder.name(any())).thenReturn(builder);
when(builder.addon(any())).thenReturn(builder);
@ -290,7 +292,7 @@ public class IslandResetCommandTest {
// Mock up NewIsland builder
NewIsland.Builder builder = mock(NewIsland.Builder.class);
when(builder.player(any())).thenReturn(builder);
when(builder.oldIsland(any())).thenReturn(builder);
when(builder.oldIslands(any())).thenReturn(builder);
when(builder.reason(any())).thenReturn(builder);
when(builder.name(any())).thenReturn(builder);
when(builder.addon(any())).thenReturn(builder);
@ -322,7 +324,7 @@ public class IslandResetCommandTest {
// Mock up NewIsland builder
NewIsland.Builder builder = mock(NewIsland.Builder.class);
when(builder.player(any())).thenReturn(builder);
when(builder.oldIsland(any())).thenReturn(builder);
when(builder.oldIslands(any())).thenReturn(builder);
when(builder.reason(any())).thenReturn(builder);
when(builder.name(any())).thenReturn(builder);
when(builder.addon(any())).thenReturn(builder);
@ -358,7 +360,7 @@ public class IslandResetCommandTest {
// Mock up NewIsland builder
NewIsland.Builder builder = mock(NewIsland.Builder.class);
when(builder.player(any())).thenReturn(builder);
when(builder.oldIsland(any())).thenReturn(builder);
when(builder.oldIslands(any())).thenReturn(builder);
when(builder.reason(any())).thenReturn(builder);
when(builder.name(any())).thenReturn(builder);
when(builder.addon(any())).thenReturn(builder);
@ -430,7 +432,7 @@ public class IslandResetCommandTest {
// Mock up NewIsland builder
NewIsland.Builder builder = mock(NewIsland.Builder.class);
when(builder.player(any())).thenReturn(builder);
when(builder.oldIsland(any())).thenReturn(builder);
when(builder.oldIslands(any())).thenReturn(builder);
when(builder.reason(any())).thenReturn(builder);
when(builder.name(any())).thenReturn(builder);
when(builder.addon(any())).thenReturn(builder);

View File

@ -11,7 +11,9 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
@ -68,6 +70,7 @@ public class NewIslandTest {
private User user;
@Mock
private Island oldIsland;
private Set<Island> oldIslands;
@Mock
private IslandsManager im;
@Mock
@ -139,6 +142,7 @@ public class NewIslandTest {
when(builder.location(any())).thenReturn(builder);
when(builder.reason(any())).thenReturn(builder);
when(builder.oldIsland(any())).thenReturn(builder);
when(builder.oldIslands(any())).thenReturn(builder);
when(builder.build()).thenReturn(ice);
when(ice.getBlueprintBundle()).thenReturn(bpb);
when(ire.getBlueprintBundle()).thenReturn(bpb);
@ -152,6 +156,8 @@ public class NewIslandTest {
when(block.isEmpty()).thenReturn(true);
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenReturn(block);
when(oldIsland.getWorld()).thenReturn(world);
oldIslands = new HashSet<>();
oldIslands.add(island);
// Util - return the same location
PowerMockito.mockStatic(Util.class);
@ -189,7 +195,7 @@ public class NewIslandTest {
*/
@Test
public void testBuilder() throws Exception {
NewIsland.builder().addon(addon).name(NAME).player(user).noPaste().reason(Reason.CREATE).oldIsland(oldIsland).build();
NewIsland.builder().addon(addon).name(NAME).player(user).noPaste().reason(Reason.CREATE).oldIslands(oldIslands).build();
// Verifications
verify(im).save(eq(island));
verify(island).setFlagsDefaults();
@ -208,7 +214,7 @@ public class NewIslandTest {
@Test
public void testBuilderReset() throws Exception {
when(builder.build()).thenReturn(ire);
NewIsland.builder().addon(addon).name(NAME).player(user).noPaste().reason(Reason.RESET).oldIsland(oldIsland).build();
NewIsland.builder().addon(addon).name(NAME).player(user).noPaste().reason(Reason.RESET).oldIslands(oldIslands).build();
// Verifications
verify(im).save(eq(island));
verify(island).setFlagsDefaults();
@ -261,7 +267,7 @@ public class NewIslandTest {
@Test
public void testBuilderHasIsland() throws Exception {
when(im.hasIsland(any(), any(User.class))).thenReturn(true);
NewIsland.builder().addon(addon).name(NAME).player(user).noPaste().reason(Reason.CREATE).oldIsland(oldIsland).build();
NewIsland.builder().addon(addon).name(NAME).player(user).noPaste().reason(Reason.CREATE).oldIslands(oldIslands).build();
// Verifications
verify(im).save(eq(island));
verify(island).setFlagsDefaults();