WIP multipaper

This commit is contained in:
tastybento 2024-04-07 17:05:21 -07:00
parent c34d6ff868
commit aaa1504dc6
25 changed files with 327 additions and 740 deletions

23
pom.xml
View File

@ -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

@ -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();

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

@ -206,11 +206,11 @@ public class AdminSettingsCommand extends CompositeCommand {
switch (f.getType()) {
case PROTECTION -> {
island.setFlag(f, rank);
getIslands().save(island);
getIslands().updateIsland(island);
}
case SETTING -> {
island.setSettingsFlag(f, activeState);
getIslands().save(island);
getIslands().updateIsland(island);
}
case WORLD_SETTING -> f.setSetting(getWorld(), activeState);
default -> {

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

View File

@ -13,6 +13,7 @@ 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.IslandsManager;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.bentobox.util.Util;
@ -197,7 +198,7 @@ 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);
IslandsManager.updateIsland(teamIsland);
// Fire event
TeamEvent.builder().island(teamIsland).reason(TeamEvent.Reason.JOINED).involvedPlayer(user.getUniqueId())
.build();

View File

@ -91,7 +91,7 @@ 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);
getIslands().updateIsland(island);
return true;
}

View File

@ -41,6 +41,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;
@ -243,7 +244,6 @@ public class Island implements DataObject, MetaDataAble {
range = BentoBox.getInstance().getIWM().getIslandDistance(world);
this.protectionRange = protectionRange;
this.maxEverProtectionRange = protectionRange;
this.setChanged();
}
/**
@ -290,6 +290,7 @@ public class Island implements DataObject, MetaDataAble {
this.updatedDate = island.getUpdatedDate();
this.world = island.getWorld();
this.bonusRanges.addAll(island.getBonusRanges());
this.primary = island.primary;
this.setChanged();
}
@ -304,8 +305,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 +323,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 +1011,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 (!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 +1049,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();
}
/**
@ -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();
}
/**
@ -1206,8 +1226,14 @@ public class Island implements DataObject, MetaDataAble {
if (uuid == null) {
return; // Defensive code
}
members.put(uuid, rank);
setChanged();
members.compute(uuid, (key, value) -> {
if (value == null || !value.equals(rank)) {
setChanged(); // Call setChanged only if the value is updated.
BentoBox.getInstance().logDebug("Set rank for " + uuid + " to " + rank);
return rank;
}
return value;
});
}
/**
@ -1266,7 +1292,6 @@ public class Island implements DataObject, MetaDataAble {
@Override
public void setUniqueId(String uniqueId) {
this.uniqueId = uniqueId;
setChanged();
}
/**
@ -1274,7 +1299,6 @@ public class Island implements DataObject, MetaDataAble {
*/
public void setUpdatedDate(long updatedDate) {
this.updatedDate = updatedDate;
setChanged();
}
/**
@ -1347,8 +1371,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 +1397,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 +1485,6 @@ public class Island implements DataObject, MetaDataAble {
*/
public void setGameMode(String gameMode) {
this.gameMode = gameMode;
setChanged();
}
/**
@ -1603,8 +1632,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 +1658,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 +1694,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 +1730,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 +1782,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 +1807,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 +1821,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 +1864,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 +1886,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 +1914,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 +1983,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();
}
}
/**
@ -1946,8 +2007,10 @@ public class Island implements DataObject, MetaDataAble {
* @param primary the primary to set
*/
public void setPrimary(boolean primary) {
this.primary = primary;
setChanged();
if (this.primary != primary) {
this.primary = primary;
setChanged();
}
}
/**

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;
@ -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);
}
@ -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,7 +61,7 @@ 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);
plugin.getIslands().updateIsland(island);
} else {
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_METAL_HIT, 1F, 1F);

View File

@ -37,6 +37,8 @@ import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import com.github.puregero.multilib.MultiLib;
import io.papermc.lib.PaperLib;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
@ -44,7 +46,6 @@ 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.objects.Island;
@ -65,29 +66,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 +96,52 @@ 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 -> {
BentoBox.getInstance().logDebug("Updating island " + id);
Island island = handler.loadObject(id);
if (island != null) {
islandCache.updateIsland(island);
}
});
// List for new islands
MultiLib.onString(plugin, "bentobox-newIsland", id -> {
BentoBox.getInstance().logDebug("New island " + id);
Island island = handler.loadObject(id);
if (island != null) {
islandCache.addIsland(island);
}
});
// Remove islands
MultiLib.onString(plugin, "bentobox-deleteIsland", id -> {
BentoBox.getInstance().logDebug("Delete island " + id);
Island island = handler.loadObject(id);
if (island != null) {
islandCache.removeIsland(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));
BentoBox.getInstance().logDebug("Setting spawn for world " + world);
}
}
});
}
/**
@ -121,8 +149,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 +255,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;
@ -260,15 +287,10 @@ public class IslandsManager {
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);
// Inform other servers
MultiLib.notify("bentobox-deletedIsland", island.getUniqueId());
// Remove players from island
removePlayersFromIsland(island);
if (!plugin.getSettings().isKeepPreviousIslandOnReset()) {
@ -462,7 +484,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 +508,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
@ -508,7 +530,7 @@ public class IslandsManager {
islandMax);
}
island.setMaxMembers(rank, islandMax == worldDefault ? null : islandMax);
this.save(island);
updateIsland(island);
return islandMax;
}
@ -547,12 +569,12 @@ 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);
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
@ -737,7 +759,7 @@ public class IslandsManager {
public boolean setHomeLocation(@Nullable Island island, Location location, String name) {
if (island != null) {
island.addHome(name, location);
this.save(island);
updateIsland(island);
return true;
}
return false;
@ -890,7 +912,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 +923,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 +1154,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 +1166,12 @@ 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);
}
}
this.spawn.put(spawn.getWorld(), spawn);
spawn.setSpawn(true);
spawns.put(Util.getWorld(spawn.getWorld()), spawn);
// Tell other servers
MultiLib.notify("bentobox-setspawn", spawn.getWorld().getUID().toString() + "," + spawn.getUniqueId());
}
/**
* Clears the spawn island for this world
*
@ -1164,11 +1179,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 +1205,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 +1218,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 +1228,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 +1394,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 +1468,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 +1607,17 @@ 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()));
BentoBox.getInstance().logDebug("Saved island " + island.getUniqueId());
}
}
/**
@ -1628,108 +1632,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

@ -2,18 +2,13 @@ package world.bentobox.bentobox.managers;
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.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;
@ -32,8 +27,7 @@ public class PlayersManager {
private Database<Players> handler;
private final Database<Names> names;
private final Map<UUID, Players> playerCache;
private final Set<UUID> inTeleport;
private final Set<UUID> inTeleport; // this needs databasing
private boolean isSaveTaskRunning;
@ -50,7 +44,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<>();
}
@ -66,63 +59,14 @@ public class PlayersManager {
* 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();
}
@ -133,10 +77,7 @@ public class PlayersManager {
*/
@Nullable
public Players getPlayer(UUID uuid){
if (!playerCache.containsKey(uuid)) {
addPlayer(uuid);
}
return playerCache.get(uuid);
return addPlayer(uuid);
}
/**
@ -146,7 +87,7 @@ public class PlayersManager {
*/
@NonNull
public Collection<Players> getPlayers() {
return Collections.unmodifiableCollection(playerCache.values());
return Collections.unmodifiableCollection(handler.loadObjects());
}
/*
@ -154,29 +95,20 @@ public class PlayersManager {
*/
/**
* Adds a player to the cache. If the UUID does not exist, a new player is made
* Adds a player to the database. 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;
public Players addPlayer(UUID playerUUID) {
// 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());
Players player = handler.loadObject(playerUUID.toString());
if (player != null) {
return player;
}
} else {
player = new Players(plugin, playerUUID);
}
playerCache.put(playerUUID, player);
}
Players player = new Players(plugin, playerUUID);
handler.saveObject(player);
return player;
}
/**
@ -187,7 +119,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 handler.objectExists(uniqueID.toString());
}
/**
@ -206,11 +138,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 +147,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 = addPlayer(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 +167,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 +178,7 @@ public class PlayersManager {
* @return number of resets
*/
public int getResets(World world, UUID playerUUID) {
addPlayer(playerUUID);
return playerCache.get(playerUUID).getResets(world);
return addPlayer(playerUUID).getResets(world);
}
/**
@ -277,8 +206,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 = addPlayer(playerUUID);
p.setResets(world, resets);
handler.saveObject(p);
}
/**
@ -287,11 +217,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 addPlayer(playerUUID).getLocale();
}
/**
@ -300,8 +226,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 = addPlayer(playerUUID);
p.setLocale(localeName);
handler.saveObject(p);
}
/**
@ -310,8 +237,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 = addPlayer(playerUUID);
p.addDeath(world);
handler.saveObject(p);
}
/**
@ -321,8 +249,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 = addPlayer(playerUUID);
p.setDeaths(world, deaths);
handler.saveObject(p);
}
/**
@ -332,8 +261,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 addPlayer(playerUUID).getDeaths(world);
}
/**
@ -360,16 +288,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,8 +313,9 @@ public class PlayersManager {
* @param playerUUID player's UUID
*/
public void addReset(World world, UUID playerUUID) {
addPlayer(playerUUID);
playerCache.get(playerUUID).addReset(world);
Players p = addPlayer(playerUUID);
p.addReset(world);
handler.saveObject(p);
}
/**
@ -406,8 +325,9 @@ public class PlayersManager {
* @since 1.6.0
*/
public void setFlagsDisplayMode(UUID playerUUID, Flag.Mode displayMode) {
addPlayer(playerUUID);
playerCache.get(playerUUID).setFlagsDisplayMode(displayMode);
Players p = addPlayer(playerUUID);
p.setFlagsDisplayMode(displayMode);
handler.saveObject(p);
}
/**
@ -417,19 +337,15 @@ public class PlayersManager {
* @since 1.6.0
*/
public Flag.Mode getFlagsDisplayMode(UUID playerUUID) {
addPlayer(playerUUID);
return playerCache.get(playerUUID).getFlagsDisplayMode();
return addPlayer(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 +411,6 @@ public class PlayersManager {
// Player total XP (not displayed)
target.getPlayer().setTotalExperience(0);
}
// Save player
save(target.getUniqueId());
}
}

