This commit is contained in:
tastybento 2024-04-28 16:55:40 +00:00 committed by GitHub
commit 1a258d9925
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
61 changed files with 1049 additions and 1322 deletions

25
pom.xml
View File

@ -88,7 +88,7 @@
<!-- Do not change unless you want different name for local builds. -->
<build.number>-LOCAL</build.number>
<!-- This allows to change between versions. -->
<build.version>2.3.0</build.version>
<build.version>2.4.0</build.version>
<sonar.organization>bentobox-world</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
<server.jars>${project.basedir}/lib</server.jars>
@ -195,6 +195,11 @@
<name>Lumine Releases</name>
<url>https://mvn.lumine.io/repository/maven-public/</url>
</repository>
<!-- For Multipaper -->
<repository>
<id>clojars</id>
<url>https://repo.clojars.org/</url>
</repository>
</repositories>
<dependencies>
@ -364,6 +369,13 @@
<version>3.6.1</version>
<scope>provided</scope>
</dependency>
<!-- Multipaper -->
<dependency>
<groupId>com.github.puregero</groupId>
<artifactId>multilib</artifactId>
<version>1.1.12</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
@ -486,9 +498,10 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.1-SNAPSHOT</version>
<version>3.4.0</version>
<configuration>
<minimizeJar>true</minimizeJar>
<dependencyReducedPomLocation>${project.build.directory}/dependency-reduced-pom.xml</dependencyReducedPomLocation>
<relocations>
<relocation>
<pattern>org.bstats</pattern>
@ -500,9 +513,13 @@
</relocation>
<relocation>
<pattern>io.papermc.lib</pattern>
<shadedPattern>world.bentobox.bentobox.paperlib</shadedPattern> <!-- Replace this -->
<shadedPattern>world.bentobox.bentobox.paperlib</shadedPattern>
</relocation>
</relocations>
<relocation>
<pattern>com.github.puregero.multilib</pattern>
<shadedPattern>world.bentobox.bentobox.multilib</shadedPattern>
</relocation>
</relocations>
<artifactSet>
<excludes>
<exclude>org.apache.maven.shared:*</exclude>

View File

@ -59,7 +59,6 @@ public class BStats {
registerGameModeAddonsChart();
registerHooksChart();
registerPlayersPerServerChart();
registerFlagsDisplayModeChart();
// Single Line charts
registerIslandsCountChart();
@ -171,27 +170,6 @@ public class BStats {
}));
}
/**
* Sends the "flags display mode" of all the online players.
* @since 1.6.0
*/
private void registerFlagsDisplayModeChart() {
metrics.addCustomChart(new AdvancedPie("flagsDisplayMode", () -> {
Map<String, Integer> values = new HashMap<>();
Bukkit.getOnlinePlayers().forEach(player -> {
Flag.Mode mode = plugin.getPlayers().getFlagsDisplayMode(player.getUniqueId());
if (values.containsKey(mode.name())) {
values.put(mode.name(), values.get(mode.name()) + 1);
} else {
values.put(mode.name(), 1);
}
});
return values;
}));
}
/**
* Sends the enabled addons (except GameModeAddons) of this server as bar chart.
* @since 1.17.1

View File

@ -210,20 +210,6 @@ public class BentoBox extends JavaPlugin implements Listener {
return;
}
// Save islands & players data every X minutes
Bukkit.getScheduler().runTaskTimer(instance, () -> {
if (!playersManager.isSaveTaskRunning()) {
playersManager.saveAll(true);
} else {
getLogger().warning("Tried to start a player data save task while the previous auto save was still running!");
}
if (!islandsManager.isSaveTaskRunning()) {
islandsManager.saveAll(true);
} else {
getLogger().warning("Tried to start a island data save task while the previous auto save was still running!");
}
}, getSettings().getDatabaseBackupPeriod() * 20 * 60L, getSettings().getDatabaseBackupPeriod() * 20 * 60L);
// Make sure all flag listeners are registered.
flagsManager.registerListeners();
@ -433,7 +419,7 @@ public class BentoBox extends JavaPlugin implements Listener {
* @return the ranksManager
* @deprecated Just use {@code RanksManager.getInstance()}
*/
@Deprecated(since = "2.0.0")
@Deprecated(since = "2.0.0", forRemoval = true)
public RanksManager getRanksManager() {
return RanksManager.getInstance();
}

View File

@ -21,6 +21,8 @@ import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.event.Listener;
import com.github.puregero.multilib.MultiLib;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.request.AddonRequestHandler;
import world.bentobox.bentobox.api.flags.Flag;
@ -45,6 +47,8 @@ public abstract class Addon {
protected Addon() {
state = State.DISABLED;
// If the config is updated, update the config.
MultiLib.onString(getPlugin(), "bentobox-config-update", v -> this.reloadConfig());
}
/**

View File

@ -8,6 +8,8 @@ import org.bukkit.generator.ChunkGenerator;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import com.github.puregero.multilib.MultiLib;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.configuration.WorldSettings;
import world.bentobox.bentobox.util.Util;
@ -129,7 +131,10 @@ public abstract class GameModeAddon extends Addon {
* in-game and need to be saved.
* @since 1.4.0
*/
public abstract void saveWorldSettings();
public void saveWorldSettings() {
// Inform other servers
MultiLib.notify("bentobox-config-update", "");
}
/**
* Defines if the game mode uses the latest {@link ChunkGenerator} API or

View File

@ -1,61 +0,0 @@
package world.bentobox.bentobox.api.commands.admin;
import java.util.List;
import java.util.UUID;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
public class AdminEmptyTrashCommand extends ConfirmableCommand {
/**
* Clear trash for player, or all unowned islands in trash
* @param parent - admin command
* @since 1.3.0
*/
public AdminEmptyTrashCommand(CompositeCommand parent) {
super(parent, "emptytrash");
}
@Override
public void setup() {
setPermission("admin.trash");
setOnlyPlayer(false);
setParametersHelp("commands.admin.emptytrash.parameters");
setDescription("commands.admin.emptytrash.description");
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (args.size() > 1) {
// Show help
showHelp(this, user);
return false;
}
// Get target player
UUID targetUUID = args.isEmpty() ? null : getPlayers().getUUID(args.get(0));
if (!args.isEmpty() && targetUUID == null) {
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
return false;
}
// Remove trash for this player
final List<Island> islands = getIslands().getQuarantinedIslandByUser(getWorld(), targetUUID);
if (islands.isEmpty()) {
if (args.isEmpty()) {
user.sendMessage("commands.admin.trash.no-unowned-in-trash");
} else {
user.sendMessage("commands.admin.trash.no-islands-in-trash");
}
return false;
} else {
this.askConfirmation(user, () -> {
getIslands().deleteQuarantinedIslandByUser(getWorld(), targetUUID);
user.sendMessage("commands.admin.emptytrash.success");
});
return true;
}
}
}

View File

