diff --git a/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java b/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java index 9805e84ae..7d7364365 100644 --- a/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java +++ b/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java @@ -254,7 +254,7 @@ public class IslandsManager { island.setUniqueId(gmName + island.getUniqueId()); if (islandCache.addIsland(island)) { // Save to database and notify other servers - handler.saveObjectAsync(island).thenAccept(b -> { + saveIsland(island).thenAccept(b -> { if (b.equals(Boolean.TRUE)) { MultiLib.notify("bentobox-newIsland", island.getUniqueId()); } @@ -468,6 +468,16 @@ public class IslandsManager { return handler.loadObjects().stream().filter(i -> world.equals(i.getWorld())).toList(); } + /** + * Return island with uniqueId. Loads from database. Will block, so be careful. + * @param uniqueID id of island + * @return Optional Island object + * @since 2.4.0 + */ + public Optional loadIsland(String uniqueID) { + return Optional.ofNullable(handler.loadObject(uniqueID)); + } + /** * Returns the IslandCache instance. * @@ -1448,7 +1458,7 @@ public class IslandsManager { } /** - * Save the all the islands to the database + * Save the all the cached islands to the database * * @param schedule true if we should let the task run over multiple ticks to * reduce lag spikes @@ -1458,7 +1468,7 @@ public class IslandsManager { for (Island island : islandCache.getCachedIslands()) { if (island.isChanged()) { try { - handler.saveObjectAsync(island); + saveIsland(island); } catch (Exception e) { plugin.logError("Could not save island to database when running sync! " + e.getMessage()); } @@ -1481,7 +1491,7 @@ public class IslandsManager { } if (island.isChanged()) { try { - handler.saveObjectAsync(island); + saveIsland(island); } catch (Exception e) { plugin.logError("Could not save island to database when running sync! " + e.getMessage()); } @@ -1516,7 +1526,7 @@ public class IslandsManager { public void shutdown() { plugin.log("Removing coops from islands..."); // Remove all coop associations - islandCache.getIslands().forEach(i -> i.getMembers().values().removeIf(p -> p == RanksManager.COOP_RANK)); + islandCache.getCachedIslands().forEach(i -> i.getMembers().values().removeIf(p -> p == RanksManager.COOP_RANK)); plugin.log("Saving islands - this has to be done sync so it may take a while with a lot of islands..."); saveAll(); plugin.log("Islands saved."); @@ -1636,7 +1646,7 @@ public class IslandsManager { * @param uniqueId - UUID of player */ public void clearRank(int rank, UUID uniqueId) { - islandCache.getIslands().forEach( + islandCache.getCachedIslands().forEach( i -> i.getMembers().entrySet().removeIf(e -> e.getKey().equals(uniqueId) && e.getValue() == rank)); } @@ -1649,11 +1659,20 @@ public class IslandsManager { // When mocking, handler can be null so this null check avoids errors if (handler != null && handler.objectExists(island.getUniqueId())) { island.clearChanged(); - handler.saveObjectAsync(island) - .thenAccept(b -> MultiLib.notify("bentobox-updateIsland", island.getUniqueId())); + saveIsland(island).thenAccept(b -> MultiLib.notify("bentobox-updateIsland", island.getUniqueId())); } } + /** + * Saves the island async to the database + * @param island Island object to be saved + * @return CompletableFuture when done + * @since 2.4.0 + */ + public static CompletableFuture saveIsland(Island island) { + return handler.saveObjectAsync(island); + } + /** * Try to get an island by its unique id * diff --git a/src/main/java/world/bentobox/bentobox/managers/PlayersManager.java b/src/main/java/world/bentobox/bentobox/managers/PlayersManager.java index 2be4565cb..957f1a37c 100644 --- a/src/main/java/world/bentobox/bentobox/managers/PlayersManager.java +++ b/src/main/java/world/bentobox/bentobox/managers/PlayersManager.java @@ -7,6 +7,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import org.bukkit.World; @@ -81,17 +82,26 @@ public class PlayersManager { Objects.requireNonNull(playerUUID, "Player UUID must not be null"); // If the player exists in the database, load it; otherwise, create and save a new player - if (handler.objectExists(playerUUID.toString())) { - Players player = handler.loadObject(playerUUID.toString()); - if (player != null) { - return player; - } + Players player = loadPlayer(playerUUID); + if (player != null) { + return player; } Players newPlayer = new Players(plugin, playerUUID); handler.saveObjectAsync(newPlayer); return newPlayer; } + /** + * Force load the player from the database. The player must be known to BenoBox. If it is not + * use {@link #addPlayer(UUID)} instead. This is a blocking call, so be careful. + * @param uuid UUID of player + * @return Players object representing that player + * @since 2.4.0 + */ + public @Nullable Players loadPlayer(UUID uuid) { + return handler.loadObject(uuid.toString()); + } + /** * Returns an unmodifiable collection of all the players that are currently in the cache. * @return unmodifiable collection containing every player in the cache. @@ -382,4 +392,19 @@ public class PlayersManager { } } + /** + * Saves the player async to the database. The player has to be known to BentoBox to be saved. + * Players are usually detected by BentoBox when they join the server, so this is not an issue. + * @param uuid UUID of the player + * @return Completable future true when done, or false if not saved for some reason, e.g., invalid UUID + * @since 2.4.0 + */ + public CompletableFuture savePlayer(UUID uuid) { + Players p = this.getPlayer(uuid); + if (p != null) { + return handler.saveObjectAsync(p); + } + return CompletableFuture.completedFuture(false); + } + } diff --git a/src/main/java/world/bentobox/bentobox/managers/island/IslandCache.java b/src/main/java/world/bentobox/bentobox/managers/island/IslandCache.java index ed2ee7183..acfdabc8f 100644 --- a/src/main/java/world/bentobox/bentobox/managers/island/IslandCache.java +++ b/src/main/java/world/bentobox/bentobox/managers/island/IslandCache.java @@ -269,7 +269,7 @@ public class IslandCache { /** * Returns an unmodifiable collection of all the islands (even * those who may be unowned). Gets them from the cache or from the database if not - * loaded. + * loaded. This is a very heavy operation likely to cause lag. * * @return unmodifiable collection containing every island. */ @@ -277,7 +277,7 @@ public class IslandCache { public Collection getIslands() { List result = new ArrayList<>(); for (Entry<@NonNull String, @NonNull Island> entry : islandsById.entrySet()) { - Island island = entry.getValue() != null ? entry.getValue() : handler.loadObject(entry.getKey()); + Island island = entry.getValue() != null ? entry.getValue() : loadIsland(entry.getKey()); if (island != null) { result.add(island); } @@ -286,6 +286,17 @@ public class IslandCache { return Collections.unmodifiableCollection(result); } + /** + * Loads the island with the uniqueId from the database. Note, this could be a blocking call + * and lag the server, so be careful using it. + * @param uniqueId unique ID of the island + * @return Island or null if that uniqueID is unknown + * @since 2.4.0 + */ + public Island loadIsland(String uniqueId) { + return handler.loadObject(uniqueId); + } + /** * Returns an unmodifiable collection of all the islands (even * those who may be unowned) that are cached. @@ -317,7 +328,7 @@ public class IslandCache { List result = new ArrayList<>(); for (Entry<@NonNull String, @NonNull Island> entry : islandsById.entrySet()) { - Island island = entry.getValue() != null ? entry.getValue() : handler.loadObject(entry.getKey()); + Island island = entry.getValue() != null ? entry.getValue() : loadIsland(entry.getKey()); if (island != null && overworld.equals(island.getWorld())) { result.add(island); } @@ -461,7 +472,7 @@ public class IslandCache { return island; } - island = handler.loadObject(uniqueId); + island = loadIsland(uniqueId); if (cache && island != null) { islandsById.put(uniqueId, island); } diff --git a/src/test/java/world/bentobox/bentobox/managers/IslandsManagerTest.java b/src/test/java/world/bentobox/bentobox/managers/IslandsManagerTest.java index 09b3b40bd..e6f355dda 100644 --- a/src/test/java/world/bentobox/bentobox/managers/IslandsManagerTest.java +++ b/src/test/java/world/bentobox/bentobox/managers/IslandsManagerTest.java @@ -1045,7 +1045,7 @@ public class IslandsManagerTest extends AbstractCommonSetup { Collection collection = new ArrayList<>(); collection.add(is); - when(islandCache.getIslands()).thenReturn(collection); + when(islandCache.getCachedIslands()).thenReturn(collection); im.setIslandCache(islandCache); Map members = new HashMap<>(); @@ -1085,7 +1085,7 @@ public class IslandsManagerTest extends AbstractCommonSetup { Collection collection = new ArrayList<>(); collection.add(is); - when(islandCache.getIslands()).thenReturn(collection); + when(islandCache.getCachedIslands()).thenReturn(collection); im.setIslandCache(islandCache); Map members = new HashMap<>();