View File

@ -54,6 +54,18 @@ public class IslandCache {
grids = new HashMap<>();
}
public void updateIsland(@NonNull Island island) {
if (island.getCenter() != null || island.getWorld() != null) {
islandsByLocation.put(island.getCenter(), island);
islandsById.put(island.getUniqueId(), island);
// Only add islands to this map if they are owned
if (island.isOwned()) {
islandsByUUID.computeIfAbsent(island.getOwner(), k -> new HashSet<>()).add(island);
island.getMemberSet().forEach(member -> addPlayer(member, island));
}
}
}
/**
* Adds an island to the grid
*
@ -62,12 +74,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);
@ -122,8 +129,10 @@ public class IslandCache {
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 +153,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;
}
/**

View File

@ -13,48 +13,21 @@ 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();
/**
* Adds island to grid
* @param island - island to add
* @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());
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()).getUniqueId())) {
BentoBox.getInstance().logDebug("I already know about this island");
return true;
}
BentoBox.getInstance().logDebug("Overlapping island");
return false;
} else {
// Add island

View File

@ -217,7 +217,7 @@ public class NewIsland {
// Register metrics
plugin.getMetrics().ifPresent(BStats::increaseIslandsCreatedCount);
// Save island
plugin.getIslands().save(island);
plugin.getIslands().updateIsland(island);
}
/**
@ -266,8 +266,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

@ -276,7 +276,7 @@ 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);
verify(im).updateIsland(island);
}
/**
@ -292,7 +292,7 @@ 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);
verify(im).updateIsland(island);
}
/**

View File

@ -1105,15 +1105,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

@ -236,7 +236,6 @@ public class JoinLeaveListenerTest {
jll.onPlayerJoin(event);
// Verify
verify(pm, times(2)).addPlayer(any());
verify(pm, times(2)).save(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());
}
/**
@ -356,7 +353,6 @@ public class JoinLeaveListenerTest {
jll.onPlayerJoin(event);
// Verify
verify(pm, times(2)).addPlayer(any());
verify(pm, times(2)).save(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

@ -970,7 +970,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() {

View File

@ -596,43 +596,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)}.

View File

@ -205,7 +205,7 @@ public class NewIslandTest {
NewIsland.builder().addon(addon).name(NAME).player(user).noPaste().reason(Reason.CREATE).oldIsland(oldIsland)
.build();
// Verifications
verify(im).save(eq(island));
verify(im).updateIsland(eq(island));
verify(island).setFlagsDefaults();
verify(scheduler).runTask(any(BentoBox.class), any(Runnable.class));
verify(builder, times(2)).build();
@ -224,7 +224,7 @@ 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));
verify(im).updateIsland(eq(island));
verify(island).setFlagsDefaults();
verify(scheduler).runTask(any(BentoBox.class), any(Runnable.class));
verify(builder, times(2)).build();
@ -243,7 +243,7 @@ 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));
verify(im).updateIsland(eq(island));
verify(island).setFlagsDefaults();
verify(scheduler).runTask(any(BentoBox.class), any(Runnable.class));
verify(builder, times(2)).build();
@ -262,7 +262,7 @@ 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));
verify(im).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 +281,7 @@ public class NewIslandTest {
NewIsland.builder().addon(addon).name(NAME).player(user).reason(Reason.CREATE).build();
PowerMockito.mockStatic(Bukkit.class);
// Verifications
verify(im).save(island);
verify(im).updateIsland(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 +299,7 @@ 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));
verify(im).updateIsland(eq(island));
verify(island).setFlagsDefaults();
verify(scheduler).runTask(any(BentoBox.class), any(Runnable.class));
verify(builder, times(2)).build();
@ -320,7 +320,7 @@ 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));
verify(im).updateIsland(eq(island));
verify(island).setFlagsDefaults();
verify(scheduler).runTask(any(BentoBox.class), any(Runnable.class));
verify(builder, times(2)).build();
@ -342,7 +342,7 @@ 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));
verify(im).updateIsland(eq(island));
verify(island).setFlagsDefaults();
verify(scheduler).runTask(any(BentoBox.class), any(Runnable.class));
verify(builder, times(2)).build();