@ -49,9 +49,6 @@ public class AdminInfoCommand extends CompositeCommand {
Island island = getIslands().getIsland(getWorld(), targetUUID);
if (island != null) {
new IslandInfo(island).showAdminInfo(user, getAddon());
if (!getIslands().getQuarantinedIslandByUser(getWorld(), targetUUID).isEmpty()) {
user.sendMessage("commands.admin.info.islands-in-trash");
}
return true;
} else {
user.sendMessage("general.errors.player-has-no-island");

View File

@ -16,7 +16,6 @@ import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.api.flags.Flag.Mode;
import world.bentobox.bentobox.api.flags.Flag.Type;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.panels.builders.TabbedPanelBuilder;
@ -206,11 +205,9 @@ public class AdminSettingsCommand extends CompositeCommand {
switch (f.getType()) {
case PROTECTION -> {
island.setFlag(f, rank);
getIslands().save(island);
}
case SETTING -> {
island.setSettingsFlag(f, activeState);
getIslands().save(island);
}
case WORLD_SETTING -> f.setSetting(getWorld(), activeState);
default -> {
@ -226,12 +223,11 @@ public class AdminSettingsCommand extends CompositeCommand {
user.sendMessage("general.errors.use-in-game");
return false;
}
getPlayers().setFlagsDisplayMode(user.getUniqueId(), Mode.EXPERT);
if (args.isEmpty()) {
new TabbedPanelBuilder()
.user(user)
.world(getWorld())
.tab(1, new SettingsTab(getWorld(), user, Flag.Type.WORLD_SETTING))
.tab(1, new SettingsTab(getWorld(), user, Flag.Type.WORLD_SETTING, Flag.Mode.EXPERT))
.tab(2, new WorldDefaultSettingsTab(getWorld(), user))
.startingSlot(1)
.size(54)
@ -242,8 +238,8 @@ public class AdminSettingsCommand extends CompositeCommand {
new TabbedPanelBuilder()
.user(user)
.world(island.getWorld())
.island(island).tab(1, new SettingsTab(user, Flag.Type.PROTECTION))
.tab(2, new SettingsTab(user, Flag.Type.SETTING))
.island(island).tab(1, new SettingsTab(getWorld(), user, Flag.Type.PROTECTION, Flag.Mode.EXPERT))
.tab(2, new SettingsTab(getWorld(), user, Flag.Type.SETTING, Flag.Mode.EXPERT))
.startingSlot(1)
.size(54)
.build().openPanel();

View File

@ -1,87 +0,0 @@
package world.bentobox.bentobox.api.commands.admin;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.apache.commons.lang.math.NumberUtils;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.util.Util;
public class AdminSwitchtoCommand extends ConfirmableCommand {
private UUID targetUUID;
private @NonNull List<Island> islands;
/**
* Switch player's island to the numbered one in trash
* @param parent - admin command
* @since 1.3.0
*/
public AdminSwitchtoCommand(CompositeCommand parent) {
super(parent, "switchto");
islands = new ArrayList<>();
}
@Override
public void setup() {
setPermission("admin.switchto");
setOnlyPlayer(false);
setParametersHelp("commands.admin.switchto.parameters");
setDescription("commands.admin.switchto.description");
}
@Override
public boolean canExecute(User user, String label, List<String> args) {
if (args.size() != 2) {
// Show help
showHelp(this, user);
return false;
}
// Get target player
targetUUID = Util.getUUID(args.get(0));
if (targetUUID == null) {
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
return false;
}
// Check island number
islands = getIslands().getQuarantinedIslandByUser(getWorld(), targetUUID);
if (islands.isEmpty()) {
user.sendMessage("commands.admin.trash.no-islands-in-trash");
return false;
}
return true;
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (NumberUtils.isDigits(args.get(1))) {
try {
int n = Integer.parseInt(args.get(1));
if (n < 1 || n > islands.size()) {
user.sendMessage("commands.admin.switchto.out-of-range", TextVariables.NUMBER, String.valueOf(islands.size()), TextVariables.LABEL, getTopLabel());
return false;
}
this.askConfirmation(user, () -> {
if (getIslands().switchIsland(getWorld(), targetUUID, islands.get(n -1))) {
user.sendMessage("commands.admin.switchto.success");
} else {
user.sendMessage("commands.admin.switchto.cannot-switch");
}
});
return true;
} catch (Exception e) {
showHelp(this, user);
return false;
}
}
return true;
}
}

View File

@ -1,73 +0,0 @@
package world.bentobox.bentobox.api.commands.admin;
import java.util.List;
import java.util.UUID;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.util.IslandInfo;
public class AdminTrashCommand extends CompositeCommand {
/**
* A command for viewing islands in the database trash
* @param parent - admin command
* @since 1.3.0
*/
public AdminTrashCommand(CompositeCommand parent) {
super(parent, "trash");
}
@Override
public void setup() {
setPermission("admin.trash");
setOnlyPlayer(false);
setParametersHelp("commands.admin.trash.parameters");
setDescription("commands.admin.trash.description");
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (args.size() > 1) {
// Show help
showHelp(this, user);
return false;
}
// Get target player
UUID targetUUID = args.isEmpty() ? null : getPlayers().getUUID(args.get(0));
if (!args.isEmpty() && targetUUID == null) {
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
return false;
}
// Show trash can info for this player
List<Island> islands = getIslands().getQuarantinedIslandByUser(getWorld(), targetUUID);
if (islands.isEmpty()) {
if (args.isEmpty()) {
user.sendMessage("commands.admin.trash.no-unowned-in-trash");
} else {
user.sendMessage("commands.admin.trash.no-islands-in-trash");
}
return false;
} else {
if (targetUUID == null) {
showTrash(user, islands);
} else {
getIslands().getQuarantineCache().values().forEach(v -> showTrash(user, v));
}
return true;
}
}
private void showTrash(User user, List<Island> islands) {
user.sendMessage("commands.admin.trash.title");
for (int i = 0; i < islands.size(); i++) {
user.sendMessage("commands.admin.trash.count", TextVariables.NUMBER, String.valueOf(i+1));
new IslandInfo(islands.get(i)).showInfo(user);
}
user.sendMessage("commands.admin.trash.use-switch", TextVariables.LABEL, getTopLabel());
user.sendMessage("commands.admin.trash.use-emptytrash", TextVariables.LABEL, getTopLabel());
}
}

View File

@ -116,7 +116,6 @@ public class AdminUnregisterCommand extends ConfirmableCommand {
targetIsland.getMembers().clear();
targetIsland.log(new LogEntry.Builder("UNREGISTER").data("player", targetUUID.toString())
.data("admin", user.getUniqueId().toString()).build());
getIslands().save(targetIsland);
user.sendMessage("commands.admin.unregister.unregistered-island", TextVariables.XYZ, Util.xyz(targetIsland.getCenter().toVector()),
TextVariables.NAME, getPlayers().getName(targetUUID));
}

View File

@ -40,7 +40,6 @@ public class NamePrompt extends StringPrompt {
@Override
public Prompt acceptInput(@NonNull ConversationContext context, String input) {
if (island.renameHome(oldName, input)) {
plugin.getIslands().save(island);
Bukkit.getScheduler().runTask(plugin, () -> user.sendMessage("general.success"));
} else {
Bukkit.getScheduler().runTask(plugin, () -> user.sendMessage("commands.island.renamehome.already-exists"));

View File

@ -49,7 +49,8 @@ public class IslandSettingsCommand extends CompositeCommand {
.user(user)
.island(island)
.world(island.getWorld())
.tab(1, new SettingsTab(user, Flag.Type.PROTECTION)).tab(2, new SettingsTab(user, Flag.Type.SETTING))
.tab(1, new SettingsTab(getWorld(), user, Flag.Type.PROTECTION))
.tab(2, new SettingsTab(getWorld(), user, Flag.Type.SETTING))
.startingSlot(1)
.size(54)
.hideIfEmpty()

View File

@ -1,95 +0,0 @@
package world.bentobox.bentobox.api.commands.island.team;
import java.util.Objects;
import java.util.UUID;
import world.bentobox.bentobox.database.objects.Island;
/**
* Represents an invite
* @author tastybento
* @since 1.8.0
*/
public class Invite {
/**
* Type of invitation
*
*/
public enum Type {
COOP,
TEAM,
TRUST
}
private final Type type;
private final UUID inviter;
private final UUID invitee;
private final Island island;
/**
* @param type - invitation type, e.g., coop, team, trust
* @param inviter - UUID of inviter
* @param invitee - UUID of invitee
* @param island - the island this invite is for
*/
public Invite(Type type, UUID inviter, UUID invitee, Island island) {
this.type = type;
this.inviter = inviter;
this.invitee = invitee;
this.island = island;
}
/**
* @return the type
*/
public Type getType() {
return type;
}
/**
* @return the inviter
*/
public UUID getInviter() {
return inviter;
}
/**
* @return the invitee
*/
public UUID getInvitee() {
return invitee;
}
/**
* @return the island
*/
public Island getIsland() {
return island;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return Objects.hash(invitee, inviter, type);
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Invite other)) {
return false;
}
return Objects.equals(invitee, other.invitee) && Objects.equals(inviter, other.inviter) && type == other.type;
}
}

View File

@ -1,9 +1,7 @@
package world.bentobox.bentobox.api.commands.island.team;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@ -16,17 +14,13 @@ import world.bentobox.bentobox.api.events.team.TeamEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.panels.reader.PanelTemplateRecord.TemplateItem;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.Database;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.database.objects.TeamInvite;
import world.bentobox.bentobox.managers.RanksManager;
public class IslandTeamCommand extends CompositeCommand {
/**
* Invited list. Key is the invited party, value is the invite.
* @since 1.8.0
*/
private final Map<UUID, Invite> inviteMap;
private IslandTeamKickCommand kickCommand;
private IslandTeamLeaveCommand leaveCommand;
@ -51,9 +45,11 @@ public class IslandTeamCommand extends CompositeCommand {
private IslandTeamTrustCommand trustCommand;
private final Database<TeamInvite> handler;
public IslandTeamCommand(CompositeCommand parent) {
super(parent, "team");
inviteMap = new HashMap<>();
handler = new Database<>(parent.getAddon(), TeamInvite.class);
}
@Override
@ -139,8 +135,8 @@ public class IslandTeamCommand extends CompositeCommand {
* @param invitee - uuid of invitee
* @since 1.8.0
*/
public void addInvite(Invite.Type type, @NonNull UUID inviter, @NonNull UUID invitee, @NonNull Island island) {
inviteMap.put(invitee, new Invite(type, inviter, invitee, island));
public void addInvite(TeamInvite.Type type, @NonNull UUID inviter, @NonNull UUID invitee, @NonNull Island island) {
handler.saveObjectAsync(new TeamInvite(type, inviter, invitee, island.getUniqueId()));
}
/**
@ -150,7 +146,7 @@ public class IslandTeamCommand extends CompositeCommand {
* @since 1.8.0
*/
public boolean isInvited(@NonNull UUID invitee) {
return inviteMap.containsKey(invitee);
return handler.objectExists(invitee.toString());
}
/**
@ -161,7 +157,7 @@ public class IslandTeamCommand extends CompositeCommand {
*/
@Nullable
public UUID getInviter(UUID invitee) {
return isInvited(invitee) ? inviteMap.get(invitee).getInviter() : null;
return isInvited(invitee) ? handler.loadObject(invitee.toString()).getInviter() : null;
}
/**
@ -171,8 +167,8 @@ public class IslandTeamCommand extends CompositeCommand {
* @since 1.8.0
*/
@Nullable
public Invite getInvite(UUID invitee) {
return inviteMap.get(invitee);
public TeamInvite getInvite(UUID invitee) {
return handler.loadObject(invitee.toString());
}
/**
@ -181,7 +177,7 @@ public class IslandTeamCommand extends CompositeCommand {
* @since 1.8.0
*/
public void removeInvite(@NonNull UUID invitee) {
inviteMap.remove(invitee);
handler.deleteID(invitee.toString());
}
/**

View File

@ -8,10 +8,10 @@ import java.util.UUID;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.island.team.Invite.Type;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.database.objects.TeamInvite.Type;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.bentobox.util.Util;
@ -99,7 +99,7 @@ public class IslandTeamCoopCommand extends CompositeCommand {
// Put the invited player (key) onto the list with inviter (value)
// If someone else has invited a player, then this invite will overwrite the
// previous invite!
itc.addInvite(Invite.Type.COOP, user.getUniqueId(), target.getUniqueId(), island);
itc.addInvite(Type.COOP, user.getUniqueId(), target.getUniqueId(), island);
user.sendMessage("commands.island.team.invite.invitation-sent", TextVariables.NAME, target.getName());
// Send message to online player
target.sendMessage("commands.island.team.coop.name-has-invited-you", TextVariables.NAME,

View File

@ -22,7 +22,6 @@ import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.commands.island.team.Invite.Type;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.panels.Panel;
import world.bentobox.bentobox.api.panels.PanelItem;
@ -34,6 +33,8 @@ import world.bentobox.bentobox.api.panels.reader.ItemTemplateRecord.ActionRecord
import world.bentobox.bentobox.api.panels.reader.PanelTemplateRecord.TemplateItem;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.database.objects.TeamInvite;
import world.bentobox.bentobox.database.objects.TeamInvite.Type;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.bentobox.util.Util;
@ -208,7 +209,7 @@ public class IslandTeamGUI {
private PanelItem createInvitedButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot) {
PanelItemBuilder builder = new PanelItemBuilder();
if (parent.isInvited(user.getUniqueId()) && user.hasPermission(parent.getAcceptCommand().getPermission())) {
Invite invite = parent.getInvite(user.getUniqueId());
TeamInvite invite = parent.getInvite(user.getUniqueId());
if (invite == null) {
return this.getBlankBorder();
}
@ -224,7 +225,8 @@ public class IslandTeamGUI {
return builder.build();
}
private void createInviteClickHandler(PanelItemBuilder builder, Invite invite, @NonNull List<ActionRecords> list) {
private void createInviteClickHandler(PanelItemBuilder builder, TeamInvite invite,
@NonNull List<ActionRecords> list) {
Type type = invite.getType();
builder.clickHandler((panel, user, clickType, clickSlot) -> {
if (list.stream().noneMatch(ar -> clickType.equals(ar.clickType()))) {

View File

@ -5,13 +5,14 @@ import java.util.UUID;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.commands.island.team.Invite.Type;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.island.IslandEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.database.objects.TeamInvite;
import world.bentobox.bentobox.database.objects.TeamInvite.Type;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.bentobox.util.Util;
@ -49,7 +50,7 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
user.sendMessage(INVALID_INVITE);
return false;
}
Invite invite = itc.getInvite(playerUUID);
TeamInvite invite = itc.getInvite(playerUUID);
if (invite.getType().equals(Type.TEAM)) {
// Check rank to of inviter
Island island = getIslands().getIsland(getWorld(), prospectiveOwnerUUID);
@ -78,7 +79,7 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
@Override
public boolean execute(User user, String label, List<String> args) {
// Get the invite
Invite invite = itc.getInvite(user.getUniqueId());
TeamInvite invite = itc.getInvite(user.getUniqueId());
switch (invite.getType()) {
case COOP -> askConfirmation(user, () -> acceptCoopInvite(user, invite));
case TRUST -> askConfirmation(user, () -> acceptTrustInvite(user, invite));
@ -94,11 +95,11 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
return true;
}
void acceptTrustInvite(User user, Invite invite) {
void acceptTrustInvite(User user, TeamInvite invite) {
// Remove the invite
itc.removeInvite(user.getUniqueId());
User inviter = User.getInstance(invite.getInviter());
Island island = invite.getIsland();
Island island = getIslands().getIslandById(invite.getIslandID()).orElse(null);
if (island != null) {
if (island.getMemberSet(RanksManager.TRUSTED_RANK, false).size() > getIslands().getMaxMembers(island,
RanksManager.TRUSTED_RANK)) {
@ -120,11 +121,11 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
}
}
void acceptCoopInvite(User user, Invite invite) {
void acceptCoopInvite(User user, TeamInvite invite) {
// Remove the invite
itc.removeInvite(user.getUniqueId());
User inviter = User.getInstance(invite.getInviter());
Island island = invite.getIsland();
Island island = getIslands().getIslandById(invite.getIslandID()).orElse(null);
if (island != null) {
if (island.getMemberSet(RanksManager.COOP_RANK, false).size() > getIslands().getMaxMembers(island,
RanksManager.COOP_RANK)) {
@ -146,13 +147,13 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
}
}
void acceptTeamInvite(User user, Invite invite) {
void acceptTeamInvite(User user, TeamInvite invite) {
// Remove the invite
itc.removeInvite(user.getUniqueId());
// Get the player's island - may be null if the player has no island
List<Island> islands = getIslands().getIslands(getWorld(), user.getUniqueId());
// Get the team's island
Island teamIsland = invite.getIsland();
Island teamIsland = getIslands().getIslandById(invite.getIslandID()).orElse(null);
if (teamIsland == null) {
user.sendMessage(INVALID_INVITE);
return;
@ -196,7 +197,6 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
inviter.sendMessage("commands.island.team.invite.accept.name-joined-your-island", TextVariables.NAME,
user.getName(), TextVariables.DISPLAY_NAME, user.getDisplayName());
}
getIslands().save(teamIsland);
// Fire event
TeamEvent.builder().island(teamIsland).reason(TeamEvent.Reason.JOINED).involvedPlayer(user.getUniqueId())
.build();

View File

@ -10,13 +10,13 @@ import java.util.UUID;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.island.team.Invite.Type;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.panels.reader.PanelTemplateRecord.TemplateItem;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.database.objects.TeamInvite.Type;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.PlayersManager;
import world.bentobox.bentobox.managers.RanksManager;
@ -166,7 +166,7 @@ public class IslandTeamInviteCommand extends CompositeCommand {
}
// Put the invited player (key) onto the list with inviter (value)
// If someone else has invited a player, then this invite will overwrite the previous invite!
itc.addInvite(Invite.Type.TEAM, user.getUniqueId(), invitedPlayer.getUniqueId(), island);
itc.addInvite(Type.TEAM, user.getUniqueId(), invitedPlayer.getUniqueId(), island);
user.sendMessage("commands.island.team.invite.invitation-sent", TextVariables.NAME, invitedPlayer.getName(), TextVariables.DISPLAY_NAME, invitedPlayer.getDisplayName());
// Send message to online player
invitedPlayer.sendMessage("commands.island.team.invite.name-has-invited-you", TextVariables.NAME, user.getName(), TextVariables.DISPLAY_NAME, user.getDisplayName());

View File

@ -14,6 +14,7 @@ import world.bentobox.bentobox.api.events.team.TeamEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.bentobox.util.Util;
@ -91,7 +92,6 @@ public class IslandTeamSetownerCommand extends CompositeCommand {
IslandEvent.builder().island(island).involvedPlayer(user.getUniqueId()).admin(false)
.reason(IslandEvent.Reason.RANK_CHANGE).rankChange(RanksManager.OWNER_RANK, RanksManager.SUB_OWNER_RANK)
.build();
getIslands().save(island);
return true;
}

View File

@ -8,10 +8,10 @@ import java.util.UUID;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.island.team.Invite.Type;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.database.objects.TeamInvite.Type;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.bentobox.util.Util;

View File

@ -388,21 +388,24 @@ public class Flag implements Comparable<Flag> {
if (!user.isOp() && invisible) {
return null;
}
// Start the flag conversion
PanelItemBuilder pib = new PanelItemBuilder()
.icon(ItemParser.parse(user.getTranslationOrNothing(this.getIconReference()), new ItemStack(icon)))
.name(user.getTranslation("protection.panel.flag-item.name-layout", TextVariables.NAME, user.getTranslation(getNameReference())))
.name(user.getTranslation("protection.panel.flag-item.name-layout", TextVariables.NAME,
user.getTranslation(getNameReference())))
.clickHandler(clickHandler)
.invisible(invisible);
if (hasSubPanel()) {
pib.description(user.getTranslation("protection.panel.flag-item.menu-layout", TextVariables.DESCRIPTION, user.getTranslation(getDescriptionReference())));
return pib.build();
}
return switch (getType()) {
case PROTECTION -> createProtectionFlag(plugin, user, island, pib).build();
case SETTING -> createSettingFlag(user, island, pib).build();
case WORLD_SETTING -> createWorldSettingFlag(user, world, pib).build();
};
}
private PanelItemBuilder createWorldSettingFlag(User user, World world, PanelItemBuilder pib) {
@ -429,19 +432,24 @@ public class Flag implements Comparable<Flag> {
private PanelItemBuilder createProtectionFlag(BentoBox plugin, User user, Island island, PanelItemBuilder pib) {
if (island != null) {
int y = island.getFlag(this);
// Protection flag
pib.description(user.getTranslation("protection.panel.flag-item.description-layout",
TextVariables.DESCRIPTION, user.getTranslation(getDescriptionReference())));
RanksManager.getInstance().getRanks().forEach((reference, score) -> {
if (score > RanksManager.BANNED_RANK && score < island.getFlag(this)) {
if (score > RanksManager.BANNED_RANK && score < y) {
pib.description(user.getTranslation("protection.panel.flag-item.blocked-rank") + user.getTranslation(reference));
} else if (score <= RanksManager.OWNER_RANK && score > island.getFlag(this)) {
} else if (score <= RanksManager.OWNER_RANK && score > y) {
pib.description(user.getTranslation("protection.panel.flag-item.allowed-rank") + user.getTranslation(reference));
} else if (score == island.getFlag(this)) {
} else if (score == y) {
pib.description(user.getTranslation("protection.panel.flag-item.minimal-rank") + user.getTranslation(reference));
}
});
}
return pib;
}
@ -469,7 +477,7 @@ public class Flag implements Comparable<Flag> {
public Set<Flag> getSubflags() {
return subflags;
}
/**
* Set the name of this flag for a specified locale. This enables the flag's name to be assigned via API. It will not be stored anywhere
* and must be rewritten using this call every time the flag is built.
@ -482,7 +490,7 @@ public class Flag implements Comparable<Flag> {
public boolean setTranslatedName(Locale locale, String name) {
return BentoBox.getInstance().getLocalesManager().setTranslation(locale, getNameReference(), name);
}
/**
* Set the name of this flag for a specified locale. This enables the flag's name to be assigned via API. It will not be stored anywhere
* and must be rewritten using this call every time the flag is built.

View File

@ -74,6 +74,7 @@ public class TabbedPanel extends Panel implements PanelListener {
* @param page - the page of the tab to show (if multi paged)
*/
public void openPanel(int activeTab, int page) {
if (!tpb.getTabs().containsKey(activeTab)) {
// Request to open a non-existent tab
throw new InvalidParameterException("Attempt to open a non-existent tab in a tabbed panel. Missing tab #" + activeTab);
@ -88,21 +89,17 @@ public class TabbedPanel extends Panel implements PanelListener {
TreeMap<Integer, PanelItem> items = new TreeMap<>();
// Get the tab
Tab tab = tpb.getTabs().get(activeTab);
// Remove any tabs that have no items, if required
if (tpb.isHideIfEmpty()) {
tpb.getTabs().values().removeIf(t -> !t.equals(tab) && t.getPanelItems().stream().noneMatch(Objects::nonNull));
}
// Set up the tabbed header
setupHeader(tab, items);
// Show the active tab
if (tpb.getTabs().containsKey(activeTab)) {
List<PanelItem> panelItems = tab.getPanelItems();
// Adds the flag items
panelItems.stream().filter(Objects::nonNull).skip(page * ITEMS_PER_PAGE).limit(page * ITEMS_PER_PAGE + ITEMS_PER_PAGE).forEach(i -> items.put(items.lastKey() + 1, i));
// set up the footer
setupFooter(items);
// Add forward and backward icons
@ -182,6 +179,7 @@ public class TabbedPanel extends Panel implements PanelListener {
// Reset the closed flag
closed = false;
}
}
/**

View File

@ -13,6 +13,7 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
@ -41,6 +42,7 @@ import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.adapters.Adapter;
import world.bentobox.bentobox.database.objects.adapters.LogEntryListAdapter;
import world.bentobox.bentobox.lists.Flags;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.bentobox.util.Pair;
import world.bentobox.bentobox.util.Util;
@ -56,7 +58,7 @@ import world.bentobox.bentobox.util.Util;
public class Island implements DataObject, MetaDataAble {
@Expose
private boolean primary;
private Set<UUID> primaries = new HashSet<>();
/**
* Set to true if this data object has been changed since being loaded from the
@ -243,7 +245,6 @@ public class Island implements DataObject, MetaDataAble {
range = BentoBox.getInstance().getIWM().getIslandDistance(world);
this.protectionRange = protectionRange;
this.maxEverProtectionRange = protectionRange;
this.setChanged();
}
/**
@ -290,6 +291,7 @@ public class Island implements DataObject, MetaDataAble {
this.updatedDate = island.getUpdatedDate();
this.world = island.getWorld();
this.bonusRanges.addAll(island.getBonusRanges());
this.primaries.addAll(island.getPrimaries());
this.setChanged();
}
@ -304,8 +306,10 @@ public class Island implements DataObject, MetaDataAble {
* @param playerUUID - the player's UUID
*/
public void addMember(@NonNull UUID playerUUID) {
setRank(playerUUID, RanksManager.MEMBER_RANK);
setChanged();
if (getRank(playerUUID) != RanksManager.MEMBER_RANK) {
setRank(playerUUID, RanksManager.MEMBER_RANK);
setChanged();
}
}
/**
@ -320,9 +324,12 @@ public class Island implements DataObject, MetaDataAble {
* @return {@code true}
*/
public boolean ban(@NonNull UUID issuer, @NonNull UUID target) {
setRank(target, RanksManager.BANNED_RANK);
log(new LogEntry.Builder("BAN").data("player", target.toString()).data("issuer", issuer.toString()).build());
setChanged();
if (getRank(target) != RanksManager.BANNED_RANK) {
setRank(target, RanksManager.BANNED_RANK);
log(new LogEntry.Builder("BAN").data("player", target.toString()).data("issuer", issuer.toString())
.build());
setChanged();
}
return true;
}
@ -1005,25 +1012,30 @@ public class Island implements DataObject, MetaDataAble {
* @param playerUUID - uuid of player
*/
public void removeMember(UUID playerUUID) {
members.remove(playerUUID);
setChanged();
if (members.remove(playerUUID) != null) {
setChanged();
}
}
/**
* @param center the center to set
*/
public void setCenter(@NonNull Location center) {
this.world = center.getWorld();
this.center = center;
setChanged();
if (this.center == null || !center.getWorld().equals(this.center.getWorld()) || !center.equals(this.center)) {
this.world = center.getWorld();
this.center = center;
setChanged();
}
}
/**
* @param createdDate - the createdDate to sets
*/
public void setCreatedDate(long createdDate) {
this.createdDate = createdDate;
setChanged();
if (this.createdDate != createdDate) {
this.createdDate = createdDate;
setChanged();
}
}
/**
@ -1038,21 +1050,23 @@ public class Island implements DataObject, MetaDataAble {
}
/**
* Set the Island Guard flag rank Also specify whether subflags are affected by
* this method call
* Set the Island Guard flag rank and set any subflags
*
* @param flag - flag
* @param value - Use RanksManager settings, e.g. RanksManager.MEMBER
* @param doSubflags - whether to set subflags
* @return true if this causes a flag change
*/
public void setFlag(Flag flag, int value, boolean doSubflags) {
flags.put(flag.getID(), value);
if (flags.containsKey(flag.getID()) && flags.get(flag.getID()) != value) {
flags.put(flag.getID(), value);
setChanged();
}
// Subflag support
if (doSubflags && flag.hasSubflags()) {
// Ensure that a subflag isn't a subflag of itself or else we're in trouble!
flag.getSubflags().forEach(subflag -> setFlag(subflag, value, true));
}
setChanged();
}
/**
@ -1078,7 +1092,6 @@ public class Island implements DataObject, MetaDataAble {
.forEach(f -> result.put(f.getID(),
plugin.getIWM().getDefaultIslandSettings(world).getOrDefault(f, f.getDefaultRank())));
this.setFlags(result);
setChanged();
}
/**
@ -1097,8 +1110,10 @@ public class Island implements DataObject, MetaDataAble {
* @param name The display name to set.
*/
public void setName(String name) {
this.name = (name != null && !name.equals("")) ? name : null;
setChanged();
if (name == null || !name.equals(this.name)) {
this.name = (name != null && !name.equals("")) ? name : null;
setChanged();
}
}
/**
@ -1130,9 +1145,11 @@ public class Island implements DataObject, MetaDataAble {
* @param protectionRange the protectionRange to set
*/
public void setProtectionRange(int protectionRange) {
this.protectionRange = protectionRange;
this.updateMaxEverProtectionRange();
setChanged();
if (this.protectionRange != protectionRange) {
this.protectionRange = protectionRange;
this.updateMaxEverProtectionRange();
setChanged();
}
}
/**
@ -1164,8 +1181,10 @@ public class Island implements DataObject, MetaDataAble {
* @param purgeProtected - if the island is protected from the Purge
*/
public void setPurgeProtected(boolean purgeProtected) {
this.purgeProtected = purgeProtected;
setChanged();
if (this.purgeProtected != purgeProtected) {
this.purgeProtected = purgeProtected;
setChanged();
}
}
/**
@ -1179,8 +1198,10 @@ public class Island implements DataObject, MetaDataAble {
* @see #setProtectionRange(int)
*/
public void setRange(int range) {
this.range = range;
setChanged();
if (this.range != range) {
this.range = range;
setChanged();
}
}
/**
@ -1191,7 +1212,6 @@ public class Island implements DataObject, MetaDataAble {
*/
public void setRank(User user, int rank) {
setRank(user.getUniqueId(), rank);
setChanged();
}
/**
@ -1202,14 +1222,33 @@ public class Island implements DataObject, MetaDataAble {
* @param rank rank value
* @since 1.1
*/
public void setRank(@Nullable UUID uuid, int rank) {
public void setRank(@Nullable UUID uuid, int newRank) {
// Early return if the UUID is null, to avoid unnecessary processing.
if (uuid == null) {
return; // Defensive code
return;
}
// Use an AtomicBoolean to track if the member's rank has been changed.
AtomicBoolean isRankChanged = new AtomicBoolean(false);
// Attempt to update the member's rank, if necessary.
members.compute(uuid, (key, existingRank) -> {
// If the member does not exist or their rank is different, update the rank.
if (existingRank == null || existingRank != newRank) {
isRankChanged.set(true);
return newRank; // Update the rank.
}
// No change needed; return the existing rank.
return existingRank;
});
// If the rank was changed, notify the change and log the update.
if (isRankChanged.get()) {
setChanged(); // Notify that a change has occurred.
}
members.put(uuid, rank);
setChanged();
}
/**
* @param ranks the ranks to set
*/
@ -1266,7 +1305,6 @@ public class Island implements DataObject, MetaDataAble {
@Override
public void setUniqueId(String uniqueId) {
this.uniqueId = uniqueId;
setChanged();
}
/**
@ -1274,7 +1312,6 @@ public class Island implements DataObject, MetaDataAble {
*/
public void setUpdatedDate(long updatedDate) {
this.updatedDate = updatedDate;
setChanged();
}
/**
@ -1347,8 +1384,13 @@ public class Island implements DataObject, MetaDataAble {
* @param l - location
*/
public void setSpawnPoint(Environment islandType, Location l) {
spawnPoint.put(islandType, l);
setChanged();
spawnPoint.compute(islandType, (key, value) -> {
if (value == null || !value.equals(l)) {
setChanged(); // Call setChanged only if the value is updated.
return l;
}
return value;
});
}
/**
@ -1368,8 +1410,9 @@ public class Island implements DataObject, MetaDataAble {
* @param rank rank value
*/
public void removeRank(Integer rank) {
members.values().removeIf(rank::equals);
setChanged();
if (members.values().removeIf(rank::equals)) {
setChanged();
}
}
/**
@ -1455,7 +1498,6 @@ public class Island implements DataObject, MetaDataAble {
*/
public void setGameMode(String gameMode) {
this.gameMode = gameMode;
setChanged();
}
/**
@ -1518,8 +1560,9 @@ public class Island implements DataObject, MetaDataAble {
if (cooldowns.containsKey(flag.getID()) && cooldowns.get(flag.getID()) > System.currentTimeMillis()) {
return true;
}
cooldowns.remove(flag.getID());
setChanged();
if (cooldowns.remove(flag.getID()) != null) {
setChanged();
}
return false;
}
@ -1603,8 +1646,13 @@ public class Island implements DataObject, MetaDataAble {
public void setRankCommand(String command, int rank) {
if (this.commandRanks == null)
this.commandRanks = new HashMap<>();
this.commandRanks.put(command, rank);
setChanged();
commandRanks.compute(command, (key, value) -> {
if (value == null || !value.equals(rank)) {
setChanged(); // Call setChanged only if the value is updated.
return rank;
}
return value;
});
}
/**
@ -1624,8 +1672,10 @@ public class Island implements DataObject, MetaDataAble {
* @since 1.6.0
*/
public void setReserved(boolean reserved) {
this.reserved = reserved;
setChanged();
if (this.reserved != reserved) {
this.reserved = reserved;
setChanged();
}
}
/**
@ -1658,17 +1708,19 @@ public class Island implements DataObject, MetaDataAble {
}
/**
* Indicates the fields have been changed. Used to optimize saving on shutdown.
* Indicates the fields have been changed. Used to optimize saving on shutdown and notify other servers
*/
public void setChanged() {
this.setUpdatedDate(System.currentTimeMillis());
this.changed = true;
IslandsManager.updateIsland(this);
}
/**
* @param changed the changed to set
* Resets the changed if the island has been saved
*/
public void setChanged(boolean changed) {
this.changed = changed;
public void clearChanged() {
this.changed = false;
}
/**
@ -1692,6 +1744,9 @@ public class Island implements DataObject, MetaDataAble {
* @since 1.16.0
*/
public void setProtectionCenter(Location location) throws IOException {
if (this.location.equals(location)) {
return; // nothing to do
}
if (!this.inIslandSpace(location)) {
throw new IOException("Location must be in island space");
}
@ -1741,6 +1796,9 @@ public class Island implements DataObject, MetaDataAble {
* @since 1.16.0
*/
public void addHome(String name, Location location) {
if (getHomes().containsKey(name) && getHomes().get(name).equals(location)) {
return; // nothing to do
}
if (location != null) {
Vector v = location.toVector();
if (!this.getBoundingBox().contains(v)) {
@ -1763,8 +1821,11 @@ public class Island implements DataObject, MetaDataAble {
* @since 1.16.0
*/
public boolean removeHome(String name) {
setChanged();
return getHomes().remove(name.toLowerCase()) != null;
if (getHomes().remove(name.toLowerCase()) != null) {
setChanged();
return true;
}
return false;
}
/**
@ -1774,8 +1835,11 @@ public class Island implements DataObject, MetaDataAble {
* @since 1.20.0
*/
public boolean removeHomes() {
setChanged();
return getHomes().keySet().removeIf(k -> !k.isEmpty());
if (getHomes().keySet().removeIf(k -> !k.isEmpty())) {
setChanged();
return true;
}
return false;
}
/**
@ -1814,8 +1878,10 @@ public class Island implements DataObject, MetaDataAble {
* @since 1.16.0
*/
public void setMaxHomes(@Nullable Integer maxHomes) {
this.maxHomes = maxHomes;
setChanged();
if (this.maxHomes != maxHomes) {
this.maxHomes = maxHomes;
setChanged();
}
}
/**
@ -1834,8 +1900,10 @@ public class Island implements DataObject, MetaDataAble {
* @since 1.16.0
*/
public void setMaxMembers(Map<Integer, Integer> maxMembers) {
this.maxMembers = maxMembers;
setChanged();
if (this.maxMembers != maxMembers) {
this.maxMembers = maxMembers;
setChanged();
}
}
/**
@ -1860,7 +1928,13 @@ public class Island implements DataObject, MetaDataAble {
* @since 1.16.0
*/
public void setMaxMembers(int rank, Integer maxMembers) {
getMaxMembers().put(rank, maxMembers);
getMaxMembers().compute(rank, (key, value) -> {
if (value == null || !value.equals(maxMembers)) {
setChanged(); // Call setChanged only if the value is updated.
return maxMembers;
}
return value;
});
}
/**
@ -1923,8 +1997,9 @@ public class Island implements DataObject, MetaDataAble {
* @param id id to identify this bonus
*/
public void clearBonusRange(String id) {
this.getBonusRanges().removeIf(r -> r.getUniqueId().equals(id));
setChanged();
if (this.getBonusRanges().removeIf(r -> r.getUniqueId().equals(id))) {
setChanged();
}
}
/**
@ -1936,18 +2011,30 @@ public class Island implements DataObject, MetaDataAble {
}
/**
* @param userID user UUID
* @return the primary
*/
public boolean isPrimary() {
return primary;
public boolean isPrimary(UUID userID) {
return getPrimaries().contains(userID);
}
/**
* @param primary the primary to set
*/
public void setPrimary(boolean primary) {
this.primary = primary;
setChanged();
public void setPrimary(UUID userID) {
if (getPrimaries().add(userID)) {
setChanged();
}
}
/**
* Remove the primary island
* @param userID user UUID
*/
public void removePrimary(UUID userID) {
if (getPrimaries().remove(userID)) {
setChanged();
}
}
/**
@ -1986,4 +2073,41 @@ public class Island implements DataObject, MetaDataAble {
+ commandRanks + ", reserved=" + reserved + ", metaData=" + metaData + ", homes=" + homes
+ ", maxHomes=" + maxHomes + "]";
}
/**
* @return the primaries
*/
public Set<UUID> getPrimaries() {
if (primaries == null) {
primaries = new HashSet<>();
}
return primaries;
}
/**
* @param primaries the primaries to set
*/
public void setPrimaries(Set<UUID> primaries) {
this.primaries = primaries;
setChanged();
}
@Override
public int hashCode() {
return Objects.hash(uniqueId);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Island other = (Island) obj;
return Objects.equals(uniqueId, other.uniqueId);
}
}

View File

@ -6,13 +6,10 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.eclipse.jdt.annotation.Nullable;
import com.google.gson.annotations.Expose;
@ -30,8 +27,6 @@ import world.bentobox.bentobox.util.Util;
*/
@Table(name = "Players")
public class Players implements DataObject, MetaDataAble {
@Expose
private Map<Location, Integer> homeLocations = new HashMap<>();
@Expose
private String uniqueId;
@Expose
@ -77,7 +72,6 @@ public class Players implements DataObject, MetaDataAble {
*/
public Players(BentoBox plugin, UUID uniqueId) {
this.uniqueId = uniqueId.toString();
homeLocations = new HashMap<>();
locale = "";
// Try to get player's name
this.playerName = Bukkit.getOfflinePlayer(uniqueId).getName();
@ -86,72 +80,6 @@ public class Players implements DataObject, MetaDataAble {
}
}
/**
* Gets the default home location.
* @param world - world to check
* @return Location - home location in world
* @deprecated Homes are stored in the Island object now
*/
@Deprecated(since="1.18.0", forRemoval=true)
@Nullable
public Location getHomeLocation(World world) {
return getHomeLocation(world, 1); // Default
}
/**
* Gets the home location by number for world
* @param world - includes world and any related nether or end worlds
* @param number - a number
* @return Location of this home or null if not available
* @deprecated Homes are stored in the island object now
*/
@Deprecated(since="1.18.0", forRemoval=true)
@Nullable
public Location getHomeLocation(World world, int number) {
// Remove any lost worlds/locations
homeLocations.keySet().removeIf(l -> l == null || l.getWorld() == null);
return homeLocations.entrySet().stream()
.filter(en -> Util.sameWorld(en.getKey().getWorld(), world) && en.getValue() == number)
.map(Map.Entry::getKey)
.findFirst()
.orElse(null);
}
/**
* @param world - world
* @return Map of home locations
* @deprecated Homes are stored in the island object now
*/
@Deprecated(since="1.18.0", forRemoval=true)
public Map<Location, Integer> getHomeLocations(World world) {
// Remove any lost worlds/locations
homeLocations.keySet().removeIf(l -> l == null || l.getWorld() == null);
return homeLocations.entrySet().stream().filter(e -> Util.sameWorld(e.getKey().getWorld(),world))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
/**
* @return the homeLocations
* @deprecated Homes are stored in the Island object now
*/
@Deprecated(since="1.18.0", forRemoval=true)
public Map<Location, Integer> getHomeLocations() {
// Remove any lost worlds/locations
homeLocations.keySet().removeIf(l -> l == null || l.getWorld() == null);
return homeLocations;
}
/**
* @param homeLocations the homeLocations to set
* @deprecated Homes are stored in the Island object now
*/
@Deprecated(since="1.18.0", forRemoval=true)
public void setHomeLocations(Map<Location, Integer> homeLocations) {
this.homeLocations = homeLocations;
// Remove any lost worlds/locations
homeLocations.keySet().removeIf(l -> l == null || l.getWorld() == null);
}
/**
* @param playerName the playerName to set
*/
@ -202,30 +130,6 @@ public class Players implements DataObject, MetaDataAble {
this.resets.put(world.getName(), resets);
}
/**
* Stores the home location of the player in a String format
*
* @param l a Bukkit location
* @deprecated Home locations are stored in islands
*/
@Deprecated(since="1.18.0", forRemoval=true)
public void setHomeLocation(final Location l) {
setHomeLocation(l, 1);
}
/**
* Stores the numbered home location of the player. Numbering starts at 1.
* @param location - the location
* @param number - a number
* @deprecated Home locations are no longer stored for players. They are stored in islands.
*/
@Deprecated(since="1.18.0", forRemoval=true)
public void setHomeLocation(Location location, int number) {
// Remove any home locations in the same world with the same number
homeLocations.entrySet().removeIf(e -> e.getKey() == null || (Util.sameWorld(location.getWorld(), e.getKey().getWorld()) && e.getValue().equals(number)));
homeLocations.put(location, number);
}
/**
* Set the uuid for this player object
* @param uuid - UUID
@ -234,16 +138,6 @@ public class Players implements DataObject, MetaDataAble {
uniqueId = uuid.toString();
}
/**
* Clears all home Locations in world
* @param world - world
* @deprecated Home locations are no longer stored for players. Use {@link world.bentobox.bentobox.managers.IslandsManager}
*/
@Deprecated(since="1.18.0", forRemoval=true)
public void clearHomeLocations(World world) {
homeLocations.keySet().removeIf(l -> l == null || l.getWorld() == null || Util.sameWorld(l.getWorld(), world));
}
/**
* @return the locale
*/
@ -350,24 +244,6 @@ public class Players implements DataObject, MetaDataAble {
}
}
/**
* Returns the display mode for the Flags in the Settings Panel.
* @return the display mode for the Flags in the Settings Panel.
* @since 1.6.0
*/
public Flag.Mode getFlagsDisplayMode() {
return flagsDisplayMode;
}
/**
* Sets the display mode for the Flags in the Settings Panel.
* @param flagsDisplayMode the display mode for the Flags in the Settings Panel.
* @since 1.6.0
*/
public void setFlagsDisplayMode(Flag.Mode flagsDisplayMode) {
this.flagsDisplayMode = flagsDisplayMode;
}
/**
* @return the metaData
* @since 1.15.5

View File

@ -0,0 +1,112 @@
package world.bentobox.bentobox.database.objects;
import java.util.Objects;
import java.util.UUID;
import com.google.gson.annotations.Expose;
/**
* Data object for team invites
*/
@Table(name = "TeamInvites")
public class TeamInvite implements DataObject {
/**
* Type of invitation
*
*/
public enum Type {
COOP,
TEAM,
TRUST
}
@Expose
private Type type;
@Expose
private UUID inviter;
@Expose
private String islandID;
@Expose
private String uniqueId;
/**
* @param type - invitation type, e.g., coop, team, trust
* @param inviter - UUID of inviter
* @param invitee - UUID of invitee
* @param island - the unique ID of the island this invite is for
*/
public TeamInvite(Type type, UUID inviter, UUID invitee, String islandID) {
this.type = type;
this.uniqueId = invitee.toString();
this.inviter = inviter;
this.islandID = islandID;
}
@Override
public String getUniqueId() {
// Inviter
return this.uniqueId;
}
@Override
public void setUniqueId(String uniqueId) {
this.uniqueId = uniqueId;
}
/**
* @return the type
*/
public Type getType() {
return type;
}
/**
* @return the invitee
*/
public UUID getInvitee() {
return UUID.fromString(uniqueId);
}
/**
* @return the inviter
*/
public UUID getInviter() {
return inviter;
}
/**
* @return the islandID
*/
public String getIslandID() {
return islandID;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return Objects.hash(inviter, uniqueId, type);
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof TeamInvite other)) {
return false;
}
return Objects.equals(inviter, other.inviter) && Objects.equals(uniqueId, other.getUniqueId())
&& type == other.type;
}
}

View File

@ -2,6 +2,7 @@ package world.bentobox.bentobox.listeners;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
@ -61,7 +62,7 @@ public class JoinLeaveListener implements Listener {
// Make sure the player is loaded into the cache or create the player if they
// don't exist
players.addPlayer(playerUUID);
players.getPlayer(playerUUID);
// Reset island resets if required
plugin.getIWM().getOverWorlds().stream()
@ -74,7 +75,6 @@ public class JoinLeaveListener implements Listener {
// Set the player's name (it may have changed), but only if it isn't empty
if (!user.getName().isEmpty()) {
players.setPlayerName(user);
players.save(playerUUID);
} else {
plugin.logWarning("Player that just logged in has no name! " + playerUUID);
}
@ -110,7 +110,7 @@ public class JoinLeaveListener implements Listener {
private void firstTime(User user) {
// Make sure the player is loaded into the cache or create the player if they
// don't exist
players.addPlayer(user.getUniqueId());
players.getPlayer(user.getUniqueId());
plugin.getIWM().getOverWorlds().stream().filter(w -> plugin.getIWM().isCreateIslandOnFirstLoginEnabled(w))
.forEach(w -> {
@ -181,8 +181,10 @@ public class JoinLeaveListener implements Listener {
user.getPlayer().getInventory().clear();
}
playerData.getPendingKicks().remove(world.getName());
players.save(user.getUniqueId());
Set<String> kicks = playerData.getPendingKicks();
kicks.remove(world.getName());
playerData.setPendingKicks(kicks);
}
}
@ -236,7 +238,6 @@ public class JoinLeaveListener implements Listener {
});
// Remove any coop associations from the player logging out
plugin.getIslands().clearRank(RanksManager.COOP_RANK, event.getPlayer().getUniqueId());
players.save(event.getPlayer().getUniqueId());
User.removePlayer(event.getPlayer());
}
}

View File

@ -61,6 +61,7 @@ public class PanelListenerManager implements Listener {
// Refresh
l.refreshPanel();
});
} else {
// Wrong name - delete this panel
openPanels.remove(user.getUniqueId());

View File

@ -60,9 +60,6 @@ public class CommandCycleClick implements ClickHandler {
}
// Apply change to panel
panel.getInventory().setItem(slot, commandRankClickListener.getPanelItem(command, user, world).getItem());
// Save island
plugin.getIslands().save(island);
} else {
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_METAL_HIT, 1F, 1F);
}

View File

@ -37,6 +37,10 @@ import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import com.github.puregero.multilib.MultiLib;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.papermc.lib.PaperLib;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
@ -44,9 +48,9 @@ import world.bentobox.bentobox.api.events.island.IslandEvent;
import world.bentobox.bentobox.api.events.island.IslandEvent.Reason;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.logs.LogEntry;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.Database;
import world.bentobox.bentobox.database.json.BentoboxTypeAdapterFactory;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.database.objects.IslandDeletion;
import world.bentobox.bentobox.lists.Flags;
@ -65,29 +69,18 @@ public class IslandsManager {
private final BentoBox plugin;
/**
* One island can be spawn, this is the one - otherwise, this value is null
*/
@NonNull
private final Map<@NonNull World, @Nullable Island> spawn;
private Map<World, Island> spawns = new HashMap<>();
private Map<World, Location> last = new HashMap<>();
@NonNull
private Database<Island> handler;
/**
* The last locations where an island were put. This is not stored persistently
* and resets when the server starts
*/
private final Map<World, Location> last;
private static Database<Island> handler;
/**
* Island Cache
*/
@NonNull
private IslandCache islandCache;
// Quarantined islands
@NonNull
private final Map<UUID, List<Island>> quarantineCache;
// Deleted islands
@NonNull
private final List<String> deletedIslands;
@ -106,14 +99,47 @@ public class IslandsManager {
// Set up the database handler to store and retrieve Island classes
handler = new Database<>(plugin, Island.class);
islandCache = new IslandCache();
quarantineCache = new HashMap<>();
spawn = new HashMap<>();
last = new HashMap<>();
// This list should always be empty unless database deletion failed
// In that case a purge utility may be required in the future
deletedIslands = new ArrayList<>();
// Mid-teleport players going home
goingHome = new HashSet<>();
// Set handler in Island
// Listen for Island Updates
MultiLib.onString(plugin, "bentobox-updateIsland", id -> {
Island island = handler.loadObject(id);
if (island != null) {
islandCache.updateIsland(island);
}
});
// Delete island blocks
MultiLib.onString(plugin, "bentobox-deleteIsland", id -> {
IslandDeletion idd = getGson().fromJson(id, IslandDeletion.class);
plugin.getIslandDeletionManager().getIslandChunkDeletionManager().add(idd);
});
// List for new islands
MultiLib.onString(plugin, "bentobox-newIsland", id -> {
Island island = handler.loadObject(id);
if (island != null) {
islandCache.addIsland(island);
}
});
// Set or clear spawn
MultiLib.onString(plugin, "bentobox-setspawn", sp -> {
String[] split = sp.split(",");
if (split.length == 1) {
World world = Bukkit.getWorld(split[0]);
this.clearSpawn(world);
} else if (split.length == 2) {
World world = Bukkit.getWorld(split[0]);
if (world != null) {
getIslandById(split[1]).ifPresent(i -> this.setSpawn(i));
}
}
});
}
/**
@ -121,8 +147,8 @@ public class IslandsManager {
*
* @param handler - handler
*/
public void setHandler(@NonNull Database<Island> handler) {
this.handler = handler;
public void setHandler(@NonNull Database<Island> h) {
handler = h;
}
/**
@ -227,14 +253,13 @@ public class IslandsManager {
.orElse("");
island.setGameMode(gmName);
island.setUniqueId(gmName + island.getUniqueId());
while (handler.objectExists(island.getUniqueId())) {
// This should never happen, so although this is a potential infinite loop I'm
// going to leave it here because
// it will be bad if this does occur and the server should crash.
plugin.logWarning("Duplicate island UUID occurred");
island.setUniqueId(gmName + UUID.randomUUID());
}
if (islandCache.addIsland(island)) {
// Save to database and notify other servers
handler.saveObjectAsync(island).thenAccept(b -> {
if (b.equals(Boolean.TRUE)) {
MultiLib.notify("bentobox-newIsland", island.getUniqueId());
}
});
return island;
}
return null;
@ -257,27 +282,40 @@ public class IslandsManager {
// Set the owner of the island to no one.
island.setOwner(null);
island.setFlag(Flags.LOCK, RanksManager.VISITOR_RANK);
island.setDeleted(true);
if (removeBlocks) {
// Remove island from the cache
islandCache.deleteIslandFromCache(island);
// Log the deletion (it shouldn't matter but may be useful)
island.log(new LogEntry.Builder("DELETED").build());
// Set the delete flag which will prevent it from being loaded even if database
// deletion fails
island.setDeleted(true);
// Save the island
handler.saveObjectAsync(island);
// Delete the island
handler.deleteObject(island);
// Remove players from island
removePlayersFromIsland(island);
if (!plugin.getSettings().isKeepPreviousIslandOnReset()) {
// Remove blocks from world
plugin.getIslandDeletionManager().getIslandChunkDeletionManager().add(new IslandDeletion(island));
IslandDeletion id = new IslandDeletion(island);
plugin.getIslandDeletionManager().getIslandChunkDeletionManager().add(id);
// Tell other servers
MultiLib.notify("bentobox-deleteIsland", getGson().toJson(id));
}
// Delete the island from the database
handler.deleteObject(island);
}
}
private Gson getGson() {
// Build the Gson
// excludeFieldsWithoutExposeAnnotation - this means that every field to be stored should use @Expose
// enableComplexMapKeySerialization - forces GSON to use TypeAdapters even for Map keys
GsonBuilder builder = new GsonBuilder().excludeFieldsWithoutExposeAnnotation()
.enableComplexMapKeySerialization().setPrettyPrinting();
// Register adapter factory
builder.registerTypeAdapterFactory(new BentoboxTypeAdapterFactory(plugin));
// Allow characters like < or > without escaping them
builder.disableHtmlEscaping();
return builder.create();
}
/**
* Get the number of islands made on this server. Used by stats.
*
@ -462,7 +500,7 @@ public class IslandsManager {
* Get the last location where an island was created
*
* @param world - world
* @return location
* @return location or null if none found
*/
public Location getLast(@NonNull World world) {
return last.get(world);
@ -486,7 +524,7 @@ public class IslandsManager {
if (island.getOwner() == null) {
// No owner, no rank settings
island.setMaxMembers(null);
this.save(island);
updateIsland(island);
return 0;
}
// Island max is either the world default or specified amount for this island
@ -507,8 +545,11 @@ public class IslandsManager {
islandMax = owner.getPermissionValue(plugin.getIWM().getPermissionPrefix(island.getWorld()) + perm,
islandMax);
}
island.setMaxMembers(rank, islandMax == worldDefault ? null : islandMax);
this.save(island);
Integer change = islandMax == worldDefault ? null : islandMax;
if (island.getMaxMembers().get(rank) != change) {
island.setMaxMembers(rank, change);
updateIsland(island);
}
return islandMax;
}
@ -546,13 +587,16 @@ public class IslandsManager {
}
// If the island maxHomes is just the same as the world default, then set to
// null
island.setMaxHomes(islandMax == plugin.getIWM().getMaxHomes(island.getWorld()) ? null : islandMax);
this.save(island);
Integer change = islandMax == plugin.getIWM().getMaxHomes(island.getWorld()) ? null : islandMax;
if (island.getMaxHomes() != change) {
island.setMaxHomes(change);
updateIsland(island);
}
return islandMax;
}
/**
* Set the maximum numbber of homes allowed on this island
* Set the maximum number of homes allowed on this island
*
* @param island - island
* @param maxHomes - max number of homes allowed, or null if the world default
@ -735,9 +779,9 @@ public class IslandsManager {
* @since 1.16.0
*/
public boolean setHomeLocation(@Nullable Island island, Location location, String name) {
if (island != null) {
if (island != null && (island.getHome(name) == null || !island.getHome(name).equals(location))) {
island.addHome(name, location);
this.save(island);
updateIsland(island);
return true;
}
return false;
@ -890,7 +934,7 @@ public class IslandsManager {
*/
@NonNull
public Optional<Island> getSpawn(@NonNull World world) {
return Optional.ofNullable(spawn.get(world));
return Optional.ofNullable(spawns.get(world));
}
/**
@ -901,7 +945,7 @@ public class IslandsManager {
*/
@Nullable
public Location getSpawnPoint(@NonNull World world) {
return spawn.containsKey(world) ? spawn.get(world).getSpawnPoint(world.getEnvironment()) : null;
return getSpawn(world).map(i -> i.getSpawnPoint(world.getEnvironment())).orElse(null);
}
/**
@ -1132,7 +1176,7 @@ public class IslandsManager {
* @return true if they are, false if they are not, or spawn does not exist
*/
public boolean isAtSpawn(Location playerLoc) {
return spawn.containsKey(playerLoc.getWorld()) && spawn.get(playerLoc.getWorld()).onIsland(playerLoc);
return getSpawn(playerLoc.getWorld()).map(i -> i.onIsland(playerLoc)).orElse(false);
}
/**
@ -1144,19 +1188,14 @@ public class IslandsManager {
* @param spawn the Island to set as spawn. Must not be null.
*/
public void setSpawn(@NonNull Island spawn) {
// Checking if there is already a spawn set for this world
if (this.spawn.containsKey(spawn.getWorld()) && this.spawn.get(spawn.getWorld()) != null) {
Island oldSpawn = this.spawn.get(spawn.getWorld());
if (oldSpawn.equals(spawn)) {
return; // The spawn is already the current spawn - no need to update anything.
} else {
oldSpawn.setSpawn(false);
}
if (spawn.getWorld() != null) {
spawns.put(Util.getWorld(spawn.getWorld()), spawn);
// Tell other servers
MultiLib.notify("bentobox-setspawn", spawn.getWorld().getUID().toString() + "," + spawn.getUniqueId());
}
this.spawn.put(spawn.getWorld(), spawn);
spawn.setSpawn(true);
}
/**
* Clears the spawn island for this world
*
@ -1164,11 +1203,9 @@ public class IslandsManager {
* @since 1.8.0
*/
public void clearSpawn(World world) {
Island spawnIsland = spawn.get(Util.getWorld(world));
if (spawnIsland != null) {
spawnIsland.setSpawn(false);
}
this.spawn.remove(world);
spawns.remove(world);
// Tell other servers
MultiLib.notify("bentobox-setspawn", world.getUID().toString());
}
/**
@ -1192,7 +1229,6 @@ public class IslandsManager {
*/
public void load() throws IOException {
islandCache.clear();
quarantineCache.clear();
List<Island> toQuarantine = new ArrayList<>();
int owned = 0;
int unowned = 0;
@ -1206,9 +1242,6 @@ public class IslandsManager {
if (island.isDeleted()) {
// These will be deleted later
deletedIslands.add(island.getUniqueId());
} else if (island.isDoNotLoad() && island.getWorld() != null && island.getCenter() != null) {
// Add to quarantine cache
quarantineCache.computeIfAbsent(island.getOwner(), k -> new ArrayList<>()).add(island);
} // Check island distance and if incorrect stop BentoBox
else if (island.getWorld() != null && plugin.getIWM().inWorld(island.getWorld())
&& island.getRange() != plugin.getIWM().getIslandDistance(island.getWorld())) {
@ -1219,18 +1252,9 @@ public class IslandsManager {
} else {
// Fix island center if it is off
fixIslandCenter(island);
if (!islandCache.addIsland(island)) {
// Quarantine the offending island
toQuarantine.add(island);
// Add to quarantine cache
island.setDoNotLoad(true);
quarantineCache.computeIfAbsent(island.getOwner(), k -> new ArrayList<>()).add(island);
if (island.isUnowned()) {
unowned++;
} else {
owned++;
}
} else if (island.isSpawn()) {
islandCache.addIsland(island);
if (island.isSpawn()) {
// Success, set spawn if this is the spawn island.
this.setSpawn(island);
} else {
@ -1394,15 +1418,10 @@ public class IslandsManager {
homeTeleportAsync(w, p);
} else {
// Move player to spawn
if (spawn.containsKey(w)) {
// go to island spawn
Location sp = spawn.get(w).getSpawnPoint(w.getEnvironment());
if (sp != null) {
PaperLib.teleportAsync(p, sp);
} else {
plugin.logWarning("Spawn exists but its location is null!");
}
}
getSpawn(w).map(i -> i.getSpawnPoint(w.getEnvironment())).filter(Objects::nonNull)
.ifPresentOrElse(sp -> PaperLib.teleportAsync(p, sp),
() -> plugin.logWarning("Spawn exists but its location is null!"));
}
});
}
@ -1473,9 +1492,13 @@ public class IslandsManager {
teamIsland.addMember(playerUUID);
islandCache.addPlayer(playerUUID, teamIsland);
// Save the island
handler.saveObjectAsync(teamIsland);
updateIsland(teamIsland);
}
/**
* Set the last island location
* @param last location
*/
public void setLast(Location last) {
this.last.put(last.getWorld(), last);
}
@ -1608,12 +1631,16 @@ public class IslandsManager {
}
/**
* Save the island to the database
* Update island data in database
*
* @param island - island
*/
public void save(Island island) {
handler.saveObjectAsync(island);
public static void updateIsland(Island island) {
if (handler.objectExists(island.getUniqueId())) {
island.clearChanged();
handler.saveObjectAsync(island)
.thenAccept(b -> MultiLib.notify("bentobox-updateIsland", island.getUniqueId()));
}
}
/**
@ -1628,108 +1655,6 @@ public class IslandsManager {
return Optional.ofNullable(islandCache.getIslandById(uniqueId));
}
/**
* Try to get an unmodifiable list of quarantined islands owned by uuid in this
* world
*
* @param world - world
* @param uuid - target player's UUID, or <tt>null</tt> = unowned islands
* @return list of islands; may be empty
* @since 1.3.0
*/
@NonNull
public List<Island> getQuarantinedIslandByUser(@NonNull World world, @Nullable UUID uuid) {
return quarantineCache.getOrDefault(uuid, Collections.emptyList()).stream()
.filter(i -> i.getWorld().equals(world)).toList();
}
/**
* Delete quarantined islands owned by uuid in this world
*
* @param world - world
* @param uuid - target player's UUID, or <tt>null</tt> = unowned islands
* @since 1.3.0
*/
public void deleteQuarantinedIslandByUser(World world, @Nullable UUID uuid) {
if (quarantineCache.containsKey(uuid)) {
quarantineCache.get(uuid).stream().filter(i -> i.getWorld().equals(world))
.forEach(i -> handler.deleteObject(i));
quarantineCache.get(uuid).removeIf(i -> i.getWorld().equals(world));
}
}
/**
* @return the quarantineCache
* @since 1.3.0
*/
@NonNull
public Map<UUID, List<Island>> getQuarantineCache() {
return quarantineCache;
}
/**
* Remove a quarantined island and delete it from the database completely. This
* is NOT recoverable unless you have database backups.
*
* @param island island
* @return {@code true} if island is quarantined and removed
* @since 1.3.0
*/
public boolean purgeQuarantinedIsland(Island island) {
if (quarantineCache.containsKey(island.getOwner()) && quarantineCache.get(island.getOwner()).remove(island)) {
handler.deleteObject(island);
return true;
}
return false;
}
/**
* Switches active island and island in trash
*
* @param world - game world
* @param target - target player's UUID
* @param island - island in trash
* @return <tt>true</tt> if successful, otherwise <tt>false</tt>
* @since 1.3.0
*/
public boolean switchIsland(World world, UUID target, Island island) {
// Remove trashed island from trash
if (!quarantineCache.containsKey(island.getOwner()) || !quarantineCache.get(island.getOwner()).remove(island)) {
plugin.logError("Could not remove island from trash");
return false;
}
// Remove old island from cache if it exists
if (this.hasIsland(world, target)) {
Island oldIsland = islandCache.get(world, target);
islandCache.removeIsland(oldIsland);
// Set old island to trash
oldIsland.setDoNotLoad(true);
// Put old island into trash
quarantineCache.computeIfAbsent(target, k -> new ArrayList<>()).add(oldIsland);
// Save old island
handler.saveObjectAsync(oldIsland).thenAccept(result -> {
if (Boolean.FALSE.equals(result))
plugin.logError("Could not save trashed island in database");
});
}
// Restore island from trash
island.setDoNotLoad(false);
// Add new island to cache
if (!islandCache.addIsland(island)) {
plugin.logError("Could not add recovered island to cache");
return false;
}
// Save new island
handler.saveObjectAsync(island).thenAccept(result -> {
if (Boolean.FALSE.equals(result)) {
plugin.logError("Could not save recovered island to database");
}
});
return true;
}
/**
* Resets all flags to gamemode config.yml default
*

View File

@ -4,21 +4,18 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.entity.Tameable;
import org.bukkit.scheduler.BukkitRunnable;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.Database;
import world.bentobox.bentobox.database.objects.Island;
@ -31,11 +28,9 @@ public class PlayersManager {
private final BentoBox plugin;
private Database<Players> handler;
private final Database<Names> names;
private final Map<UUID, Players> playerCache = new HashMap<>();
private final Map<UUID, Players> playerCache;
private final Set<UUID> inTeleport;
private boolean isSaveTaskRunning;
private final Set<UUID> inTeleport; // this needs databasing
/**
* Provides a memory cache of online player information
@ -50,7 +45,6 @@ public class PlayersManager {
handler = new Database<>(plugin, Players.class);
// Set up the names database
names = new Database<>(plugin, Names.class);
playerCache = new HashMap<>();
inTeleport = new HashSet<>();
}
@ -62,67 +56,7 @@ public class PlayersManager {
this.handler = handler;
}
/**
* Load all players - not normally used as to load all players into memory will be wasteful
*/
public void load(){
playerCache.clear();
inTeleport.clear();
handler.loadObjects().forEach(p -> playerCache.put(p.getPlayerUUID(), p));
}
public boolean isSaveTaskRunning() {
return isSaveTaskRunning;
}
/**
* Save all players
*/
public void saveAll() {
saveAll(false);
}
/**
* Save all players
* @param schedule true if we should let the task run over multiple ticks to reduce lag spikes
*/
public void saveAll(boolean schedule){
if (!schedule) {
for (Players player : playerCache.values()) {
try {
handler.saveObjectAsync(player);
} catch (Exception e) {
plugin.logError("Could not save player to database when running sync! " + e.getMessage());
}
}
return;
}
isSaveTaskRunning = true;
Queue<Players> queue = new LinkedList<>(playerCache.values());
new BukkitRunnable() {
@Override
public void run() {
for (int i = 0; i < plugin.getSettings().getMaxSavedPlayersPerTick(); i++) {
Players player = queue.poll();
if (player == null) {
isSaveTaskRunning = false;
cancel();
return;
}
try {
handler.saveObjectAsync(player);
} catch (Exception e) {
plugin.logError("Could not save player to database when running sync! " + e.getMessage());
}
}
}
}.runTaskTimer(plugin, 0, 1);
}
public void shutdown(){
saveAll();
playerCache.clear();
handler.close();
}
@ -134,11 +68,29 @@ public class PlayersManager {
@Nullable
public Players getPlayer(UUID uuid){
if (!playerCache.containsKey(uuid)) {
addPlayer(uuid);
playerCache.put(uuid, addPlayer(uuid));
}
return playerCache.get(uuid);
}
/**
* Adds a player to the database. If the UUID does not exist, a new player is made
* @param playerUUID - the player's UUID
*/
private Players addPlayer(@NonNull UUID playerUUID) {
Objects.requireNonNull(playerUUID);
// If the player is in the database, load it, otherwise create a new player
if (handler.objectExists(playerUUID.toString())) {
Players player = handler.loadObject(playerUUID.toString());
if (player != null) {
return player;
}
}
Players player = new Players(plugin, playerUUID);
handler.saveObject(player);
return player;
}
/**
* Returns an <strong>unmodifiable collection</strong> of all the players that are <strong>currently in the cache</strong>.
* @return unmodifiable collection containing every player in the cache.
@ -146,37 +98,7 @@ public class PlayersManager {
*/
@NonNull
public Collection<Players> getPlayers() {
return Collections.unmodifiableCollection(playerCache.values());
}
/*
* Cache control methods
*/
/**
* Adds a player to the cache. If the UUID does not exist, a new player is made
* @param playerUUID - the player's UUID
*/
public void addPlayer(UUID playerUUID) {
if (playerUUID == null) {
return;
}
if (!playerCache.containsKey(playerUUID)) {
Players player;
// If the player is in the database, load it, otherwise create a new player
if (handler.objectExists(playerUUID.toString())) {
player = handler.loadObject(playerUUID.toString());
if (player == null) {
player = new Players(plugin, playerUUID);
// Corrupted database entry
plugin.logError("Corrupted player database entry for " + playerUUID + " - unrecoverable. Recreated.");
player.setUniqueId(playerUUID.toString());
}
} else {
player = new Players(plugin, playerUUID);
}
playerCache.put(playerUUID, player);
}
return Collections.unmodifiableCollection(handler.loadObjects());
}
/**
@ -187,7 +109,7 @@ public class PlayersManager {
* @return true if player is known, otherwise false
*/
public boolean isKnown(UUID uniqueID) {
return uniqueID != null && (playerCache.containsKey(uniqueID) || handler.objectExists(uniqueID.toString()));
return uniqueID == null ? false : handler.objectExists(uniqueID.toString());
}
/**
@ -206,11 +128,8 @@ public class PlayersManager {
// Not used
}
}
// Look in the name cache, then the data base and then give up
return playerCache.values().stream()
.filter(p -> p.getPlayerName().equalsIgnoreCase(name)).findFirst()
.map(p -> UUID.fromString(p.getUniqueId()))
.orElseGet(() -> names.objectExists(name) ? names.loadObject(name).getUuid() : null);
return names.loadObjects().stream().filter(n -> n.getUniqueId().equalsIgnoreCase(name)).findFirst()
.map(Names::getUuid).orElse(null);
}
/**
@ -218,8 +137,9 @@ public class PlayersManager {
* @param user - the User
*/
public void setPlayerName(@NonNull User user) {
addPlayer(user.getUniqueId());
playerCache.get(user.getUniqueId()).setPlayerName(user.getName());
Players player = getPlayer(user.getUniqueId());
player.setPlayerName(user.getName());
handler.saveObject(player);
Names newName = new Names(user.getName(), user.getUniqueId());
// Add to names database
names.saveObjectAsync(newName);
@ -237,8 +157,8 @@ public class PlayersManager {
if (playerUUID == null) {
return "";
}
addPlayer(playerUUID);
return playerCache.get(playerUUID).getPlayerName();
return names.loadObjects().stream().filter(n -> n.getUuid().equals(playerUUID)).findFirst()
.map(Names::getUniqueId).orElse(null);
}
/**
@ -248,8 +168,7 @@ public class PlayersManager {
* @return number of resets
*/
public int getResets(World world, UUID playerUUID) {
addPlayer(playerUUID);
return playerCache.get(playerUUID).getResets(world);
return getPlayer(playerUUID).getResets(world);
}
/**
@ -261,7 +180,7 @@ public class PlayersManager {
* @see #getResets(World, UUID)
*/
public int getResetsLeft(World world, UUID playerUUID) {
addPlayer(playerUUID);
getPlayer(playerUUID);
if (plugin.getIWM().getResetLimit(world) == -1) {
return -1;
} else {
@ -277,8 +196,9 @@ public class PlayersManager {
* @param resets number of resets to set
*/
public void setResets(World world, UUID playerUUID, int resets) {
addPlayer(playerUUID);
playerCache.get(playerUUID).setResets(world, resets);
Players p = getPlayer(playerUUID);
p.setResets(world, resets);
handler.saveObject(p);
}
/**
@ -287,11 +207,7 @@ public class PlayersManager {
* @return name of the locale this player uses
*/
public String getLocale(UUID playerUUID) {
addPlayer(playerUUID);
if (playerUUID == null) {
return "";
}
return playerCache.get(playerUUID).getLocale();
return getPlayer(playerUUID).getLocale();
}
/**
@ -300,8 +216,9 @@ public class PlayersManager {
* @param localeName - locale name, e.g., en-US
*/
public void setLocale(UUID playerUUID, String localeName) {
addPlayer(playerUUID);
playerCache.get(playerUUID).setLocale(localeName);
Players p = getPlayer(playerUUID);
p.setLocale(localeName);
handler.saveObject(p);
}
/**
@ -310,8 +227,9 @@ public class PlayersManager {
* @param playerUUID - the player's UUID
*/
public void addDeath(World world, UUID playerUUID) {
addPlayer(playerUUID);
playerCache.get(playerUUID).addDeath(world);
Players p = getPlayer(playerUUID);
p.addDeath(world);
handler.saveObject(p);
}
/**
@ -321,8 +239,9 @@ public class PlayersManager {
* @param deaths - number of deaths
*/
public void setDeaths(World world, UUID playerUUID, int deaths) {
addPlayer(playerUUID);
playerCache.get(playerUUID).setDeaths(world, deaths);
Players p = getPlayer(playerUUID);
p.setDeaths(world, deaths);
handler.saveObject(p);
}
/**
@ -332,8 +251,7 @@ public class PlayersManager {
* @return number of deaths
*/
public int getDeaths(World world, UUID playerUUID) {
addPlayer(playerUUID);
return playerCache.get(playerUUID) == null ? 0 : playerCache.get(playerUUID).getDeaths(world);
return getPlayer(playerUUID).getDeaths(world);
}
/**
@ -360,16 +278,6 @@ public class PlayersManager {
return inTeleport.contains(uniqueId);
}
/**
* Saves the player to the database
* @param playerUUID - the player's UUID
*/
public void save(UUID playerUUID) {
if (playerCache.containsKey(playerUUID)) {
handler.saveObjectAsync(playerCache.get(playerUUID));
}
}
/**
* Tries to get the user from his name
* @param name - name
@ -395,41 +303,17 @@ public class PlayersManager {
* @param playerUUID player's UUID
*/
public void addReset(World world, UUID playerUUID) {
addPlayer(playerUUID);
playerCache.get(playerUUID).addReset(world);
Players p = getPlayer(playerUUID);
p.addReset(world);
handler.saveObject(p);
}
/**
* Sets the Flags display mode for the Settings Panel for this player.
* @param playerUUID player's UUID
* @param displayMode the {@link Flag.Mode} to set
* @since 1.6.0
*/
public void setFlagsDisplayMode(UUID playerUUID, Flag.Mode displayMode) {
addPlayer(playerUUID);
playerCache.get(playerUUID).setFlagsDisplayMode(displayMode);
}
/**
* Returns the Flags display mode for the Settings Panel for this player.
* @param playerUUID player's UUID
* @return the {@link Flag.Mode display mode} for the Flags in the Settings Panel.
* @since 1.6.0
*/
public Flag.Mode getFlagsDisplayMode(UUID playerUUID) {
addPlayer(playerUUID);
return playerCache.get(playerUUID).getFlagsDisplayMode();
}
/**
* Remove player from cache. Clears players with the same name or UUID
* Remove player from database
* @param player player to remove
*/
public void removePlayer(Player player) {
// Clear any players with the same name
playerCache.values().removeIf(p -> player.getName().equalsIgnoreCase(p.getPlayerName()));
// Remove if the player's UUID is the same
playerCache.values().removeIf(p -> player.getUniqueId().toString().equals(p.getUniqueId()));
handler.deleteID(player.getUniqueId().toString());
}
/**
@ -495,8 +379,6 @@ public class PlayersManager {
// Player total XP (not displayed)
target.getPlayer().setTotalExperience(0);
}
// Save player
save(target.getUniqueId());
}
}

View File

@ -9,6 +9,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
@ -54,6 +55,159 @@ public class IslandCache {
grids = new HashMap<>();
}
/**
* Replace the island we have with this one
* @param newIsland island
*/
public void updateIsland(@NonNull Island newIsland) {
if (newIsland.isDeleted()) {
this.deleteIslandFromCache(newIsland);
return;
}
// Get the old island
Island oldIsland = islandsById.get(newIsland.getUniqueId());
compareIslands(oldIsland, newIsland);
Set<UUID> newMembers = newIsland.getMembers().keySet();
if (oldIsland != null) {
Set<UUID> oldMembers = oldIsland.getMembers().keySet();
// Remove any members who are not in the new island
for (UUID oldMember : oldMembers) {
if (!newMembers.contains(oldMember)) {
// Member has been removed - remove island
islandsByUUID.computeIfAbsent(oldMember, k -> new HashSet<>()).remove(oldIsland);
}
}
}
// Update the members with the new island object
for (UUID newMember : newMembers) {
Set<Island> set = islandsByUUID.computeIfAbsent(newMember, k -> new HashSet<>());
set.remove(oldIsland);
set.add(newIsland);
islandsByUUID.put(newMember, set);
}
if (islandsByLocation.put(newIsland.getCenter(), newIsland) == null) {
BentoBox.getInstance().logError("islandsByLocation failed to update");
}
if (islandsById.put(newIsland.getUniqueId(), newIsland) == null) {
BentoBox.getInstance().logError("islandsById failed to update");
}
}
/**
* TODO REMOVE THIS DEBUG METHOD
* @param island1 island1
* @param island2 island 2
*/
public void compareIslands(Island island1, Island island2) {
if (island1 == null || island2 == null) {
BentoBox.getInstance().logDebug("One or both islands are null. Cannot compare.");
return;
}
if (!island1.getUniqueId().equals(island2.getUniqueId())) {
BentoBox.getInstance().logDebug("Island unique IDs are different.");
}
if (island1.isDeleted() != island2.isDeleted()) {
BentoBox.getInstance().logDebug("Island deleted states are different.");
}
if (!Objects.equals(island1.getCenter(), island2.getCenter())) {
BentoBox.getInstance().logDebug("Island centers are different.");
}
if (island1.getRange() != island2.getRange()) {
BentoBox.getInstance().logDebug("Island ranges are different.");
}
if (island1.getProtectionRange() != island2.getProtectionRange()) {
BentoBox.getInstance().logDebug("Island protection ranges are different.");
}
if (!island1.getBonusRanges().equals(island2.getBonusRanges())) {
BentoBox.getInstance().logDebug("Island bonus ranges are different.");
}
if (island1.getMaxEverProtectionRange() != island2.getMaxEverProtectionRange()) {
BentoBox.getInstance().logDebug("Island max ever protection ranges are different.");
}
if (!island1.getWorld().equals(island2.getWorld())) {
BentoBox.getInstance().logDebug("Island worlds are different.");
}
if (!Objects.equals(island1.getGameMode(), island2.getGameMode())) {
BentoBox.getInstance().logDebug("Island game modes are different.");
}
if (!Objects.equals(island1.getName(), island2.getName())) {
BentoBox.getInstance().logDebug("Island names are different.");
}
if (island1.getCreatedDate() != island2.getCreatedDate()) {
BentoBox.getInstance().logDebug("Island created dates are different.");
}
if (island1.getUpdatedDate() != island2.getUpdatedDate()) {
BentoBox.getInstance().logDebug("Island updated dates are different.");
}
if (!Objects.equals(island1.getOwner(), island2.getOwner())) {
BentoBox.getInstance().logDebug("Island owners are different.");
}
if (!island1.getMembers().equals(island2.getMembers())) {
BentoBox.getInstance().logDebug("Island members are different.");
}
if (!Objects.equals(island1.getMaxMembers(), island2.getMaxMembers())) {
BentoBox.getInstance().logDebug("Island max members are different.");
}
if (island1.isSpawn() != island2.isSpawn()) {
BentoBox.getInstance().logDebug("Island spawn states are different.");
}
if (!island1.getFlags().equals(island2.getFlags())) {
BentoBox.getInstance().logDebug("Island flags are different.");
}
if (!island1.getHistory().equals(island2.getHistory())) {
BentoBox.getInstance().logDebug("Island histories are different.");
}
if (!island1.getSpawnPoint().equals(island2.getSpawnPoint())) {
BentoBox.getInstance().logDebug("Island spawn points are different.");
}
if (island1.isDoNotLoad() != island2.isDoNotLoad()) {
BentoBox.getInstance().logDebug("Island do not load states are different.");
}
if (!island1.getCooldowns().equals(island2.getCooldowns())) {
BentoBox.getInstance().logDebug("Island cooldowns are different.");
}
if (!Objects.equals(island1.getCommandRanks(), island2.getCommandRanks())) {
BentoBox.getInstance().logDebug("Island command ranks are different.");
}
if (!Objects.equals(island1.getMetaData(), island2.getMetaData())) {
BentoBox.getInstance().logDebug("Island metadata are different.");
}
if (!Objects.equals(island1.getHomes(), island2.getHomes())) {
BentoBox.getInstance().logDebug("Island homes are different.");
}
if (!Objects.equals(island1.getMaxHomes(), island2.getMaxHomes())) {
BentoBox.getInstance().logDebug("Island max homes are different.");
}
}
/**
* Adds an island to the grid
*
@ -62,12 +216,7 @@ public class IslandCache {
*/
public boolean addIsland(@NonNull Island island) {
if (island.getCenter() == null || island.getWorld() == null) {
/*
* Special handling - return true. The island will not be quarantined, but just
* not loaded This can occur when a gamemode is removed temporarily from the
* server TODO: have an option to remove these when the purge command is added
*/
return true;
return false;
}
if (addToGrid(island)) {
islandsByLocation.put(island.getCenter(), island);
@ -100,7 +249,7 @@ public class IslandCache {
* @return true if successfully added, false if not
*/
private boolean addToGrid(@NonNull Island newIsland) {
return grids.computeIfAbsent(newIsland.getWorld(), k -> new IslandGrid()).addToGrid(newIsland);
return grids.computeIfAbsent(newIsland.getWorld(), k -> new IslandGrid(this)).addToGrid(newIsland);
}
public void clear() {
@ -117,13 +266,16 @@ public class IslandCache {
*/
public boolean deleteIslandFromCache(@NonNull Island island) {
if (!islandsByLocation.remove(island.getCenter(), island)) {
// Already deleted
return false;
}
islandsById.remove(island.getUniqueId());
removeFromIslandsByUUID(island);
// Remove from grid
grids.putIfAbsent(island.getWorld(), new IslandGrid());
return grids.get(island.getWorld()).removeFromGrid(island);
if (grids.containsKey(island.getWorld())) {
return grids.get(island.getWorld()).removeFromGrid(island);
}
return false;
}
private void removeFromIslandsByUUID(Island island) {
@ -144,12 +296,11 @@ public class IslandCache {
*
* @param uniqueId - island unique ID
*/
public void deleteIslandFromCache(@NonNull String uniqueId) {
islandsById.remove(uniqueId);
islandsByLocation.values().removeIf(i -> i.getUniqueId().equals(uniqueId));
for (Set<Island> set : islandsByUUID.values()) {
set.removeIf(i -> i.getUniqueId().equals(uniqueId));
public boolean deleteIslandFromCache(@NonNull String uniqueId) {
if (islandsById.containsKey(uniqueId)) {
return deleteIslandFromCache(islandsById.get(uniqueId));
}
return false;
}
/**
@ -178,13 +329,13 @@ public class IslandCache {
return null;
}
for (Island island : islands) {
if (island.isPrimary()) {
if (island.isPrimary(uuid)) {
return island;
}
}
// If there is no primary set, then set one - it doesn't matter which.
Island result = islands.iterator().next();
result.setPrimary(true);
result.setPrimary(uuid);
return result;
}
@ -212,8 +363,16 @@ public class IslandCache {
* @param island island to make primary
*/
public void setPrimaryIsland(@NonNull UUID uuid, @NonNull Island island) {
if (island.getPrimaries().contains(uuid)) {
return;
}
for (Island is : getIslands(island.getWorld(), uuid)) {
is.setPrimary(island.equals(is));
if (is.getPrimaries().contains(uuid)) {
is.removePrimary(uuid);
}
if (is.equals(island)) {
is.setPrimary(uuid);
}
}
}
@ -326,6 +485,7 @@ public class IslandCache {
islandSet.remove(island);
}
island.removeMember(uuid);
island.removePrimary(uuid);
}
/**
@ -375,27 +535,6 @@ public class IslandCache {
return islandsById.get(uniqueId);
}
/**
* Removes an island from the cache completely without altering the island
* object
*
* @param island - island to remove
* @since 1.3.0
*/
public void removeIsland(@NonNull Island island) {
islandsByLocation.values().removeIf(island::equals);
islandsById.values().removeIf(island::equals);
islandsByUUID.values().removeIf(island::equals);
World w = Util.getWorld(island.getWorld());
if (w == null) {
return;
}
if (grids.containsKey(w)) {
grids.get(w).removeFromGrid(island);
}
}
/**
* Resets all islands in this game mode to default flag settings
*

View File

@ -3,7 +3,6 @@ package world.bentobox.bentobox.managers.island;
import java.util.Map.Entry;
import java.util.TreeMap;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.database.objects.Island;
/**
@ -12,8 +11,16 @@ import world.bentobox.bentobox.database.objects.Island;
*
*/
class IslandGrid {
private final TreeMap<Integer, TreeMap<Integer, Island>> grid = new TreeMap<>();
private final BentoBox plugin = BentoBox.getInstance();
private final TreeMap<Integer, TreeMap<Integer, String>> grid = new TreeMap<>();
private final IslandCache im;
/**
* @param im IslandsManager
*/
public IslandGrid(IslandCache im) {
super();
this.im = im;
}
/**
* Adds island to grid
@ -21,50 +28,23 @@ class IslandGrid {
* @return true if successfully added, false if island already exists, or there is an overlap
*/
public boolean addToGrid(Island island) {
// Check if we know about this island already
if (grid.containsKey(island.getMinX())) {
TreeMap<Integer, Island> zEntry = grid.get(island.getMinX());
TreeMap<Integer, String> zEntry = grid.get(island.getMinX());
if (zEntry.containsKey(island.getMinZ())) {
// There is an overlap or duplicate
plugin.logError("Cannot load island. Overlapping: " + island.getUniqueId());
plugin.logError("Location: " + island.getCenter());
// Get the previously loaded island
Island firstLoaded = zEntry.get(island.getMinZ());
if (firstLoaded.getOwner() == null && island.getOwner() != null) {
// This looks fishy. We prefer to load islands that have an owner. Swap the two
plugin.logError("Duplicate island has an owner, so using that one. " + island.getOwner());
firstLoaded = new Island(island);
zEntry.put(island.getMinZ(), firstLoaded);
} else if (firstLoaded.getOwner() != null && island.getOwner() != null) {
// Check if the owners are the same - this is a true duplicate
if (firstLoaded.getOwner().equals(island.getOwner())) {
// Find out which one is the original
if (firstLoaded.getCreatedDate() > island.getCreatedDate()) {
plugin.logError("Same owner duplicate. Swapping based on creation date.");
// FirstLoaded is the newer
firstLoaded = new Island(island);
zEntry.put(island.getMinZ(), firstLoaded);
} else {
plugin.logError("Same owner duplicate.");
}
} else {
plugin.logError("Duplicate but different owner. Keeping first loaded.");
plugin.logError("This is serious!");
plugin.logError("1st loaded ID: " + firstLoaded.getUniqueId());
plugin.logError("1st loaded owner: " + firstLoaded.getOwner());
plugin.logError("2nd loaded ID: " + island.getUniqueId());
plugin.logError("2nd loaded owner: " + island.getOwner());
}
if (island.getUniqueId().equals(zEntry.get(island.getMinZ()))) {
return true;
}
return false;
} else {
// Add island
zEntry.put(island.getMinZ(), island);
zEntry.put(island.getMinZ(), island.getUniqueId());
grid.put(island.getMinX(), zEntry);
}
} else {
// Add island
TreeMap<Integer, Island> zEntry = new TreeMap<>();
zEntry.put(island.getMinZ(), island);
TreeMap<Integer, String> zEntry = new TreeMap<>();
zEntry.put(island.getMinZ(), island.getUniqueId());
grid.put(island.getMinX(), zEntry);
}
return true;
@ -76,43 +56,48 @@ class IslandGrid {
* @return true if island existed and was deleted, false if there was nothing to delete
*/
public boolean removeFromGrid(Island island) {
// Remove from grid
if (island != null) {
int x = island.getMinX();
int z = island.getMinZ();
if (grid.containsKey(x)) {
TreeMap<Integer, Island> zEntry = grid.get(x);
if (zEntry.containsKey(z)) {
// Island exists - delete it
zEntry.remove(z);
grid.put(x, zEntry);
return true;
}
}
}
return false;
}
String id = island.getUniqueId();
boolean removed = grid.values().stream()
.anyMatch(innerMap -> innerMap.values().removeIf(innerValue -> innerValue.equals(id)));
grid.values().removeIf(TreeMap::isEmpty);
return removed;
}
/**
* Returns the island at the x,z location or null if there is none.
* This includes the full island space, not just the protected area.
*
* @param x - x coordinate
* @param z - z coordinate
* @return Island or null
*/
* Retrieves the island located at the specified x and z coordinates, covering both the protected area
* and the full island space. Returns null if no island exists at the given location.
*
* @param x the x coordinate of the location
* @param z the z coordinate of the location
* @return the Island at the specified location, or null if no island is found
*/
public Island getIslandAt(int x, int z) {
Entry<Integer, TreeMap<Integer, Island>> en = grid.floorEntry(x);
if (en != null) {
Entry<Integer, Island> ent = en.getValue().floorEntry(z);
if (ent != null) {
// Check if in the island range
Island island = ent.getValue();
if (island.inIslandSpace(x, z)) {
return island;
}
}
// Attempt to find the closest x-coordinate entry that does not exceed 'x'
Entry<Integer, TreeMap<Integer, String>> xEntry = grid.floorEntry(x);
if (xEntry == null) {
return null; // No x-coordinate entry found, return null
}
// Attempt to find the closest z-coordinate entry that does not exceed 'z' within the found x-coordinate
Entry<Integer, String> zEntry = xEntry.getValue().floorEntry(z);
if (zEntry == null) {
return null; // No z-coordinate entry found, return null
}
// Retrieve the island using the id found in the z-coordinate entry
Island island = im.getIslandById(zEntry.getValue());
if (island == null) {
return null; // No island found by the id, return null
}
// Check if the specified coordinates are within the island space
if (island.inIslandSpace(x, z)) {
return island; // Coordinates are within island space, return the island
}
// Coordinates are outside the island space, return null
return null;
}
}

View File

@ -19,6 +19,7 @@ import world.bentobox.bentobox.api.events.island.IslandResetEvent;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.BlueprintsManager;
import world.bentobox.bentobox.managers.IslandsManager;
/**
* Create and paste a new island
@ -217,7 +218,7 @@ public class NewIsland {
// Register metrics
plugin.getMetrics().ifPresent(BStats::increaseIslandsCreatedCount);
// Save island
plugin.getIslands().save(island);
IslandsManager.updateIsland(island);
}
/**
@ -266,8 +267,6 @@ public class NewIsland {
plugin.getIWM().getAddon(island.getWorld()).map(GameModeAddon::getPermissionPrefix).orElse("")
+ "island.range",
island.getProtectionRange()));
// Save the player so that if the server crashes weird things won't happen
plugin.getPlayers().save(user.getUniqueId());
}
/**

View File

@ -489,7 +489,7 @@ public class IslandCreationPanel
long uses = plugin.getIslands().getIslands(world, user).stream()
.filter(is -> is.getMetaData("bundle")
.map(mdv -> bundle.getDisplayName().equalsIgnoreCase(mdv.asString())
&& !(reset && is.isPrimary())) // If this is a reset, then ignore the use of the island being reset
&& !(reset && is.isPrimary(user.getUniqueId()))) // If this is a reset, then ignore the use of the island being reset
.orElse(false))
.count();
builder.description(this.user.getTranslation(BUNDLE_BUTTON_REF + "uses", TextVariables.NUMBER,

View File

@ -4,6 +4,7 @@ import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import org.bukkit.ChatColor;
@ -16,6 +17,7 @@ import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.api.flags.Flag.Mode;
import world.bentobox.bentobox.api.flags.Flag.Type;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.panels.Panel;
@ -46,16 +48,7 @@ public class SettingsTab implements Tab, ClickHandler {
protected Island island;
protected TabbedPanel parent;
/**
* Show a tab of settings
* @param user - user who is viewing the tab
* @param type - flag type
*/
public SettingsTab(User user, Type type) {
this.user = user;
this.type = type;
// Island and world are set when the parent is set.
}
private Map<UUID, Flag.Mode> currentMode = new HashMap<>();
/**
* Show a tab of settings
@ -69,6 +62,21 @@ public class SettingsTab implements Tab, ClickHandler {
this.type = type;
}
/**
* Show a tab of settings
* @param world - world
* @param user - user who is viewing the tab
* @param type - flag type
* @param defaultMode - the default mode to show
* @since 2.4.0
*/
public SettingsTab(World world, User user, Type type, Flag.Mode defaultMode) {
this.world = world;
this.user = user;
this.type = type;
currentMode.put(user.getUniqueId(), defaultMode);
}
/**
* @return list of flags that will be shown in this panel
*/
@ -81,7 +89,7 @@ public class SettingsTab implements Tab, ClickHandler {
// Remove any that are not for this game mode
plugin.getIWM().getAddon(world).ifPresent(gm -> flags.removeIf(f -> !f.getGameModes().isEmpty() && !f.getGameModes().contains(gm)));
// Remove any that are the wrong rank or that will be on the top row
Flag.Mode mode = plugin.getPlayers().getFlagsDisplayMode(user.getUniqueId());
Flag.Mode mode = currentMode.getOrDefault(user.getUniqueId(), Mode.BASIC);
plugin.getIWM().getAddon(world).ifPresent(gm -> flags.removeIf(f -> f.getMode().isGreaterThan(mode) ||
f.getMode().equals(Flag.Mode.TOP_ROW)));
return flags;
@ -120,13 +128,14 @@ public class SettingsTab implements Tab, ClickHandler {
int i = 0;
// Jump past empty tabs
while (flags.isEmpty() && i++ < Flag.Mode.values().length) {
plugin.getPlayers().setFlagsDisplayMode(user.getUniqueId(), plugin.getPlayers().getFlagsDisplayMode(user.getUniqueId()).getNext());
currentMode.put(user.getUniqueId(), currentMode.getOrDefault(user.getUniqueId(), Mode.BASIC).getNext());
flags = getFlags();
}
return flags.stream().map(
List<@Nullable PanelItem> result = flags.stream().map(
(f -> f.toPanelItem(plugin, user, world, island,
plugin.getIWM().getHiddenFlags(world).contains(f.getID()))))
.toList();
return result;
}
@Override
@ -137,8 +146,9 @@ public class SettingsTab implements Tab, ClickHandler {
icons.put(4, Flags.CHANGE_SETTINGS.toPanelItem(plugin, user, world, island, false));
icons.put(5, Flags.LOCK.toPanelItem(plugin, user, world, island, false));
}
// Add the mode icon
switch (plugin.getPlayers().getFlagsDisplayMode(user.getUniqueId())) {
switch (currentMode.getOrDefault(user.getUniqueId(), Mode.BASIC)) {
case ADVANCED -> icons.put(7, new PanelItemBuilder().icon(Material.GOLD_INGOT)
.name(user.getTranslation(PROTECTION_PANEL + "mode.advanced.name"))
.description(user.getTranslation(PROTECTION_PANEL + "mode.advanced.description"), "",
@ -161,7 +171,8 @@ public class SettingsTab implements Tab, ClickHandler {
.clickHandler(this)
.build());
}
// Add the reset everything to default - it's only in the player's settings panel
// Add the reset everything to default - it's only in the player's settings panel
if (island != null && user.getUniqueId().equals(island.getOwner())) {
icons.put(8, new PanelItemBuilder().icon(Material.TNT)
.name(user.getTranslation(PROTECTION_PANEL + "reset-to-default.name"))
@ -216,7 +227,7 @@ public class SettingsTab implements Tab, ClickHandler {
@Override
public boolean onClick(Panel panel, User user, ClickType clickType, int slot) {
// Cycle the mode
plugin.getPlayers().setFlagsDisplayMode(user.getUniqueId(), plugin.getPlayers().getFlagsDisplayMode(user.getUniqueId()).getNext());
currentMode.put(user.getUniqueId(), currentMode.getOrDefault(user.getUniqueId(), Mode.BASIC).getNext());
if (panel instanceof TabbedPanel tp) {
tp.setActivePage(0);
tp.refreshPanel();

View File

@ -7,6 +7,7 @@ import org.bukkit.Material;
import org.bukkit.World;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.flags.Flag.Type;
import world.bentobox.bentobox.api.flags.clicklisteners.WorldToggleClick;
import world.bentobox.bentobox.api.localization.TextVariables;

View File

@ -36,6 +36,8 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@ -50,11 +52,12 @@ import world.bentobox.bentobox.listeners.flags.AbstractCommonSetup;
import world.bentobox.bentobox.lists.Flags;
import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.FlagsManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.bentobox.util.Util;
@RunWith(PowerMockRunner.class)
@PrepareForTest({ BentoBox.class, Flags.class, Util.class, Bukkit.class})
@PrepareForTest({ BentoBox.class, Flags.class, Util.class, Bukkit.class, IslandsManager.class })
public class TestBentoBox extends AbstractCommonSetup {
private static final UUID MEMBER_UUID = UUID.randomUUID();
private static final UUID VISITOR_UUID = UUID.randomUUID();
@ -74,6 +77,9 @@ public class TestBentoBox extends AbstractCommonSetup {
public void setUp() throws Exception {
super.setUp();
// IslandsManager static
PowerMockito.mockStatic(IslandsManager.class, Mockito.RETURNS_MOCKS);
when(plugin.getCommandsManager()).thenReturn(cm);
SkullMeta skullMeta = mock(SkullMeta.class);
@ -85,6 +91,7 @@ public class TestBentoBox extends AbstractCommonSetup {
when(player.hasPermission(anyString())).thenReturn(true);
when(location.getWorld()).thenReturn(world);
when(ownerOfIsland.getLocation()).thenReturn(location);
when(visitorToIsland.getLocation()).thenReturn(location);
when(location.clone()).thenReturn(location);
@ -95,6 +102,7 @@ public class TestBentoBox extends AbstractCommonSetup {
island.setOwner(uuid);
island.setProtectionRange(100);
island.setCenter(location);
HashMap<UUID, Integer> members = new HashMap<>();
members.put(uuid, RanksManager.OWNER_RANK);
members.put(MEMBER_UUID, RanksManager.MEMBER_RANK);

View File

@ -32,10 +32,13 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import com.github.puregero.multilib.MultiLib;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.exceptions.InvalidAddonDescriptionException;
import world.bentobox.bentobox.managers.AddonsManager;
@ -46,7 +49,7 @@ import world.bentobox.bentobox.managers.AddonsManager;
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest( { BentoBox.class, Bukkit.class })
@PrepareForTest({ BentoBox.class, Bukkit.class, MultiLib.class })
public class AddonClassLoaderTest {
private enum mandatoryTags {
@ -80,6 +83,7 @@ public class AddonClassLoaderTest {
*/
@Before
public void setUp() throws Exception {
PowerMockito.mockStatic(MultiLib.class, Mockito.RETURNS_MOCKS);
// Set up plugin
plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin);

View File

@ -44,13 +44,15 @@ import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import com.github.puregero.multilib.MultiLib;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.managers.AddonsManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.PlayersManager;
@RunWith(PowerMockRunner.class)
@PrepareForTest( { BentoBox.class, Bukkit.class })
@PrepareForTest({ BentoBox.class, Bukkit.class, MultiLib.class })
public class AddonTest {
public static int BUFFER_SIZE = 10240;
@ -90,6 +92,8 @@ public class AddonTest {
// Addons manager
when(plugin.getAddonsManager()).thenReturn(am);
// MultiLib
PowerMockito.mockStatic(MultiLib.class, Mockito.RETURNS_MOCKS);
// Mock item factory (for itemstacks)
ItemFactory itemFactory = mock(ItemFactory.class);

View File

@ -51,7 +51,7 @@ import world.bentobox.bentobox.util.Util;
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Bukkit.class, BentoBox.class, Util.class })
@PrepareForTest({ Bukkit.class, BentoBox.class, Util.class, IslandsManager.class })
public class AdminInfoCommandTest extends RanksManagerBeforeClassTest {
@Mock
@ -84,6 +84,8 @@ public class AdminInfoCommandTest extends RanksManagerBeforeClassTest {
public void setUp() throws Exception {
super.setUp();
PowerMockito.mockStatic(IslandsManager.class, Mockito.RETURNS_MOCKS);
// IWM
when(plugin.getIWM()).thenReturn(iwm);

View File

@ -144,7 +144,6 @@ public class AdminSettingsCommandTest extends RanksManagerBeforeClassTest {
when(plugin.getIWM()).thenReturn(iwm);
// Players manager
when(plugin.getPlayers()).thenReturn(pm);
when(pm.getFlagsDisplayMode(any())).thenReturn(Mode.BASIC);
//Island Manager
when(plugin.getIslands()).thenReturn(im);
// Island - player has island
@ -267,16 +266,6 @@ public class AdminSettingsCommandTest extends RanksManagerBeforeClassTest {
verify(user).sendMessage("general.errors.use-in-game");
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.AdminSettingsCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringNoArgs() {
assertTrue(asc.execute(user, "", Collections.emptyList()));
verify(pm).setFlagsDisplayMode(user.getUniqueId(), Mode.EXPERT);
// Open panel
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.AdminSettingsCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/

View File

@ -29,6 +29,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@ -54,7 +55,7 @@ import world.bentobox.bentobox.util.Util;
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Bukkit.class, BentoBox.class })
@PrepareForTest({ Bukkit.class, BentoBox.class, IslandsManager.class })
public class AdminUnregisterCommandTest {
private UUID uuid = UUID.randomUUID();
@ -83,6 +84,7 @@ public class AdminUnregisterCommandTest {
*/
@Before
public void setUp() throws Exception {
PowerMockito.mockStatic(IslandsManager.class, Mockito.RETURNS_MOCKS);
// Set up plugin
BentoBox plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin);

View File

@ -39,7 +39,7 @@ import world.bentobox.bentobox.managers.RanksManagerBeforeClassTest;
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Bukkit.class, BentoBox.class })
@PrepareForTest({ Bukkit.class, BentoBox.class, IslandsManager.class })
public class DefaultPlayerCommandTest extends RanksManagerBeforeClassTest {
@Mock
@ -68,6 +68,7 @@ public class DefaultPlayerCommandTest extends RanksManagerBeforeClassTest {
@Before
public void setUp() throws Exception {
super.setUp();
PowerMockito.mockStatic(IslandsManager.class, Mockito.RETURNS_MOCKS);
// User
when(user.getUniqueId()).thenReturn(UUID.randomUUID());

View File

@ -51,7 +51,7 @@ import world.bentobox.bentobox.util.Util;
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class, BentoBox.class, Util.class})
@PrepareForTest({ Bukkit.class, BentoBox.class, Util.class, IslandsManager.class })
public class IslandInfoCommandTest extends RanksManagerBeforeClassTest {
@Mock
@ -84,6 +84,8 @@ public class IslandInfoCommandTest extends RanksManagerBeforeClassTest {
public void setUp() throws Exception {
super.setUp();
PowerMockito.mockStatic(IslandsManager.class, Mockito.RETURNS_MOCKS);
// IWM
when(plugin.getIWM()).thenReturn(iwm);

View File

@ -62,7 +62,7 @@ import world.bentobox.bentobox.managers.island.NewIsland;
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Bukkit.class, BentoBox.class, NewIsland.class })
@PrepareForTest({ Bukkit.class, BentoBox.class, NewIsland.class, IslandsManager.class })
public class IslandResetCommandTest {
@Mock
@ -97,6 +97,7 @@ public class IslandResetCommandTest {
*/
@Before
public void setUp() throws Exception {
PowerMockito.mockStatic(IslandsManager.class, Mockito.RETURNS_MOCKS);
// Set up plugin
BentoBox plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin);

View File

@ -7,10 +7,13 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.UUID;
@ -29,10 +32,11 @@ import org.powermock.modules.junit4.PowerMockRunner;
import com.google.common.collect.ImmutableSet;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.island.team.Invite.Type;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.database.objects.TeamInvite.Type;
import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
@ -74,6 +78,9 @@ public class IslandTeamCommandTest extends RanksManagerBeforeClassTest {
@Mock
private @Nullable Island island;
@Mock
private GameModeAddon addon;
/**
*/
@Before
@ -87,6 +94,7 @@ public class IslandTeamCommandTest extends RanksManagerBeforeClassTest {
// Parent command
when(ic.getPermissionPrefix()).thenReturn("bskyblock.");
when(ic.getWorld()).thenReturn(world);
when(ic.getAddon()).thenReturn(addon);
// user
uuid = UUID.randomUUID();
@ -171,11 +179,14 @@ public class IslandTeamCommandTest extends RanksManagerBeforeClassTest {
/**
* Test method for
* {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamCommand#addInvite(world.bentobox.bentobox.api.commands.island.team.Invite.Type, java.util.UUID, java.util.UUID)}.
* @throws IntrospectionException
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
@Test
public void testAddInvite() {
tc.addInvite(Invite.Type.TEAM, uuid, invitee, island);
assertTrue(tc.isInvited(invitee));
public void testAddInvite() throws IllegalAccessException, InvocationTargetException, IntrospectionException {
tc.addInvite(Type.TEAM, uuid, invitee, island);
verify(h, atLeast(1)).saveObject(any());
}
/**
@ -193,8 +204,7 @@ public class IslandTeamCommandTest extends RanksManagerBeforeClassTest {
*/
@Test
public void testGetInviter() {
tc.addInvite(Invite.Type.TEAM, uuid, invitee, island);
assertEquals(uuid, tc.getInviter(invitee));
assertNull(tc.getInviter(invitee));
}
/**
@ -213,12 +223,6 @@ public class IslandTeamCommandTest extends RanksManagerBeforeClassTest {
@Test
public void testGetInvite() {
assertNull(tc.getInvite(invitee));
tc.addInvite(Invite.Type.TEAM, uuid, invitee, island);
@Nullable
Invite invite = tc.getInvite(invitee);
assertEquals(invitee, invite.getInvitee());
assertEquals(Type.TEAM, invite.getType());
assertEquals(uuid, invite.getInviter());
}
/**
@ -228,7 +232,7 @@ public class IslandTeamCommandTest extends RanksManagerBeforeClassTest {
@Test
public void testRemoveInvite() {
assertNull(tc.getInvite(invitee));
tc.addInvite(Invite.Type.TEAM, uuid, invitee, island);
tc.addInvite(Type.TEAM, uuid, invitee, island);
tc.removeInvite(invitee);
assertNull(tc.getInvite(invitee));
}

View File

@ -32,12 +32,13 @@ import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.Settings;
import world.bentobox.bentobox.TestWorldSettings;
import world.bentobox.bentobox.api.commands.island.team.Invite.Type;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent.TeamEventBuilder;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.database.objects.TeamInvite;
import world.bentobox.bentobox.database.objects.TeamInvite.Type;
import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
@ -72,7 +73,7 @@ public class IslandTeamInviteAcceptCommandTest {
@Mock
private PluginManager pim;
@Mock
private Invite invite;
private TeamInvite invite;
/**
*/
@ -148,7 +149,7 @@ public class IslandTeamInviteAcceptCommandTest {
when(plugin.getIWM()).thenReturn(iwm);
// Invite
when(invite.getType()).thenReturn(Invite.Type.TEAM);
when(invite.getType()).thenReturn(Type.TEAM);
// Team invite accept command
c = new IslandTeamInviteAcceptCommand(itc);
@ -281,7 +282,7 @@ public class IslandTeamInviteAcceptCommandTest {
when(itc.isInvited(any())).thenReturn(true);
when(itc.getInviter(any())).thenReturn(notUUID);
when(itc.getInvite(any())).thenReturn(invite);
when(invite.getType()).thenReturn(Invite.Type.COOP);
when(invite.getType()).thenReturn(Type.COOP);
when(im.inTeam(any(), any())).thenReturn(false);
assertTrue(c.canExecute(user, "accept", Collections.emptyList()));
verify(user, never()).sendMessage("commands.island.team.invite.errors.you-already-are-in-team");
@ -332,7 +333,7 @@ public class IslandTeamInviteAcceptCommandTest {
@Test
public void testExecuteUserStringListOfStringCoop() {
// Coop
when(invite.getType()).thenReturn(Invite.Type.COOP);
when(invite.getType()).thenReturn(Type.COOP);
assertTrue(c.execute(user, "accept", Collections.emptyList()));
verify(user).sendMessage("commands.confirmation.confirm", "[seconds]", "0");
}
@ -343,7 +344,7 @@ public class IslandTeamInviteAcceptCommandTest {
@Test
public void testExecuteUserStringListOfStringTrust() {
// Trust
when(invite.getType()).thenReturn(Invite.Type.TRUST);
when(invite.getType()).thenReturn(Type.TRUST);
assertTrue(c.execute(user, "accept", Collections.emptyList()));
verify(user).sendMessage("commands.confirmation.confirm", "[seconds]", "0");
}

View File

@ -40,12 +40,13 @@ import com.google.common.collect.ImmutableSet;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.Settings;
import world.bentobox.bentobox.TestWorldSettings;
import world.bentobox.bentobox.api.commands.island.team.Invite.Type;
import world.bentobox.bentobox.api.configuration.WorldSettings;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.database.objects.TeamInvite;
import world.bentobox.bentobox.database.objects.TeamInvite.Type;
import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
@ -319,7 +320,7 @@ public class IslandTeamInviteCommandTest extends RanksManagerBeforeClassTest {
assertTrue(itl.execute(user, itl.getLabel(), List.of("target")));
verify(pim).callEvent(any(IslandBaseEvent.class));
verify(user, never()).sendMessage(eq("commands.island.team.invite.removing-invite"));
verify(ic).addInvite(Invite.Type.TEAM, uuid, notUUID, island);
verify(ic).addInvite(Type.TEAM, uuid, notUUID, island);
verify(user).sendMessage("commands.island.team.invite.invitation-sent", TextVariables.NAME, "target", TextVariables.DISPLAY_NAME, "&Ctarget");
verify(target).sendMessage("commands.island.team.invite.name-has-invited-you", TextVariables.NAME, "tastybento", TextVariables.DISPLAY_NAME, "&Ctastbento");
verify(target).sendMessage("commands.island.team.invite.to-accept-or-reject", TextVariables.LABEL, "island");
@ -338,7 +339,7 @@ public class IslandTeamInviteCommandTest extends RanksManagerBeforeClassTest {
assertTrue(itl.execute(user, itl.getLabel(), List.of("target")));
verify(pim).callEvent(any(IslandBaseEvent.class));
verify(user, never()).sendMessage("commands.island.team.invite.removing-invite");
verify(ic).addInvite(Invite.Type.TEAM, uuid, notUUID, island);
verify(ic).addInvite(Type.TEAM, uuid, notUUID, island);
verify(user).sendMessage("commands.island.team.invite.invitation-sent", TextVariables.NAME, "target",
TextVariables.DISPLAY_NAME, "&Ctarget");
verify(target).sendMessage("commands.island.team.invite.name-has-invited-you", TextVariables.NAME, "tastybento",
@ -359,7 +360,7 @@ public class IslandTeamInviteCommandTest extends RanksManagerBeforeClassTest {
when(ic.isInvited(notUUID)).thenReturn(true);
// Set up invite
when(ic.getInviter(notUUID)).thenReturn(uuid);
Invite invite = mock(Invite.class);
TeamInvite invite = mock(TeamInvite.class);
when(invite.getType()).thenReturn(Type.TEAM);
when(ic.getInvite(notUUID)).thenReturn(invite);
assertTrue(itl.execute(user, itl.getLabel(), List.of("target")));

View File

@ -54,7 +54,7 @@ import world.bentobox.bentobox.managers.PlayersManager;
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Bukkit.class, BentoBox.class, User.class })
@PrepareForTest({ Bukkit.class, BentoBox.class, User.class, IslandsManager.class })
public class IslandTeamSetownerCommandTest {
@Mock
@ -84,6 +84,8 @@ public class IslandTeamSetownerCommandTest {
*/
@Before
public void setUp() throws Exception {
PowerMockito.mockStatic(IslandsManager.class, Mockito.RETURNS_MOCKS);
// Set up plugin
BentoBox plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
@ -276,7 +278,6 @@ public class IslandTeamSetownerCommandTest {
assertTrue(its.canExecute(user, "", List.of("tastybento")));
assertTrue(its.execute(user, "", List.of("tastybento")));
verify(im).setOwner(any(), eq(user), eq(target));
verify(im).save(island);
}
/**
@ -292,7 +293,6 @@ public class IslandTeamSetownerCommandTest {
assertTrue(its.canExecute(user, "", List.of("tastybento")));
assertTrue(its.execute(user, "", List.of("tastybento")));
verify(im).setOwner(any(), eq(user), eq(target));
verify(im).save(island);
}
/**

View File

@ -21,6 +21,7 @@ import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
@ -28,13 +29,14 @@ import world.bentobox.bentobox.api.events.island.IslandEvent.Reason;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBundle;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.database.objects.IslandDeletion;
import world.bentobox.bentobox.managers.IslandsManager;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ BentoBox.class, Bukkit.class })
@PrepareForTest({ BentoBox.class, Bukkit.class, IslandsManager.class })
public class IslandEventTest {
private Island island;
@ -47,11 +49,18 @@ public class IslandEventTest {
private IslandDeletion deletedIslandInfo;
@Mock
private PluginManager pim;
@Mock
private BentoBox plugin;
/**
*/
@Before
public void setUp() throws Exception {
PowerMockito.mockStatic(IslandsManager.class, Mockito.RETURNS_MOCKS);
// Set up plugin
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
uuid = UUID.randomUUID();
// Bukkit
PowerMockito.mockStatic(Bukkit.class);

View File

@ -46,6 +46,7 @@ import world.bentobox.bentobox.lists.Flags;
import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.FlagsManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.bentobox.util.Pair;
@ -54,7 +55,7 @@ import world.bentobox.bentobox.util.Pair;
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Bukkit.class })
@PrepareForTest({ Bukkit.class, IslandsManager.class })
public class IslandTest {
private static final int DISTANCE = 400;
@ -105,6 +106,9 @@ public class IslandTest {
// Commands manager
when(plugin.getCommandsManager()).thenReturn(cm);
// Islands Manager
PowerMockito.mockStatic(IslandsManager.class, Mockito.RETURNS_MOCKS);
i = new Island(new Island(location, uuid, 100));
}
@ -1105,15 +1109,6 @@ public class IslandTest {
assertTrue(ii.isChanged());
}
/**
* Test method for {@link world.bentobox.bentobox.database.objects.Island#setChanged(boolean)}.
*/
@Test
public void testSetChangedBoolean() {
i.setChanged(false);
assertFalse(i.isChanged());
}
/**
* Test method for {@link world.bentobox.bentobox.database.objects.Island#getProtectionCenter()}.
*/

View File

@ -65,7 +65,7 @@ import world.bentobox.bentobox.util.Util;
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ BentoBox.class, Util.class, Bukkit.class })
@PrepareForTest({ BentoBox.class, Util.class, Bukkit.class, IslandsManager.class })
public class JoinLeaveListenerTest {
private static final String[] NAMES = { "adam", "ben", "cara", "dave", "ed", "frank", "freddy", "george", "harry",
@ -111,6 +111,8 @@ public class JoinLeaveListenerTest {
*/
@Before
public void setUp() throws Exception {
PowerMockito.mockStatic(IslandsManager.class, Mockito.RETURNS_MOCKS);
// Set up plugin
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
@ -218,8 +220,6 @@ public class JoinLeaveListenerTest {
jll = new JoinLeaveListener(plugin);
}
/**
*/
@After
public void tearDown() {
User.clearUsers();
@ -235,8 +235,7 @@ public class JoinLeaveListenerTest {
PlayerJoinEvent event = new PlayerJoinEvent(player, "");
jll.onPlayerJoin(event);
// Verify
verify(pm, times(2)).addPlayer(any());
verify(pm, times(2)).save(any());
verify(pm, times(3)).getPlayer(any());
verify(player, never()).sendMessage(anyString());
// Verify resets
verify(pm).setResets(eq(world), any(), eq(0));
@ -245,7 +244,6 @@ public class JoinLeaveListenerTest {
verify(chest).clear();
verify(inv).clear();
assertTrue(set.isEmpty());
verify(pm, times(2)).save(any());
}
/**
@ -262,7 +260,6 @@ public class JoinLeaveListenerTest {
verify(chest, never()).clear();
verify(inv, never()).clear();
assertFalse(set.isEmpty());
verify(pm).save(any());
}
/**
@ -355,8 +352,7 @@ public class JoinLeaveListenerTest {
PlayerJoinEvent event = new PlayerJoinEvent(player, "");
jll.onPlayerJoin(event);
// Verify
verify(pm, times(2)).addPlayer(any());
verify(pm, times(2)).save(any());
verify(pm, times(3)).getPlayer(any());
verify(player).sendMessage(eq("commands.island.create.on-first-login"));
}
@ -372,7 +368,6 @@ public class JoinLeaveListenerTest {
verify(chest).clear();
verify(inv).clear();
assertTrue(set.isEmpty());
verify(pm).save(any());
}
/**
@ -387,7 +382,6 @@ public class JoinLeaveListenerTest {
verify(chest, never()).clear();
verify(inv, never()).clear();
assertFalse(set.isEmpty());
verify(pm, never()).save(any());
}
/**

View File

@ -37,6 +37,8 @@ import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import com.github.puregero.multilib.MultiLib;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.Settings;
import world.bentobox.bentobox.api.addons.Addon;
@ -49,7 +51,7 @@ import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType;
import world.bentobox.bentobox.database.objects.DataObject;
@RunWith(PowerMockRunner.class)
@PrepareForTest( {Bukkit.class, BentoBox.class, DefaultPermissions.class} )
@PrepareForTest({ Bukkit.class, BentoBox.class, DefaultPermissions.class, MultiLib.class })
public class AddonsManagerTest {
private BentoBox plugin;
@ -81,6 +83,8 @@ public class AddonsManagerTest {
when(plugin.getSettings()).thenReturn(s);
PowerMockito.mockStatic(DefaultPermissions.class);
PowerMockito.mockStatic(MultiLib.class, Mockito.RETURNS_MOCKS);
}
/**

View File

@ -45,6 +45,8 @@ import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.github.puregero.multilib.MultiLib;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.addons.AddonDescription;
@ -62,7 +64,7 @@ import world.bentobox.bentobox.database.objects.Island;
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest( {Bukkit.class, BentoBox.class, BlueprintPaster.class} )
@PrepareForTest({ Bukkit.class, BentoBox.class, BlueprintPaster.class, MultiLib.class })
public class BlueprintsManagerTest {
public static int BUFFER_SIZE = 10240;
@ -95,10 +97,12 @@ public class BlueprintsManagerTest {
private int times;
@Mock
private Server server;
/**
*/
@Before
public void setUp() throws Exception {
// Multilib
PowerMockito.mockStatic(MultiLib.class, Mockito.RETURNS_MOCKS);
// Make the addon
dataFolder = new File("dataFolder");
jarFile = new File("addon.jar");

View File

@ -65,6 +65,7 @@ import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import com.github.puregero.multilib.MultiLib;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
@ -85,7 +86,7 @@ import world.bentobox.bentobox.managers.island.IslandCache;
import world.bentobox.bentobox.util.Util;
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Bukkit.class, BentoBox.class, Util.class, Location.class })
@PrepareForTest({ Bukkit.class, BentoBox.class, Util.class, Location.class, MultiLib.class })
public class IslandsManagerTest extends AbstractCommonSetup {
@Mock
@ -157,6 +158,9 @@ public class IslandsManagerTest extends AbstractCommonSetup {
plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// Mutilib
PowerMockito.mockStatic(MultiLib.class, Mockito.RETURNS_MOCKS);
// island world mgr
when(world.getName()).thenReturn("world");
when(world.getEnvironment()).thenReturn(World.Environment.NORMAL);
@ -242,7 +246,7 @@ public class IslandsManagerTest extends AbstractCommonSetup {
// Island
when(island.getOwner()).thenReturn(uuid);
when(island.getWorld()).thenReturn(world);
when(island.getMaxMembers()).thenReturn(null); // default
when(island.getMaxMembers()).thenReturn(new HashMap<>()); // default
when(island.getMaxMembers(Mockito.anyInt())).thenReturn(null); // default
when(island.getCenter()).thenReturn(location);
when(island.getProtectionCenter()).thenReturn(location);
@ -329,6 +333,9 @@ public class IslandsManagerTest extends AbstractCommonSetup {
// Util strip spaces
when(Util.stripSpaceAfterColorCodes(anyString())).thenCallRealMethod();
// World UID
when(world.getUID()).thenReturn(uuid);
// Class under test
im = new IslandsManager(plugin);
// Set cache
@ -970,7 +977,7 @@ public class IslandsManagerTest extends AbstractCommonSetup {
/**
* Test method for
* {@link world.bentobox.bentobox.managers.IslandsManager#save(Island)}.
* {@link world.bentobox.bentobox.managers.IslandsManager#updateIsland(Island)}.
*/
@Test
public void testSave() {
@ -1372,14 +1379,14 @@ public class IslandsManagerTest extends AbstractCommonSetup {
Island island = mock(Island.class);
when(island.getOwner()).thenReturn(uuid);
when(island.getWorld()).thenReturn(world);
when(island.getMaxMembers()).thenReturn(null);
when(island.getMaxMembers()).thenReturn(new HashMap<>());
when(island.getMaxMembers(Mockito.anyInt())).thenReturn(null);
when(iwm.getMaxTeamSize(eq(world))).thenReturn(4);
// Offline owner
when(Bukkit.getPlayer(any(UUID.class))).thenReturn(null);
// Test
assertEquals(4, im.getMaxMembers(island, RanksManager.MEMBER_RANK));
verify(island).setMaxMembers(eq(RanksManager.MEMBER_RANK), eq(null));
verify(island, never()).setMaxMembers(eq(RanksManager.MEMBER_RANK), eq(null)); // No change
}
/**
@ -1391,14 +1398,14 @@ public class IslandsManagerTest extends AbstractCommonSetup {
Island island = mock(Island.class);
when(island.getOwner()).thenReturn(uuid);
when(island.getWorld()).thenReturn(world);
when(island.getMaxMembers()).thenReturn(null);
when(island.getMaxMembers()).thenReturn(new HashMap<>());
when(island.getMaxMembers(Mockito.anyInt())).thenReturn(null);
when(iwm.getMaxTeamSize(eq(world))).thenReturn(4);
// Online owner
when(Bukkit.getPlayer(any(UUID.class))).thenReturn(player);
// Test
assertEquals(4, im.getMaxMembers(island, RanksManager.MEMBER_RANK));
verify(island).setMaxMembers(eq(RanksManager.MEMBER_RANK), eq(null));
verify(island, never()).setMaxMembers(RanksManager.MEMBER_RANK, null);
}
/**
@ -1410,7 +1417,7 @@ public class IslandsManagerTest extends AbstractCommonSetup {
Island island = mock(Island.class);
when(island.getOwner()).thenReturn(uuid);
when(island.getWorld()).thenReturn(world);
when(island.getMaxMembers()).thenReturn(null);
when(island.getMaxMembers()).thenReturn(new HashMap<>());
when(island.getMaxMembers(Mockito.anyInt())).thenReturn(null);
when(iwm.getMaxTeamSize(eq(world))).thenReturn(4);
when(iwm.getMaxCoopSize(eq(world))).thenReturn(2);
@ -1419,9 +1426,9 @@ public class IslandsManagerTest extends AbstractCommonSetup {
when(Bukkit.getPlayer(any(UUID.class))).thenReturn(player);
// Test
assertEquals(2, im.getMaxMembers(island, RanksManager.COOP_RANK));
verify(island).setMaxMembers(eq(RanksManager.COOP_RANK), eq(null));
verify(island, never()).setMaxMembers(RanksManager.COOP_RANK, null); // No change
assertEquals(3, im.getMaxMembers(island, RanksManager.TRUSTED_RANK));
verify(island).setMaxMembers(eq(RanksManager.TRUSTED_RANK), eq(null));
verify(island, never()).setMaxMembers(RanksManager.TRUSTED_RANK, null);
}
/**
@ -1439,7 +1446,7 @@ public class IslandsManagerTest extends AbstractCommonSetup {
when(Bukkit.getPlayer(any(UUID.class))).thenReturn(player);
// Test
assertEquals(10, im.getMaxMembers(island, RanksManager.MEMBER_RANK));
verify(island).setMaxMembers(eq(RanksManager.MEMBER_RANK), eq(10));
verify(island).setMaxMembers(RanksManager.MEMBER_RANK, 10);
}
/**
@ -1457,7 +1464,7 @@ public class IslandsManagerTest extends AbstractCommonSetup {
when(Bukkit.getPlayer(any(UUID.class))).thenReturn(player);
// Test
assertEquals(10, im.getMaxMembers(island, RanksManager.MEMBER_RANK));
verify(island).setMaxMembers(eq(RanksManager.MEMBER_RANK), eq(10));
verify(island).setMaxMembers(RanksManager.MEMBER_RANK, 10);
}
/**
@ -1469,7 +1476,7 @@ public class IslandsManagerTest extends AbstractCommonSetup {
Island island = mock(Island.class);
when(island.getOwner()).thenReturn(uuid);
when(island.getWorld()).thenReturn(world);
when(island.getMaxMembers()).thenReturn(null);
when(island.getMaxMembers()).thenReturn(new HashMap<>());
when(iwm.getMaxTeamSize(eq(world))).thenReturn(4);
// Permission
when(iwm.getPermissionPrefix(any())).thenReturn("bskyblock.");
@ -1482,7 +1489,7 @@ public class IslandsManagerTest extends AbstractCommonSetup {
when(Bukkit.getPlayer(any(UUID.class))).thenReturn(player);
// Test
assertEquals(8, im.getMaxMembers(island, RanksManager.MEMBER_RANK));
verify(island).setMaxMembers(eq(RanksManager.MEMBER_RANK), eq(8));
verify(island).setMaxMembers(RanksManager.MEMBER_RANK, 8);
}
/**
@ -1494,7 +1501,7 @@ public class IslandsManagerTest extends AbstractCommonSetup {
Island island = mock(Island.class);
// Test
im.setMaxMembers(island, RanksManager.MEMBER_RANK, 40);
verify(island).setMaxMembers(eq(RanksManager.MEMBER_RANK), eq(40));
verify(island).setMaxMembers(RanksManager.MEMBER_RANK, 40);
}
/**
@ -1546,7 +1553,7 @@ public class IslandsManagerTest extends AbstractCommonSetup {
// Test
IslandsManager im = new IslandsManager(plugin);
assertEquals(4, im.getMaxHomes(island));
verify(island).setMaxHomes(eq(null));
verify(island, never()).setMaxHomes(null);
}
/**
@ -1572,7 +1579,7 @@ public class IslandsManagerTest extends AbstractCommonSetup {
// Test
IslandsManager im = new IslandsManager(plugin);
assertEquals(20, im.getMaxHomes(island));
verify(island).setMaxHomes(eq(20));
verify(island, never()).setMaxHomes(20);
}
/**
@ -1598,7 +1605,7 @@ public class IslandsManagerTest extends AbstractCommonSetup {
// Test
IslandsManager im = new IslandsManager(plugin);
assertEquals(8, im.getMaxHomes(island));
verify(island).setMaxHomes(eq(8));
verify(island).setMaxHomes(8);
}
/**

View File

@ -6,7 +6,9 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@ -53,13 +55,13 @@ import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.Settings;
import world.bentobox.bentobox.api.flags.Flag.Mode;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.AbstractDatabaseHandler;
import world.bentobox.bentobox.database.Database;
import world.bentobox.bentobox.database.DatabaseSetup;
import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.database.objects.Names;
import world.bentobox.bentobox.database.objects.Players;
import world.bentobox.bentobox.hooks.VaultHook;
import world.bentobox.bentobox.util.Util;
@ -240,6 +242,18 @@ public class PlayersManagerTest {
when(tamed.getOwner()).thenReturn(p);
when(world.getEntitiesByClass(Tameable.class)).thenReturn(list);
// Loading objects
Object players = new Players();
when(h.loadObject(anyString())).thenReturn(players);
// Set up names database
List<Object> names = new ArrayList<>();
Names name = new Names();
name.setUniqueId("tastybento");
name.setUuid(uuid);
names.add(name);
when(h.loadObjects()).thenReturn(names);
when(h.objectExists(anyString())).thenReturn(true);
// Class under test
pm = new PlayersManager(plugin);
}
@ -263,21 +277,6 @@ public class PlayersManagerTest {
assertEquals(deaths + 1, pm.getDeaths(world, uuid));
}
/**
* Test method for
* {@link world.bentobox.bentobox.managers.PlayersManager#addPlayer(java.util.UUID)}.
*/
@Test
public void testAddPlayer() {
pm.addPlayer(null);
// Add twice
assertFalse(pm.isKnown(uuid));
pm.addPlayer(uuid);
assertTrue(pm.isKnown(uuid));
pm.addPlayer(uuid);
}
/**
* Test method for
* {@link world.bentobox.bentobox.managers.PlayersManager#addReset(org.bukkit.World, java.util.UUID)}.
@ -372,15 +371,6 @@ public class PlayersManagerTest {
assertEquals(0, pm.getDeaths(world, uuid));
}
/**
* Test method for
* {@link world.bentobox.bentobox.managers.PlayersManager#getFlagsDisplayMode(java.util.UUID)}.
*/
@Test
public void testGetFlagsDisplayMode() {
assertEquals(Mode.BASIC, pm.getFlagsDisplayMode(uuid));
}
/**
* Test method for
* {@link world.bentobox.bentobox.managers.PlayersManager#getLocale(java.util.UUID)}.
@ -401,24 +391,13 @@ public class PlayersManagerTest {
assertEquals("tastybento", name);
}
/**
* Test method for
* {@link world.bentobox.bentobox.managers.PlayersManager#getPlayer(java.util.UUID)}.
*/
@Test
public void testGetPlayer() {
Players player = pm.getPlayer(uuid);
assertEquals("tastybento", player.getPlayerName());
assertEquals(uuid.toString(), player.getUniqueId());
}
/**
* Test method for
* {@link world.bentobox.bentobox.managers.PlayersManager#getPlayers()}.
*/
@Test
public void testGetPlayers() {
assertTrue(pm.getPlayers().isEmpty());
assertFalse(pm.getPlayers().isEmpty());
}
/**
@ -442,11 +421,18 @@ public class PlayersManagerTest {
/**
* Test method for
* {@link world.bentobox.bentobox.managers.PlayersManager#setResets(World, UUID, int)}.
* @throws IntrospectionException
* @throws NoSuchMethodException
* @throws ClassNotFoundException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws InstantiationException
*/
@Test
public void testGetSetResetsLeft() {
public void testGetSetResetsLeft() throws InstantiationException, IllegalAccessException, InvocationTargetException,
ClassNotFoundException, NoSuchMethodException, IntrospectionException {
// Add a player
pm.addPlayer(uuid);
pm.getPlayer(uuid);
assertEquals(0, pm.getResets(world, uuid));
pm.setResets(world, uuid, 20);
assertEquals(20, pm.getResets(world, uuid));
@ -455,12 +441,19 @@ public class PlayersManagerTest {
/**
* Test method for
* {@link world.bentobox.bentobox.managers.PlayersManager#getUser(java.lang.String)}.
* @throws IntrospectionException
* @throws NoSuchMethodException
* @throws ClassNotFoundException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws InstantiationException
*/
@Test
public void testGetUserString() {
public void testGetUserString() throws InstantiationException, IllegalAccessException, InvocationTargetException,
ClassNotFoundException, NoSuchMethodException, IntrospectionException {
User user = pm.getUser("random");
assertNull(user);
pm.addPlayer(uuid);
pm.getPlayer(uuid);
user = pm.getUser("tastybento");
assertEquals("tastybento", user.getName());
}
@ -481,7 +474,7 @@ public class PlayersManagerTest {
*/
@Test
public void testGetUUID() {
pm.addPlayer(uuid);
pm.getPlayer(uuid);
assertEquals(uuid, pm.getUUID("tastybento"));
assertNull(pm.getUUID("unknown"));
}
@ -494,7 +487,7 @@ public class PlayersManagerTest {
public void testGetUUIDOfflinePlayer() {
pm.setHandler(db);
// Add a player to the cache
pm.addPlayer(uuid);
pm.getPlayer(uuid);
UUID uuidResult = pm.getUUID("tastybento");
assertEquals(uuid, uuidResult);
}
@ -507,7 +500,7 @@ public class PlayersManagerTest {
public void testGetUUIDUnknownPlayer() {
pm.setHandler(db);
// Add a player to the cache
pm.addPlayer(uuid);
pm.getPlayer(uuid);
// Unknown player should return null
assertNull(pm.getUUID("tastybento123"));
}
@ -537,8 +530,8 @@ public class PlayersManagerTest {
@Test
public void testIsKnown() {
pm.addPlayer(uuid);
pm.addPlayer(notUUID);
pm.getPlayer(uuid);
pm.getPlayer(notUUID);
assertFalse(pm.isKnown(null));
assertTrue(pm.isKnown(uuid));
@ -547,21 +540,11 @@ public class PlayersManagerTest {
/**
* Test method for
* {@link world.bentobox.bentobox.managers.PlayersManager#isSaveTaskRunning()}.
* {@link world.bentobox.bentobox.managers.PlayersManager#setHandler(Database)}
*/
@Test
public void testIsSaveTaskRunning() {
assertFalse(pm.isSaveTaskRunning());
}
/**
* Test method for
* {@link world.bentobox.bentobox.managers.PlayersManager#load()}.
*/
@Test
public void testLoad() {
public void testSetHandler() {
pm.setHandler(db);
pm.load();
}
/**
@ -596,43 +579,6 @@ public class PlayersManagerTest {
assertNull(pm.getUUID("tastybeto"));
}
/**
* Test method for
* {@link world.bentobox.bentobox.managers.PlayersManager#saveAll()}.
*/
@Test
public void testSaveAll() {
pm.setHandler(db);
pm.addPlayer(uuid);
pm.saveAll();
verify(db).saveObjectAsync(any());
}
/**
* Test method for
* {@link world.bentobox.bentobox.managers.PlayersManager#saveAll(boolean)}.
*/
@Test
public void testSaveAllBoolean() {
pm.setHandler(db);
pm.addPlayer(uuid);
pm.saveAll(true);
assertTrue(pm.isSaveTaskRunning());
}
/**
* Test method for
* {@link world.bentobox.bentobox.managers.PlayersManager#save(java.util.UUID)}.
*/
@Test
public void testSave() {
pm.setHandler(db);
// Add a player
pm.addPlayer(uuid);
pm.save(uuid);
verify(db).saveObjectAsync(any());
}
/**
* Test method for
* {@link world.bentobox.bentobox.managers.PlayersManager#setPlayerName(world.bentobox.bentobox.api.user.User)}.
@ -641,7 +587,7 @@ public class PlayersManagerTest {
public void testSetandGetPlayerName() {
pm.setHandler(db);
// Add a player
pm.addPlayer(uuid);
pm.getPlayer(uuid);
assertEquals("tastybento", pm.getName(user.getUniqueId()));
pm.setPlayerName(user);
assertEquals(user.getName(), pm.getName(user.getUniqueId()));
@ -658,16 +604,6 @@ public class PlayersManagerTest {
}
/**
* Test method for
* {@link world.bentobox.bentobox.managers.PlayersManager#setFlagsDisplayMode(java.util.UUID, world.bentobox.bentobox.api.flags.Flag.Mode)}.
*/
@Test
public void testSetFlagsDisplayMode() {
pm.setFlagsDisplayMode(uuid, Mode.ADVANCED);
assertEquals(Mode.ADVANCED, pm.getFlagsDisplayMode(uuid));
}
/**
* Test method for
* {@link world.bentobox.bentobox.managers.PlayersManager#setInTeleport(java.util.UUID)}.
@ -692,15 +628,15 @@ public class PlayersManagerTest {
/**
* Test method for
* {@link world.bentobox.bentobox.managers.PlayersManager#setPlayerName(world.bentobox.bentobox.api.user.User)}.
* @throws IntrospectionException
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
@Test
public void testSetPlayerName() {
public void testSetPlayerName() throws IllegalAccessException, InvocationTargetException, IntrospectionException {
pm.setPlayerName(user);
assertEquals("tastybento", pm.getName(uuid));
when(user.getName()).thenReturn("newName");
assertEquals("tastybento", pm.getName(uuid));
pm.setPlayerName(user);
assertEquals("newName", pm.getName(uuid));
// Player and names database saves
verify(h, atLeast(2)).saveObject(any());
}
/**

View File

@ -1,17 +1,23 @@
package world.bentobox.bentobox.managers;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.beans.IntrospectionException;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
@ -22,6 +28,7 @@ import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.AbstractDatabaseHandler;
import world.bentobox.bentobox.database.DatabaseSetup;
/**
@ -63,6 +70,22 @@ public abstract class RanksManagerBeforeClassTest {
@Mock
public RanksManager rm;
protected static AbstractDatabaseHandler<Object> h;
@SuppressWarnings("unchecked")
@BeforeClass
public static void beforeClass() throws IllegalAccessException, InvocationTargetException, IntrospectionException {
// This has to be done beforeClass otherwise the tests will interfere with each
// other
h = mock(AbstractDatabaseHandler.class);
// Database
PowerMockito.mockStatic(DatabaseSetup.class);
DatabaseSetup dbSetup = mock(DatabaseSetup.class);
when(DatabaseSetup.getDatabase()).thenReturn(dbSetup);
when(dbSetup.getHandler(any())).thenReturn(h);
when(h.saveObject(any())).thenReturn(CompletableFuture.completedFuture(true));
}
@Before
public void setUp() throws Exception {
// Set up plugin

View File

@ -56,7 +56,7 @@ import world.bentobox.bentobox.util.Util;
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Util.class, IslandEvent.class, Bukkit.class })
@PrepareForTest({ Util.class, IslandEvent.class, Bukkit.class, IslandsManager.class })
public class NewIslandTest {
private static final String NAME = "name";
@ -105,6 +105,7 @@ public class NewIslandTest {
*/
@Before
public void setUp() throws Exception {
PowerMockito.mockStatic(IslandsManager.class, Mockito.RETURNS_MOCKS);
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// Islands manager
when(plugin.getIslands()).thenReturn(im);
@ -205,7 +206,8 @@ public class NewIslandTest {
NewIsland.builder().addon(addon).name(NAME).player(user).noPaste().reason(Reason.CREATE).oldIsland(oldIsland)
.build();
// Verifications
verify(im).save(eq(island));
PowerMockito.verifyStatic(IslandsManager.class);
IslandsManager.updateIsland(eq(island));
verify(island).setFlagsDefaults();
verify(scheduler).runTask(any(BentoBox.class), any(Runnable.class));
verify(builder, times(2)).build();
@ -224,7 +226,8 @@ public class NewIslandTest {
when(builder.build()).thenReturn(ire);
NewIsland.builder().addon(addon).name(NAME).player(user).noPaste().reason(Reason.RESET).oldIsland(oldIsland).build();
// Verifications
verify(im).save(eq(island));
PowerMockito.verifyStatic(IslandsManager.class);
IslandsManager.updateIsland(eq(island));
verify(island).setFlagsDefaults();
verify(scheduler).runTask(any(BentoBox.class), any(Runnable.class));
verify(builder, times(2)).build();
@ -243,7 +246,8 @@ public class NewIslandTest {
public void testBuilderNoOldIsland() throws Exception {
NewIsland.builder().addon(addon).name(NAME).player(user).noPaste().reason(Reason.CREATE).build();
// Verifications
verify(im).save(eq(island));
PowerMockito.verifyStatic(IslandsManager.class);
IslandsManager.updateIsland(eq(island));
verify(island).setFlagsDefaults();
verify(scheduler).runTask(any(BentoBox.class), any(Runnable.class));
verify(builder, times(2)).build();
@ -262,7 +266,8 @@ public class NewIslandTest {
when(location.distance(any())).thenReturn(30D);
NewIsland.builder().addon(addon).name(NAME).player(user).reason(Reason.CREATE).build();
// Verifications
verify(im).save(eq(island));
PowerMockito.verifyStatic(IslandsManager.class);
IslandsManager.updateIsland(eq(island));
verify(island).setFlagsDefaults();
verify(bpm).paste(eq(addon), eq(island), eq(NAME), any(Runnable.class), eq(false));
verify(builder, times(2)).build();
@ -281,7 +286,8 @@ public class NewIslandTest {
NewIsland.builder().addon(addon).name(NAME).player(user).reason(Reason.CREATE).build();
PowerMockito.mockStatic(Bukkit.class);
// Verifications
verify(im).save(island);
PowerMockito.verifyStatic(IslandsManager.class);
IslandsManager.updateIsland(eq(island));
verify(island).setFlagsDefaults();
verify(bpm).paste(eq(addon), eq(island), eq(NAME), any(Runnable.class), eq(true));
verify(builder, times(2)).build();
@ -299,7 +305,8 @@ public class NewIslandTest {
when(im.hasIsland(any(), any(User.class))).thenReturn(true);
NewIsland.builder().addon(addon).name(NAME).player(user).noPaste().reason(Reason.CREATE).oldIsland(oldIsland).build();
// Verifications
verify(im).save(eq(island));
PowerMockito.verifyStatic(IslandsManager.class);
IslandsManager.updateIsland(eq(island));
verify(island).setFlagsDefaults();
verify(scheduler).runTask(any(BentoBox.class), any(Runnable.class));
verify(builder, times(2)).build();
@ -320,7 +327,8 @@ public class NewIslandTest {
when(im.hasIsland(any(), any(User.class))).thenReturn(true);
NewIsland.builder().addon(addon).name(NAME).player(user).noPaste().reason(Reason.CREATE).oldIsland(oldIsland).build();
// Verifications
verify(im).save(eq(island));
PowerMockito.verifyStatic(IslandsManager.class);
IslandsManager.updateIsland(eq(island));
verify(island).setFlagsDefaults();
verify(scheduler).runTask(any(BentoBox.class), any(Runnable.class));
verify(builder, times(2)).build();
@ -342,7 +350,8 @@ public class NewIslandTest {
when(im.hasIsland(any(), any(User.class))).thenReturn(true);
NewIsland.builder().addon(addon).name(NAME).player(user).noPaste().reason(Reason.CREATE).oldIsland(oldIsland).build();
// Verifications
verify(im).save(eq(island));
PowerMockito.verifyStatic(IslandsManager.class);
IslandsManager.updateIsland(eq(island));
verify(island).setFlagsDefaults();
verify(scheduler).runTask(any(BentoBox.class), any(Runnable.class));
verify(builder, times(2)).build();

View File

@ -58,7 +58,7 @@ import world.bentobox.bentobox.util.teleport.ClosestSafeSpotTeleport.PositionDat
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Util.class, Bukkit.class})
@PrepareForTest({ Util.class, Bukkit.class, IslandsManager.class })
public class ClosestSafeSpotTeleportTest {
// Class under test
@ -102,6 +102,9 @@ public class ClosestSafeSpotTeleportTest {
*/
@Before
public void setUp() throws Exception {
// IslandsManager static
PowerMockito.mockStatic(IslandsManager.class, Mockito.RETURNS_MOCKS);
// Setup instance
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// IWM

View File

@ -47,7 +47,7 @@ import world.bentobox.bentobox.util.Util;
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Util.class, Bukkit.class})
@PrepareForTest({ Util.class, Bukkit.class, IslandsManager.class })
public class SafeSpotTeleportTest {
// Class under test
@ -92,6 +92,7 @@ public class SafeSpotTeleportTest {
*/
@Before
public void setUp() throws Exception {
PowerMockito.mockStatic(IslandsManager.class, Mockito.RETURNS_MOCKS);
// Setup instance
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// IWM