diff --git a/pom.xml b/pom.xml
index 5006baaeb..ec646dbe7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -66,23 +66,29 @@
172.0.9
+
3.12.8
+ 3.0.5
+ 8.0.27
+ 42.2.18
+ 5.0.1
- 1.19.2-R0.1-SNAPSHOT
+ 1.19.3-R0.1-SNAPSHOT1.19-R0.1-SNAPSHOT
- 2.2.1
- 1.7
+ 3.0.0
+ 1.7.12.10.9d5f5e0bbd83.0-SNAPSHOT
+ 1.19.3-v1${build.version}-SNAPSHOT-LOCAL
- 1.21.1
+ 1.22.0bentobox-worldhttps://sonarcloud.io
@@ -176,6 +182,11 @@
nms-repohttps://repo.codemc.io/repository/nms/
+
+
+ MG-Dev Jenkins CI Maven Repository
+ https://ci.mg-dev.eu/plugin/repository/everything
+
@@ -197,7 +208,7 @@
com.mojangauthlib
- 3.2.38
+ 3.16.29provided
@@ -232,10 +243,11 @@
${mongodb.version}provided
+
- postgresql
- postgresql
- 9.1-901-1.jdbc4
+ com.zaxxer
+ HikariCP
+ ${hikaricp.version}provided
@@ -260,6 +272,12 @@
${dynmap.version}provided
+
+ com.bergerkiller.bukkit
+ MyWorlds
+ ${myworlds.version}
+ provided
+ com.github.TheBusyBiscuit
@@ -269,7 +287,7 @@
com.github.Marcono1234gson-record-type-adapter-factory
- 0.1.0
+ 0.3.0
@@ -495,16 +515,21 @@
- pre-unit-test
+ prepare-agentprepare-agent
- post-unit-test
+ reportreport
+
+
+ XML
+
+
diff --git a/src/main/java/world/bentobox/bentobox/BentoBox.java b/src/main/java/world/bentobox/bentobox/BentoBox.java
index 04bfc548d..956ff030e 100644
--- a/src/main/java/world/bentobox/bentobox/BentoBox.java
+++ b/src/main/java/world/bentobox/bentobox/BentoBox.java
@@ -20,6 +20,7 @@
import world.bentobox.bentobox.commands.BentoBoxCommand;
import world.bentobox.bentobox.database.DatabaseSetup;
import world.bentobox.bentobox.hooks.MultiverseCoreHook;
+import world.bentobox.bentobox.hooks.MyWorldsHook;
import world.bentobox.bentobox.hooks.VaultHook;
import world.bentobox.bentobox.hooks.placeholders.PlaceholderAPIHook;
import world.bentobox.bentobox.listeners.BannedCommands;
@@ -27,9 +28,9 @@
import world.bentobox.bentobox.listeners.DeathListener;
import world.bentobox.bentobox.listeners.JoinLeaveListener;
import world.bentobox.bentobox.listeners.PanelListenerManager;
+import world.bentobox.bentobox.listeners.StandardSpawnProtectionListener;
import world.bentobox.bentobox.listeners.teleports.EntityTeleportListener;
import world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener;
-import world.bentobox.bentobox.listeners.StandardSpawnProtectionListener;
import world.bentobox.bentobox.managers.AddonsManager;
import world.bentobox.bentobox.managers.BlueprintsManager;
import world.bentobox.bentobox.managers.CommandsManager;
@@ -225,6 +226,7 @@ private void completeSetup(long loadTime) {
// Register Multiverse hook - MV loads AFTER BentoBox
// Make sure all worlds are already registered to Multiverse.
hooksManager.registerHook(new MultiverseCoreHook());
+ hooksManager.registerHook(new MyWorldsHook());
islandWorldManager.registerWorldsToMultiverse();
// TODO: re-enable after implementation
diff --git a/src/main/java/world/bentobox/bentobox/Settings.java b/src/main/java/world/bentobox/bentobox/Settings.java
index b539fbc63..384447caf 100644
--- a/src/main/java/world/bentobox/bentobox/Settings.java
+++ b/src/main/java/world/bentobox/bentobox/Settings.java
@@ -1,6 +1,8 @@
package world.bentobox.bentobox;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
import org.bukkit.Material;
@@ -11,8 +13,10 @@
import world.bentobox.bentobox.api.configuration.StoreAt;
import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType;
+
/**
* All the plugin settings are here
+ *
* @author tastybento
*/
@StoreAt(filename="config.yml") // Explicitly call out what name this should have.
@@ -68,6 +72,7 @@ public class Settings implements ConfigObject {
@ConfigComment("Transition options enable migration from one database type to another. Use /bbox migrate.")
@ConfigComment("YAML and JSON are file-based databases.")
@ConfigComment("MYSQL might not work with all implementations: if available, use a dedicated database type (e.g. MARIADB).")
+ @ConfigComment("BentoBox uses HikariCP for connecting with SQL databases.")
@ConfigComment("If you use MONGODB, you must also run the BSBMongo plugin (not addon).")
@ConfigComment("See https://github.com/tastybento/bsbMongo/releases/.")
@ConfigEntry(path = "general.database.type", video = "https://youtu.be/FFzCk5-y7-g")
@@ -107,6 +112,11 @@ public class Settings implements ConfigObject {
@ConfigEntry(path = "general.database.max-saved-islands-per-tick")
private int maxSavedIslandsPerTick = 20;
+ @ConfigComment("Number of active connections to the SQL database at the same time.")
+ @ConfigComment("Default 10.")
+ @ConfigEntry(path = "general.database.max-pool-size", since = "1.21.0")
+ private int maximumPoolSize = 10;
+
@ConfigComment("Enable SSL connection to MongoDB, MariaDB, MySQL and PostgreSQL databases.")
@ConfigEntry(path = "general.database.use-ssl", since = "1.12.0")
private boolean useSSL = false;
@@ -118,6 +128,16 @@ public class Settings implements ConfigObject {
@ConfigEntry(path = "general.database.prefix-character", since = "1.13.0")
private String databasePrefix = "";
+ @ConfigComment("Custom connection datasource properties that will be applied to connection pool.")
+ @ConfigComment("Check available values to your SQL driver implementation.")
+ @ConfigComment("Example: ")
+ @ConfigComment(" custom-properties: ")
+ @ConfigComment(" cachePrepStmts: 'true'")
+ @ConfigComment(" prepStmtCacheSize: '250'")
+ @ConfigComment(" prepStmtCacheSqlLimit: '2048'")
+ @ConfigEntry(path = "general.database.custom-properties", since = "1.21.0")
+ private Map customPoolProperties = new HashMap<>();
+
@ConfigComment("MongoDB client connection URI to override default connection options.")
@ConfigComment("See: https://docs.mongodb.com/manual/reference/connection-string/")
@ConfigEntry(path = "general.database.mongodb-connection-uri", since = "1.14.0")
@@ -954,6 +974,17 @@ public void setSlowDeletion(boolean slowDeletion) {
}
+ /**
+ * Gets maximum pool size.
+ *
+ * @return the maximum pool size
+ */
+ public int getMaximumPoolSize()
+ {
+ return maximumPoolSize;
+ }
+
+
/**
* Gets safe spot search range.
*
@@ -965,6 +996,39 @@ public int getSafeSpotSearchRange()
}
+ /**
+ * Sets maximum pool size.
+ *
+ * @param maximumPoolSize the maximum pool size
+ */
+ public void setMaximumPoolSize(int maximumPoolSize)
+ {
+ this.maximumPoolSize = maximumPoolSize;
+ }
+
+
+ /**
+ * Gets custom pool properties.
+ *
+ * @return the custom pool properties
+ */
+ public Map getCustomPoolProperties()
+ {
+ return customPoolProperties;
+ }
+
+
+ /**
+ * Sets custom pool properties.
+ *
+ * @param customPoolProperties the custom pool properties
+ */
+ public void setCustomPoolProperties(Map customPoolProperties)
+ {
+ this.customPoolProperties = customPoolProperties;
+ }
+
+
/**
* Sets safe spot search range.
*
diff --git a/src/main/java/world/bentobox/bentobox/api/addons/AddonClassLoader.java b/src/main/java/world/bentobox/bentobox/api/addons/AddonClassLoader.java
index 85ba85c88..2efa293f6 100644
--- a/src/main/java/world/bentobox/bentobox/api/addons/AddonClassLoader.java
+++ b/src/main/java/world/bentobox/bentobox/api/addons/AddonClassLoader.java
@@ -7,6 +7,7 @@
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -33,6 +34,19 @@ public class AddonClassLoader extends URLClassLoader {
private final Addon addon;
private final AddonsManager loader;
+ /**
+ * For testing only
+ * @param addon addon
+ * @param loader Addons Manager
+ * @param jarFile Jar File
+ * @throws MalformedURLException exception
+ */
+ protected AddonClassLoader(Addon addon, AddonsManager loader, File jarFile) throws MalformedURLException {
+ super(new URL[]{jarFile.toURI().toURL()});
+ this.addon = addon;
+ this.loader = loader;
+ }
+
public AddonClassLoader(AddonsManager addonsManager, YamlConfiguration data, File jarFile, ClassLoader parent)
throws InvalidAddonInheritException,
MalformedURLException,
@@ -79,8 +93,27 @@ public AddonClassLoader(AddonsManager addonsManager, YamlConfiguration data, Fil
*/
@NonNull
public static AddonDescription asDescription(YamlConfiguration data) throws InvalidAddonDescriptionException {
- AddonDescription.Builder builder = new AddonDescription.Builder(Objects.requireNonNull(data.getString("main")), Objects.requireNonNull(data.getString("name")), Objects.requireNonNull(data.getString("version")))
+ // Validate addon.yml
+ if (!data.contains("main")) {
+ throw new InvalidAddonDescriptionException("Missing 'main' tag. A main class must be listed in addon.yml");
+ }
+ if (!data.contains("name")) {
+ throw new InvalidAddonDescriptionException("Missing 'name' tag. An addon name must be listed in addon.yml");
+ }
+ if (!data.contains("version")) {
+ throw new InvalidAddonDescriptionException("Missing 'version' tag. A version must be listed in addon.yml");
+ }
+ if (!data.contains("authors")) {
+ throw new InvalidAddonDescriptionException("Missing 'authors' tag. At least one author must be listed in addon.yml");
+ }
+
+ AddonDescription.Builder builder = new AddonDescription.Builder(
+ // Mandatory elements
+ Objects.requireNonNull(data.getString("main")),
+ Objects.requireNonNull(data.getString("name")),
+ Objects.requireNonNull(data.getString("version")))
.authors(Objects.requireNonNull(data.getString("authors")))
+ // Optional elements
.metrics(data.getBoolean("metrics", true))
.repository(data.getString("repository", ""));
@@ -92,7 +125,7 @@ public static AddonDescription asDescription(YamlConfiguration data) throws Inva
if (softDepend != null) {
builder.softDependencies(Arrays.asList(softDepend.split("\\s*,\\s*")));
}
- builder.icon(Objects.requireNonNull(Material.getMaterial(data.getString("icon", "PAPER"))));
+ builder.icon(Objects.requireNonNull(Material.getMaterial(data.getString("icon", "PAPER").toUpperCase(Locale.ENGLISH))));
String apiVersion = data.getString("api-version");
if (apiVersion != null) {
diff --git a/src/main/java/world/bentobox/bentobox/api/addons/AddonDescription.java b/src/main/java/world/bentobox/bentobox/api/addons/AddonDescription.java
index b7e35b142..a6f34363b 100644
--- a/src/main/java/world/bentobox/bentobox/api/addons/AddonDescription.java
+++ b/src/main/java/world/bentobox/bentobox/api/addons/AddonDescription.java
@@ -287,7 +287,7 @@ public Builder permissions(ConfigurationSection permissions) {
*/
@Override
public String toString() {
- return "AddonDescription [" + (name != null ? "name=" + name + ", " : "")
+ return "AddonDescription [" + "name=" + name + ", "
+ "version=" + version + "]";
}
}
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/CompositeCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/CompositeCommand.java
index cb3e4ca9d..8301b13b3 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/CompositeCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/CompositeCommand.java
@@ -11,7 +11,6 @@
import java.util.Set;
import java.util.UUID;
import java.util.logging.Logger;
-import java.util.stream.Collectors;
import org.bukkit.World;
import org.bukkit.command.Command;
@@ -286,10 +285,10 @@ private boolean runPermissionCheck(User user)
{
// Check perms, but only if this isn't the console
if (user.isPlayer() &&
- !user.isOp() &&
- this.getPermission() != null &&
- !this.getPermission().isEmpty() &&
- !user.hasPermission(this.getPermission()))
+ !user.isOp() &&
+ this.getPermission() != null &&
+ !this.getPermission().isEmpty() &&
+ !user.hasPermission(this.getPermission()))
{
user.sendMessage("general.errors.no-permission", TextVariables.PERMISSION, this.getPermission());
return false;
@@ -514,18 +513,6 @@ public boolean isOnlyPlayer() {
return onlyPlayer;
}
- /**
- * Convenience method to check if a user is a player
- * @param user - the User
- * @return true if sender is a player
- * @deprecated use {@link User#isPlayer()}
- * @forRemove 1.18.0
- */
- @Deprecated
- protected boolean isPlayer(User user) {
- return user.isPlayer();
- }
-
/**
* Sets whether this command should only be run by players.
* If this is set to {@code true}, this command will only be runnable by objects implementing {@link Player}.
@@ -663,7 +650,7 @@ public List tabComplete(final @NonNull CommandSender sender, final @NonN
/* ------------ */
String lastArg = args.length != 0 ? args[args.length - 1] : "";
- return Util.tabLimit(options, lastArg).stream().sorted().collect(Collectors.toList());
+ return Util.tabLimit(options, lastArg).stream().sorted().toList();
}
/**
@@ -677,7 +664,7 @@ private List getSubCommandLabels(@NonNull CommandSender sender, @NonNull
return command.getSubCommands().values().stream()
.filter(cmd -> !cmd.isHidden())
.filter(cmd -> !cmd.isOnlyPlayer() || sender.isOp() || (sender instanceof Player && cmd.getPermission() != null && (cmd.getPermission().isEmpty() || sender.hasPermission(cmd.getPermission()))) )
- .map(CompositeCommand::getLabel).collect(Collectors.toList());
+ .map(CompositeCommand::getLabel).toList();
}
/**
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminDeleteCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminDeleteCommand.java
index e499bc26e..c8e6be0d1 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminDeleteCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminDeleteCommand.java
@@ -83,7 +83,7 @@ private void deletePlayer(User user, UUID targetUUID) {
// Remove them from this island (it still exists and will be deleted later)
getIslands().removePlayer(getWorld(), targetUUID);
if (target.isPlayer() && target.isOnline()) {
- cleanUp(user, target);
+ cleanUp(target);
}
vector = oldIsland.getCenter().toVector();
getIslands().deleteIsland(oldIsland, true, targetUUID);
@@ -95,7 +95,7 @@ private void deletePlayer(User user, UUID targetUUID) {
}
}
- private void cleanUp(User user, User target) {
+ private void cleanUp(User target) {
// Remove money inventory etc.
if (getIWM().isOnLeaveResetEnderChest(getWorld())) {
target.getPlayer().getEnderChest().clear();
@@ -122,7 +122,7 @@ private void cleanUp(User user, User target) {
}
// Execute commands when leaving
- Util.runCommands(target, getIWM().getOnLeaveCommands(getWorld()), "leave");
+ Util.runCommands(target, target.getName(), getIWM().getOnLeaveCommands(getWorld()), "leave");
}
@Override
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminDeleteHomesCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminDeleteHomesCommand.java
index d6f7d1805..cddf6a8d1 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminDeleteHomesCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminDeleteHomesCommand.java
@@ -55,11 +55,11 @@ public boolean execute(User user, String label, List args) {
return false;
}
// Confirm
- askConfirmation(user, user.getTranslation("commands.admin.deletehomes.warning"), () -> deleteHomes(user, targetUUID, island));
+ askConfirmation(user, user.getTranslation("commands.admin.deletehomes.warning"), () -> deleteHomes(user, island));
return true;
}
- private boolean deleteHomes(User user, UUID targetUUID, Island island) {
+ private boolean deleteHomes(User user, Island island) {
island.removeHomes();
user.sendMessage("general.success");
return true;
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminGetrankCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminGetrankCommand.java
index f27f5f25b..676127186 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminGetrankCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminGetrankCommand.java
@@ -3,7 +3,6 @@
import java.util.List;
import java.util.Optional;
import java.util.UUID;
-import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@@ -98,7 +97,7 @@ public Optional> tabComplete(User user, String alias, List
return Optional.empty();
}
String lastArg = args.get(args.size() - 1);
- List options = Bukkit.getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
+ List options = Bukkit.getOnlinePlayers().stream().map(Player::getName).toList();
return Optional.of(Util.tabLimit(options, lastArg));
}
}
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminResetFlagsCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminResetFlagsCommand.java
index 29f0a500f..23afe5dd4 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminResetFlagsCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminResetFlagsCommand.java
@@ -3,7 +3,6 @@
import java.util.List;
import java.util.Locale;
import java.util.Optional;
-import java.util.stream.Collectors;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
@@ -26,7 +25,7 @@ public AdminResetFlagsCommand(CompositeCommand parent) {
super(parent, "resetflags");
options = getPlugin().getFlagsManager().getFlags().stream()
.filter(f -> f.getType().equals(Type.PROTECTION) || f.getType().equals(Type.SETTING))
- .map(Flag::getID).collect(Collectors.toList());
+ .map(Flag::getID).toList();
}
@Override
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminResetNameCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminResetNameCommand.java
index 852b1d92d..ac8befdc9 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminResetNameCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminResetNameCommand.java
@@ -1,10 +1,11 @@
package world.bentobox.bentobox.api.commands.admin;
-import org.eclipse.jdt.annotation.Nullable;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
+import org.eclipse.jdt.annotation.Nullable;
+
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminSetProtectionCenterCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminSetProtectionCenterCommand.java
index 77de3e13e..ab61bfa53 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminSetProtectionCenterCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminSetProtectionCenterCommand.java
@@ -50,7 +50,7 @@ public void setup()
public boolean canExecute(User user, String label, List args) {
if (args.size() == 3) {
// Get location
- targetLoc = getLocation(user, args);
+ targetLoc = getLocation(args);
} else {
targetLoc = new Location(getWorld(), user.getLocation().getBlockX(), user.getLocation().getBlockY(), user.getLocation().getBlockZ());
}
@@ -67,7 +67,7 @@ public boolean canExecute(User user, String label, List args) {
return true;
}
- private Location getLocation(User user, List args) {
+ private Location getLocation(List args) {
try {
int x = Integer.parseInt(args.get(0));
int y = Integer.parseInt(args.get(1));
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminSetrankCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminSetrankCommand.java
index 7a835c70a..d0ff2d416 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminSetrankCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminSetrankCommand.java
@@ -4,7 +4,6 @@
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
-import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.Nullable;
@@ -140,7 +139,7 @@ public Optional> tabComplete(User user, String alias, List
return Optional.of(getPlugin().getRanksManager().getRanks()
.entrySet().stream()
.filter(entry -> entry.getValue() > RanksManager.VISITOR_RANK)
- .map(entry -> user.getTranslation(entry.getKey())).collect(Collectors.toList()));
+ .map(entry -> user.getTranslation(entry.getKey())).toList());
}
// Return the player names again for the optional island owner argument
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminSettingsCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminSettingsCommand.java
index d9cb0a12f..7e34456b6 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminSettingsCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminSettingsCommand.java
@@ -8,7 +8,6 @@
import java.util.Map.Entry;
import java.util.Optional;
import java.util.UUID;
-import java.util.stream.Collectors;
import org.bukkit.ChatColor;
import org.eclipse.jdt.annotation.NonNull;
@@ -88,11 +87,9 @@ public boolean canExecute(User user, String label, List args) {
}
private boolean getIsland(User user, List args) {
- if (args.get(0).equalsIgnoreCase(SPAWN_ISLAND)) {
- if (getIslands().getSpawn(getWorld()).isPresent()) {
- island = getIslands().getSpawn(getWorld()).get();
- return true;
- }
+ if (args.get(0).equalsIgnoreCase(SPAWN_ISLAND) && getIslands().getSpawn(getWorld()).isPresent()) {
+ island = getIslands().getSpawn(getWorld()).get();
+ return true;
}
// Get target player
@Nullable UUID targetUUID = Util.getUUID(args.get(0));
@@ -192,19 +189,18 @@ public boolean execute(User user, String label, List args) {
// Command line setting
flag.ifPresent(f -> {
switch (f.getType()) {
- case PROTECTION:
+ case PROTECTION -> {
island.setFlag(f, rank);
getIslands().save(island);
- break;
- case SETTING:
+ }
+ case SETTING -> {
island.setSettingsFlag(f, activeState);
getIslands().save(island);
- break;
- case WORLD_SETTING:
- f.setSetting(getWorld(), activeState);
- break;
- default:
- break;
+ }
+ case WORLD_SETTING -> f.setSetting(getWorld(), activeState);
+ default -> {
+ // Do nothing
+ }
}
});
user.sendMessage("general.success");
@@ -270,7 +266,7 @@ public Optional> tabComplete(User user, String alias, List
.getRanks().entrySet().stream()
.filter(en -> en.getValue() > RanksManager.BANNED_RANK && en.getValue() <= RanksManager.OWNER_RANK)
.map(Entry::getKey)
- .map(user::getTranslation).collect(Collectors.toList());
+ .map(user::getTranslation).toList();
case SETTING -> Arrays.asList(active, disabled);
default -> Collections.emptyList();
}).orElse(Collections.emptyList());
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/DefaultAdminCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/DefaultAdminCommand.java
index 81192d164..80bc7db57 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/admin/DefaultAdminCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/DefaultAdminCommand.java
@@ -9,7 +9,12 @@
import world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand;
import world.bentobox.bentobox.api.commands.admin.range.AdminRangeCommand;
import world.bentobox.bentobox.api.commands.admin.resets.AdminResetsCommand;
-import world.bentobox.bentobox.api.commands.admin.team.*;
+import world.bentobox.bentobox.api.commands.admin.team.AdminTeamAddCommand;
+import world.bentobox.bentobox.api.commands.admin.team.AdminTeamCommand;
+import world.bentobox.bentobox.api.commands.admin.team.AdminTeamDisbandCommand;
+import world.bentobox.bentobox.api.commands.admin.team.AdminTeamFixCommand;
+import world.bentobox.bentobox.api.commands.admin.team.AdminTeamKickCommand;
+import world.bentobox.bentobox.api.commands.admin.team.AdminTeamSetownerCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@@ -25,7 +30,7 @@ public abstract class DefaultAdminCommand extends CompositeCommand {
*
* @param addon - GameMode addon
*/
- public DefaultAdminCommand(GameModeAddon addon) {
+ protected DefaultAdminCommand(GameModeAddon addon) {
// Register command with alias from config.
super(addon,
addon.getWorldSettings().getAdminCommandAliases().split(" ")[0],
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintDeleteCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintDeleteCommand.java
index 0a3615f77..65bbb830f 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintDeleteCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintDeleteCommand.java
@@ -2,7 +2,6 @@
import java.util.LinkedList;
import java.util.List;
-import java.util.Locale;
import java.util.Optional;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintRenameCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintRenameCommand.java
index f7863715d..568e061e3 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintRenameCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintRenameCommand.java
@@ -2,13 +2,11 @@
import java.io.File;
import java.util.List;
-import java.util.Locale;
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.blueprints.Blueprint;
-import world.bentobox.bentobox.blueprints.BlueprintClipboard;
import world.bentobox.bentobox.managers.BlueprintsManager;
import world.bentobox.bentobox.util.Util;
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintSaveCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintSaveCommand.java
index b0b957171..f4c5a749d 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintSaveCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintSaveCommand.java
@@ -42,7 +42,7 @@ public boolean canExecute(User user, String label, List args)
}
BlueprintClipboard clipboard = ((AdminBlueprintCommand) this.getParent()).getClipboards().
- computeIfAbsent(user.getUniqueId(), v -> new BlueprintClipboard());
+ computeIfAbsent(user.getUniqueId(), v -> new BlueprintClipboard());
if (!clipboard.isFull())
{
@@ -51,7 +51,7 @@ public boolean canExecute(User user, String label, List args)
return false;
}
- if (clipboard.getBlueprint().getBedrock() == null)
+ if (clipboard.getBlueprint() != null && clipboard.getBlueprint().getBedrock() == null)
{
// Bedrock is required for all blueprints.
user.sendMessage("commands.admin.blueprint.bedrock-required");
@@ -67,7 +67,7 @@ public boolean execute(User user, String label, List args)
{
AdminBlueprintCommand parent = (AdminBlueprintCommand) this.getParent();
BlueprintClipboard clipboard = parent.getClipboards().
- computeIfAbsent(user.getUniqueId(), v -> new BlueprintClipboard());
+ computeIfAbsent(user.getUniqueId(), v -> new BlueprintClipboard());
String fileName = Util.sanitizeInput(args.get(0));
@@ -77,8 +77,8 @@ public boolean execute(User user, String label, List args)
if (newFile.exists())
{
this.askConfirmation(user,
- user.getTranslation("commands.admin.blueprint.file-exists"),
- () -> this.hideAndSave(user, parent, clipboard, fileName, args.get(0)));
+ user.getTranslation("commands.admin.blueprint.file-exists"),
+ () -> this.hideAndSave(user, parent, clipboard, fileName, args.get(0)));
return false;
}
@@ -96,15 +96,15 @@ public boolean execute(User user, String label, List args)
* @return {@code true} if blueprint is saved, {@code false} otherwise.
*/
private boolean hideAndSave(User user,
- AdminBlueprintCommand parent,
- BlueprintClipboard clipboard,
- String name,
- String displayName)
+ AdminBlueprintCommand parent,
+ BlueprintClipboard clipboard,
+ String name,
+ String displayName)
{
parent.hideClipboard(user);
boolean result = new BlueprintClipboardManager(this.getPlugin(),
- parent.getBlueprintsFolder(), clipboard).
- save(user, name, displayName);
+ parent.getBlueprintsFolder(), clipboard).
+ save(user, name, displayName);
if (result && clipboard.isFull())
{
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/conversations/NamePrompt.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/conversations/NamePrompt.java
index 4569489e8..e0edd1b25 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/admin/conversations/NamePrompt.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/conversations/NamePrompt.java
@@ -17,8 +17,10 @@
*/
public class NamePrompt extends StringPrompt {
- private @NonNull final Island island;
- private @NonNull final User user;
+ @NonNull
+ private final Island island;
+ @NonNull
+ private final User user;
private final String oldName;
private final BentoBox plugin;
@@ -30,7 +32,8 @@ public NamePrompt(BentoBox plugin, @NonNull Island island, @NonNull User user, S
}
@Override
- public @NonNull String getPromptText(@NonNull ConversationContext context) {
+ @NonNull
+ public String getPromptText(@NonNull ConversationContext context) {
return user.getTranslation("commands.island.renamehome.enter-new-name");
}
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/range/AdminRangeDisplayCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/range/AdminRangeDisplayCommand.java
index 1b5135fb8..f79049829 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/admin/range/AdminRangeDisplayCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/range/AdminRangeDisplayCommand.java
@@ -99,10 +99,10 @@ private void drawZone(User user, Particle particle, Object dustOptions, Island i
// Draw 3 "stages" (one line below, at and above player's y coordinate)
for (int stage = -1 ; stage <= 1 ; stage++) {
for (int i = -range ; i <= range ; i++) {
- user.spawnParticle(particle, dustOptions, center.getBlockX() + i, playerY + stage, center.getBlockZ() + range);
- user.spawnParticle(particle, dustOptions, center.getBlockX() + i, playerY + stage, center.getBlockZ() - range);
- user.spawnParticle(particle, dustOptions, center.getBlockX() + range, playerY + stage, center.getBlockZ() + i);
- user.spawnParticle(particle, dustOptions, center.getBlockX() - range, playerY + stage, center.getBlockZ() + i);
+ user.spawnParticle(particle, dustOptions, (double)center.getBlockX() + i, (double)playerY + stage, (double)center.getBlockZ() + range);
+ user.spawnParticle(particle, dustOptions, (double)center.getBlockX() + i, (double)playerY + stage, (double)center.getBlockZ() - range);
+ user.spawnParticle(particle, dustOptions, (double)center.getBlockX() + range, (double)playerY + stage, (double)center.getBlockZ() + i);
+ user.spawnParticle(particle, dustOptions, (double)center.getBlockX() - range, (double)playerY + stage, (double)center.getBlockZ() + i);
}
}
}
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandBanCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandBanCommand.java
index 7d65bf42f..388e4b1ce 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandBanCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandBanCommand.java
@@ -4,7 +4,6 @@
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
-import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
@@ -142,7 +141,7 @@ public Optional> tabComplete(User user, String alias, List
.filter(p -> !p.getUniqueId().equals(user.getUniqueId()))
.filter(p -> !island.isBanned(p.getUniqueId()))
.filter(p -> user.getPlayer().canSee(p))
- .map(Player::getName).collect(Collectors.toList());
+ .map(Player::getName).toList();
return Optional.of(Util.tabLimit(options, lastArg));
} else {
return Optional.empty();
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandBanlistCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandBanlistCommand.java
index 95ee5cacf..7d19f5c81 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandBanlistCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandBanlistCommand.java
@@ -3,7 +3,6 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
-import java.util.stream.Collectors;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
@@ -57,7 +56,7 @@ public boolean execute(User user, String label, List args) {
// Title
user.sendMessage("commands.island.banlist.the-following");
// Create a nicely formatted list
- List names = island.getBanned().stream().map(u -> getPlayers().getName(u)).sorted().collect(Collectors.toList());
+ List names = island.getBanned().stream().map(u -> getPlayers().getName(u)).sorted().toList();
List lines = new ArrayList<>();
StringBuilder line = new StringBuilder();
// Put the names into lines of no more than 40 characters long, separated by commas
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandDeletehomeCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandDeletehomeCommand.java
index 00eed9393..8b10540fb 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandDeletehomeCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandDeletehomeCommand.java
@@ -84,9 +84,9 @@ private void delete(Island island, User user, String name) {
@Override
public Optional> tabComplete(User user, String alias, List args) {
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
- Island island = getIslands().getIsland(getWorld(), user.getUniqueId());
- if (island != null) {
- return Optional.of(Util.tabLimit(new ArrayList<>(island.getHomes().keySet()), lastArg));
+ Island is = getIslands().getIsland(getWorld(), user.getUniqueId());
+ if (is != null) {
+ return Optional.of(Util.tabLimit(new ArrayList<>(is.getHomes().keySet()), lastArg));
} else {
return Optional.empty();
}
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandExpelCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandExpelCommand.java
index cc957cb09..a13ad2587 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandExpelCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandExpelCommand.java
@@ -4,7 +4,6 @@
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
-import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
@@ -156,7 +155,7 @@ public Optional> tabComplete(User user, String alias, List
.filter(p -> !p.isOp()) // Not op
.filter(p -> !p.hasPermission(this.getPermissionPrefix() + "admin.noexpel"))
.filter(p -> !p.hasPermission(this.getPermissionPrefix() + "mod.bypassexpel"))
- .map(Player::getName).collect(Collectors.toList());
+ .map(Player::getName).toList();
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
return Optional.of(Util.tabLimit(options, lastArg));
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandGoCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandGoCommand.java
index 055850486..dba774532 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandGoCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandGoCommand.java
@@ -55,13 +55,11 @@ public boolean canExecute(User user, String label, List args) {
user.sendMessage(Flags.PREVENT_TELEPORT_WHEN_FALLING.getHintReference());
return false;
}
- if (!args.isEmpty()) {
- if (!getIslands().isHomeLocation(island, String.join(" ", args))) {
- user.sendMessage("commands.island.go.unknown-home");
- user.sendMessage("commands.island.sethome.homes-are");
- island.getHomes().keySet().stream().filter(s -> !s.isEmpty()).forEach(s -> user.sendMessage("commands.island.sethome.home-list-syntax", TextVariables.NAME, s));
- return false;
- }
+ if (!args.isEmpty() && !getIslands().isHomeLocation(island, String.join(" ", args))) {
+ user.sendMessage("commands.island.go.unknown-home");
+ user.sendMessage("commands.island.sethome.homes-are");
+ island.getHomes().keySet().stream().filter(s -> !s.isEmpty()).forEach(s -> user.sendMessage("commands.island.sethome.home-list-syntax", TextVariables.NAME, s));
+ return false;
}
return true;
}
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandRenamehomeCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandRenamehomeCommand.java
index c1ceac91f..591fbbafb 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandRenamehomeCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandRenamehomeCommand.java
@@ -87,9 +87,9 @@ public boolean execute(User user, String label, List args) {
@Override
public Optional> tabComplete(User user, String alias, List args) {
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
- Island island = getIslands().getIsland(getWorld(), user.getUniqueId());
- if (island != null) {
- return Optional.of(Util.tabLimit(new ArrayList<>(island.getHomes().keySet()), lastArg));
+ Island is = getIslands().getIsland(getWorld(), user.getUniqueId());
+ if (is != null) {
+ return Optional.of(Util.tabLimit(new ArrayList<>(is.getHomes().keySet()), lastArg));
} else {
return Optional.empty();
}
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandResetCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandResetCommand.java
index f6c60aa83..128ae6370 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandResetCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandResetCommand.java
@@ -187,7 +187,7 @@ private void kickMembers(Island island) {
getIslands().removePlayer(getWorld(), memberUUID);
// Clean player
- getPlayers().cleanLeavingPlayer(getWorld(), member, false);
+ getPlayers().cleanLeavingPlayer(getWorld(), member, false, island);
// Fire event
TeamEvent.builder()
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandUnbanCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandUnbanCommand.java
index 595e6ae68..9f4f25a93 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandUnbanCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandUnbanCommand.java
@@ -4,7 +4,6 @@
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
-import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.Nullable;
@@ -112,7 +111,7 @@ public boolean execute(User user, String label, List args) {
public Optional> tabComplete(User user, String alias, List args) {
Island island = getIslands().getIsland(getWorld(), user.getUniqueId());
if (island != null) {
- List options = island.getBanned().stream().map(getPlayers()::getName).collect(Collectors.toList());
+ List options = island.getBanned().stream().map(getPlayers()::getName).toList();
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
return Optional.of(Util.tabLimit(options, lastArg));
} else {
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCommand.java
index b1d2681e3..c8c8935b8 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCommand.java
@@ -7,7 +7,6 @@
import java.util.Map;
import java.util.Set;
import java.util.UUID;
-import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
@@ -91,12 +90,11 @@ public boolean execute(User user, String label, List args) {
private void showMembers(Island island, User user) {
// Gather online members
- List onlineMembers = island
+ long count = island
.getMemberSet(RanksManager.MEMBER_RANK)
.stream()
- .filter(uuid -> Bukkit.getOfflinePlayer(uuid)
- .isOnline())
- .collect(Collectors.toList());
+ .filter(uuid -> Util.getOnlinePlayerList(user).contains(Bukkit.getOfflinePlayer(uuid).getName()))
+ .count();
// List of ranks that we will loop through
Integer[] ranks = new Integer[]{RanksManager.OWNER_RANK, RanksManager.SUB_OWNER_RANK, RanksManager.MEMBER_RANK, RanksManager.TRUSTED_RANK, RanksManager.COOP_RANK};
@@ -105,11 +103,11 @@ private void showMembers(Island island, User user) {
user.sendMessage("commands.island.team.info.header",
"[max]", String.valueOf(getIslands().getMaxMembers(island, RanksManager.MEMBER_RANK)),
"[total]", String.valueOf(island.getMemberSet().size()),
- "[online]", String.valueOf(onlineMembers.size()));
+ "[online]", String.valueOf(count));
// We now need to get all online "members" of the island - incl. Trusted and coop
- onlineMembers = island.getMemberSet(RanksManager.COOP_RANK).stream()
- .filter(uuid -> Util.getOnlinePlayerList(user).contains(Bukkit.getOfflinePlayer(uuid).getName())).collect(Collectors.toList());
+ List onlineMembers = island.getMemberSet(RanksManager.COOP_RANK).stream()
+ .filter(uuid -> Util.getOnlinePlayerList(user).contains(Bukkit.getOfflinePlayer(uuid).getName())).toList();
for (int rank : ranks) {
Set players = island.getMemberSet(rank, false);
@@ -123,47 +121,52 @@ private void showMembers(Island island, User user) {
TextVariables.RANK, user.getTranslation(getPlugin().getRanksManager().getRank(rank)),
TextVariables.NUMBER, String.valueOf(island.getMemberSet(rank, false).size()));
}
- for (UUID member : island.getMemberSet(rank, false)) {
- OfflinePlayer offlineMember = Bukkit.getOfflinePlayer(member);
- if (onlineMembers.contains(member)) {
- // the player is online
- user.sendMessage("commands.island.team.info.member-layout.online",
- TextVariables.NAME, offlineMember.getName());
- } else {
- // A bit of handling for the last joined date
- Instant lastJoined = Instant.ofEpochMilli(offlineMember.getLastPlayed());
- Instant now = Instant.now();
-
- Duration duration = Duration.between(lastJoined, now);
- String lastSeen;
- final String reference = "commands.island.team.info.last-seen.layout";
- if (duration.toMinutes() < 60L) {
- lastSeen = user.getTranslation(reference,
- TextVariables.NUMBER, String.valueOf(duration.toMinutes()),
- TextVariables.UNIT, user.getTranslation("commands.island.team.info.last-seen.minutes"));
- } else if (duration.toHours() < 24L) {
- lastSeen = user.getTranslation(reference,
- TextVariables.NUMBER, String.valueOf(duration.toHours()),
- TextVariables.UNIT, user.getTranslation("commands.island.team.info.last-seen.hours"));
- } else {
- lastSeen = user.getTranslation(reference,
- TextVariables.NUMBER, String.valueOf(duration.toDays()),
- TextVariables.UNIT, user.getTranslation("commands.island.team.info.last-seen.days"));
- }
-
- if(island.getMemberSet(RanksManager.MEMBER_RANK, true).contains(member)) {
- user.sendMessage("commands.island.team.info.member-layout.offline",
- TextVariables.NAME, offlineMember.getName(),
- "[last_seen]", lastSeen);
- }else{
- // This will prevent anyone that is trusted or below to not have a last-seen status
- user.sendMessage("commands.island.team.info.member-layout.offline-not-last-seen",
- TextVariables.NAME, offlineMember.getName());
- }
- }
+ displayOnOffline(user, rank, island, onlineMembers);
+ }
+ }
+ }
+
+ private void displayOnOffline(User user, int rank, Island island, List onlineMembers) {
+ for (UUID member : island.getMemberSet(rank, false)) {
+ OfflinePlayer offlineMember = Bukkit.getOfflinePlayer(member);
+ if (onlineMembers.contains(member)) {
+ // the player is online
+ user.sendMessage("commands.island.team.info.member-layout.online",
+ TextVariables.NAME, offlineMember.getName());
+ } else {
+ // A bit of handling for the last joined date
+ Instant lastJoined = Instant.ofEpochMilli(offlineMember.getLastPlayed());
+ Instant now = Instant.now();
+
+ Duration duration = Duration.between(lastJoined, now);
+ String lastSeen;
+ final String reference = "commands.island.team.info.last-seen.layout";
+ if (duration.toMinutes() < 60L) {
+ lastSeen = user.getTranslation(reference,
+ TextVariables.NUMBER, String.valueOf(duration.toMinutes()),
+ TextVariables.UNIT, user.getTranslation("commands.island.team.info.last-seen.minutes"));
+ } else if (duration.toHours() < 24L) {
+ lastSeen = user.getTranslation(reference,
+ TextVariables.NUMBER, String.valueOf(duration.toHours()),
+ TextVariables.UNIT, user.getTranslation("commands.island.team.info.last-seen.hours"));
+ } else {
+ lastSeen = user.getTranslation(reference,
+ TextVariables.NUMBER, String.valueOf(duration.toDays()),
+ TextVariables.UNIT, user.getTranslation("commands.island.team.info.last-seen.days"));
+ }
+
+ if(island.getMemberSet(RanksManager.MEMBER_RANK, true).contains(member)) {
+ user.sendMessage("commands.island.team.info.member-layout.offline",
+ TextVariables.NAME, offlineMember.getName(),
+ "[last_seen]", lastSeen);
+ } else {
+ // This will prevent anyone that is trusted or below to not have a last-seen status
+ user.sendMessage("commands.island.team.info.member-layout.offline-not-last-seen",
+ TextVariables.NAME, offlineMember.getName());
}
}
}
+
}
private boolean fireEvent(User user) {
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteAcceptCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteAcceptCommand.java
index bc5ceb271..5f17a3ab2 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteAcceptCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteAcceptCommand.java
@@ -96,22 +96,24 @@ private void acceptTrustInvite(User user, Invite invite) {
// Remove the invite
itc.removeInvite(playerUUID);
User inviter = User.getInstance(invite.getInviter());
- if (inviter != null) {
- Island island = getIslands().getIsland(getWorld(), inviter);
- if (island != null) {
- if (island.getMemberSet(RanksManager.TRUSTED_RANK, false).size() > getIslands().getMaxMembers(island, RanksManager.TRUSTED_RANK)) {
- user.sendMessage("commands.island.team.trust.is-full");
- return;
- }
- island.setRank(user, RanksManager.TRUSTED_RANK);
- IslandEvent.builder()
- .island(island)
- .involvedPlayer(user.getUniqueId())
- .admin(false)
- .reason(IslandEvent.Reason.RANK_CHANGE)
- .rankChange(island.getRank(user), RanksManager.TRUSTED_RANK)
- .build();
+ Island island = getIslands().getIsland(getWorld(), inviter);
+ if (island != null) {
+ if (island.getMemberSet(RanksManager.TRUSTED_RANK, false).size() > getIslands().getMaxMembers(island, RanksManager.TRUSTED_RANK)) {
+ user.sendMessage("commands.island.team.trust.is-full");
+ return;
+ }
+ island.setRank(user, RanksManager.TRUSTED_RANK);
+ IslandEvent.builder()
+ .island(island)
+ .involvedPlayer(user.getUniqueId())
+ .admin(false)
+ .reason(IslandEvent.Reason.RANK_CHANGE)
+ .rankChange(island.getRank(user), RanksManager.TRUSTED_RANK)
+ .build();
+ if (inviter.isOnline()) {
inviter.sendMessage("commands.island.team.trust.success", TextVariables.NAME, user.getName());
+ }
+ if (inviter.isPlayer()) {
user.sendMessage("commands.island.team.trust.you-are-trusted", TextVariables.NAME, inviter.getName());
}
}
@@ -121,22 +123,24 @@ private void acceptCoopInvite(User user, Invite invite) {
// Remove the invite
itc.removeInvite(playerUUID);
User inviter = User.getInstance(invite.getInviter());
- if (inviter != null) {
- Island island = getIslands().getIsland(getWorld(), inviter);
- if (island != null) {
- if (island.getMemberSet(RanksManager.COOP_RANK, false).size() > getIslands().getMaxMembers(island, RanksManager.COOP_RANK)) {
- user.sendMessage("commands.island.team.coop.is-full");
- return;
- }
- island.setRank(user, RanksManager.COOP_RANK);
- IslandEvent.builder()
- .island(island)
- .involvedPlayer(user.getUniqueId())
- .admin(false)
- .reason(IslandEvent.Reason.RANK_CHANGE)
- .rankChange(island.getRank(user), RanksManager.COOP_RANK)
- .build();
+ Island island = getIslands().getIsland(getWorld(), inviter);
+ if (island != null) {
+ if (island.getMemberSet(RanksManager.COOP_RANK, false).size() > getIslands().getMaxMembers(island, RanksManager.COOP_RANK)) {
+ user.sendMessage("commands.island.team.coop.is-full");
+ return;
+ }
+ island.setRank(user, RanksManager.COOP_RANK);
+ IslandEvent.builder()
+ .island(island)
+ .involvedPlayer(user.getUniqueId())
+ .admin(false)
+ .reason(IslandEvent.Reason.RANK_CHANGE)
+ .rankChange(island.getRank(user), RanksManager.COOP_RANK)
+ .build();
+ if (inviter.isOnline()) {
inviter.sendMessage("commands.island.team.coop.success", TextVariables.NAME, user.getName());
+ }
+ if (inviter.isPlayer()) {
user.sendMessage("commands.island.team.coop.you-are-a-coop-member", TextVariables.NAME, inviter.getName());
}
}
@@ -153,7 +157,7 @@ private void acceptTeamInvite(User user, Invite invite) {
user.sendMessage(INVALID_INVITE);
return;
}
- if (teamIsland.getMemberSet(RanksManager.MEMBER_RANK, true).size() > getIslands().getMaxMembers(teamIsland, RanksManager.MEMBER_RANK)) {
+ if (teamIsland.getMemberSet(RanksManager.MEMBER_RANK, true).size() >= getIslands().getMaxMembers(teamIsland, RanksManager.MEMBER_RANK)) {
user.sendMessage("commands.island.team.invite.errors.island-is-full");
return;
}
@@ -172,6 +176,10 @@ private void acceptTeamInvite(User user, Invite invite) {
// Put player back into normal mode
user.setGameMode(getIWM().getDefaultGameMode(getWorld()));
+ // Execute commands
+ String ownerName = this.getPlayers().getName(teamIsland.getOwner());
+ Util.runCommands(user, ownerName, getIWM().getOnJoinCommands(getWorld()), "join");
+
});
// Reset deaths
if (getIWM().isTeamJoinDeathReset(getWorld())) {
@@ -179,7 +187,7 @@ private void acceptTeamInvite(User user, Invite invite) {
}
user.sendMessage("commands.island.team.invite.accept.you-joined-island", TextVariables.LABEL, getTopLabel());
User inviter = User.getInstance(invite.getInviter());
- if (inviter != null) {
+ if (inviter.isOnline()) {
inviter.sendMessage("commands.island.team.invite.accept.name-joined-your-island", TextVariables.NAME, user.getName());
}
getIslands().save(teamIsland);
@@ -224,7 +232,5 @@ private void cleanPlayer(User user) {
user.getPlayer().setTotalExperience(0);
}
- // Execute commands
- Util.runCommands(user, getIWM().getOnJoinCommands(getWorld()), "join");
}
}
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteCommand.java
index 2785fb95c..a36584f14 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteCommand.java
@@ -51,9 +51,9 @@ public boolean canExecute(User user, String label, List args) {
Invite invite = itc.getInvite(playerUUID);
String name = getPlayers().getName(playerUUID);
switch (invite.getType()) {
- case COOP -> user.sendMessage("commands.island.team.invite.name-has-invited-you.coop", TextVariables.NAME, name);
- case TRUST -> user.sendMessage("commands.island.team.invite.name-has-invited-you.trust", TextVariables.NAME, name);
- default -> user.sendMessage("commands.island.team.invite.name-has-invited-you", TextVariables.NAME, name);
+ case COOP -> user.sendMessage("commands.island.team.invite.name-has-invited-you.coop", TextVariables.NAME, name);
+ case TRUST -> user.sendMessage("commands.island.team.invite.name-has-invited-you.trust", TextVariables.NAME, name);
+ default -> user.sendMessage("commands.island.team.invite.name-has-invited-you", TextVariables.NAME, name);
}
return true;
}
@@ -69,7 +69,7 @@ public boolean canExecute(User user, String label, List args) {
return false;
}
// Check for space on team
- if (island.getMemberSet().size() > getIslands().getMaxMembers(island, RanksManager.MEMBER_RANK)) {
+ if (island.getMemberSet().size() >= getIslands().getMaxMembers(island, RanksManager.MEMBER_RANK)) {
user.sendMessage("commands.island.team.invite.errors.island-is-full");
return false;
}
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamKickCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamKickCommand.java
index 44ca46783..8722dfa1f 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamKickCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamKickCommand.java
@@ -4,7 +4,6 @@
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
-import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
@@ -103,7 +102,7 @@ TextVariables.GAMEMODE, getAddon().getDescription().getName(),
getIslands().removePlayer(getWorld(), targetUUID);
// Clean the target player
- getPlayers().cleanLeavingPlayer(getWorld(), target, true);
+ getPlayers().cleanLeavingPlayer(getWorld(), target, true, oldIsland);
user.sendMessage("commands.island.team.kick.success", TextVariables.NAME, target.getName());
IslandEvent.builder()
@@ -131,7 +130,7 @@ public Optional> tabComplete(User user, String alias, List
List options = island.getMemberSet().stream()
.filter(uuid -> island.getRank(uuid) >= RanksManager.MEMBER_RANK)
.map(Bukkit::getOfflinePlayer)
- .map(OfflinePlayer::getName).collect(Collectors.toList());
+ .map(OfflinePlayer::getName).toList();
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
return Optional.of(Util.tabLimit(options, lastArg));
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamLeaveCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamLeaveCommand.java
index 7fcfa2a60..db1a37379 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamLeaveCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamLeaveCommand.java
@@ -82,7 +82,7 @@ private void leave(User user) {
}
getIslands().setLeaveTeam(getWorld(), user.getUniqueId());
// Clean the player
- getPlayers().cleanLeavingPlayer(getWorld(), user, false);
+ getPlayers().cleanLeavingPlayer(getWorld(), user, false, island);
// Add cooldown for this player and target
if (getSettings().getInviteCooldown() > 0 && getParent() != null) {
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamPromoteCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamPromoteCommand.java
index 49ff21566..7c8722a79 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamPromoteCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamPromoteCommand.java
@@ -3,7 +3,6 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
-import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
@@ -125,7 +124,7 @@ public Optional> tabComplete(User user, String alias, List
if (island != null) {
List options = island.getMemberSet().stream()
.map(Bukkit::getOfflinePlayer)
- .map(OfflinePlayer::getName).collect(Collectors.toList());
+ .map(OfflinePlayer::getName).toList();
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
return Optional.of(Util.tabLimit(options, lastArg));
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamUncoopCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamUncoopCommand.java
index 16bff8b7a..e219d3043 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamUncoopCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamUncoopCommand.java
@@ -4,7 +4,6 @@
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
-import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
@@ -114,7 +113,7 @@ public Optional> tabComplete(User user, String alias, List
List options = island.getMembers().entrySet().stream()
.filter(e -> e.getValue() == RanksManager.COOP_RANK)
.map(e -> Bukkit.getOfflinePlayer(e.getKey()))
- .map(OfflinePlayer::getName).collect(Collectors.toList());
+ .map(OfflinePlayer::getName).toList();
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
return Optional.of(Util.tabLimit(options, lastArg));
} else {
diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamUntrustCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamUntrustCommand.java
index 2b3403ca1..74b3de095 100644
--- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamUntrustCommand.java
+++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamUntrustCommand.java
@@ -4,7 +4,6 @@
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
-import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
@@ -114,7 +113,7 @@ public Optional> tabComplete(User user, String alias, List
List options = island.getMembers().entrySet().stream()
.filter(e -> e.getValue() == RanksManager.TRUSTED_RANK)
.map(e -> Bukkit.getOfflinePlayer(e.getKey()))
- .map(OfflinePlayer::getName).collect(Collectors.toList());
+ .map(OfflinePlayer::getName).toList();
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
return Optional.of(Util.tabLimit(options, lastArg));
} else {
diff --git a/src/main/java/world/bentobox/bentobox/api/configuration/WorldSettings.java b/src/main/java/world/bentobox/bentobox/api/configuration/WorldSettings.java
index 47e2ce3c6..100ff2606 100644
--- a/src/main/java/world/bentobox/bentobox/api/configuration/WorldSettings.java
+++ b/src/main/java/world/bentobox/bentobox/api/configuration/WorldSettings.java
@@ -32,12 +32,12 @@ public interface WorldSettings extends ConfigObject {
/**
* @return default rank settings for new islands
- * @deprecated since 1.21
- * Map of Flag, Integer does not allow to load other plugin/addon flags.
+ * @deprecated Map of Flag, Integer does not allow to load other plugin/addon flags.
* It cannot be replaced with Map of String, Integer due to compatibility issues.
* @see WorldSettings#getDefaultIslandFlagNames()
+ * @since 1.21.0
*/
- @Deprecated
+ @Deprecated(since="1.21.0", forRemoval=true)
Map getDefaultIslandFlags();
/**
@@ -57,12 +57,12 @@ default Map getDefaultIslandFlagNames()
/**
* @return default settings for new
- * @deprecated since 1.21
- * Map of Flag, Integer does not allow to load other plugin/addon flags.
+ * @deprecated Map of Flag, Integer does not allow to load other plugin/addon flags.
* It cannot be replaced with Map of String, Integer due to compatibility issues.
* @see WorldSettings#getDefaultIslandSettingNames()
+ * @since 1.21.0
*/
- @Deprecated
+ @Deprecated(since="1.21.0", forRemoval=true)
Map getDefaultIslandSettings();
/**
@@ -70,7 +70,7 @@ default Map getDefaultIslandFlagNames()
* This is necessary so users could specify any flag names in settings file from other plugins and addons.
* Otherwise, Flag reader would mark flag as invalid and remove it.
* Default implementation is compatibility layer so GameModes that are not upgraded still works.
- * @since 1.21
+ * @since 1.21.0
* @return default settings for new islands.
*/
default Map getDefaultIslandSettingNames()
@@ -288,6 +288,8 @@ default List getFallingBannedCommands() {
* Available placeholders for the commands are the following:
*
*
{@code [player]}: name of the player
+ *
{@code [owner]}: name of the owner of the island. When joining a team, this will be the team leader's name. When
+ * creating an island, it is the name of the player
*
*
* Here are some examples of valid commands to execute:
@@ -345,6 +347,8 @@ default List getFallingBannedCommands() {
* Available placeholders for the commands are the following:
*
*
{@code [player]}: name of the player
+ *
{@code [owner]}: name of the owner of the island. When joining a team, this will be the team leader's name. When
+ * creating an island, it is the name of the player
*
*
* Here are some examples of valid commands to execute:
@@ -363,6 +367,22 @@ default List getFallingBannedCommands() {
/**
* Returns a list of commands that should be executed when the player respawns after death if {@link Flags#ISLAND_RESPAWN} is true.
+ * These commands are executed by the console, unless otherwise stated using the {@code [SUDO]} prefix, in which case they are executed by the player.
+ *
+ * Available placeholders for the commands are the following:
+ *
+ *
{@code [player]}: name of the player
+ *
{@code [owner]}: name of the owner of the island. When joining a team, this will be the team leader's name. When
+ * creating an island, it is the name of the player
+ *
+ *
+ * Here are some examples of valid commands to execute:
+ *
+ *
{@code "[SUDO] bbox version"}
+ *
{@code "bsbadmin deaths set [player] 0"}
+ *
+ *
+ * Note that player-executed commands might not work, as these commands can be run with said player being offline.
* @return a list of commands.
* @since 1.14.0
* @see #getOnJoinCommands()
@@ -599,7 +619,7 @@ default boolean isMakeNetherPortals() {
default boolean isMakeEndPortals() {
return false;
}
-
+
/**
* Check for blocks when searching for a new island. This is a safety net check that does a look
* around the new island location (3x3x3 block check). If any non-air or non-water blocks are found
diff --git a/src/main/java/world/bentobox/bentobox/api/flags/Flag.java b/src/main/java/world/bentobox/bentobox/api/flags/Flag.java
index 2acd4f604..e860b44e1 100644
--- a/src/main/java/world/bentobox/bentobox/api/flags/Flag.java
+++ b/src/main/java/world/bentobox/bentobox/api/flags/Flag.java
@@ -53,8 +53,8 @@ public enum Type {
*/
WORLD_SETTING(Material.GRASS_BLOCK);
- private @NonNull
- final Material icon;
+ @NonNull
+ private final Material icon;
Type(@NonNull Material icon) {
this.icon = icon;
diff --git a/src/main/java/world/bentobox/bentobox/api/flags/FlagListener.java b/src/main/java/world/bentobox/bentobox/api/flags/FlagListener.java
index 10c999abe..b1fbd273b 100644
--- a/src/main/java/world/bentobox/bentobox/api/flags/FlagListener.java
+++ b/src/main/java/world/bentobox/bentobox/api/flags/FlagListener.java
@@ -95,8 +95,8 @@ public void noGo(@NonNull Event e, @NonNull Flag flag) {
* @param string - translation reference
*/
public void noGo(@NonNull Event e, @NonNull Flag flag, boolean silent, String string) {
- if (e instanceof Cancellable) {
- ((Cancellable)e).setCancelled(true);
+ if (e instanceof Cancellable cancellable) {
+ cancellable.setCancelled(true);
}
if (user != null && !silent) {
user.notify(string, TextVariables.DESCRIPTION, user.getTranslation(flag.getHintReference()));
@@ -128,7 +128,7 @@ public boolean checkIsland(@NonNull Event e, @Nullable Player player, @Nullable
// Set user
user = player == null ? null : User.getInstance(player);
if (loc == null) {
- if (user != null && user.getLocation() != null && user.getLocation().getWorld() != null) {
+ if (user != null && user.getLocation().getWorld() != null) {
report(user, e, user.getLocation(), flag, Why.NULL_LOCATION);
}
return true;
@@ -144,13 +144,7 @@ public boolean checkIsland(@NonNull Event e, @Nullable Player player, @Nullable
Optional island = getIslands().getProtectedIslandAt(loc);
// Handle Settings Flag
if (flag.getType().equals(Flag.Type.SETTING)) {
- // If the island exists, return the setting, otherwise return the default setting for this flag
- if (island.isPresent()) {
- report(user, e, loc, flag, island.map(x -> x.isAllowed(flag)).orElse(false) ? Why.SETTING_ALLOWED_ON_ISLAND : Why.SETTING_NOT_ALLOWED_ON_ISLAND);
- } else {
- report(user, e, loc, flag, flag.isSetForWorld(loc.getWorld()) ? Why.SETTING_ALLOWED_IN_WORLD : Why.SETTING_NOT_ALLOWED_IN_WORLD);
- }
- return island.map(x -> x.isAllowed(flag)).orElseGet(() -> flag.isSetForWorld(loc.getWorld()));
+ return processSetting(flag, island, e, loc);
}
// Protection flag
@@ -169,31 +163,14 @@ public boolean checkIsland(@NonNull Event e, @Nullable Player player, @Nullable
// Handle World Settings
if (flag.getType().equals(Flag.Type.WORLD_SETTING)) {
- if (flag.isSetForWorld(loc.getWorld())) {
- report(user, e, loc, flag, Why.ALLOWED_IN_WORLD);
- return true;
- }
- report(user, e, loc, flag, Why.NOT_ALLOWED_IN_WORLD);
- noGo(e, flag, silent, "protection.world-protected");
- return false;
+ return processWorldSetting(flag, loc, e, silent);
}
// Check if the plugin is set in User (required for testing)
User.setPlugin(plugin);
if (island.isPresent()) {
- // If it is not allowed on the island, "bypass island" moderators can do anything
- if (island.get().isAllowed(user, flag)) {
- report(user, e, loc, flag, Why.RANK_ALLOWED);
- return true;
- } else if (!user.getMetaData(AdminSwitchCommand.META_TAG).map(MetaDataValue::asBoolean).orElse(false)
- && (user.hasPermission(getIWM().getPermissionPrefix(loc.getWorld()) + "mod.bypass." + flag.getID() + ".island"))) {
- report(user, e, loc, flag, Why.BYPASS_ISLAND);
- return true;
- }
- report(user, e, loc, flag, Why.NOT_ALLOWED_ON_ISLAND);
- noGo(e, flag, silent, island.get().isSpawn() ? "protection.spawn-protected" : "protection.protected");
- return false;
+ return processBypass(flag, island.get(), e, loc, silent);
}
// The player is in the world, but not on an island, so general world settings apply
if (flag.isSetForWorld(loc.getWorld())) {
@@ -206,6 +183,41 @@ public boolean checkIsland(@NonNull Event e, @Nullable Player player, @Nullable
}
}
+ private boolean processBypass(@NonNull Flag flag, Island island, @NonNull Event e, @NonNull Location loc, boolean silent) {
+ // If it is not allowed on the island, "bypass island" moderators can do anything
+ if (island.isAllowed(user, flag)) {
+ report(user, e, loc, flag, Why.RANK_ALLOWED);
+ return true;
+ } else if (!user.getMetaData(AdminSwitchCommand.META_TAG).map(MetaDataValue::asBoolean).orElse(false)
+ && (user.hasPermission(getIWM().getPermissionPrefix(loc.getWorld()) + "mod.bypass." + flag.getID() + ".island"))) {
+ report(user, e, loc, flag, Why.BYPASS_ISLAND);
+ return true;
+ }
+ report(user, e, loc, flag, Why.NOT_ALLOWED_ON_ISLAND);
+ noGo(e, flag, silent, island.isSpawn() ? "protection.spawn-protected" : "protection.protected");
+ return false;
+ }
+
+ private boolean processWorldSetting(@NonNull Flag flag, @NonNull Location loc, @NonNull Event e, boolean silent) {
+ if (flag.isSetForWorld(loc.getWorld())) {
+ report(user, e, loc, flag, Why.ALLOWED_IN_WORLD);
+ return true;
+ }
+ report(user, e, loc, flag, Why.NOT_ALLOWED_IN_WORLD);
+ noGo(e, flag, silent, "protection.world-protected");
+ return false;
+ }
+
+ private boolean processSetting(@NonNull Flag flag, Optional island, @NonNull Event e, @NonNull Location loc) {
+ // If the island exists, return the setting, otherwise return the default setting for this flag
+ if (island.isPresent()) {
+ report(user, e, loc, flag, island.map(x -> x.isAllowed(flag)).orElse(false) ? Why.SETTING_ALLOWED_ON_ISLAND : Why.SETTING_NOT_ALLOWED_ON_ISLAND);
+ } else {
+ report(user, e, loc, flag, flag.isSetForWorld(loc.getWorld()) ? Why.SETTING_ALLOWED_IN_WORLD : Why.SETTING_NOT_ALLOWED_IN_WORLD);
+ }
+ return island.map(x -> x.isAllowed(flag)).orElseGet(() -> flag.isSetForWorld(loc.getWorld()));
+ }
+
/**
* Report why something did or did not happen for the admin why command
* @param user user involved
@@ -229,7 +241,7 @@ protected void report(@Nullable User user, @NonNull Event e, @NonNull Location l
.filter(p -> getPlugin().equals(p.getOwningPlugin())).findFirst().map(MetadataValue::asString).orElse("");
if (!issuerUUID.isEmpty()) {
User issuer = User.getInstance(UUID.fromString(issuerUUID));
- if (issuer != null && issuer.isPlayer()) {
+ if (issuer.isPlayer()) {
user.sendRawMessage(whyEvent);
user.sendRawMessage(whyBypass);
}
diff --git a/src/main/java/world/bentobox/bentobox/api/flags/clicklisteners/CycleClick.java b/src/main/java/world/bentobox/bentobox/api/flags/clicklisteners/CycleClick.java
index 5b807a4a3..c1a281e37 100644
--- a/src/main/java/world/bentobox/bentobox/api/flags/clicklisteners/CycleClick.java
+++ b/src/main/java/world/bentobox/bentobox/api/flags/clicklisteners/CycleClick.java
@@ -1,14 +1,15 @@
package world.bentobox.bentobox.api.flags.clicklisteners;
+import java.util.Objects;
+
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.event.inventory.ClickType;
-import java.util.Objects;
-
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.events.flags.FlagProtectionChangeEvent;
+import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.panels.Panel;
import world.bentobox.bentobox.api.panels.PanelItem;
@@ -57,13 +58,13 @@ public CycleClick(String id, int minRank, int maxRank) {
}
@Override
- public boolean onClick(Panel panel, User user, ClickType click, int slot) {
+ public boolean onClick(Panel panel, User user2, ClickType click, int slot) {
// This click listener is used with TabbedPanel and SettingsTabs only
TabbedPanel tp = (TabbedPanel)panel;
SettingsTab st = (SettingsTab)tp.getActiveTab();
// Get the island for this tab
island = st.getIsland();
- this.user = user;
+ this.user = user2;
changeOccurred = false;
// Permission prefix
String prefix = plugin.getIWM().getPermissionPrefix(Util.getWorld(user.getWorld()));
@@ -85,61 +86,81 @@ public boolean onClick(Panel panel, User user, ClickType click, int slot) {
// Rank
int currentRank = island.getFlag(flag);
if (click.equals(ClickType.LEFT)) {
- if (currentRank >= maxRank) {
- island.setFlag(flag, minRank);
- } else {
- island.setFlag(flag, rm.getRankUpValue(currentRank));
- }
- user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_OFF, 1F, 1F);
- // Fire event
- Bukkit.getPluginManager().callEvent(new FlagProtectionChangeEvent(island, user.getUniqueId(), flag, island.getFlag(flag)));
-
- // Subflag support
- if (flag.hasSubflags()) {
- // Fire events for all subflags as well
- flag.getSubflags().forEach(subflag -> Bukkit.getPluginManager().callEvent(new FlagProtectionChangeEvent(island, user.getUniqueId(), subflag, island.getFlag(subflag))));
- }
+ leftClick(flag, rm, currentRank);
+
} else if (click.equals(ClickType.RIGHT)) {
- if (currentRank <= minRank) {
- island.setFlag(flag, maxRank);
- } else {
- island.setFlag(flag, rm.getRankDownValue(currentRank));
- }
- user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1F, 1F);
- // Fire event
- Bukkit.getPluginManager().callEvent(new FlagProtectionChangeEvent(island, user.getUniqueId(), flag, island.getFlag(flag)));
-
- // Subflag support
- if (flag.hasSubflags()) {
- // Fire events for all subflags as well
- flag.getSubflags().forEach(subflag -> Bukkit.getPluginManager().callEvent(new FlagProtectionChangeEvent(island, user.getUniqueId(), subflag, island.getFlag(subflag))));
- }
- } else if (click.equals(ClickType.SHIFT_LEFT) && user.isOp()) {
- if (!plugin.getIWM().getHiddenFlags(user.getWorld()).contains(flag.getID())) {
- plugin.getIWM().getHiddenFlags(user.getWorld()).add(flag.getID());
- user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_GLASS_BREAK, 1F, 1F);
- } else {
- plugin.getIWM().getHiddenFlags(user.getWorld()).remove(flag.getID());
- user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_NOTE_BLOCK_CHIME, 1F, 1F);
- }
- // Save changes
- plugin.getIWM().getAddon(user.getWorld()).ifPresent(GameModeAddon::saveWorldSettings);
+ rightClick(flag, rm, currentRank);
+
+ } else if (click.equals(ClickType.SHIFT_LEFT) && user2.isOp()) {
+ leftShiftClick(flag);
}
});
} else {
- if (island == null) {
- // Island is not targeted.
- user.sendMessage("general.errors.not-on-island");
- } else {
- // Player is not the allowed to change settings.
- user.sendMessage("general.errors.insufficient-rank",
+ reportError();
+ }
+ return true;
+ }
+
+ private void reportError() {
+ if (island == null) {
+ // Island is not targeted.
+ user.sendMessage("general.errors.not-on-island");
+ } else {
+ // Player is not the allowed to change settings.
+ user.sendMessage("general.errors.insufficient-rank",
TextVariables.RANK,
user.getTranslation(plugin.getRanksManager().getRank(Objects.requireNonNull(island).getRank(user))));
- }
+ }
+ user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_METAL_HIT, 1F, 1F);
+ }
- user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_METAL_HIT, 1F, 1F);
+ private void leftClick(Flag flag, RanksManager rm, int currentRank) {
+ if (currentRank >= maxRank) {
+ island.setFlag(flag, minRank);
+ } else {
+ island.setFlag(flag, rm.getRankUpValue(currentRank));
}
- return true;
+ user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_OFF, 1F, 1F);
+ // Fire event
+ Bukkit.getPluginManager().callEvent(new FlagProtectionChangeEvent(island, user.getUniqueId(), flag, island.getFlag(flag)));
+
+ // Subflag support
+ if (flag.hasSubflags()) {
+ // Fire events for all subflags as well
+ flag.getSubflags().forEach(subflag -> Bukkit.getPluginManager().callEvent(new FlagProtectionChangeEvent(island, user.getUniqueId(), subflag, island.getFlag(subflag))));
+ }
+
+ }
+
+ private void rightClick(Flag flag, RanksManager rm, int currentRank) {
+ if (currentRank <= minRank) {
+ island.setFlag(flag, maxRank);
+ } else {
+ island.setFlag(flag, rm.getRankDownValue(currentRank));
+ }
+ user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1F, 1F);
+ // Fire event
+ Bukkit.getPluginManager().callEvent(new FlagProtectionChangeEvent(island, user.getUniqueId(), flag, island.getFlag(flag)));
+
+ // Subflag support
+ if (flag.hasSubflags()) {
+ // Fire events for all subflags as well
+ flag.getSubflags().forEach(subflag -> Bukkit.getPluginManager().callEvent(new FlagProtectionChangeEvent(island, user.getUniqueId(), subflag, island.getFlag(subflag))));
+ }
+
+ }
+
+ private void leftShiftClick(Flag flag) {
+ if (!plugin.getIWM().getHiddenFlags(user.getWorld()).contains(flag.getID())) {
+ plugin.getIWM().getHiddenFlags(user.getWorld()).add(flag.getID());
+ user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_GLASS_BREAK, 1F, 1F);
+ } else {
+ plugin.getIWM().getHiddenFlags(user.getWorld()).remove(flag.getID());
+ user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_NOTE_BLOCK_CHIME, 1F, 1F);
+ }
+ // Save changes
+ plugin.getIWM().getAddon(user.getWorld()).ifPresent(GameModeAddon::saveWorldSettings);
+
}
/**
diff --git a/src/main/java/world/bentobox/bentobox/api/flags/clicklisteners/IslandToggleClick.java b/src/main/java/world/bentobox/bentobox/api/flags/clicklisteners/IslandToggleClick.java
index 311165a59..056af998c 100644
--- a/src/main/java/world/bentobox/bentobox/api/flags/clicklisteners/IslandToggleClick.java
+++ b/src/main/java/world/bentobox/bentobox/api/flags/clicklisteners/IslandToggleClick.java
@@ -1,14 +1,15 @@
package world.bentobox.bentobox.api.flags.clicklisteners;
+import java.util.Objects;
+
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.event.inventory.ClickType;
-import java.util.Objects;
-
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.events.flags.FlagSettingChangeEvent;
+import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.panels.Panel;
import world.bentobox.bentobox.api.panels.PanelItem.ClickHandler;
@@ -60,18 +61,7 @@ public boolean onClick(Panel panel, User user, ClickType click, int slot) {
{
if (click.equals(ClickType.SHIFT_LEFT) && user.isOp())
{
- if (!plugin.getIWM().getHiddenFlags(user.getWorld()).contains(flag.getID()))
- {
- plugin.getIWM().getHiddenFlags(user.getWorld()).add(flag.getID());
- user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_GLASS_BREAK, 1F, 1F);
- }
- else
- {
- plugin.getIWM().getHiddenFlags(user.getWorld()).remove(flag.getID());
- user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_NOTE_BLOCK_CHIME, 1F, 1F);
- }
- // Save changes
- plugin.getIWM().getAddon(user.getWorld()).ifPresent(GameModeAddon::saveWorldSettings);
+ shiftLeftClick(user, flag);
}
else
{
@@ -82,40 +72,66 @@ public boolean onClick(Panel panel, User user, ClickType click, int slot) {
user.notify("protection.panel.flag-item.setting-cooldown");
return;
}
- // Toggle flag
- island.toggleFlag(flag);
- user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1F, 1F);
- // Set cooldown
- island.setCooldown(flag);
- // Fire event
- Bukkit.getPluginManager().callEvent(new FlagSettingChangeEvent(island,
- user.getUniqueId(),
- flag,
- island.isAllowed(flag)));
-
- if (flag.hasSubflags())
- {
- // Fire events for all subflags as well
- flag.getSubflags().forEach(subflag -> Bukkit.getPluginManager()
- .callEvent(new FlagSettingChangeEvent(island,
- user.getUniqueId(),
- subflag,
- island.isAllowed(subflag))));
- }
+ toggleFlag(user, flag, island);
}
});
} else {
- if (island == null) {
- user.sendMessage("general.errors.not-on-island");
- } else {
- // Player is not the allowed to change settings.
- user.sendMessage("general.errors.insufficient-rank",
+ reportError(user, island);
+ }
+ return true;
+ }
+
+ private void toggleFlag(User user, Flag flag, Island island) {
+ // Toggle flag
+ island.toggleFlag(flag);
+ user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1F, 1F);
+ // Set cooldown
+ island.setCooldown(flag);
+ // Fire event
+ Bukkit.getPluginManager().callEvent(new FlagSettingChangeEvent(island,
+ user.getUniqueId(),
+ flag,
+ island.isAllowed(flag)));
+
+ if (flag.hasSubflags())
+ {
+ // Fire events for all subflags as well
+ flag.getSubflags().forEach(subflag -> Bukkit.getPluginManager()
+ .callEvent(new FlagSettingChangeEvent(island,
+ user.getUniqueId(),
+ subflag,
+ island.isAllowed(subflag))));
+ }
+
+ }
+
+ private void reportError(User user, Island island) {
+ if (island == null) {
+ user.sendMessage("general.errors.not-on-island");
+ } else {
+ // Player is not the allowed to change settings.
+ user.sendMessage("general.errors.insufficient-rank",
TextVariables.RANK,
user.getTranslation(plugin.getRanksManager().getRank(Objects.requireNonNull(island).getRank(user))));
- }
+ }
- user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_METAL_HIT, 1F, 1F);
+ user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_METAL_HIT, 1F, 1F);
+
+ }
+
+ private void shiftLeftClick(User user, Flag flag) {
+ if (!plugin.getIWM().getHiddenFlags(user.getWorld()).contains(flag.getID()))
+ {
+ plugin.getIWM().getHiddenFlags(user.getWorld()).add(flag.getID());
+ user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_GLASS_BREAK, 1F, 1F);
}
- return true;
+ else
+ {
+ plugin.getIWM().getHiddenFlags(user.getWorld()).remove(flag.getID());
+ user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_NOTE_BLOCK_CHIME, 1F, 1F);
+ }
+ // Save changes
+ plugin.getIWM().getAddon(user.getWorld()).ifPresent(GameModeAddon::saveWorldSettings);
+
}
}
diff --git a/src/main/java/world/bentobox/bentobox/api/metadata/MetaDataValue.java b/src/main/java/world/bentobox/bentobox/api/metadata/MetaDataValue.java
index ea6d7c0a9..9695c907c 100644
--- a/src/main/java/world/bentobox/bentobox/api/metadata/MetaDataValue.java
+++ b/src/main/java/world/bentobox/bentobox/api/metadata/MetaDataValue.java
@@ -36,22 +36,22 @@ public class MetaDataValue {
* @param value the value assigned to this metadata value
*/
public MetaDataValue(@NonNull Object value) {
- if (value instanceof Integer) {
- intValue = (int)value;
- } else if (value instanceof Float) {
- floatValue = (float)value;
- } else if (value instanceof Double) {
- doubleValue = (double)value;
- } else if (value instanceof Long) {
- longValue = (long)value;
- } else if (value instanceof Short) {
- shortValue = (short)value;
- } else if (value instanceof Byte) {
- byteValue = (byte)value;
- } else if (value instanceof Boolean) {
- booleanValue = (boolean)value;
- } else if (value instanceof String) {
- stringValue = (String)value;
+ if (value instanceof Integer i) {
+ intValue = i;
+ } else if (value instanceof Float f) {
+ floatValue = f;
+ } else if (value instanceof Double d) {
+ doubleValue = d;
+ } else if (value instanceof Long l) {
+ longValue = l;
+ } else if (value instanceof Short s) {
+ shortValue = s;
+ } else if (value instanceof Byte b) {
+ byteValue = b;
+ } else if (value instanceof Boolean bo) {
+ booleanValue = bo;
+ } else if (value instanceof String st) {
+ stringValue = st;
}
}
diff --git a/src/main/java/world/bentobox/bentobox/api/panels/Tab.java b/src/main/java/world/bentobox/bentobox/api/panels/Tab.java
index 4eb839359..989b179e1 100644
--- a/src/main/java/world/bentobox/bentobox/api/panels/Tab.java
+++ b/src/main/java/world/bentobox/bentobox/api/panels/Tab.java
@@ -24,7 +24,7 @@ public interface Tab {
String getName();
/**
- * Return the panel items for this tab
+ * Return an immutable list of the panel items for this tab
* @return a list of items in slot order
*/
List<@Nullable PanelItem> getPanelItems();
diff --git a/src/main/java/world/bentobox/bentobox/api/panels/TabbedPanel.java b/src/main/java/world/bentobox/bentobox/api/panels/TabbedPanel.java
index 9ff12d57c..1589877b2 100644
--- a/src/main/java/world/bentobox/bentobox/api/panels/TabbedPanel.java
+++ b/src/main/java/world/bentobox/bentobox/api/panels/TabbedPanel.java
@@ -31,8 +31,8 @@ public class TabbedPanel extends Panel implements PanelListener {
private static final String PROTECTION_PANEL = "protection.panel.";
private static final long ITEMS_PER_PAGE = 36;
private final TabbedPanelBuilder tpb;
- private @NonNull
- final BentoBox plugin = BentoBox.getInstance();
+ @NonNull
+ private final BentoBox plugin = BentoBox.getInstance();
private int activeTab;
private int activePage;
private boolean closed;
diff --git a/src/main/java/world/bentobox/bentobox/api/panels/TemplatedPanel.java b/src/main/java/world/bentobox/bentobox/api/panels/TemplatedPanel.java
index 914ee10b0..0968e6630 100644
--- a/src/main/java/world/bentobox/bentobox/api/panels/TemplatedPanel.java
+++ b/src/main/java/world/bentobox/bentobox/api/panels/TemplatedPanel.java
@@ -96,11 +96,11 @@ private Map populateInventoryPanel()
{
for (int k = 0; k < this.panelTemplate.content()[i].length; k++)
{
- ItemTemplateRecord record = this.panelTemplate.content()[i][k];
+ ItemTemplateRecord rec = this.panelTemplate.content()[i][k];
- if (record != null && record.dataMap().containsKey("type"))
+ if (rec != null && rec.dataMap().containsKey("type"))
{
- String type = String.valueOf(record.dataMap().get("type"));
+ String type = String.valueOf(rec.dataMap().get("type"));
int counter = this.typeSlotMap.computeIfAbsent(type, key -> 0);
this.typeSlotMap.put(type, counter + 1);
@@ -226,11 +226,11 @@ private Map populateHopperPanel()
// Analyze the template
for (int i = 0; i < 5; i++)
{
- ItemTemplateRecord record = this.panelTemplate.content()[0][i];
+ ItemTemplateRecord rec = this.panelTemplate.content()[0][i];
- if (record != null && record.dataMap().containsKey("type"))
+ if (rec != null && rec.dataMap().containsKey("type"))
{
- String type = String.valueOf(record.dataMap().get("type"));
+ String type = String.valueOf(rec.dataMap().get("type"));
int counter = this.typeSlotMap.computeIfAbsent(type, key -> 0);
this.typeSlotMap.put(type, counter + 1);
@@ -289,11 +289,11 @@ private Map populateDropperPanel()
{
for (int k = 0; k < 3; k++)
{
- ItemTemplateRecord record = this.panelTemplate.content()[i][k];
+ ItemTemplateRecord rec = this.panelTemplate.content()[i][k];
- if (record != null && record.dataMap().containsKey("type"))
+ if (rec != null && rec.dataMap().containsKey("type"))
{
- String type = String.valueOf(record.dataMap().get("type"));
+ String type = String.valueOf(rec.dataMap().get("type"));
int counter = this.typeSlotMap.computeIfAbsent(type, key -> 0);
this.typeSlotMap.put(type, counter + 1);
@@ -354,41 +354,41 @@ private Map populateDropperPanel()
/**
* This method passes button creation from given record template.
- * @param record Template of the button that must be created.
+ * @param rec Template of the button that must be created.
* @return PanelItem of the template, otherwise null.
*/
@Nullable
- private PanelItem makeButton(@Nullable ItemTemplateRecord record)
+ private PanelItem makeButton(@Nullable ItemTemplateRecord rec)
{
- if (record == null)
+ if (rec == null)
{
// Immediate exit if record is null.
return null;
}
- if (record.dataMap().containsKey("type"))
+ if (rec.dataMap().containsKey("type"))
{
// If dataMap is not null, and it is not empty, then pass button to the object creator function.
- return this.makeAddonButton(record);
+ return this.makeAddonButton(rec);
}
else
{
PanelItemBuilder itemBuilder = new PanelItemBuilder();
- if (record.icon() != null)
+ if (rec.icon() != null)
{
- itemBuilder.icon(record.icon().clone());
+ itemBuilder.icon(rec.icon().clone());
}
- if (record.title() != null)
+ if (rec.title() != null)
{
- itemBuilder.name(this.user.getTranslation(record.title()));
+ itemBuilder.name(this.user.getTranslation(rec.title()));
}
- if (record.description() != null)
+ if (rec.description() != null)
{
- itemBuilder.description(this.user.getTranslation(record.description()));
+ itemBuilder.description(this.user.getTranslation(rec.description()));
}
// If there are generic click handlers that could be added, then this is a place
@@ -402,19 +402,19 @@ private PanelItem makeButton(@Nullable ItemTemplateRecord record)
/**
* This method passes button to the type creator, if that exists.
- * @param record Template of the button that must be created.
+ * @param rec Template of the button that must be created.
* @return PanelItem of the button created by typeCreator, otherwise null.
*/
@Nullable
- private PanelItem makeAddonButton(@NonNull ItemTemplateRecord record)
+ private PanelItem makeAddonButton(@NonNull ItemTemplateRecord rec)
{
// Get object type.
- String type = String.valueOf(record.dataMap().getOrDefault("type", ""));
+ String type = String.valueOf(rec.dataMap().getOrDefault("type", ""));
if (!this.typeCreators.containsKey(type))
{
// There are no object with a given type.
- return this.makeFallBack(record.fallback());
+ return this.makeFallBack(rec.fallback());
}
BiFunction buttonBuilder = this.typeCreators.get(type);
@@ -426,48 +426,48 @@ private PanelItem makeAddonButton(@NonNull ItemTemplateRecord record)
this.typeIndex.put(type, itemSlot.nextItemSlot());
// Try to get next object.
- PanelItem item = buttonBuilder.apply(record, itemSlot);
- return item == null ? this.makeFallBack(record.fallback()) : item;
+ PanelItem item = buttonBuilder.apply(rec, itemSlot);
+ return item == null ? this.makeFallBack(rec.fallback()) : item;
}
/**
* This method creates a fall back button for given record.
- * @param record Record which fallback must be created.
+ * @param rec Record which fallback must be created.
* @return PanelItem if fallback was creates successfully, otherwise null.
*/
@Nullable
- private PanelItem makeFallBack(@Nullable ItemTemplateRecord record)
+ private PanelItem makeFallBack(@Nullable ItemTemplateRecord rec)
{
- return record == null ? null : this.makeButton(record.fallback());
+ return rec == null ? null : this.makeButton(rec.fallback());
}
/**
* This method translates template record into a panel item.
- * @param record Record that must be translated.
+ * @param rec Record that must be translated.
* @return PanelItem that contains all information from the record.
*/
- private PanelItem makeTemplate(PanelTemplateRecord.TemplateItem record)
+ private PanelItem makeTemplate(PanelTemplateRecord.TemplateItem rec)
{
PanelItemBuilder itemBuilder = new PanelItemBuilder();
// Read icon only if it is not null.
- if (record.icon() != null)
+ if (rec.icon() != null)
{
- itemBuilder.icon(record.icon().clone());
+ itemBuilder.icon(rec.icon().clone());
}
// Read title only if it is not null.
- if (record.title() != null)
+ if (rec.title() != null)
{
- itemBuilder.name(this.user.getTranslation(record.title()));
+ itemBuilder.name(this.user.getTranslation(rec.title()));
}
// Read description only if it is not null.
- if (record.description() != null)
+ if (rec.description() != null)
{
- itemBuilder.description(this.user.getTranslation(record.description()));
+ itemBuilder.description(this.user.getTranslation(rec.description()));
}
// Click Handlers are managed by custom addon buttons.
diff --git a/src/main/java/world/bentobox/bentobox/api/panels/builders/TemplatedPanelBuilder.java b/src/main/java/world/bentobox/bentobox/api/panels/builders/TemplatedPanelBuilder.java
index 409c878a7..fb6b4c8f6 100644
--- a/src/main/java/world/bentobox/bentobox/api/panels/builders/TemplatedPanelBuilder.java
+++ b/src/main/java/world/bentobox/bentobox/api/panels/builders/TemplatedPanelBuilder.java
@@ -8,7 +8,11 @@
import java.io.File;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.function.BiFunction;
import org.bukkit.World;
diff --git a/src/main/java/world/bentobox/bentobox/api/panels/reader/ItemTemplateRecord.java b/src/main/java/world/bentobox/bentobox/api/panels/reader/ItemTemplateRecord.java
index f00dbc592..c1c157124 100644
--- a/src/main/java/world/bentobox/bentobox/api/panels/reader/ItemTemplateRecord.java
+++ b/src/main/java/world/bentobox/bentobox/api/panels/reader/ItemTemplateRecord.java
@@ -19,7 +19,6 @@
import world.bentobox.bentobox.api.panels.reader.ItemTemplateRecord.ActionRecords;
-
/**
* This Record contains all necessary information about Item Template that can be used to craft panel item.
*
@@ -33,11 +32,11 @@
* @since 1.17.3
*/
public record ItemTemplateRecord(@Nullable ItemStack icon,
- @Nullable String title,
- @Nullable String description,
- @NonNull List actions,
- @NonNull Map dataMap,
- @Nullable ItemTemplateRecord fallback)
+ @Nullable String title,
+ @Nullable String description,
+ @NonNull List actions,
+ @NonNull Map dataMap,
+ @Nullable ItemTemplateRecord fallback)
{
/**
* Instantiates a new Item template record without actions and data map.
diff --git a/src/main/java/world/bentobox/bentobox/api/panels/reader/PanelTemplateRecord.java b/src/main/java/world/bentobox/bentobox/api/panels/reader/PanelTemplateRecord.java
index 2bd0a2e49..18d5506f1 100644
--- a/src/main/java/world/bentobox/bentobox/api/panels/reader/PanelTemplateRecord.java
+++ b/src/main/java/world/bentobox/bentobox/api/panels/reader/PanelTemplateRecord.java
@@ -17,7 +17,6 @@
import world.bentobox.bentobox.api.panels.Panel;
import world.bentobox.bentobox.api.panels.reader.PanelTemplateRecord.TemplateItem;
-
/**
* This is template object for the panel reader. It contains data that can exist in the panel.
* PanelBuilder will use this to build panel.
@@ -98,10 +97,9 @@ public boolean equals(Object obj) {
if (this == obj) {
return true;
}
- if (!(obj instanceof PanelTemplateRecord)) {
+ if (!(obj instanceof PanelTemplateRecord other)) {
return false;
}
- PanelTemplateRecord other = (PanelTemplateRecord) obj;
return Objects.equals(background, other.background) && Objects.equals(border, other.border)
&& Arrays.deepEquals(content, other.content) && Arrays.equals(forcedRows, other.forcedRows)
&& Objects.equals(title, other.title) && type == other.type;
diff --git a/src/main/java/world/bentobox/bentobox/api/panels/reader/TemplateReader.java b/src/main/java/world/bentobox/bentobox/api/panels/reader/TemplateReader.java
index 4407ae8d2..9d8158b1b 100644
--- a/src/main/java/world/bentobox/bentobox/api/panels/reader/TemplateReader.java
+++ b/src/main/java/world/bentobox/bentobox/api/panels/reader/TemplateReader.java
@@ -6,6 +6,12 @@
package world.bentobox.bentobox.api.panels.reader;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
@@ -14,12 +20,6 @@
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
-import java.io.File;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
import com.google.common.base.Enums;
import world.bentobox.bentobox.api.panels.Panel;
@@ -49,6 +49,14 @@ public class TemplateReader
private static final String TYPE = "type";
+ /**
+ * Utility classes, which are collections of static members, are not meant to be instantiated.
+ * Even abstract utility classes, which can be extended, should not have public constructors.
+ * Java adds an implicit public constructor to every class which does not define at least one explicitly.
+ * Hence, at least one non-public constructor should be defined.
+ */
+ private TemplateReader() {}
+
/**
* Read template panel panel template record.
*
@@ -95,7 +103,7 @@ public static PanelTemplateRecord readTemplatePanel(@NonNull String panelName, @
return TemplateReader.loadedPanels.get(panelKey);
}
- PanelTemplateRecord record;
+ PanelTemplateRecord rec;
try
{
@@ -103,16 +111,16 @@ public static PanelTemplateRecord readTemplatePanel(@NonNull String panelName, @
YamlConfiguration config = new YamlConfiguration();
config.load(file);
// Read panel
- record = readPanelTemplate(config.getConfigurationSection(panelName));
+ rec = readPanelTemplate(config.getConfigurationSection(panelName));
// Put panel into memory
- TemplateReader.loadedPanels.put(panelKey, record);
+ TemplateReader.loadedPanels.put(panelKey, rec);
}
catch (IOException | InvalidConfigurationException e)
{
- record = null;
+ rec = null;
}
- return record;
+ return rec;
}
diff --git a/src/main/java/world/bentobox/bentobox/api/placeholders/placeholderapi/BasicPlaceholderExpansion.java b/src/main/java/world/bentobox/bentobox/api/placeholders/placeholderapi/BasicPlaceholderExpansion.java
index 0a506073b..40822dbee 100644
--- a/src/main/java/world/bentobox/bentobox/api/placeholders/placeholderapi/BasicPlaceholderExpansion.java
+++ b/src/main/java/world/bentobox/bentobox/api/placeholders/placeholderapi/BasicPlaceholderExpansion.java
@@ -6,6 +6,7 @@
import org.bukkit.entity.Player;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import world.bentobox.bentobox.api.placeholders.PlaceholderReplacer;
@@ -42,9 +43,9 @@ public void unregisterPlaceholder(@NonNull String placeholder) {
}
@Override
- public String onPlaceholderRequest(Player p, @NonNull String placeholder) {
- if (placeholders.containsKey(placeholder) && p != null) {
- return placeholders.get(placeholder).onReplace(User.getInstance(p));
+ public String onPlaceholderRequest(@Nullable Player p, @NonNull String placeholder) {
+ if (placeholders.containsKey(placeholder)) {
+ return placeholders.get(placeholder).onReplace(p != null ? User.getInstance(p) : null);
}
return null;
}
diff --git a/src/main/java/world/bentobox/bentobox/api/user/User.java b/src/main/java/world/bentobox/bentobox/api/user/User.java
index 11a7e593f..68dd641e3 100644
--- a/src/main/java/world/bentobox/bentobox/api/user/User.java
+++ b/src/main/java/world/bentobox/bentobox/api/user/User.java
@@ -1,5 +1,7 @@
package world.bentobox.bentobox.api.user;
+import java.util.Collections;
+import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -8,7 +10,6 @@
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
-import java.util.stream.Collectors;
import org.apache.commons.lang.math.NumberUtils;
import org.bukkit.Bukkit;
@@ -17,6 +18,7 @@
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.Particle;
+import org.bukkit.Particle.DustTransition;
import org.bukkit.Vibration;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
@@ -54,6 +56,26 @@ public class User implements MetaDataAble {
private static final Map users = new HashMap<>();
+ // Used for particle validation
+ private static final Map> VALIDATION_CHECK;
+ static {
+ Map> v = new EnumMap<>(Particle.class);
+ v.put(Particle.REDSTONE, Particle.DustOptions.class);
+ v.put(Particle.ITEM_CRACK, ItemStack.class);
+ v.put(Particle.BLOCK_CRACK, BlockData.class);
+ v.put(Particle.BLOCK_DUST, BlockData.class);
+ v.put(Particle.FALLING_DUST, BlockData.class);
+ v.put(Particle.BLOCK_MARKER, BlockData.class);
+ v.put(Particle.DUST_COLOR_TRANSITION, DustTransition.class);
+ v.put(Particle.VIBRATION, Vibration.class);
+ v.put(Particle.SCULK_CHARGE, Float.class);
+ v.put(Particle.SHRIEK, Integer.class);
+ v.put(Particle.LEGACY_BLOCK_CRACK, BlockData.class);
+ v.put(Particle.LEGACY_BLOCK_DUST, BlockData.class);
+ v.put(Particle.LEGACY_FALLING_DUST, BlockData.class);
+ VALIDATION_CHECK = Collections.unmodifiableMap(v);
+ }
+
/**
* Clears all users from the user list
*/
@@ -89,7 +111,8 @@ public static User getInstance(@NonNull Player player) {
}
/**
- * Gets an instance of User from a UUID.
+ * Gets an instance of User from a UUID. This will always return a user object.
+ * If the player is offline then the getPlayer value will be null.
* @param uuid - UUID
* @return user - user
*/
@@ -98,7 +121,7 @@ public static User getInstance(@NonNull UUID uuid) {
if (users.containsKey(uuid)) {
return users.get(uuid);
}
- // Return player, or null if they are not online
+ // Return a user instance
return new User(uuid);
}
@@ -317,8 +340,6 @@ public int getPermissionValue(String permissionPrefix, int defaultValue) {
// If requester is console, then return the default value
if (!isPlayer()) return defaultValue;
- int value = 0;
-
// If there is a dot at the end of the permissionPrefix, remove it
if (permissionPrefix.endsWith(".")) {
permissionPrefix = permissionPrefix.substring(0, permissionPrefix.length()-1);
@@ -330,10 +351,16 @@ public int getPermissionValue(String permissionPrefix, int defaultValue) {
.filter(PermissionAttachmentInfo::getValue) // Must be a positive permission, not a negative one
.map(PermissionAttachmentInfo::getPermission)
.filter(permission -> permission.startsWith(permPrefix))
- .collect(Collectors.toList());
+ .toList();
if (permissions.isEmpty()) return defaultValue;
+ return iteratePerms(permissions, permPrefix, defaultValue);
+
+ }
+
+ private int iteratePerms(List permissions, String permPrefix, int defaultValue) {
+ int value = 0;
for (String permission : permissions) {
if (permission.contains(permPrefix + "*")) {
// 'Star' permission
@@ -403,46 +430,68 @@ public String getTranslationNoColor(String reference, String... variables) {
}
private String translate(String addonPrefix, String reference, String[] variables) {
+ // Try to get the translation for this specific addon
String translation = plugin.getLocalesManager().get(this, addonPrefix + reference);
if (translation == null) {
+ // No luck, try to get the generic translation
translation = plugin.getLocalesManager().get(this, reference);
if (translation == null) {
- // If no translation has been found, return the reference for debug purposes.
- return reference;
+ // Nothing found. Replace vars (probably will do nothing) and return
+ return replaceVars(reference, variables);
}
}
// If this is a prefix, just gather and return the translation
- if (reference.startsWith("prefixes.")) {
- return translation;
- } else {
+ if (!reference.startsWith("prefixes.")) {
// Replace the prefixes
- for (String prefix : plugin.getLocalesManager().getAvailablePrefixes(this)) {
- String prefixTranslation = getTranslation("prefixes." + prefix);
- // Replace the [gamemode] text variable
- prefixTranslation = prefixTranslation.replace("[gamemode]", addon != null ? addon.getDescription().getName() : "[gamemode]");
- // Replace the [friendly_name] text variable
- prefixTranslation = prefixTranslation.replace("[friendly_name]", isPlayer() ? plugin.getIWM().getFriendlyName(getWorld()) : "[friendly_name]");
-
- // Replace the prefix in the actual message
- translation = translation.replace("[prefix_" + prefix + "]", prefixTranslation);
- }
+ return replacePrefixes(translation, variables);
+ }
+ return translation;
+ }
- // Then replace variables
- if (variables.length > 1) {
- for (int i = 0; i < variables.length; i += 2) {
- translation = translation.replace(variables[i], variables[i + 1]);
- }
+ private String replacePrefixes(String translation, String[] variables) {
+ for (String prefix : plugin.getLocalesManager().getAvailablePrefixes(this)) {
+ String prefixTranslation = getTranslation("prefixes." + prefix);
+ // Replace the [gamemode] text variable
+ prefixTranslation = prefixTranslation.replace("[gamemode]", addon != null ? addon.getDescription().getName() : "[gamemode]");
+ // Replace the [friendly_name] text variable
+ prefixTranslation = prefixTranslation.replace("[friendly_name]", isPlayer() ? plugin.getIWM().getFriendlyName(getWorld()) : "[friendly_name]");
+
+ // Replace the prefix in the actual message
+ translation = translation.replace("[prefix_" + prefix + "]", prefixTranslation);
+ }
+
+ // Then replace variables
+ if (variables.length > 1) {
+ for (int i = 0; i < variables.length; i += 2) {
+ translation = translation.replace(variables[i], variables[i + 1]);
}
+ }
+
+ // Then replace Placeholders, this will only work if this is a player
+ if (player != null) {
+ translation = plugin.getPlaceholdersManager().replacePlaceholders(player, translation);
+ }
+ return translation;
+ }
- // Then replace Placeholders, this will only work if this is a player
- if (player != null) {
- translation = plugin.getPlaceholdersManager().replacePlaceholders(player, translation);
+ private String replaceVars(String reference, String[] variables) {
+
+ // Then replace variables
+ if (variables.length > 1) {
+ for (int i = 0; i < variables.length; i += 2) {
+ reference = reference.replace(variables[i], variables[i + 1]);
}
+ }
- return translation;
+ // Then replace Placeholders, this will only work if this is a player
+ if (player != null) {
+ reference = plugin.getPlaceholdersManager().replacePlaceholders(player, reference);
}
+
+ // If no translation has been found, return the reference for debug purposes.
+ return reference;
}
/**
@@ -600,72 +649,18 @@ public boolean inWorld() {
* @param y Y coordinate of the particle to display.
* @param z Z coordinate of the particle to display.
*/
- public void spawnParticle(Particle particle, Object dustOptions, double x, double y, double z)
+ public void spawnParticle(Particle particle, @Nullable Object dustOptions, double x, double y, double z)
{
- // Improve particle validation.
- switch (particle)
- {
- case REDSTONE ->
- {
- if (!(dustOptions instanceof Particle.DustOptions))
- {
- throw new IllegalArgumentException("A non-null Particle.DustOptions must be provided when using Particle.REDSTONE as particle.");
- }
- }
- case ITEM_CRACK ->
- {
- if (!(dustOptions instanceof ItemStack))
- {
- throw new IllegalArgumentException("A non-null ItemStack must be provided when using Particle.ITEM_CRACK as particle.");
- }
- }
- case BLOCK_CRACK, BLOCK_DUST, FALLING_DUST, BLOCK_MARKER ->
- {
- if (!(dustOptions instanceof BlockData))
- {
- throw new IllegalArgumentException("A non-null BlockData must be provided when using Particle." + particle + " as particle.");
- }
- }
- case DUST_COLOR_TRANSITION ->
- {
- if (!(dustOptions instanceof Particle.DustTransition))
- {
- throw new IllegalArgumentException("A non-null Particle.DustTransition must be provided when using Particle.DUST_COLOR_TRANSITION as particle.");
- }
- }
- case VIBRATION ->
- {
- if (!(dustOptions instanceof Vibration))
- {
- throw new IllegalArgumentException("A non-null Vibration must be provided when using Particle.VIBRATION as particle.");
- }
- }
- case SCULK_CHARGE ->
- {
- if (!(dustOptions instanceof Float))
- {
- throw new IllegalArgumentException("A non-null Float must be provided when using Particle.SCULK_CHARGE as particle.");
- }
- }
- case SHRIEK ->
- {
- if (!(dustOptions instanceof Integer))
- {
- throw new IllegalArgumentException("A non-null Integer must be provided when using Particle.SHRIEK as particle.");
- }
- }
- case LEGACY_BLOCK_CRACK, LEGACY_BLOCK_DUST, LEGACY_FALLING_DUST ->
- {
- if (!(dustOptions instanceof BlockData))
- {
- throw new IllegalArgumentException("A non-null MaterialData must be provided when using Particle." + particle + " as particle.");
- }
- }
+ Class> expectedClass = VALIDATION_CHECK.get(particle);
+ if (expectedClass == null) throw new IllegalArgumentException("Unexpected value: " + particle);
+
+ if (!(expectedClass.isInstance(dustOptions))) {
+ throw new IllegalArgumentException("A non-null " + expectedClass.getSimpleName() + " must be provided when using Particle." + particle + " as particle.");
}
// Check if this particle is beyond the viewing distance of the server
- if (this.player != null &&
- this.player.getLocation().toVector().distanceSquared(new Vector(x, y, z)) <
+ if (this.player != null
+ && this.player.getLocation().toVector().distanceSquared(new Vector(x, y, z)) <
(Bukkit.getServer().getViewDistance() * 256 * Bukkit.getServer().getViewDistance()))
{
if (particle.equals(Particle.REDSTONE))
@@ -678,6 +673,7 @@ else if (dustOptions != null)
}
else
{
+ // This will never be called unless the value in VALIDATION_CHECK is null in the future
player.spawnParticle(particle, x, y, z, 1);
}
}
diff --git a/src/main/java/world/bentobox/bentobox/blueprints/Blueprint.java b/src/main/java/world/bentobox/bentobox/blueprints/Blueprint.java
index da3304b59..f488c8ea6 100644
--- a/src/main/java/world/bentobox/bentobox/blueprints/Blueprint.java
+++ b/src/main/java/world/bentobox/bentobox/blueprints/Blueprint.java
@@ -2,7 +2,6 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
import org.bukkit.Material;
diff --git a/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java b/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java
index fb8ac322c..c0dff17bc 100644
--- a/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java
+++ b/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java
@@ -8,7 +8,6 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@@ -138,7 +137,7 @@ private void copyAsync(World world, User user, List vectorsToCopy, int s
.filter(e -> new Vector(Math.rint(e.getLocation().getX()),
Math.rint(e.getLocation().getY()),
Math.rint(e.getLocation().getZ())).equals(v))
- .collect(Collectors.toList());
+ .toList();
if (copyBlock(v.toLocation(world), copyAir, copyBiome, ents)) {
count++;
}
@@ -288,19 +287,17 @@ private List setEntities(Collection entities) {
if (entity instanceof Villager villager) {
setVillager(villager, bpe);
}
- if (entity instanceof Colorable c) {
- if (c.getColor() != null) {
- bpe.setColor(c.getColor());
- }
+ if (entity instanceof Colorable c && c.getColor() != null) {
+ bpe.setColor(c.getColor());
}
- if (entity instanceof Tameable) {
- bpe.setTamed(((Tameable)entity).isTamed());
+ if (entity instanceof Tameable tameable) {
+ bpe.setTamed(tameable.isTamed());
}
- if (entity instanceof ChestedHorse) {
- bpe.setChest(((ChestedHorse)entity).isCarryingChest());
+ if (entity instanceof ChestedHorse chestedHorse) {
+ bpe.setChest(chestedHorse.isCarryingChest());
}
// Only set if child. Most animals are adults
- if (entity instanceof Ageable && !((Ageable)entity).isAdult()) {
+ if (entity instanceof Ageable ageable && !ageable.isAdult()) {
bpe.setAdult(false);
}
if (entity instanceof AbstractHorse horse) {
@@ -375,7 +372,7 @@ public void setPos1(@Nullable Location pos1) {
if (pos1 != null) {
final int minHeight = pos1.getWorld() == null ? 0 : pos1.getWorld().getMinHeight();
final int maxHeight = pos1.getWorld() == null ? 255 : pos1.getWorld().getMaxHeight();
-
+
if (pos1.getBlockY() < minHeight)
{
pos1.setY(minHeight);
diff --git a/src/main/java/world/bentobox/bentobox/blueprints/BlueprintPaster.java b/src/main/java/world/bentobox/bentobox/blueprints/BlueprintPaster.java
index 2e0bc9362..8536ff294 100644
--- a/src/main/java/world/bentobox/bentobox/blueprints/BlueprintPaster.java
+++ b/src/main/java/world/bentobox/bentobox/blueprints/BlueprintPaster.java
@@ -1,5 +1,17 @@
package world.bentobox.bentobox.blueprints;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
@@ -7,6 +19,7 @@
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@@ -16,12 +29,6 @@
import world.bentobox.bentobox.nms.PasteHandler;
import world.bentobox.bentobox.util.Util;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.*;
-import java.util.Map.Entry;
-import java.util.concurrent.CompletableFuture;
-
/**
* This class pastes the clipboard it is given
* @author tastybento
@@ -77,10 +84,10 @@ enum PasteState {
private final Island island;
/**
- * Paste a clipboard to a location and run task
+ * Paste a clipboard to a location. Run {@link #paste()} to paste
* @param plugin - BentoBox
* @param clipboard - clipboard to paste
- * @param location - location to paste to
+ * @param location - location to which to paste
*/
public BlueprintPaster(@NonNull BentoBox plugin, @NonNull BlueprintClipboard clipboard, @NonNull Location location) {
this.plugin = plugin;
@@ -90,9 +97,6 @@ public BlueprintPaster(@NonNull BentoBox plugin, @NonNull BlueprintClipboard cli
this.location = location;
this.world = location.getWorld();
this.island = null;
-
- // Paste
- paste();
}
/**
@@ -136,7 +140,7 @@ public CompletableFuture paste() {
// If this is an island OVERWORLD paste, get the island owner.
final Optional owner = Optional.ofNullable(island).map(i -> User.getInstance(i.getOwner()));
- // Tell the owner we're pasting blocks and how much time it might take
+ // Tell the owner we're pasting blocks and how much time it might take
owner.ifPresent(user -> tellOwner(user, blocks.size(), attached.size(), entities.size(), plugin.getSettings().getPasteSpeed()));
Bits bits = new Bits(blocks, attached, entities,
blocks.entrySet().iterator(), attached.entrySet().iterator(), entities.entrySet().iterator(),
@@ -151,95 +155,19 @@ private void pasterTask(CompletableFuture result, Optional owner,
final int pasteSpeed = plugin.getSettings().getPasteSpeed();
- long timer = System.currentTimeMillis();
int count = 0;
if (pasteState.equals(PasteState.CHUNK_LOAD)) {
- pasteState = PasteState.CHUNK_LOADING;
- // Load chunk
- currentTask = Util.getChunkAtAsync(location).thenRun(() -> {
- pasteState = PasteState.BLOCKS;
- long duration = System.currentTimeMillis() - timer;
- if (duration > chunkLoadTime) {
- chunkLoadTime = duration;
- }
- });
+ loadChunk();
}
else if (pasteState.equals(PasteState.BLOCKS) || pasteState.equals(PasteState.ATTACHMENTS)) {
- Iterator> it = pasteState.equals(PasteState.BLOCKS) ? bits.it : bits.it2;
- if (it.hasNext()) {
- Map blockMap = new HashMap<>();
- // Paste blocks
- while (count < pasteSpeed) {
- if (!it.hasNext()) {
- break;
- }
- Entry entry = it.next();
- Location pasteTo = location.clone().add(entry.getKey());
- // pos1 and pos2 update
- updatePos(pasteTo);
-
- BlueprintBlock block = entry.getValue();
- blockMap.put(pasteTo, block);
- count++;
- }
- if (!blockMap.isEmpty()) {
- currentTask = paster.pasteBlocks(island, world, blockMap);
- }
- } else {
- if (pasteState.equals(PasteState.BLOCKS)) {
- // Blocks done
- // Next paste attachments
- pasteState = PasteState.ATTACHMENTS;
- } else {
- // Attachments done. Next paste entities
- pasteState = PasteState.ENTITIES;
- if (bits.entities.size() != 0) {
- owner.ifPresent(user -> user.sendMessage("commands.island.create.pasting.entities", TextVariables.NUMBER, String.valueOf(bits.entities.size())));
- }
- }
- }
+ pasteBlocks(bits, count, owner, pasteSpeed);
}
else if (pasteState.equals(PasteState.ENTITIES)) {
- if (bits.it3().hasNext()) {
- Map> entityMap = new HashMap<>();
- // Paste entities
- while (count < pasteSpeed) {
- if (!bits.it3().hasNext()) {
- break;
- }
- Entry> entry = bits.it3().next();
- int x = location.getBlockX() + entry.getKey().getBlockX();
- int y = location.getBlockY() + entry.getKey().getBlockY();
- int z = location.getBlockZ() + entry.getKey().getBlockZ();
- Location center = new Location(world, x, y, z).add(new Vector(0.5, 0.5, 0.5));
- List entities = entry.getValue();
- entityMap.put(center, entities);
- count++;
- }
- if (!entityMap.isEmpty()) {
- currentTask = paster.pasteEntities(island, world, entityMap);
- }
- } else {
- pasteState = PasteState.DONE;
-
- String world = switch (location.getWorld().getEnvironment()) {
- case NETHER -> owner.map(user -> user.getTranslation("general.worlds.nether")).orElse("");
- case THE_END -> owner.map(user -> user.getTranslation("general.worlds.the-end")).orElse("");
- default -> owner.map(user -> user.getTranslation("general.worlds.overworld")).orElse("");
- };
-
- owner.ifPresent(user -> user.sendMessage("commands.island.create.pasting.dimension-done", "[world]", world));
- }
+ pasteEntities(bits, count, owner, pasteSpeed);
}
else if (pasteState.equals(PasteState.DONE)) {
// All done. Cancel task
- // Set pos1 and 2 if this was a clipboard paste
- if (island == null && clipboard != null) {
- clipboard.setPos1(pos1);
- clipboard.setPos2(pos2);
- }
- pasteState = PasteState.CANCEL;
- result.complete(true);
+ cancelTask(result);
} else if (pasteState.equals(PasteState.CANCEL)) {
// This state makes sure the follow-on task only ever runs once
pastingTask.cancel();
@@ -247,6 +175,101 @@ else if (pasteState.equals(PasteState.DONE)) {
}
}
+ private void cancelTask(CompletableFuture result) {
+ // Set pos1 and 2 if this was a clipboard paste
+ if (island == null && clipboard != null) {
+ clipboard.setPos1(pos1);
+ clipboard.setPos2(pos2);
+ }
+ pasteState = PasteState.CANCEL;
+ result.complete(true);
+ }
+
+ private void pasteEntities(Bits bits, int count, Optional owner, int pasteSpeed) {
+ if (bits.it3().hasNext()) {
+ Map> entityMap = new HashMap<>();
+ // Paste entities
+ while (count < pasteSpeed) {
+ if (!bits.it3().hasNext()) {
+ break;
+ }
+ Entry> entry = bits.it3().next();
+ int x = location.getBlockX() + entry.getKey().getBlockX();
+ int y = location.getBlockY() + entry.getKey().getBlockY();
+ int z = location.getBlockZ() + entry.getKey().getBlockZ();
+ Location center = new Location(world, x, y, z).add(new Vector(0.5, 0.5, 0.5));
+ List entities = entry.getValue();
+ entityMap.put(center, entities);
+ count++;
+ }
+ if (!entityMap.isEmpty()) {
+ currentTask = paster.pasteEntities(island, world, entityMap);
+ }
+ } else {
+ pasteState = PasteState.DONE;
+
+ String dimensionType = switch (location.getWorld().getEnvironment()) {
+ case NETHER -> owner.map(user -> user.getTranslation("general.worlds.nether")).orElse("");
+ case THE_END -> owner.map(user -> user.getTranslation("general.worlds.the-end")).orElse("");
+ default -> owner.map(user -> user.getTranslation("general.worlds.overworld")).orElse("");
+ };
+
+ owner.ifPresent(user -> user.sendMessage("commands.island.create.pasting.dimension-done", "[world]", dimensionType));
+ }
+
+ }
+
+ private void pasteBlocks(Bits bits, int count, Optional owner, int pasteSpeed) {
+ Iterator> it = pasteState.equals(PasteState.BLOCKS) ? bits.it : bits.it2;
+ if (it.hasNext()) {
+ Map blockMap = new HashMap<>();
+ // Paste blocks
+ while (count < pasteSpeed) {
+ if (!it.hasNext()) {
+ break;
+ }
+ Entry entry = it.next();
+ Location pasteTo = location.clone().add(entry.getKey());
+ // pos1 and pos2 update
+ updatePos(pasteTo);
+
+ BlueprintBlock block = entry.getValue();
+ blockMap.put(pasteTo, block);
+ count++;
+ }
+ if (!blockMap.isEmpty()) {
+ currentTask = paster.pasteBlocks(island, world, blockMap);
+ }
+ } else {
+ if (pasteState.equals(PasteState.BLOCKS)) {
+ // Blocks done
+ // Next paste attachments
+ pasteState = PasteState.ATTACHMENTS;
+ } else {
+ // Attachments done. Next paste entities
+ pasteState = PasteState.ENTITIES;
+ if (bits.entities.size() != 0) {
+ owner.ifPresent(user -> user.sendMessage("commands.island.create.pasting.entities", TextVariables.NUMBER, String.valueOf(bits.entities.size())));
+ }
+ }
+ }
+
+ }
+
+ private void loadChunk() {
+ long timer = System.currentTimeMillis();
+ pasteState = PasteState.CHUNK_LOADING;
+ // Load chunk
+ currentTask = Util.getChunkAtAsync(location).thenRun(() -> {
+ pasteState = PasteState.BLOCKS;
+ long duration = System.currentTimeMillis() - timer;
+ if (duration > chunkLoadTime) {
+ chunkLoadTime = duration;
+ }
+ });
+
+ }
+
private void tellOwner(User user, int blocksSize, int attachedSize, int entitiesSize, int pasteSpeed) {
// Estimated time:
double total = (double) blocksSize + attachedSize + entitiesSize;
diff --git a/src/main/java/world/bentobox/bentobox/blueprints/conversation/NameSuccessPrompt.java b/src/main/java/world/bentobox/bentobox/blueprints/conversation/NameSuccessPrompt.java
index 2b2c6a4e3..09ff0fa08 100644
--- a/src/main/java/world/bentobox/bentobox/blueprints/conversation/NameSuccessPrompt.java
+++ b/src/main/java/world/bentobox/bentobox/blueprints/conversation/NameSuccessPrompt.java
@@ -8,7 +8,6 @@
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
-import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.Blueprint;
diff --git a/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintBundle.java b/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintBundle.java
index 59f457c28..ce7474653 100644
--- a/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintBundle.java
+++ b/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintBundle.java
@@ -3,7 +3,6 @@
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
import org.bukkit.Material;
diff --git a/src/main/java/world/bentobox/bentobox/database/Database.java b/src/main/java/world/bentobox/bentobox/database/Database.java
index 5da65334f..0eae05e35 100644
--- a/src/main/java/world/bentobox/bentobox/database/Database.java
+++ b/src/main/java/world/bentobox/bentobox/database/Database.java
@@ -99,12 +99,11 @@ public CompletableFuture saveObjectAsync(T instance) {
}
/**
- * Save object. Saving may be done async or sync, depending on the underlying database.
+ * Save object. Saving is done async. Same as {@link #saveObjectAsync(Object)}, which is recommended.
* @param instance to save
* @return true - always.
- * @deprecated As of 1.13.0. Use {@link #saveObjectAsync(Object)}.
+ * @since 1.13.0
*/
- @Deprecated
public boolean saveObject(T instance) {
saveObjectAsync(instance).thenAccept(r -> {
if (Boolean.FALSE.equals(r)) logger.severe(() -> "Could not save object to database!");
diff --git a/src/main/java/world/bentobox/bentobox/database/DatabaseConnectionSettingsImpl.java b/src/main/java/world/bentobox/bentobox/database/DatabaseConnectionSettingsImpl.java
index 7bddc21bf..b3a7f957d 100644
--- a/src/main/java/world/bentobox/bentobox/database/DatabaseConnectionSettingsImpl.java
+++ b/src/main/java/world/bentobox/bentobox/database/DatabaseConnectionSettingsImpl.java
@@ -1,5 +1,13 @@
package world.bentobox.bentobox.database;
+
+import java.util.Collections;
+import java.util.Map;
+
+
+/**
+ * The type Database connection settings.
+ */
public class DatabaseConnectionSettingsImpl {
private String host;
private int port;
@@ -14,23 +22,97 @@ public class DatabaseConnectionSettingsImpl {
*/
private boolean useSSL;
+ /**
+ * Number of max connections in pool.
+ * @since 1.21.0
+ */
+ private int maxConnections;
+
+ /**
+ * Map of extra properties.
+ * @since 1.21.0
+ */
+ private Map extraProperties;
+
/**
* Hosts database settings
* @param host - database host
* @param port - port
* @param databaseName - database name
- * @param username - username
+ * @param username - username
* @param password - password
+ * @param useSSL - whether to use SSL or not
+ * @param maxConnections - max number of connections
+ * @param extraProperties Map with extra properties.
*/
- public DatabaseConnectionSettingsImpl(String host, int port, String databaseName, String username, String password, boolean useSSL) {
- this.host = host;
- this.port = port;
- this.databaseName = databaseName;
- this.username = username;
- this.password = password;
- this.useSSL = useSSL;
+ public record DatabaseSettings(String host,
+ int port,
+ String databaseName,
+ String username,
+ String password,
+ boolean useSSL,
+ int maxConnections,
+ Map extraProperties) {}
+
+ /**
+ * Hosts database settings
+ * @param settings - database settings see {@link DatabaseSettings}
+ */
+ public DatabaseConnectionSettingsImpl(DatabaseSettings settings)
+ {
+ this.host = settings.host;
+ this.port = settings.port;
+ this.databaseName = settings.databaseName;
+ this.username = settings.username;
+ this.password = settings.password;
+ this.useSSL = settings.useSSL;
+ this.maxConnections = settings.maxConnections;
+ this.extraProperties = settings.extraProperties;
+ }
+
+
+ /**
+ * Hosts database settings
+ * @param host - database host
+ * @param port - port
+ * @param databaseName - database name
+ * @param username - username
+ * @param password - password
+ * @param useSSL - ssl usage.
+ * @param maxConnections - number of maximal connections in pool.
+ */
+ public DatabaseConnectionSettingsImpl(String host,
+ int port,
+ String databaseName,
+ String username,
+ String password,
+ boolean useSSL,
+ int maxConnections)
+ {
+ this(new DatabaseSettings(host, port, databaseName, username, password, useSSL, maxConnections, Collections.emptyMap()));
+ }
+
+
+ /**
+ * Hosts database settings
+ * @param host - database host
+ * @param port - port
+ * @param databaseName - database name
+ * @param username - username
+ * @param password - password
+ * @param useSSL - ssl usage.
+ */
+ public DatabaseConnectionSettingsImpl(String host,
+ int port,
+ String databaseName,
+ String username,
+ String password,
+ boolean useSSL)
+ {
+ this(new DatabaseSettings(host, port, databaseName, username, password, useSSL, 0, Collections.emptyMap()));
}
+
/**
* @return the host
*/
@@ -117,4 +199,48 @@ public boolean isUseSSL() {
public void setUseSSL(boolean useSSL) {
this.useSSL = useSSL;
}
+
+
+ /**
+ * Gets max connections.
+ *
+ * @return the max connections
+ */
+ public int getMaxConnections()
+ {
+ return this.maxConnections;
+ }
+
+
+ /**
+ * Sets max connections.
+ *
+ * @param maxConnections the max connections
+ */
+ public void setMaxConnections(int maxConnections)
+ {
+ this.maxConnections = maxConnections;
+ }
+
+
+ /**
+ * Gets extra properties.
+ *
+ * @return the extra properties
+ */
+ public Map getExtraProperties()
+ {
+ return extraProperties;
+ }
+
+
+ /**
+ * Sets extra properties.
+ *
+ * @param extraProperties the extra properties
+ */
+ public void setExtraProperties(Map extraProperties)
+ {
+ this.extraProperties = extraProperties;
+ }
}
diff --git a/src/main/java/world/bentobox/bentobox/database/DatabaseConnector.java b/src/main/java/world/bentobox/bentobox/database/DatabaseConnector.java
index ab57ac1d2..c07e843ae 100644
--- a/src/main/java/world/bentobox/bentobox/database/DatabaseConnector.java
+++ b/src/main/java/world/bentobox/bentobox/database/DatabaseConnector.java
@@ -45,10 +45,5 @@ public interface DatabaseConnector {
* @return true if it exists
*/
boolean uniqueIdExists(String tableName, String key);
-
-
-
-
-
}
diff --git a/src/main/java/world/bentobox/bentobox/database/json/BentoboxTypeAdapterFactory.java b/src/main/java/world/bentobox/bentobox/database/json/BentoboxTypeAdapterFactory.java
index 147ffe5f2..d1263ec9c 100644
--- a/src/main/java/world/bentobox/bentobox/database/json/BentoboxTypeAdapterFactory.java
+++ b/src/main/java/world/bentobox/bentobox/database/json/BentoboxTypeAdapterFactory.java
@@ -26,7 +26,6 @@
import world.bentobox.bentobox.database.json.adapters.PotionEffectTypeAdapter;
import world.bentobox.bentobox.database.json.adapters.VectorTypeAdapter;
import world.bentobox.bentobox.database.json.adapters.WorldTypeAdapter;
-import world.bentobox.bentobox.versions.ServerCompatibility;
/**
diff --git a/src/main/java/world/bentobox/bentobox/database/json/adapters/EnumTypeAdapter.java b/src/main/java/world/bentobox/bentobox/database/json/adapters/EnumTypeAdapter.java
index edccf73b8..1daff230b 100644
--- a/src/main/java/world/bentobox/bentobox/database/json/adapters/EnumTypeAdapter.java
+++ b/src/main/java/world/bentobox/bentobox/database/json/adapters/EnumTypeAdapter.java
@@ -21,7 +21,7 @@ public final class EnumTypeAdapter> extends TypeAdapter {
/**
- * Bimap to store name <-> enum references
+ * Bimap to store name,enum pair references
*/
private final BiMap enumMap = HashBiMap.create();
diff --git a/src/main/java/world/bentobox/bentobox/database/json/adapters/LocationTypeAdapter.java b/src/main/java/world/bentobox/bentobox/database/json/adapters/LocationTypeAdapter.java
index 809ce3e4e..71997eaea 100644
--- a/src/main/java/world/bentobox/bentobox/database/json/adapters/LocationTypeAdapter.java
+++ b/src/main/java/world/bentobox/bentobox/database/json/adapters/LocationTypeAdapter.java
@@ -24,8 +24,9 @@ public void write(JsonWriter out, Location location) throws IOException {
out.value(location.getX());
out.value(location.getY());
out.value(location.getZ());
- out.value(location.getYaw());
- out.value(location.getPitch());
+ // This is required for 1.19-1.19.2 compatibility.
+ out.value((double) location.getYaw());
+ out.value((double) location.getPitch());
out.endArray();
}
diff --git a/src/main/java/world/bentobox/bentobox/database/objects/BonusRangeRecord.java b/src/main/java/world/bentobox/bentobox/database/objects/BonusRangeRecord.java
index 43ad921ec..573a7ea5c 100644
--- a/src/main/java/world/bentobox/bentobox/database/objects/BonusRangeRecord.java
+++ b/src/main/java/world/bentobox/bentobox/database/objects/BonusRangeRecord.java
@@ -5,9 +5,6 @@
/**
* Record for bonus ranges
* @author tastybento
- * @param id an id to identify this bonus
- * @param range the additional bonus range
- * @param message the reference key to a locale message related to this bonus. May be blank.
*/
public class BonusRangeRecord {
@Expose
@@ -17,9 +14,9 @@ public class BonusRangeRecord {
@Expose
private String message;
/**
- * @param uniqueId
- * @param range
- * @param message
+ * @param uniqueId an id to identify this bonus
+ * @param range the additional bonus range
+ * @param message the reference key to a locale message related to this bonus. May be blank.
*/
public BonusRangeRecord(String uniqueId, int range, String message) {
this.uniqueId = uniqueId;
diff --git a/src/main/java/world/bentobox/bentobox/database/objects/Island.java b/src/main/java/world/bentobox/bentobox/database/objects/Island.java
index 6e13b6d0f..f5120c44a 100644
--- a/src/main/java/world/bentobox/bentobox/database/objects/Island.java
+++ b/src/main/java/world/bentobox/bentobox/database/objects/Island.java
@@ -16,9 +16,9 @@
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
+import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.World;
-import org.bukkit.GameMode;
import org.bukkit.World.Environment;
import org.bukkit.entity.Player;
import org.bukkit.util.BoundingBox;
@@ -728,10 +728,10 @@ public boolean inIslandSpace(int x, int z) {
@SuppressWarnings("ConstantConditions")
public boolean inIslandSpace(Location location) {
return Util.sameWorld(this.world, location.getWorld()) &&
- (location.getWorld().getEnvironment().equals(Environment.NORMAL) ||
- this.getPlugin().getIWM().isIslandNether(location.getWorld()) ||
- this.getPlugin().getIWM().isIslandEnd(location.getWorld())) &&
- this.inIslandSpace(location.getBlockX(), location.getBlockZ());
+ (location.getWorld().getEnvironment().equals(Environment.NORMAL) ||
+ this.getPlugin().getIWM().isIslandNether(location.getWorld()) ||
+ this.getPlugin().getIWM().isIslandEnd(location.getWorld())) &&
+ this.inIslandSpace(location.getBlockX(), location.getBlockZ());
}
/**
@@ -770,33 +770,33 @@ public BoundingBox getBoundingBox(Environment environment)
{
// Return normal world bounding box.
boundingBox = new BoundingBox(this.getMinX(),
- this.world.getMinHeight(),
- this.getMinZ(),
- this.getMaxX(),
- this.world.getMaxHeight(),
- this.getMaxZ());
+ this.world.getMinHeight(),
+ this.getMinZ(),
+ this.getMaxX(),
+ this.world.getMaxHeight(),
+ this.getMaxZ());
}
else if (Environment.THE_END.equals(environment) && this.isEndIslandEnabled())
{
// If end world is generated, return end island bounding box.
//noinspection ConstantConditions
boundingBox = new BoundingBox(this.getMinX(),
- this.getEndWorld().getMinHeight(),
- this.getMinZ(),
- this.getMaxX(),
- this.getEndWorld().getMaxHeight(),
- this.getMaxZ());
+ this.getEndWorld().getMinHeight(),
+ this.getMinZ(),
+ this.getMaxX(),
+ this.getEndWorld().getMaxHeight(),
+ this.getMaxZ());
}
else if (Environment.NETHER.equals(environment) && this.isNetherIslandEnabled())
{
// If nether world is generated, return nether island bounding box.
//noinspection ConstantConditions
boundingBox = new BoundingBox(this.getMinX(),
- this.getNetherWorld().getMinHeight(),
- this.getMinZ(),
- this.getMaxX(),
- this.getNetherWorld().getMaxHeight(),
- this.getMaxZ());
+ this.getNetherWorld().getMinHeight(),
+ this.getMinZ(),
+ this.getMaxX(),
+ this.getNetherWorld().getMaxHeight(),
+ this.getMaxZ());
}
else
{
@@ -913,13 +913,13 @@ public boolean isSpawn() {
@SuppressWarnings("ConstantConditions")
public boolean onIsland(@NonNull Location target) {
return Util.sameWorld(this.world, target.getWorld()) &&
- (target.getWorld().getEnvironment().equals(Environment.NORMAL) ||
- this.getPlugin().getIWM().isIslandNether(target.getWorld()) ||
- this.getPlugin().getIWM().isIslandEnd(target.getWorld())) &&
- target.getBlockX() >= this.getMinProtectedX() &&
- target.getBlockX() < (this.getMinProtectedX() + this.protectionRange * 2) &&
- target.getBlockZ() >= this.getMinProtectedZ() &&
- target.getBlockZ() < (this.getMinProtectedZ() + this.protectionRange * 2);
+ (target.getWorld().getEnvironment().equals(Environment.NORMAL) ||
+ this.getPlugin().getIWM().isIslandNether(target.getWorld()) ||
+ this.getPlugin().getIWM().isIslandEnd(target.getWorld())) &&
+ target.getBlockX() >= this.getMinProtectedX() &&
+ target.getBlockX() < (this.getMinProtectedX() + this.protectionRange * 2) &&
+ target.getBlockZ() >= this.getMinProtectedZ() &&
+ target.getBlockZ() < (this.getMinProtectedZ() + this.protectionRange * 2);
}
/**
@@ -950,33 +950,33 @@ public BoundingBox getProtectionBoundingBox(Environment environment)
{
// Return normal world bounding box.
boundingBox = new BoundingBox(this.getMinProtectedX(),
- this.world.getMinHeight(),
- this.getMinProtectedZ(),
- this.getMaxProtectedX(),
- this.world.getMaxHeight(),
- this.getMaxProtectedZ());
+ this.world.getMinHeight(),
+ this.getMinProtectedZ(),
+ this.getMaxProtectedX(),
+ this.world.getMaxHeight(),
+ this.getMaxProtectedZ());
}
else if (Environment.THE_END.equals(environment) && this.isEndIslandEnabled())
{
// If end world is generated, return end island bounding box.
//noinspection ConstantConditions
boundingBox = new BoundingBox(this.getMinProtectedX(),
- this.getEndWorld().getMinHeight(),
- this.getMinProtectedZ(),
- this.getMaxProtectedX(),
- this.getEndWorld().getMaxHeight(),
- this.getMaxProtectedZ());
+ this.getEndWorld().getMinHeight(),
+ this.getMinProtectedZ(),
+ this.getMaxProtectedX(),
+ this.getEndWorld().getMaxHeight(),
+ this.getMaxProtectedZ());
}
else if (Environment.NETHER.equals(environment) && this.isNetherIslandEnabled())
{
// If nether world is generated, return nether island bounding box.
//noinspection ConstantConditions
boundingBox = new BoundingBox(this.getMinProtectedX(),
- this.getNetherWorld().getMinHeight(),
- this.getMinProtectedZ(),
- this.getMaxProtectedX(),
- this.getNetherWorld().getMaxHeight(),
- this.getMaxProtectedZ());
+ this.getNetherWorld().getMinHeight(),
+ this.getMinProtectedZ(),
+ this.getMaxProtectedX(),
+ this.getNetherWorld().getMaxHeight(),
+ this.getMaxProtectedZ());
}
else
{
@@ -1057,11 +1057,11 @@ public void setFlagsDefaults() {
BentoBox plugin = BentoBox.getInstance();
Map result = new HashMap<>();
plugin.getFlagsManager().getFlags().stream().
- filter(f -> f.getType().equals(Flag.Type.PROTECTION)).
- forEach(f -> result.put(f.getID(), plugin.getIWM().getDefaultIslandFlags(world).getOrDefault(f, f.getDefaultRank())));
+ filter(f -> f.getType().equals(Flag.Type.PROTECTION)).
+ forEach(f -> result.put(f.getID(), plugin.getIWM().getDefaultIslandFlags(world).getOrDefault(f, f.getDefaultRank())));
plugin.getFlagsManager().getFlags().stream().
- filter(f -> f.getType().equals(Flag.Type.SETTING)).
- forEach(f -> result.put(f.getID(), plugin.getIWM().getDefaultIslandSettings(world).getOrDefault(f, f.getDefaultRank())));
+ filter(f -> f.getType().equals(Flag.Type.SETTING)).
+ forEach(f -> result.put(f.getID(), plugin.getIWM().getDefaultIslandSettings(world).getOrDefault(f, f.getDefaultRank())));
this.setFlags(result);
setChanged();
}
diff --git a/src/main/java/world/bentobox/bentobox/database/objects/adapters/FlagBooleanSerializer.java b/src/main/java/world/bentobox/bentobox/database/objects/adapters/FlagBooleanSerializer.java
index cb524268d..45efd1bcc 100644
--- a/src/main/java/world/bentobox/bentobox/database/objects/adapters/FlagBooleanSerializer.java
+++ b/src/main/java/world/bentobox/bentobox/database/objects/adapters/FlagBooleanSerializer.java
@@ -1,11 +1,12 @@
package world.bentobox.bentobox.database.objects.adapters;
-import org.bukkit.configuration.MemorySection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
+import org.bukkit.configuration.MemorySection;
+
/**
* This Serializer migrates Map of String, Boolean to Map of String, Integer in serialization process.
@@ -35,7 +36,7 @@ public Map deserialize(Object object)
{
for (Entry en : ((Map) object).entrySet())
{
- result.put(en.getKey(), en.getValue() ? 0 : -1);
+ result.put(en.getKey(), Boolean.TRUE.equals(en.getValue()) ? 0 : -1);
}
}
diff --git a/src/main/java/world/bentobox/bentobox/database/objects/adapters/FlagSerializer2.java b/src/main/java/world/bentobox/bentobox/database/objects/adapters/FlagSerializer2.java
index 0c43f6de7..4a2e963a1 100644
--- a/src/main/java/world/bentobox/bentobox/database/objects/adapters/FlagSerializer2.java
+++ b/src/main/java/world/bentobox/bentobox/database/objects/adapters/FlagSerializer2.java
@@ -29,7 +29,7 @@ public Map deserialize(Object object) {
}
} else {
for (Entry en : ((Map)object).entrySet()) {
- BentoBox.getInstance().getFlagsManager().getFlag(en.getKey()).ifPresent(flag -> result.put(flag, en.getValue() ? 0 : -1));
+ BentoBox.getInstance().getFlagsManager().getFlag(en.getKey()).ifPresent(flag -> result.put(flag, Boolean.TRUE.equals(en.getValue()) ? 0 : -1));
}
}
return result;
diff --git a/src/main/java/world/bentobox/bentobox/database/sql/SQLConfiguration.java b/src/main/java/world/bentobox/bentobox/database/sql/SQLConfiguration.java
index 373d4f04b..9f5b9cd8e 100644
--- a/src/main/java/world/bentobox/bentobox/database/sql/SQLConfiguration.java
+++ b/src/main/java/world/bentobox/bentobox/database/sql/SQLConfiguration.java
@@ -9,34 +9,44 @@
* @author tastybento
*
*/
-public class SQLConfiguration {
+public class SQLConfiguration
+{
private String loadObjectSQL;
+
private String saveObjectSQL;
+
private String deleteObjectSQL;
+
private String objectExistsSQL;
+
private String schemaSQL;
+
private String loadObjectsSQL;
+
private String renameTableSQL;
+
private final String tableName;
+
private final boolean renameRequired;
+
private final String oldTableName;
- public SQLConfiguration(BentoBox plugin, Class type) {
+
+ public SQLConfiguration(BentoBox plugin, Class type)
+ {
// Set the table name
- oldTableName = plugin.getSettings().getDatabasePrefix() + type.getCanonicalName();
+ this.oldTableName = plugin.getSettings().getDatabasePrefix() + type.getCanonicalName();
this.tableName = plugin.getSettings().getDatabasePrefix() +
- (type.getAnnotation(Table.class) == null ?
- type.getCanonicalName()
- : type.getAnnotation(Table.class).name());
+ (type.getAnnotation(Table.class) == null ? type.getCanonicalName() : type.getAnnotation(Table.class).name());
// Only rename if there is a specific Table annotation
- renameRequired = !tableName.equals(oldTableName);
- schema("CREATE TABLE IF NOT EXISTS `[tableName]` (json JSON, uniqueId VARCHAR(255) GENERATED ALWAYS AS (json->\"$.uniqueId\"), UNIQUE INDEX i (uniqueId) )");
- loadObjects("SELECT `json` FROM `[tableName]`");
- loadObject("SELECT `json` FROM `[tableName]` WHERE uniqueId = ? LIMIT 1");
- saveObject("INSERT INTO `[tableName]` (json) VALUES (?) ON DUPLICATE KEY UPDATE json = ?");
- deleteObject("DELETE FROM `[tableName]` WHERE uniqueId = ?");
- objectExists("SELECT IF ( EXISTS( SELECT * FROM `[tableName]` WHERE `uniqueId` = ?), 1, 0)");
- renameTable("SELECT Count(*) INTO @exists " +
+ this.renameRequired = !this.tableName.equals(this.oldTableName);
+ this.schema("CREATE TABLE IF NOT EXISTS `[tableName]` (json JSON, uniqueId VARCHAR(255) GENERATED ALWAYS AS (json->\"$.uniqueId\"), UNIQUE INDEX i (uniqueId) )");
+ this.loadObjects("SELECT `json` FROM `[tableName]`");
+ this.loadObject("SELECT `json` FROM `[tableName]` WHERE uniqueId = ? LIMIT 1");
+ this.saveObject("INSERT INTO `[tableName]` (json) VALUES (?) ON DUPLICATE KEY UPDATE json = ?");
+ this.deleteObject("DELETE FROM `[tableName]` WHERE uniqueId = ?");
+ this.objectExists("SELECT IF ( EXISTS( SELECT * FROM `[tableName]` WHERE `uniqueId` = ?), 1, 0)");
+ this.renameTable("SELECT Count(*) INTO @exists " +
"FROM information_schema.tables " +
"WHERE table_schema = '" + plugin.getSettings().getDatabaseName() + "' " +
"AND table_type = 'BASE TABLE' " +
@@ -46,48 +56,66 @@ public SQLConfiguration(BentoBox plugin, Class type) {
"EXECUTE stmt;");
}
- private final String TABLE_NAME = "\\[tableName]";
+
+ private static final String TABLE_NAME = "\\[tableName]";
+
/**
* By default, use quotes around the unique ID in the SQL statement
*/
private boolean useQuotes = true;
- public SQLConfiguration loadObject(String string) {
+
+ public SQLConfiguration loadObject(String string)
+ {
this.loadObjectSQL = string.replaceFirst(TABLE_NAME, tableName);
return this;
}
- public SQLConfiguration saveObject(String string) {
+
+ public SQLConfiguration saveObject(String string)
+ {
this.saveObjectSQL = string.replaceFirst(TABLE_NAME, tableName);
return this;
}
- public SQLConfiguration deleteObject(String string) {
+
+ public SQLConfiguration deleteObject(String string)
+ {
this.deleteObjectSQL = string.replaceFirst(TABLE_NAME, tableName);
return this;
}
- public SQLConfiguration objectExists(String string) {
+
+ public SQLConfiguration objectExists(String string)
+ {
this.objectExistsSQL = string.replaceFirst(TABLE_NAME, tableName);
return this;
}
- public SQLConfiguration schema(String string) {
+
+ public SQLConfiguration schema(String string)
+ {
this.schemaSQL = string.replaceFirst(TABLE_NAME, tableName);
return this;
}
- public SQLConfiguration loadObjects(String string) {
+
+ public SQLConfiguration loadObjects(String string)
+ {
this.loadObjectsSQL = string.replaceFirst(TABLE_NAME, tableName);
return this;
}
- public SQLConfiguration renameTable(String string) {
+
+ public SQLConfiguration renameTable(String string)
+ {
this.renameTableSQL = string.replace(TABLE_NAME, tableName).replace("\\[oldTableName\\]", oldTableName);
return this;
}
- public SQLConfiguration setUseQuotes(boolean b) {
+
+ public SQLConfiguration setUseQuotes(boolean b)
+ {
this.useQuotes = b;
return this;
}
@@ -96,71 +124,95 @@ public SQLConfiguration setUseQuotes(boolean b) {
/**
* @return the loadObjectSQL
*/
- public String getLoadObjectSQL() {
+ public String getLoadObjectSQL()
+ {
return loadObjectSQL;
}
+
+
/**
* @return the saveObjectSQL
*/
- public String getSaveObjectSQL() {
+ public String getSaveObjectSQL()
+ {
return saveObjectSQL;
}
+
+
/**
* @return the deleteObjectSQL
*/
- public String getDeleteObjectSQL() {
+ public String getDeleteObjectSQL()
+ {
return deleteObjectSQL;
}
+
+
/**
* @return the objectExistsSQL
*/
- public String getObjectExistsSQL() {
+ public String getObjectExistsSQL()
+ {
return objectExistsSQL;
}
+
+
/**
* @return the schemaSQL
*/
- public String getSchemaSQL() {
+ public String getSchemaSQL()
+ {
return schemaSQL;
}
+
+
/**
* @return the loadItSQL
*/
- public String getLoadObjectsSQL() {
+ public String getLoadObjectsSQL()
+ {
return loadObjectsSQL;
}
+
/**
* @return the renameTableSQL
*/
- public String getRenameTableSQL() {
+ public String getRenameTableSQL()
+ {
return renameTableSQL;
}
+
/**
* @return the tableName
*/
- public String getTableName() {
+ public String getTableName()
+ {
return tableName;
}
+
/**
* @return the oldName
*/
- public String getOldTableName() {
+ public String getOldTableName()
+ {
return oldTableName;
}
- public boolean renameRequired() {
+
+ public boolean renameRequired()
+ {
return renameRequired;
}
+
/**
* @return the useQuotes
*/
- public boolean isUseQuotes() {
+ public boolean isUseQuotes()
+ {
return useQuotes;
}
-
-
}
diff --git a/src/main/java/world/bentobox/bentobox/database/sql/SQLDatabaseConnector.java b/src/main/java/world/bentobox/bentobox/database/sql/SQLDatabaseConnector.java
index 3770062fc..1a246ff4b 100644
--- a/src/main/java/world/bentobox/bentobox/database/sql/SQLDatabaseConnector.java
+++ b/src/main/java/world/bentobox/bentobox/database/sql/SQLDatabaseConnector.java
@@ -1,7 +1,6 @@
package world.bentobox.bentobox.database.sql;
import java.sql.Connection;
-import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;
@@ -9,64 +8,136 @@
import org.bukkit.Bukkit;
import org.eclipse.jdt.annotation.NonNull;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+
import world.bentobox.bentobox.database.DatabaseConnectionSettingsImpl;
import world.bentobox.bentobox.database.DatabaseConnector;
-public abstract class SQLDatabaseConnector implements DatabaseConnector {
+/**
+ * Generic SQL database connector.
+ */
+public abstract class SQLDatabaseConnector implements DatabaseConnector
+{
+ /**
+ * The connection url string for the sql database.
+ */
protected String connectionUrl;
- private final DatabaseConnectionSettingsImpl dbSettings;
- protected static Connection connection = null;
+
+ /**
+ * The database connection settings.
+ */
+ protected final DatabaseConnectionSettingsImpl dbSettings;
+
+ /**
+ * Hikari Data Source that creates all connections.
+ */
+ protected static HikariDataSource dataSource;
+
+ /**
+ * Type of objects stored in database.
+ */
protected static Set> types = new HashSet<>();
- protected SQLDatabaseConnector(DatabaseConnectionSettingsImpl dbSettings, String connectionUrl) {
+
+ /**
+ * Default connector constructor.
+ * @param dbSettings Settings of the database.
+ * @param connectionUrl Connection url for the database.
+ */
+ protected SQLDatabaseConnector(DatabaseConnectionSettingsImpl dbSettings, String connectionUrl)
+ {
this.dbSettings = dbSettings;
this.connectionUrl = connectionUrl;
}
+
+ /**
+ * Returns connection url of database.
+ * @return Database connection url.
+ */
@Override
- public String getConnectionUrl() {
+ public String getConnectionUrl()
+ {
return connectionUrl;
}
+
+ /**
+ * {@inheritDoc}
+ */
@Override
@NonNull
- public String getUniqueId(String tableName) {
+ public String getUniqueId(String tableName)
+ {
// Not used
return "";
}
+
+ /**
+ * {@inheritDoc}
+ */
@Override
- public boolean uniqueIdExists(String tableName, String key) {
+ public boolean uniqueIdExists(String tableName, String key)
+ {
// Not used
return false;
}
+
+ /**
+ * {@inheritDoc}
+ */
@Override
- public void closeConnection(Class> type) {
+ public void closeConnection(Class> type)
+ {
types.remove(type);
- if (types.isEmpty() && connection != null) {
- try {
- connection.close();
- Bukkit.getLogger().info("Closed database connection");
- } catch (SQLException e) {
- Bukkit.getLogger().severe("Could not close database connection");
- }
+
+ if (types.isEmpty())
+ {
+ dataSource.close();
+ Bukkit.getLogger().info("Closed database connection");
}
}
+
+ /**
+ * This method creates config that is used to create HikariDataSource.
+ * @return HikariConfig object.
+ */
+ public abstract HikariConfig createConfig();
+
+
+ /**
+ * {@inheritDoc}
+ */
@Override
- public Object createConnection(Class> type) {
+ public Object createConnection(Class> type)
+ {
types.add(type);
+
// Only make one connection to the database
- if (connection == null) {
- try {
- connection = DriverManager.getConnection(connectionUrl, dbSettings.getUsername(), dbSettings.getPassword());
- } catch (SQLException e) {
+ if (dataSource == null)
+ {
+ try
+ {
+ dataSource = new HikariDataSource(this.createConfig());
+
+ // Test connection
+ try (Connection connection = dataSource.getConnection())
+ {
+ connection.isValid(5 * 1000);
+ }
+ }
+ catch (SQLException e)
+ {
Bukkit.getLogger().severe("Could not connect to the database! " + e.getMessage());
+ dataSource = null;
}
}
- return connection;
- }
-}
+ return dataSource;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/world/bentobox/bentobox/database/sql/SQLDatabaseHandler.java b/src/main/java/world/bentobox/bentobox/database/sql/SQLDatabaseHandler.java
index 6329de85b..961606b1e 100644
--- a/src/main/java/world/bentobox/bentobox/database/sql/SQLDatabaseHandler.java
+++ b/src/main/java/world/bentobox/bentobox/database/sql/SQLDatabaseHandler.java
@@ -11,6 +11,8 @@
import java.util.List;
import java.util.concurrent.CompletableFuture;
+import javax.sql.DataSource;
+
import org.bukkit.Bukkit;
import org.eclipse.jdt.annotation.NonNull;
@@ -31,246 +33,413 @@
*
* @param
*/
-public class SQLDatabaseHandler extends AbstractJSONDatabaseHandler {
-
+public class SQLDatabaseHandler extends AbstractJSONDatabaseHandler
+{
protected static final String COULD_NOT_LOAD_OBJECTS = "Could not load objects ";
protected static final String COULD_NOT_LOAD_OBJECT = "Could not load object ";
/**
- * Connection to the database
+ * DataSource of database
*/
- private Connection connection;
+ protected DataSource dataSource;
/**
* SQL configuration
*/
private SQLConfiguration sqlConfig;
+
/**
* Handles the connection to the database and creation of the initial database schema (tables) for
* the class that will be stored.
* @param plugin - plugin object
* @param type - the type of class to be stored in the database. Must inherit DataObject
- * @param dbConnecter - authentication details for the database
+ * @param databaseConnector - authentication details for the database
* @param sqlConfiguration - SQL configuration
*/
- protected SQLDatabaseHandler(BentoBox plugin, Class type, DatabaseConnector dbConnecter, SQLConfiguration sqlConfiguration) {
- super(plugin, type, dbConnecter);
+ protected SQLDatabaseHandler(BentoBox plugin, Class type, DatabaseConnector databaseConnector, SQLConfiguration sqlConfiguration)
+ {
+ super(plugin, type, databaseConnector);
this.sqlConfig = sqlConfiguration;
- if (setConnection((Connection)databaseConnector.createConnection(type))) {
+
+ if (this.setDataSource((DataSource) this.databaseConnector.createConnection(type)))
+ {
// Check if the table exists in the database and if not, create it
- createSchema();
+ this.createSchema();
}
}
+
/**
* @return the sqlConfig
*/
- public SQLConfiguration getSqlConfig() {
+ public SQLConfiguration getSqlConfig()
+ {
return sqlConfig;
}
+
/**
* @param sqlConfig the sqlConfig to set
*/
- public void setSqlConfig(SQLConfiguration sqlConfig) {
+ public void setSqlConfig(SQLConfiguration sqlConfig)
+ {
this.sqlConfig = sqlConfig;
}
+
/**
* Creates the table in the database if it doesn't exist already
*/
- protected void createSchema() {
- if (sqlConfig.renameRequired()) {
+ protected void createSchema()
+ {
+ if (this.sqlConfig.renameRequired())
+ {
// Transition from the old table name
- String sql = sqlConfig.getRenameTableSQL().replace("[oldTableName]", sqlConfig.getOldTableName()).replace("[tableName]", sqlConfig.getTableName());
- try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
- pstmt.execute();
- } catch (SQLException e) {
- plugin.logError("Could not rename " + sqlConfig.getOldTableName() + " for data object " + dataObject.getCanonicalName() + " " + e.getMessage());
+ String sql = this.sqlConfig.getRenameTableSQL().
+ replace("[oldTableName]", this.sqlConfig.getOldTableName()).
+ replace("[tableName]", this.sqlConfig.getTableName());
+
+ try (Connection connection = this.dataSource.getConnection();
+ PreparedStatement preparedStatement = connection.prepareStatement(sql))
+ {
+ preparedStatement.execute();
+ }
+ catch (SQLException e)
+ {
+ this.plugin.logError("Could not rename " + this.sqlConfig.getOldTableName() + " for data object " +
+ this.dataObject.getCanonicalName() + " " + e.getMessage());
}
}
+
// Prepare and execute the database statements
- try (PreparedStatement pstmt = connection.prepareStatement(sqlConfig.getSchemaSQL())) {
- pstmt.execute();
- } catch (SQLException e) {
- plugin.logError("Problem trying to create schema for data object " + dataObject.getCanonicalName() + " " + e.getMessage());
+ try (Connection connection = this.dataSource.getConnection();
+ PreparedStatement preparedStatement = connection.prepareStatement(this.sqlConfig.getSchemaSQL()))
+ {
+ preparedStatement.execute();
+ }
+ catch (SQLException e)
+ {
+ this.plugin.logError("Problem trying to create schema for data object " +
+ this.dataObject.getCanonicalName() + " " + e.getMessage());
}
}
+
+ /**
+ * {@inheritDoc}
+ */
@Override
- public List loadObjects() {
- try (Statement preparedStatement = connection.createStatement()) {
- return loadIt(preparedStatement);
- } catch (SQLException e) {
- plugin.logError(COULD_NOT_LOAD_OBJECTS + e.getMessage());
+ public List loadObjects()
+ {
+ try (Connection connection = this.dataSource.getConnection();
+ Statement preparedStatement = connection.createStatement())
+ {
+ return this.loadIt(preparedStatement);
+ }
+ catch (SQLException e)
+ {
+ this.plugin.logError(COULD_NOT_LOAD_OBJECTS + e.getMessage());
}
+
return Collections.emptyList();
}
- private List loadIt(Statement preparedStatement) {
+
+ /**
+ * This method loads objects based on results provided by prepared statement.
+ * @param preparedStatement Statement from database.
+ * @return List of object from database.
+ */
+ private List loadIt(Statement preparedStatement)
+ {
List list = new ArrayList<>();
- try (ResultSet resultSet = preparedStatement.executeQuery(sqlConfig.getLoadObjectsSQL())) {
+
+ try (ResultSet resultSet = preparedStatement.executeQuery(this.sqlConfig.getLoadObjectsSQL()))
+ {
// Load all the results
- Gson gson = getGson();
- while (resultSet.next()) {
+ Gson gson = this.getGson();
+
+ while (resultSet.next())
+ {
String json = resultSet.getString("json");
- if (json != null) {
- try {
- T gsonResult = gson.fromJson(json, dataObject);
- if (gsonResult != null) {
- list.add(gsonResult);
- }
- } catch (JsonSyntaxException ex) {
- plugin.logError(COULD_NOT_LOAD_OBJECT + ex.getMessage());
- plugin.logError(json);
- }
+
+ if (json != null)
+ {
+ getGsonResultSet(gson, json, list);
}
}
- } catch (Exception e) {
- plugin.logError(COULD_NOT_LOAD_OBJECTS + e.getMessage());
}
+ catch (Exception e)
+ {
+ this.plugin.logError(COULD_NOT_LOAD_OBJECTS + e.getMessage());
+ }
+
return list;
}
+
+ private void getGsonResultSet(Gson gson, String json, List list) {
+ try
+ {
+ T gsonResult = gson.fromJson(json, this.dataObject);
+
+ if (gsonResult != null)
+ {
+ list.add(gsonResult);
+ }
+ }
+ catch (JsonSyntaxException ex)
+ {
+ this.plugin.logError(COULD_NOT_LOAD_OBJECT + ex.getMessage());
+ this.plugin.logError(json);
+ }
+
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
@Override
- public T loadObject(@NonNull String uniqueId) {
- try (PreparedStatement preparedStatement = connection.prepareStatement(sqlConfig.getLoadObjectSQL())) {
+ public T loadObject(@NonNull String uniqueId)
+ {
+ T result = null;
+ try (Connection connection = this.dataSource.getConnection();
+ PreparedStatement preparedStatement = connection.prepareStatement(this.sqlConfig.getLoadObjectSQL()))
+ {
// UniqueId needs to be placed in quotes?
preparedStatement.setString(1, this.sqlConfig.isUseQuotes() ? "\"" + uniqueId + "\"" : uniqueId);
- try (ResultSet resultSet = preparedStatement.executeQuery()) {
- if (resultSet.next()) {
- // If there is a result, we only want/need the first one
- Gson gson = getGson();
- return gson.fromJson(resultSet.getString("json"), dataObject);
- }
- } catch (Exception e) {
- plugin.logError(COULD_NOT_LOAD_OBJECT + uniqueId + " " + e.getMessage());
+ result = getObject(uniqueId, preparedStatement);
+ }
+ catch (SQLException e)
+ {
+ this.plugin.logError(COULD_NOT_LOAD_OBJECT + uniqueId + " " + e.getMessage());
+ }
+
+ return result;
+ }
+
+
+ /**
+ * Return the object decoded from JSON or null if there is an error
+ * @param uniqueId - unique Id of object used in error reporting
+ * @param preparedStatement - database statement to execute
+ * @return
+ */
+ private T getObject(@NonNull String uniqueId, PreparedStatement preparedStatement) {
+ try (ResultSet resultSet = preparedStatement.executeQuery())
+ {
+ if (resultSet.next())
+ {
+ // If there is a result, we only want/need the first one
+ Gson gson = this.getGson();
+ return gson.fromJson(resultSet.getString("json"), this.dataObject);
}
- } catch (SQLException e) {
- plugin.logError(COULD_NOT_LOAD_OBJECT + uniqueId + " " + e.getMessage());
+ }
+ catch (Exception e)
+ {
+ this.plugin.logError(COULD_NOT_LOAD_OBJECT + uniqueId + " " + e.getMessage());
}
return null;
}
+
+ /**
+ * {@inheritDoc}
+ */
@Override
- public CompletableFuture saveObject(T instance) {
+ public CompletableFuture saveObject(T instance)
+ {
CompletableFuture completableFuture = new CompletableFuture<>();
+
// Null check
- if (instance == null) {
- plugin.logError("SQL database request to store a null. ");
+ if (instance == null)
+ {
+ this.plugin.logError("SQL database request to store a null. ");
completableFuture.complete(false);
return completableFuture;
}
- if (!(instance instanceof DataObject)) {
- plugin.logError("This class is not a DataObject: " + instance.getClass().getName());
+
+ if (!(instance instanceof DataObject))
+ {
+ this.plugin.logError("This class is not a DataObject: " + instance.getClass().getName());
completableFuture.complete(false);
return completableFuture;
}
+
// This has to be on the main thread to avoid concurrent modification errors
- String toStore = getGson().toJson(instance);
- if (plugin.isEnabled()) {
+ String toStore = this.getGson().toJson(instance);
+
+ if (this.plugin.isEnabled())
+ {
// Async
- processQueue.add(() -> store(completableFuture, instance.getClass().getName(), toStore, sqlConfig.getSaveObjectSQL(), true));
- } else {
+ this.processQueue.add(() -> store(completableFuture,
+ instance.getClass().getName(),
+ toStore,
+ this.sqlConfig.getSaveObjectSQL(),
+ true));
+ }
+ else
+ {
// Sync
- store(completableFuture, instance.getClass().getName(), toStore, sqlConfig.getSaveObjectSQL(), false);
+ this.store(completableFuture, instance.getClass().getName(), toStore, this.sqlConfig.getSaveObjectSQL(), false);
}
+
return completableFuture;
}
- private void store(CompletableFuture completableFuture, String name, String toStore, String sb, boolean async) {
+
+ /**
+ * This method is called to save data into database based on given parameters.
+ * @param completableFuture Failsafe on saving data.
+ * @param name Name of the class that is saved.
+ * @param toStore data that is stored.
+ * @param storeSQL SQL command for saving.
+ * @param async boolean that indicates if saving is async or not.
+ */
+ private void store(CompletableFuture completableFuture, String name, String toStore, String storeSQL, boolean async)
+ {
// Do not save anything if plug is disabled and this was an async request
- if (async && !plugin.isEnabled()) return;
- try (PreparedStatement preparedStatement = connection.prepareStatement(sb)) {
+ if (async && !this.plugin.isEnabled())
+ {
+ return;
+ }
+
+ try (Connection connection = this.dataSource.getConnection();
+ PreparedStatement preparedStatement = connection.prepareStatement(storeSQL))
+ {
preparedStatement.setString(1, toStore);
preparedStatement.setString(2, toStore);
preparedStatement.execute();
completableFuture.complete(true);
- } catch (SQLException e) {
- plugin.logError("Could not save object " + name + " " + e.getMessage());
+ }
+ catch (SQLException e)
+ {
+ this.plugin.logError("Could not save object " + name + " " + e.getMessage());
completableFuture.complete(false);
}
}
- /* (non-Javadoc)
- * @see world.bentobox.bentobox.database.AbstractDatabaseHandler#deleteID(java.lang.String)
+
+ /**
+ * {@inheritDoc}
*/
@Override
- public void deleteID(String uniqueId) {
- processQueue.add(() -> delete(uniqueId));
+ public void deleteID(String uniqueId)
+ {
+ this.processQueue.add(() -> this.delete(uniqueId));
}
- private void delete(String uniqueId) {
- try (PreparedStatement preparedStatement = connection.prepareStatement(sqlConfig.getDeleteObjectSQL())) {
+
+ /**
+ * This method triggers object deletion from the database.
+ * @param uniqueId Object unique id.
+ */
+ private void delete(String uniqueId)
+ {
+ try (Connection connection = this.dataSource.getConnection();
+ PreparedStatement preparedStatement = connection.prepareStatement(this.sqlConfig.getDeleteObjectSQL()))
+ {
// UniqueId needs to be placed in quotes?
preparedStatement.setString(1, this.sqlConfig.isUseQuotes() ? "\"" + uniqueId + "\"" : uniqueId);
preparedStatement.execute();
- } catch (Exception e) {
- plugin.logError("Could not delete object " + plugin.getSettings().getDatabasePrefix() + dataObject.getCanonicalName() + " " + uniqueId + " " + e.getMessage());
+ }
+ catch (Exception e)
+ {
+ this.plugin.logError("Could not delete object " + this.plugin.getSettings().getDatabasePrefix() +
+ this.dataObject.getCanonicalName() + " " + uniqueId + " " + e.getMessage());
}
}
+
+ /**
+ * {@inheritDoc}
+ */
@Override
- public void deleteObject(T instance) {
+ public void deleteObject(T instance)
+ {
// Null check
- if (instance == null) {
- plugin.logError("SQL database request to delete a null.");
+ if (instance == null)
+ {
+ this.plugin.logError("SQL database request to delete a null.");
return;
}
- if (!(instance instanceof DataObject)) {
- plugin.logError("This class is not a DataObject: " + instance.getClass().getName());
+
+ if (!(instance instanceof DataObject))
+ {
+ this.plugin.logError("This class is not a DataObject: " + instance.getClass().getName());
return;
}
- try {
- Method getUniqueId = dataObject.getMethod("getUniqueId");
- deleteID((String) getUniqueId.invoke(instance));
- } catch (Exception e) {
- plugin.logError("Could not delete object " + instance.getClass().getName() + " " + e.getMessage());
+
+ try
+ {
+ Method getUniqueId = this.dataObject.getMethod("getUniqueId");
+ this.deleteID((String) getUniqueId.invoke(instance));
+ }
+ catch (Exception e)
+ {
+ this.plugin.logError("Could not delete object " + instance.getClass().getName() + " " + e.getMessage());
}
}
+
+ /**
+ * {@inheritDoc}
+ */
@Override
- public boolean objectExists(String uniqueId) {
+ public boolean objectExists(String uniqueId)
+ {
// Query to see if this key exists
- try (PreparedStatement preparedStatement = connection.prepareStatement(sqlConfig.getObjectExistsSQL())) {
+ try (Connection connection = this.dataSource.getConnection();
+ PreparedStatement preparedStatement = connection.prepareStatement(this.sqlConfig.getObjectExistsSQL()))
+ {
// UniqueId needs to be placed in quotes?
preparedStatement.setString(1, this.sqlConfig.isUseQuotes() ? "\"" + uniqueId + "\"" : uniqueId);
- try (ResultSet resultSet = preparedStatement.executeQuery()) {
- if (resultSet.next()) {
+
+ try (ResultSet resultSet = preparedStatement.executeQuery())
+ {
+ if (resultSet.next())
+ {
return resultSet.getBoolean(1);
}
}
- } catch (SQLException e) {
- plugin.logError("Could not check if key exists in database! " + uniqueId + " " + e.getMessage());
}
+ catch (SQLException e)
+ {
+ this.plugin.logError("Could not check if key exists in database! " + uniqueId + " " + e.getMessage());
+ }
+
return false;
}
- @Override
- public void close() {
- shutdown = true;
- }
/**
- * @return the connection
+ * {@inheritDoc}
*/
- public Connection getConnection() {
- return connection;
+ @Override
+ public void close()
+ {
+ this.shutdown = true;
}
+
/**
- * @param connection the connection to set
- * @return true if connection is not null
+ * Sets data source of database.
+ *
+ * @param dataSource the data source
+ * @return {@code true} if data source is set, {@code false} otherwise.
*/
- public boolean setConnection(Connection connection) {
- if (connection == null) {
- plugin.logError("Could not connect to the database. Are the credentials in the config.yml file correct?");
- plugin.logWarning("Disabling the plugin...");
- Bukkit.getPluginManager().disablePlugin(plugin);
+ public boolean setDataSource(DataSource dataSource)
+ {
+ if (dataSource == null)
+ {
+ this.plugin.logError("Could not connect to the database. Are the credentials in the config.yml file correct?");
+ this.plugin.logWarning("Disabling the plugin...");
+ Bukkit.getPluginManager().disablePlugin(this.plugin);
return false;
}
- this.connection = connection;
+ this.dataSource = dataSource;
return true;
}
}
diff --git a/src/main/java/world/bentobox/bentobox/database/sql/mariadb/MariaDBDatabase.java b/src/main/java/world/bentobox/bentobox/database/sql/mariadb/MariaDBDatabase.java
index ebc44328d..bd2a41832 100644
--- a/src/main/java/world/bentobox/bentobox/database/sql/mariadb/MariaDBDatabase.java
+++ b/src/main/java/world/bentobox/bentobox/database/sql/mariadb/MariaDBDatabase.java
@@ -9,26 +9,34 @@
* @author barpec12
* @since 1.1
*/
-public class MariaDBDatabase implements DatabaseSetup {
+public class MariaDBDatabase implements DatabaseSetup
+{
+ /**
+ * MariaDB Database Connector.
+ */
private MariaDBDatabaseConnector connector;
- /* (non-Javadoc)
- * @see world.bentobox.bentobox.database.DatabaseSetup#getHandler(java.lang.Class)
+
+ /**
+ * {@inheritDoc}
*/
@Override
- public AbstractDatabaseHandler getHandler(Class type) {
+ public AbstractDatabaseHandler getHandler(Class type)
+ {
BentoBox plugin = BentoBox.getInstance();
- if (connector == null) {
- connector = new MariaDBDatabaseConnector(new DatabaseConnectionSettingsImpl(
+
+ if (this.connector == null)
+ {
+ this.connector = new MariaDBDatabaseConnector(new DatabaseConnectionSettingsImpl(
plugin.getSettings().getDatabaseHost(),
plugin.getSettings().getDatabasePort(),
plugin.getSettings().getDatabaseName(),
plugin.getSettings().getDatabaseUsername(),
plugin.getSettings().getDatabasePassword(),
- plugin.getSettings().isUseSSL()
- ));
+ plugin.getSettings().isUseSSL(),
+ plugin.getSettings().getMaximumPoolSize()));
}
- return new MariaDBDatabaseHandler<>(plugin, type, connector);
- }
+ return new MariaDBDatabaseHandler<>(plugin, type, this.connector);
+ }
}
diff --git a/src/main/java/world/bentobox/bentobox/database/sql/mariadb/MariaDBDatabaseConnector.java b/src/main/java/world/bentobox/bentobox/database/sql/mariadb/MariaDBDatabaseConnector.java
index 628b2226d..d6882b966 100644
--- a/src/main/java/world/bentobox/bentobox/database/sql/mariadb/MariaDBDatabaseConnector.java
+++ b/src/main/java/world/bentobox/bentobox/database/sql/mariadb/MariaDBDatabaseConnector.java
@@ -1,5 +1,9 @@
package world.bentobox.bentobox.database.sql.mariadb;
+import org.eclipse.jdt.annotation.NonNull;
+
+import com.zaxxer.hikari.HikariConfig;
+
import world.bentobox.bentobox.database.DatabaseConnectionSettingsImpl;
import world.bentobox.bentobox.database.sql.SQLDatabaseConnector;
@@ -7,15 +11,45 @@
* @author barpec12
* @since 1.1
*/
-public class MariaDBDatabaseConnector extends SQLDatabaseConnector {
-
+public class MariaDBDatabaseConnector extends SQLDatabaseConnector
+{
/**
* Class for MariaDB database connections using the settings provided
* @param dbSettings - database settings
*/
- MariaDBDatabaseConnector(DatabaseConnectionSettingsImpl dbSettings) {
- super(dbSettings, "jdbc:mysql://" + dbSettings.getHost() + ":" + dbSettings.getPort() + "/" + dbSettings.getDatabaseName()
- + "?autoReconnect=true&useSSL=" + dbSettings.isUseSSL() + "&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8");
+ MariaDBDatabaseConnector(@NonNull DatabaseConnectionSettingsImpl dbSettings)
+ {
+ // MariaDB does not use connectionUrl.
+ super(dbSettings, String.format("jdbc:mariadb://%s:%s/%s",
+ dbSettings.getHost(),
+ dbSettings.getPort(),
+ dbSettings.getDatabaseName()));
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public HikariConfig createConfig()
+ {
+ HikariConfig config = new HikariConfig();
+
+ config.setPoolName("BentoBox MariaDB Pool");
+ config.setDriverClassName("org.mariadb.jdbc.Driver");
+
+ config.setJdbcUrl(this.connectionUrl);
+ config.addDataSourceProperty("user", this.dbSettings.getUsername());
+ config.addDataSourceProperty("password", this.dbSettings.getPassword());
+
+ config.addDataSourceProperty("useSsl", this.dbSettings.isUseSSL());
+ config.addDataSourceProperty("allowMultiQueries", "true");
+
+ // Add extra properties.
+ this.dbSettings.getExtraProperties().forEach(config::addDataSourceProperty);
+
+ config.setMaximumPoolSize(this.dbSettings.getMaxConnections());
+
+ return config;
+ }
}
diff --git a/src/main/java/world/bentobox/bentobox/database/sql/mariadb/MariaDBDatabaseHandler.java b/src/main/java/world/bentobox/bentobox/database/sql/mariadb/MariaDBDatabaseHandler.java
index 78af08951..732a48531 100644
--- a/src/main/java/world/bentobox/bentobox/database/sql/mariadb/MariaDBDatabaseHandler.java
+++ b/src/main/java/world/bentobox/bentobox/database/sql/mariadb/MariaDBDatabaseHandler.java
@@ -13,8 +13,8 @@
*
* @param
*/
-public class MariaDBDatabaseHandler extends SQLDatabaseHandler {
-
+public class MariaDBDatabaseHandler extends SQLDatabaseHandler
+{
/**
* Handles the connection to the database and creation of the initial database schema (tables) for
* the class that will be stored.
@@ -22,9 +22,11 @@ public class MariaDBDatabaseHandler extends SQLDatabaseHandler {
* @param type - the type of class to be stored in the database. Must inherit DataObject
* @param databaseConnector - authentication details for the database
*/
- MariaDBDatabaseHandler(BentoBox plugin, Class type, DatabaseConnector databaseConnector) {
- super(plugin, type, databaseConnector,
- new SQLConfiguration(plugin, type)
- .schema("CREATE TABLE IF NOT EXISTS `[tableName]` (json JSON, uniqueId VARCHAR(255) GENERATED ALWAYS AS (JSON_EXTRACT(json, \"$.uniqueId\")), UNIQUE INDEX i (uniqueId))"));
+ MariaDBDatabaseHandler(BentoBox plugin, Class type, DatabaseConnector databaseConnector)
+ {
+ super(plugin,
+ type,
+ databaseConnector,
+ new SQLConfiguration(plugin, type).schema("CREATE TABLE IF NOT EXISTS `[tableName]` (json JSON, uniqueId VARCHAR(255) GENERATED ALWAYS AS (JSON_EXTRACT(json, \"$.uniqueId\")), UNIQUE INDEX i (uniqueId))"));
}
}
diff --git a/src/main/java/world/bentobox/bentobox/database/sql/mysql/MySQLDatabase.java b/src/main/java/world/bentobox/bentobox/database/sql/mysql/MySQLDatabase.java
index 72ec49530..d65c9a39a 100644
--- a/src/main/java/world/bentobox/bentobox/database/sql/mysql/MySQLDatabase.java
+++ b/src/main/java/world/bentobox/bentobox/database/sql/mysql/MySQLDatabase.java
@@ -5,27 +5,34 @@
import world.bentobox.bentobox.database.DatabaseConnectionSettingsImpl;
import world.bentobox.bentobox.database.DatabaseSetup;
-public class MySQLDatabase implements DatabaseSetup {
-
+public class MySQLDatabase implements DatabaseSetup
+{
+ /**
+ * MySQL Database Connector
+ */
private MySQLDatabaseConnector connector;
- /* (non-Javadoc)
- * @see world.bentobox.bentobox.database.DatabaseSetup#getHandler(java.lang.Class)
+
+ /**
+ * {@inheritDoc}
*/
@Override
- public AbstractDatabaseHandler getHandler(Class type) {
+ public AbstractDatabaseHandler getHandler(Class type)
+ {
BentoBox plugin = BentoBox.getInstance();
- if (connector == null) {
- connector = new MySQLDatabaseConnector(new DatabaseConnectionSettingsImpl(
+
+ if (this.connector == null)
+ {
+ this.connector = new MySQLDatabaseConnector(new DatabaseConnectionSettingsImpl(
plugin.getSettings().getDatabaseHost(),
plugin.getSettings().getDatabasePort(),
plugin.getSettings().getDatabaseName(),
plugin.getSettings().getDatabaseUsername(),
plugin.getSettings().getDatabasePassword(),
- plugin.getSettings().isUseSSL()
- ));
+ plugin.getSettings().isUseSSL(),
+ plugin.getSettings().getMaximumPoolSize()));
}
- return new MySQLDatabaseHandler<>(plugin, type, connector);
- }
+ return new MySQLDatabaseHandler<>(plugin, type, this.connector);
+ }
}
diff --git a/src/main/java/world/bentobox/bentobox/database/sql/mysql/MySQLDatabaseConnector.java b/src/main/java/world/bentobox/bentobox/database/sql/mysql/MySQLDatabaseConnector.java
index 3fecde45e..f50c66b44 100644
--- a/src/main/java/world/bentobox/bentobox/database/sql/mysql/MySQLDatabaseConnector.java
+++ b/src/main/java/world/bentobox/bentobox/database/sql/mysql/MySQLDatabaseConnector.java
@@ -1,16 +1,56 @@
package world.bentobox.bentobox.database.sql.mysql;
+import org.eclipse.jdt.annotation.NonNull;
+
+import com.zaxxer.hikari.HikariConfig;
+
import world.bentobox.bentobox.database.DatabaseConnectionSettingsImpl;
import world.bentobox.bentobox.database.sql.SQLDatabaseConnector;
-public class MySQLDatabaseConnector extends SQLDatabaseConnector {
-
+public class MySQLDatabaseConnector extends SQLDatabaseConnector
+{
/**
* Class for MySQL database connections using the settings provided
+ *
* @param dbSettings - database settings
*/
- MySQLDatabaseConnector(DatabaseConnectionSettingsImpl dbSettings) {
- super(dbSettings, "jdbc:mysql://" + dbSettings.getHost() + ":" + dbSettings.getPort() + "/" + dbSettings.getDatabaseName()
- + "?autoReconnect=true&useSSL=" + dbSettings.isUseSSL() + "&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8");
+ MySQLDatabaseConnector(@NonNull DatabaseConnectionSettingsImpl dbSettings)
+ {
+ super(dbSettings, String.format("jdbc:mysql://%s:%s/%s",
+ dbSettings.getHost(),
+ dbSettings.getPort(),
+ dbSettings.getDatabaseName()));
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public HikariConfig createConfig()
+ {
+ HikariConfig config = new HikariConfig();
+ config.setPoolName("BentoBox MySQL Pool");
+
+ config.setDriverClassName("com.mysql.jdbc.Driver");
+ config.setJdbcUrl(this.connectionUrl);
+ config.setUsername(this.dbSettings.getUsername());
+ config.setPassword(this.dbSettings.getPassword());
+
+ config.addDataSourceProperty("useSSL", this.dbSettings.isUseSSL());
+
+ config.addDataSourceProperty("characterEncoding", "utf8");
+ config.addDataSourceProperty("encoding", "UTF-8");
+ config.addDataSourceProperty("useUnicode", "true");
+ config.addDataSourceProperty("allowMultiQueries", "true");
+
+ config.addDataSourceProperty("allowPublicKeyRetrieval", "true");
+
+ // Add extra properties.
+ this.dbSettings.getExtraProperties().forEach(config::addDataSourceProperty);
+
+ config.setMaximumPoolSize(this.dbSettings.getMaxConnections());
+
+ return config;
}
}
diff --git a/src/main/java/world/bentobox/bentobox/database/sql/mysql/MySQLDatabaseHandler.java b/src/main/java/world/bentobox/bentobox/database/sql/mysql/MySQLDatabaseHandler.java
index 3476a0acf..af40770fd 100644
--- a/src/main/java/world/bentobox/bentobox/database/sql/mysql/MySQLDatabaseHandler.java
+++ b/src/main/java/world/bentobox/bentobox/database/sql/mysql/MySQLDatabaseHandler.java
@@ -13,17 +13,21 @@
*
* @param
*/
-public class MySQLDatabaseHandler extends SQLDatabaseHandler {
-
+public class MySQLDatabaseHandler extends SQLDatabaseHandler
+{
/**
- * Handles the connection to the database and creation of the initial database schema (tables) for
- * the class that will be stored.
+ * Handles the connection to the database and creation of the initial database schema (tables) for the class that
+ * will be stored.
+ *
* @param plugin - plugin object
* @param type - the type of class to be stored in the database. Must inherit DataObject
* @param dbConnecter - authentication details for the database
*/
- MySQLDatabaseHandler(BentoBox plugin, Class type, DatabaseConnector dbConnecter) {
- super(plugin, type, dbConnecter, new SQLConfiguration(plugin, type)
- .schema("CREATE TABLE IF NOT EXISTS `[tableName]` (json JSON, uniqueId VARCHAR(255) GENERATED ALWAYS AS (json->\"$.uniqueId\"), UNIQUE INDEX i (uniqueId) ) ENGINE = INNODB"));
+ MySQLDatabaseHandler(BentoBox plugin, Class type, DatabaseConnector dbConnecter)
+ {
+ super(plugin,
+ type,
+ dbConnecter,
+ new SQLConfiguration(plugin, type).schema("CREATE TABLE IF NOT EXISTS `[tableName]` (json JSON, uniqueId VARCHAR(255) GENERATED ALWAYS AS (json->\"$.uniqueId\"), UNIQUE INDEX i (uniqueId) ) ENGINE = INNODB"));
}
}
diff --git a/src/main/java/world/bentobox/bentobox/database/sql/postgresql/PostgreSQLDatabase.java b/src/main/java/world/bentobox/bentobox/database/sql/postgresql/PostgreSQLDatabase.java
index 9908e0c00..b1fbd29d9 100644
--- a/src/main/java/world/bentobox/bentobox/database/sql/postgresql/PostgreSQLDatabase.java
+++ b/src/main/java/world/bentobox/bentobox/database/sql/postgresql/PostgreSQLDatabase.java
@@ -9,23 +9,34 @@
* @since 1.6.0
* @author Poslovitch
*/
-public class PostgreSQLDatabase implements DatabaseSetup {
-
+public class PostgreSQLDatabase implements DatabaseSetup
+{
+ /**
+ * PostgreSQL Database Connector.
+ */
PostgreSQLDatabaseConnector connector;
+
+ /**
+ * {@inheritDoc}
+ */
@Override
- public AbstractDatabaseHandler getHandler(Class dataObjectClass) {
+ public AbstractDatabaseHandler getHandler(Class dataObjectClass)
+ {
BentoBox plugin = BentoBox.getInstance();
- if (connector == null) {
- connector = new PostgreSQLDatabaseConnector(new DatabaseConnectionSettingsImpl(
+
+ if (this.connector == null)
+ {
+ this.connector = new PostgreSQLDatabaseConnector(new DatabaseConnectionSettingsImpl(
plugin.getSettings().getDatabaseHost(),
plugin.getSettings().getDatabasePort(),
plugin.getSettings().getDatabaseName(),
plugin.getSettings().getDatabaseUsername(),
plugin.getSettings().getDatabasePassword(),
- plugin.getSettings().isUseSSL()
- ));
+ plugin.getSettings().isUseSSL(),
+ plugin.getSettings().getMaximumPoolSize()));
}
- return new PostgreSQLDatabaseHandler<>(plugin, dataObjectClass, connector);
+
+ return new PostgreSQLDatabaseHandler<>(plugin, dataObjectClass, this.connector);
}
}
diff --git a/src/main/java/world/bentobox/bentobox/database/sql/postgresql/PostgreSQLDatabaseConnector.java b/src/main/java/world/bentobox/bentobox/database/sql/postgresql/PostgreSQLDatabaseConnector.java
index 5492ad81c..b782fc5d4 100644
--- a/src/main/java/world/bentobox/bentobox/database/sql/postgresql/PostgreSQLDatabaseConnector.java
+++ b/src/main/java/world/bentobox/bentobox/database/sql/postgresql/PostgreSQLDatabaseConnector.java
@@ -1,34 +1,54 @@
package world.bentobox.bentobox.database.sql.postgresql;
import org.eclipse.jdt.annotation.NonNull;
-import org.postgresql.Driver;
+
+import com.zaxxer.hikari.HikariConfig;
import world.bentobox.bentobox.database.DatabaseConnectionSettingsImpl;
import world.bentobox.bentobox.database.sql.SQLDatabaseConnector;
+
/**
* @since 1.6.0
* @author Poslovitch
*/
-public class PostgreSQLDatabaseConnector extends SQLDatabaseConnector {
-
- /*
- * Ensure the driver is loaded as JDBC Driver might be invisible to Java's ServiceLoader.
- * Usually, this is not required as {@link DriverManager} detects JDBC drivers
- * via {@code META-INF/services/java.sql.Driver} entries. However there might be cases when the driver
- * is located at the application level classloader, thus it might be required to perform manual
- * registration of the driver.
- */
- static {
- new Driver();
- }
-
+public class PostgreSQLDatabaseConnector extends SQLDatabaseConnector
+{
/**
* Class for PostgreSQL database connections using the settings provided
+ *
* @param dbSettings - database settings
*/
- PostgreSQLDatabaseConnector(@NonNull DatabaseConnectionSettingsImpl dbSettings) {
- super(dbSettings, "jdbc:postgresql://" + dbSettings.getHost() + ":" + dbSettings.getPort() + "/" + dbSettings.getDatabaseName()
- + "?autoReconnect=true&useSSL=" + dbSettings.isUseSSL() + "&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8");
+ PostgreSQLDatabaseConnector(@NonNull DatabaseConnectionSettingsImpl dbSettings)
+ {
+ // connectionUrl is not used in PostgreSQL connection.
+ super(dbSettings, "");
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public HikariConfig createConfig()
+ {
+ HikariConfig config = new HikariConfig();
+ config.setPoolName("BentoBox PostgreSQL Pool");
+
+ config.setDataSourceClassName("org.postgresql.ds.PGSimpleDataSource");
+ config.addDataSourceProperty("user", this.dbSettings.getUsername());
+ config.addDataSourceProperty("password", this.dbSettings.getPassword());
+ config.addDataSourceProperty("databaseName", this.dbSettings.getDatabaseName());
+ config.addDataSourceProperty("serverName", this.dbSettings.getHost());
+ config.addDataSourceProperty("portNumber", this.dbSettings.getPort());
+
+ config.addDataSourceProperty("ssl", this.dbSettings.isUseSSL());
+
+ // Add extra properties.
+ this.dbSettings.getExtraProperties().forEach(config::addDataSourceProperty);
+
+ config.setMaximumPoolSize(this.dbSettings.getMaxConnections());
+
+ return config;
}
}
diff --git a/src/main/java/world/bentobox/bentobox/database/sql/postgresql/PostgreSQLDatabaseHandler.java b/src/main/java/world/bentobox/bentobox/database/sql/postgresql/PostgreSQLDatabaseHandler.java
index a1cd88a1e..7fda4f6bc 100644
--- a/src/main/java/world/bentobox/bentobox/database/sql/postgresql/PostgreSQLDatabaseHandler.java
+++ b/src/main/java/world/bentobox/bentobox/database/sql/postgresql/PostgreSQLDatabaseHandler.java
@@ -1,5 +1,6 @@
package world.bentobox.bentobox.database.sql.postgresql;
+import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.concurrent.CompletableFuture;
@@ -19,70 +20,86 @@
* @since 1.11.0
* @author tastybento
*/
-public class PostgreSQLDatabaseHandler extends SQLDatabaseHandler {
-
+public class PostgreSQLDatabaseHandler extends SQLDatabaseHandler
+{
/**
* Constructor
*
- * @param plugin BentoBox plugin
- * @param type The type of the objects that should be created and filled with
- * values from the database or inserted into the database
+ * @param plugin BentoBox plugin
+ * @param type The type of the objects that should be created and filled with values from the database or inserted
+ * into the database
* @param databaseConnector Contains the settings to create a connection to the database
*/
- PostgreSQLDatabaseHandler(BentoBox plugin, Class type, DatabaseConnector databaseConnector) {
- super(plugin, type, databaseConnector, new SQLConfiguration(plugin, type)
+ PostgreSQLDatabaseHandler(BentoBox plugin, Class type, DatabaseConnector databaseConnector)
+ {
+ super(plugin,
+ type,
+ databaseConnector,
+ new SQLConfiguration(plugin, type).
// Set uniqueid as the primary key (index). Postgresql convention is to use lower case field names
// Postgresql also uses double quotes (") instead of (`) around tables names with dots.
- .schema("CREATE TABLE IF NOT EXISTS \"[tableName]\" (uniqueid VARCHAR PRIMARY KEY, json jsonb NOT NULL)")
- .loadObject("SELECT * FROM \"[tableName]\" WHERE uniqueid = ? LIMIT 1")
- .deleteObject("DELETE FROM \"[tableName]\" WHERE uniqueid = ?")
+ schema("CREATE TABLE IF NOT EXISTS \"[tableName]\" (uniqueid VARCHAR PRIMARY KEY, json jsonb NOT NULL)").
+ loadObject("SELECT * FROM \"[tableName]\" WHERE uniqueid = ? LIMIT 1").
+ deleteObject("DELETE FROM \"[tableName]\" WHERE uniqueid = ?").
// uniqueId has to be added into the row explicitly so we need to override the saveObject method
// The json value is a string but has to be cast to json when done in Java
- .saveObject("INSERT INTO \"[tableName]\" (uniqueid, json) VALUES (?, cast(? as json)) "
+ saveObject("INSERT INTO \"[tableName]\" (uniqueid, json) VALUES (?, cast(? as json)) "
// This is the Postgresql version of UPSERT.
- + "ON CONFLICT (uniqueid) "
- + "DO UPDATE SET json = cast(? as json)")
- .loadObjects("SELECT json FROM \"[tableName]\"")
+ + "ON CONFLICT (uniqueid) DO UPDATE SET json = cast(? as json)").
+ loadObjects("SELECT json FROM \"[tableName]\"").
// Postgres exists function returns true or false natively
- .objectExists("SELECT EXISTS(SELECT * FROM \"[tableName]\" WHERE uniqueid = ?)")
- .renameTable("ALTER TABLE IF EXISTS \"[oldTableName]\" RENAME TO \"[tableName]\"")
- .setUseQuotes(false)
+ objectExists("SELECT EXISTS(SELECT * FROM \"[tableName]\" WHERE uniqueid = ?)").
+ renameTable("ALTER TABLE IF EXISTS \"[oldTableName]\" RENAME TO \"[tableName]\"").
+ setUseQuotes(false)
);
}
- /* (non-Javadoc)
- * @see world.bentobox.bentobox.database.sql.SQLDatabaseHandler#saveObject(java.lang.Object)
+
+ /**
+ * {@inheritDoc}
*/
@Override
- public CompletableFuture saveObject(T instance) {
+ public CompletableFuture saveObject(T instance)
+ {
CompletableFuture completableFuture = new CompletableFuture<>();
+
// Null check
- if (instance == null) {
- plugin.logError("PostgreSQL database request to store a null. ");
+ if (instance == null)
+ {
+ this.plugin.logError("PostgreSQL database request to store a null. ");
completableFuture.complete(false);
return completableFuture;
}
- if (!(instance instanceof DataObject)) {
- plugin.logError("This class is not a DataObject: " + instance.getClass().getName());
+
+ if (!(instance instanceof DataObject))
+ {
+ this.plugin.logError("This class is not a DataObject: " + instance.getClass().getName());
completableFuture.complete(false);
return completableFuture;
}
- Gson gson = getGson();
+
+ Gson gson = this.getGson();
String toStore = gson.toJson(instance);
- String uniqueId = ((DataObject)instance).getUniqueId();
- processQueue.add(() -> {
- try (PreparedStatement preparedStatement = getConnection().prepareStatement(getSqlConfig().getSaveObjectSQL())) {
+ String uniqueId = ((DataObject) instance).getUniqueId();
+
+ this.processQueue.add(() ->
+ {
+ try (Connection connection = this.dataSource.getConnection();
+ PreparedStatement preparedStatement = connection.prepareStatement(this.getSqlConfig().getSaveObjectSQL()))
+ {
preparedStatement.setString(1, uniqueId); // INSERT
preparedStatement.setString(2, toStore); // INSERT
preparedStatement.setString(3, toStore); // ON CONFLICT
preparedStatement.execute();
completableFuture.complete(true);
- } catch (SQLException e) {
- plugin.logError("Could not save object " + instance.getClass().getName() + " " + e.getMessage());
+ }
+ catch (SQLException e)
+ {
+ this.plugin.logError("Could not save object " + instance.getClass().getName() + " " + e.getMessage());
completableFuture.complete(false);
}
});
+
return completableFuture;
}
-
}
diff --git a/src/main/java/world/bentobox/bentobox/database/sql/sqlite/SQLiteDatabase.java b/src/main/java/world/bentobox/bentobox/database/sql/sqlite/SQLiteDatabase.java
index 327bdb657..9a65ff957 100644
--- a/src/main/java/world/bentobox/bentobox/database/sql/sqlite/SQLiteDatabase.java
+++ b/src/main/java/world/bentobox/bentobox/database/sql/sqlite/SQLiteDatabase.java
@@ -1,19 +1,51 @@
package world.bentobox.bentobox.database.sql.sqlite;
+import java.io.File;
+
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.database.AbstractDatabaseHandler;
import world.bentobox.bentobox.database.DatabaseSetup;
+
/**
* @since 1.6.0
* @author Poslovitch
*/
-public class SQLiteDatabase implements DatabaseSetup {
+public class SQLiteDatabase implements DatabaseSetup
+{
+ /**
+ * Database file name.
+ */
+ private static final String DATABASE_FOLDER_NAME = "database";
+
+ /**
+ * SQLite Database Connector.
+ */
+ private SQLiteDatabaseConnector connector;
- private final SQLiteDatabaseConnector connector = new SQLiteDatabaseConnector(BentoBox.getInstance());
+ /**
+ * {@inheritDoc}
+ */
@Override
- public AbstractDatabaseHandler getHandler(Class dataObjectClass) {
- return new SQLiteDatabaseHandler<>(BentoBox.getInstance(), dataObjectClass, connector);
+ public AbstractDatabaseHandler getHandler(Class dataObjectClass)
+ {
+ if (this.connector == null)
+ {
+ BentoBox plugin = BentoBox.getInstance();
+ File dataFolder = new File(plugin.getDataFolder(), DATABASE_FOLDER_NAME);
+
+ if (!dataFolder.exists() && !dataFolder.mkdirs())
+ {
+ plugin.logError("Could not create database folder!");
+ // Trigger plugin shutdown.
+ plugin.onDisable();
+ return null;
+ }
+
+ this.connector = new SQLiteDatabaseConnector("jdbc:sqlite:" + dataFolder.getAbsolutePath() + File.separator + "database.db");
+ }
+
+ return new SQLiteDatabaseHandler<>(BentoBox.getInstance(), dataObjectClass, this.connector);
}
}
diff --git a/src/main/java/world/bentobox/bentobox/database/sql/sqlite/SQLiteDatabaseConnector.java b/src/main/java/world/bentobox/bentobox/database/sql/sqlite/SQLiteDatabaseConnector.java
index 57f637663..ee243fc9e 100644
--- a/src/main/java/world/bentobox/bentobox/database/sql/sqlite/SQLiteDatabaseConnector.java
+++ b/src/main/java/world/bentobox/bentobox/database/sql/sqlite/SQLiteDatabaseConnector.java
@@ -1,48 +1,37 @@
package world.bentobox.bentobox.database.sql.sqlite;
-import java.io.File;
-import java.sql.DriverManager;
-import java.sql.SQLException;
+import com.zaxxer.hikari.HikariConfig;
-import org.bukkit.Bukkit;
-import org.eclipse.jdt.annotation.NonNull;
-
-import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.database.sql.SQLDatabaseConnector;
/**
* @since 1.6.0
* @author Poslovitch
*/
-public class SQLiteDatabaseConnector extends SQLDatabaseConnector {
-
- private static final String DATABASE_FOLDER_NAME = "database";
-
- SQLiteDatabaseConnector(@NonNull BentoBox plugin) {
- super(null, ""); // Not used by SQLite
- File dataFolder = new File(plugin.getDataFolder(), DATABASE_FOLDER_NAME);
- if (!dataFolder.exists() && !dataFolder.mkdirs()) {
- BentoBox.getInstance().logError("Could not create database folder!");
- return;
- }
- connectionUrl = "jdbc:sqlite:" + dataFolder.getAbsolutePath() + File.separator + "database.db";
+public class SQLiteDatabaseConnector extends SQLDatabaseConnector
+{
+ /**
+ * Default constructor.
+ */
+ SQLiteDatabaseConnector(String connectionUrl)
+ {
+ super(null, connectionUrl);
}
- /* (non-Javadoc)
- * @see world.bentobox.bentobox.database.sql.SQLDatabaseConnector#createConnection(java.lang.Class)
+ /**
+ * {@inheritDoc}
*/
@Override
- public Object createConnection(Class> type) {
- types.add(type);
- // Only make one connection at a time
- if (connection == null) {
- try {
- connection = DriverManager.getConnection(connectionUrl);
- } catch (SQLException e) {
- Bukkit.getLogger().severe("Could not connect to the database! " + e.getMessage());
- }
- }
- return connection;
+ public HikariConfig createConfig()
+ {
+ HikariConfig config = new HikariConfig();
+ config.setDataSourceClassName("org.sqlite.SQLiteDataSource");
+ config.setPoolName("BentoBox SQLite Pool");
+ config.addDataSourceProperty("encoding", "UTF-8");
+ config.addDataSourceProperty("url", this.connectionUrl);
+ config.setMaximumPoolSize(100);
+
+ return config;
}
}
diff --git a/src/main/java/world/bentobox/bentobox/database/sql/sqlite/SQLiteDatabaseHandler.java b/src/main/java/world/bentobox/bentobox/database/sql/sqlite/SQLiteDatabaseHandler.java
index 8c5bc3970..15b12dfb0 100644
--- a/src/main/java/world/bentobox/bentobox/database/sql/sqlite/SQLiteDatabaseHandler.java
+++ b/src/main/java/world/bentobox/bentobox/database/sql/sqlite/SQLiteDatabaseHandler.java
@@ -1,5 +1,6 @@
package world.bentobox.bentobox.database.sql.sqlite;
+import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -17,23 +18,24 @@
* @since 1.6.0
* @author Poslovitch, tastybento
*/
-public class SQLiteDatabaseHandler extends SQLDatabaseHandler {
-
+public class SQLiteDatabaseHandler extends SQLDatabaseHandler
+{
/**
* Constructor
*
- * @param plugin BentoBox plugin
- * @param type The type of the objects that should be created and filled with
- * values from the database or inserted into the database
+ * @param plugin BentoBox plugin
+ * @param type The type of the objects that should be created and filled with values from the database or inserted
+ * into the database
* @param databaseConnector Contains the settings to create a connection to the database
*/
- protected SQLiteDatabaseHandler(BentoBox plugin, Class type, DatabaseConnector databaseConnector) {
- super(plugin, type, databaseConnector, new SQLConfiguration(plugin, type)
- .schema("CREATE TABLE IF NOT EXISTS `[tableName]` (json JSON, uniqueId VARCHAR(255) NOT NULL PRIMARY KEY)")
- .saveObject("INSERT INTO `[tableName]` (json, uniqueId) VALUES (?, ?) ON CONFLICT(uniqueId) DO UPDATE SET json = ?")
- .objectExists("SELECT EXISTS (SELECT 1 FROM `[tableName]` WHERE `uniqueId` = ?)")
- .renameTable("ALTER TABLE `[oldTableName]` RENAME TO `[tableName]`")
- .setUseQuotes(false)
+ protected SQLiteDatabaseHandler(BentoBox plugin, Class type, DatabaseConnector databaseConnector)
+ {
+ super(plugin, type, databaseConnector, new SQLConfiguration(plugin, type).
+ schema("CREATE TABLE IF NOT EXISTS `[tableName]` (json JSON, uniqueId VARCHAR(255) NOT NULL PRIMARY KEY)").
+ saveObject("INSERT INTO `[tableName]` (json, uniqueId) VALUES (?, ?) ON CONFLICT(uniqueId) DO UPDATE SET json = ?").
+ objectExists("SELECT EXISTS (SELECT 1 FROM `[tableName]` WHERE `uniqueId` = ?)").
+ renameTable("ALTER TABLE `[oldTableName]` RENAME TO `[tableName]`").
+ setUseQuotes(false)
);
}
@@ -42,70 +44,115 @@ protected SQLiteDatabaseHandler(BentoBox plugin, Class type, DatabaseConnecto
* Creates the table in the database if it doesn't exist already
*/
@Override
- protected void createSchema() {
- if (getSqlConfig().renameRequired()) {
+ protected void createSchema()
+ {
+ if (this.getSqlConfig().renameRequired())
+ {
// SQLite does not have a rename if exists command so we have to manually check if the old table exists
- String sql = "SELECT EXISTS (SELECT 1 FROM sqlite_master WHERE type='table' AND name='" + getSqlConfig().getOldTableName() + "' COLLATE NOCASE)";
- try (PreparedStatement pstmt = getConnection().prepareStatement(sql)) {
- rename(pstmt);
- } catch (SQLException e) {
- plugin.logError("Could not check if " + getSqlConfig().getOldTableName() + " exists for data object " + dataObject.getCanonicalName() + " " + e.getMessage());
+ String sql = "SELECT EXISTS (SELECT 1 FROM sqlite_master WHERE type='table' AND name='" +
+ this.getSqlConfig().getOldTableName() + "' COLLATE NOCASE)";
+
+ try (Connection connection = this.dataSource.getConnection();
+ PreparedStatement preparedStatement = connection.prepareStatement(sql))
+ {
+ this.rename(preparedStatement);
+ }
+ catch (SQLException e)
+ {
+ this.plugin.logError("Could not check if " + this.getSqlConfig().getOldTableName() + " exists for data object " +
+ this.dataObject.getCanonicalName() + " " + e.getMessage());
}
}
// Prepare and execute the database statements
- try (PreparedStatement pstmt = getConnection().prepareStatement(getSqlConfig().getSchemaSQL())) {
- pstmt.execute();
- } catch (SQLException e) {
- plugin.logError("Problem trying to create schema for data object " + dataObject.getCanonicalName() + " " + e.getMessage());
+ try (Connection connection = this.dataSource.getConnection();
+ PreparedStatement preparedStatement = connection.prepareStatement(this.getSqlConfig().getSchemaSQL()))
+ {
+ preparedStatement.execute();
+ }
+ catch (SQLException e)
+ {
+ this.plugin.logError("Problem trying to create schema for data object " + dataObject.getCanonicalName() + " " +
+ e.getMessage());
}
}
- private void rename(PreparedStatement pstmt) {
- try (ResultSet resultSet = pstmt.executeQuery()) {
- if (resultSet.next() && resultSet.getBoolean(1)) {
+
+ private void rename(PreparedStatement pstmt)
+ {
+ try (ResultSet resultSet = pstmt.executeQuery())
+ {
+ if (resultSet.next() && resultSet.getBoolean(1))
+ {
// Transition from the old table name
- String sql = getSqlConfig().getRenameTableSQL().replace("[oldTableName]", getSqlConfig().getOldTableName().replace("[tableName]", getSqlConfig().getTableName()));
- try (PreparedStatement pstmt2 = getConnection().prepareStatement(sql)) {
- pstmt2.execute();
- } catch (SQLException e) {
- plugin.logError("Could not rename " + getSqlConfig().getOldTableName() + " for data object " + dataObject.getCanonicalName() + " " + e.getMessage());
- }
+ String sql = this.getSqlConfig().getRenameTableSQL().replace("[oldTableName]",
+ this.getSqlConfig().getOldTableName().replace("[tableName]", this.getSqlConfig().getTableName()));
+
+ executeStatement(sql);
}
- } catch (Exception ex) {
- plugin.logError("Could not check if " + getSqlConfig().getOldTableName() + " exists for data object " + dataObject.getCanonicalName() + " " + ex.getMessage());
+ }
+ catch (Exception ex)
+ {
+ this.plugin.logError("Could not check if " + getSqlConfig().getOldTableName() + " exists for data object " +
+ this.dataObject.getCanonicalName() + " " + ex.getMessage());
}
}
+
+ private void executeStatement(String sql) {
+ try (Connection connection = this.dataSource.getConnection();
+ PreparedStatement preparedStatement = connection.prepareStatement(sql))
+ {
+ preparedStatement.execute();
+ }
+ catch (SQLException e)
+ {
+ this.plugin.logError("Could not rename " + getSqlConfig().getOldTableName() + " for data object " +
+ this.dataObject.getCanonicalName() + " " + e.getMessage());
+ }
+ }
+
+
@Override
- public CompletableFuture saveObject(T instance) {
+ public CompletableFuture saveObject(T instance)
+ {
CompletableFuture completableFuture = new CompletableFuture<>();
+
// Null check
- if (instance == null) {
- plugin.logError("SQLite database request to store a null. ");
+ if (instance == null)
+ {
+ this.plugin.logError("SQLite database request to store a null. ");
completableFuture.complete(false);
return completableFuture;
}
- if (!(instance instanceof DataObject)) {
- plugin.logError("This class is not a DataObject: " + instance.getClass().getName());
+
+ if (!(instance instanceof DataObject))
+ {
+ this.plugin.logError("This class is not a DataObject: " + instance.getClass().getName());
completableFuture.complete(false);
return completableFuture;
}
- Gson gson = getGson();
+
+ Gson gson = this.getGson();
String toStore = gson.toJson(instance);
- processQueue.add(() -> {
- try (PreparedStatement preparedStatement = getConnection().prepareStatement(getSqlConfig().getSaveObjectSQL())) {
+
+ this.processQueue.add(() ->
+ {
+ try (Connection connection = this.dataSource.getConnection();
+ PreparedStatement preparedStatement = connection.prepareStatement(this.getSqlConfig().getSaveObjectSQL()))
+ {
preparedStatement.setString(1, toStore);
- preparedStatement.setString(2, ((DataObject)instance).getUniqueId());
+ preparedStatement.setString(2, ((DataObject) instance).getUniqueId());
preparedStatement.setString(3, toStore);
preparedStatement.execute();
completableFuture.complete(true);
- } catch (SQLException e) {
- plugin.logError("Could not save object " + instance.getClass().getName() + " " + e.getMessage());
+ }
+ catch (SQLException e)
+ {
+ this.plugin.logError("Could not save object " + instance.getClass().getName() + " " + ((DataObject) instance).getUniqueId() + " " + e.getMessage());
completableFuture.complete(false);
}
});
+
return completableFuture;
}
-
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/world/bentobox/bentobox/database/yaml/YamlDatabaseConnector.java b/src/main/java/world/bentobox/bentobox/database/yaml/YamlDatabaseConnector.java
index 62e9b3094..072a14a4f 100644
--- a/src/main/java/world/bentobox/bentobox/database/yaml/YamlDatabaseConnector.java
+++ b/src/main/java/world/bentobox/bentobox/database/yaml/YamlDatabaseConnector.java
@@ -25,8 +25,6 @@
import org.bukkit.configuration.file.YamlConfiguration;
import org.eclipse.jdt.annotation.NonNull;
-import com.google.common.base.Charsets;
-
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.database.DatabaseConnector;
@@ -100,11 +98,14 @@ private void removeStringFromFile(File yamlFile) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(yamlFile), StandardCharsets.UTF_8))){
File temp = File.createTempFile("file", ".tmp", yamlFile.getParentFile());
writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(temp), StandardCharsets.UTF_8));
- for (String line; (line = reader.readLine()) != null;) {
+ String line = reader.readLine();
+ while (line != null) {
line = line.replace("!!java.util.UUID", "");
writer.println(line);
+ line = reader.readLine();
}
- if (yamlFile.delete() && !temp.renameTo(yamlFile)) {
+ Files.delete(yamlFile.toPath());
+ if (!temp.renameTo(yamlFile)) {
plugin.logError("Could not rename fixed Island object. Are the writing permissions correctly setup?");
}
} catch (Exception e) {
@@ -123,7 +124,7 @@ boolean saveYamlFile(String data, String tableName, String fileName, Map commentMap) {
for (Entry e : commentMap.entrySet()) {
if (nextLine.contains(e.getKey())) {
// We want the comment to start at the same level as the entry
- String commentLine = " ".repeat(Math.max(0, nextLine.indexOf(e.getKey()))) +
+ nextLine = " ".repeat(Math.max(0, nextLine.indexOf(e.getKey()))) +
e.getValue();
- nextLine = commentLine;
break;
}
}
diff --git a/src/main/java/world/bentobox/bentobox/database/yaml/YamlDatabaseHandler.java b/src/main/java/world/bentobox/bentobox/database/yaml/YamlDatabaseHandler.java
index 008ff23a9..7de79cb79 100644
--- a/src/main/java/world/bentobox/bentobox/database/yaml/YamlDatabaseHandler.java
+++ b/src/main/java/world/bentobox/bentobox/database/yaml/YamlDatabaseHandler.java
@@ -316,9 +316,9 @@ private List getCollectionParameterTypes(Method writeMethod) {
// There could be more than one argument, so step through them
for (Type genericParameterType : genericParameterTypes) {
// If the argument is a parameter, then do something - this should always be true if the parameter is a collection
- if(genericParameterType instanceof ParameterizedType ) {
+ if(genericParameterType instanceof ParameterizedType pt) {
// Get the actual type arguments of the parameter
- Type[] parameters = ((ParameterizedType)genericParameterType).getActualTypeArguments();
+ Type[] parameters = pt.getActualTypeArguments();
result.addAll(Arrays.asList(parameters));
}
}
@@ -338,13 +338,11 @@ public CompletableFuture saveObject(T instance) throws IllegalAccessExc
// Null check
if (instance == null) {
plugin.logError("YAML database request to store a null.");
- completableFuture.complete(false);
- return completableFuture;
+ return CompletableFuture.completedFuture(false);
}
if (!(instance instanceof DataObject)) {
plugin.logError("This class is not a DataObject: " + instance.getClass().getName());
- completableFuture.complete(false);
- return completableFuture;
+ return CompletableFuture.completedFuture(false);
}
// This is the Yaml Configuration that will be used and saved at the end
YamlConfiguration config = new YamlConfiguration();
@@ -396,22 +394,21 @@ public CompletableFuture saveObject(T instance) throws IllegalAccessExc
handleConfigEntryComments(configEntry, config, yamlComments, parent);
}
- if (checkAdapter(field, config, storageLocation, value)) {
- continue;
- }
- // Set the filename if it has not be set already
- if (filename.isEmpty() && method.getName().equals("getUniqueId")) {
- // Save the name for when the file is saved
- filename = getFilename(propertyDescriptor, instance, (String)value);
- }
- // Collections need special serialization
- if (Map.class.isAssignableFrom(propertyDescriptor.getPropertyType()) && value != null) {
- serializeMap((Map