mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2024-11-01 00:10:40 +01:00
commit
fe888a8d0e
49
pom.xml
49
pom.xml
@ -66,23 +66,29 @@
|
|||||||
<java.version>17</java.version>
|
<java.version>17</java.version>
|
||||||
<!-- Non-minecraft related dependencies -->
|
<!-- Non-minecraft related dependencies -->
|
||||||
<powermock.version>2.0.9</powermock.version>
|
<powermock.version>2.0.9</powermock.version>
|
||||||
|
<!-- Database related dependencies -->
|
||||||
<mongodb.version>3.12.8</mongodb.version>
|
<mongodb.version>3.12.8</mongodb.version>
|
||||||
|
<mariadb.version>3.0.5</mariadb.version>
|
||||||
|
<mysql.version>8.0.27</mysql.version>
|
||||||
|
<postgresql.version>42.2.18</postgresql.version>
|
||||||
|
<hikaricp.version>5.0.1</hikaricp.version>
|
||||||
<!-- More visible way to change dependency versions -->
|
<!-- More visible way to change dependency versions -->
|
||||||
<spigot.version>1.19.2-R0.1-SNAPSHOT</spigot.version>
|
<spigot.version>1.19.3-R0.1-SNAPSHOT</spigot.version>
|
||||||
<!-- Might differ from the last Spigot release for short periods
|
<!-- Might differ from the last Spigot release for short periods
|
||||||
of time -->
|
of time -->
|
||||||
<paper.version>1.19-R0.1-SNAPSHOT</paper.version>
|
<paper.version>1.19-R0.1-SNAPSHOT</paper.version>
|
||||||
<bstats.version>2.2.1</bstats.version>
|
<bstats.version>3.0.0</bstats.version>
|
||||||
<vault.version>1.7</vault.version>
|
<vault.version>1.7.1</vault.version>
|
||||||
<placeholderapi.version>2.10.9</placeholderapi.version>
|
<placeholderapi.version>2.10.9</placeholderapi.version>
|
||||||
<githubapi.version>d5f5e0bbd8</githubapi.version>
|
<githubapi.version>d5f5e0bbd8</githubapi.version>
|
||||||
<dynmap.version>3.0-SNAPSHOT</dynmap.version>
|
<dynmap.version>3.0-SNAPSHOT</dynmap.version>
|
||||||
|
<myworlds.version>1.19.3-v1</myworlds.version>
|
||||||
<!-- Revision variable removes warning about dynamic version -->
|
<!-- Revision variable removes warning about dynamic version -->
|
||||||
<revision>${build.version}-SNAPSHOT</revision>
|
<revision>${build.version}-SNAPSHOT</revision>
|
||||||
<!-- Do not change unless you want different name for local builds. -->
|
<!-- Do not change unless you want different name for local builds. -->
|
||||||
<build.number>-LOCAL</build.number>
|
<build.number>-LOCAL</build.number>
|
||||||
<!-- This allows to change between versions. -->
|
<!-- This allows to change between versions. -->
|
||||||
<build.version>1.21.1</build.version>
|
<build.version>1.22.0</build.version>
|
||||||
<sonar.organization>bentobox-world</sonar.organization>
|
<sonar.organization>bentobox-world</sonar.organization>
|
||||||
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
|
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
|
||||||
</properties>
|
</properties>
|
||||||
@ -176,6 +182,11 @@
|
|||||||
<id>nms-repo</id>
|
<id>nms-repo</id>
|
||||||
<url>https://repo.codemc.io/repository/nms/</url>
|
<url>https://repo.codemc.io/repository/nms/</url>
|
||||||
</repository>
|
</repository>
|
||||||
|
<!-- Used for MyWorlds hook -->
|
||||||
|
<repository>
|
||||||
|
<id>MG-Dev Jenkins CI Maven Repository</id>
|
||||||
|
<url>https://ci.mg-dev.eu/plugin/repository/everything</url>
|
||||||
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -197,7 +208,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.mojang</groupId>
|
<groupId>com.mojang</groupId>
|
||||||
<artifactId>authlib</artifactId>
|
<artifactId>authlib</artifactId>
|
||||||
<version>3.2.38</version>
|
<version>3.16.29</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- Metrics -->
|
<!-- Metrics -->
|
||||||
@ -232,10 +243,11 @@
|
|||||||
<version>${mongodb.version}</version>
|
<version>${mongodb.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- HikariCP database handler -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>postgresql</groupId>
|
<groupId>com.zaxxer</groupId>
|
||||||
<artifactId>postgresql</artifactId>
|
<artifactId>HikariCP</artifactId>
|
||||||
<version>9.1-901-1.jdbc4</version>
|
<version>${hikaricp.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- Vault: as their maven repo is down, we need to get it from jitpack -->
|
<!-- Vault: as their maven repo is down, we need to get it from jitpack -->
|
||||||
@ -260,6 +272,12 @@
|
|||||||
<version>${dynmap.version}</version>
|
<version>${dynmap.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.bergerkiller.bukkit</groupId>
|
||||||
|
<artifactId>MyWorlds</artifactId>
|
||||||
|
<version>${myworlds.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
<!-- Shaded APIs -->
|
<!-- Shaded APIs -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.TheBusyBiscuit</groupId>
|
<groupId>com.github.TheBusyBiscuit</groupId>
|
||||||
@ -269,7 +287,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.Marcono1234</groupId>
|
<groupId>com.github.Marcono1234</groupId>
|
||||||
<artifactId>gson-record-type-adapter-factory</artifactId>
|
<artifactId>gson-record-type-adapter-factory</artifactId>
|
||||||
<version>0.1.0</version>
|
<version>0.3.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- Static analysis -->
|
<!-- Static analysis -->
|
||||||
<!-- We are using Eclipse's annotations. If you're using IDEA, update
|
<!-- We are using Eclipse's annotations. If you're using IDEA, update
|
||||||
@ -352,6 +370,7 @@
|
|||||||
<version>3.0.0-M5</version>
|
<version>3.0.0-M5</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<argLine>
|
<argLine>
|
||||||
|
${argLine}
|
||||||
--add-opens java.base/java.lang=ALL-UNNAMED
|
--add-opens java.base/java.lang=ALL-UNNAMED
|
||||||
--add-opens java.base/java.math=ALL-UNNAMED
|
--add-opens java.base/java.math=ALL-UNNAMED
|
||||||
--add-opens java.base/java.io=ALL-UNNAMED
|
--add-opens java.base/java.io=ALL-UNNAMED
|
||||||
@ -390,10 +409,11 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
<version>3.3.0</version>
|
<version>3.4.1</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>${java.version}</source>
|
<source>${java.version}</source>
|
||||||
<show>private</show>
|
<show>private</show>
|
||||||
|
<quiet>true</quiet>
|
||||||
<failOnError>false</failOnError>
|
<failOnError>false</failOnError>
|
||||||
<additionalJOption>-Xdoclint:none</additionalJOption>
|
<additionalJOption>-Xdoclint:none</additionalJOption>
|
||||||
<!-- To compile with Java 11, this tag may be required -->
|
<!-- To compile with Java 11, this tag may be required -->
|
||||||
@ -495,16 +515,21 @@
|
|||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>pre-unit-test</id>
|
<id>prepare-agent</id>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>prepare-agent</goal>
|
<goal>prepare-agent</goal>
|
||||||
</goals>
|
</goals>
|
||||||
</execution>
|
</execution>
|
||||||
<execution>
|
<execution>
|
||||||
<id>post-unit-test</id>
|
<id>report</id>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>report</goal>
|
<goal>report</goal>
|
||||||
</goals>
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<formats>
|
||||||
|
<format>XML</format>
|
||||||
|
</formats>
|
||||||
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
@ -20,6 +20,7 @@ import world.bentobox.bentobox.api.user.User;
|
|||||||
import world.bentobox.bentobox.commands.BentoBoxCommand;
|
import world.bentobox.bentobox.commands.BentoBoxCommand;
|
||||||
import world.bentobox.bentobox.database.DatabaseSetup;
|
import world.bentobox.bentobox.database.DatabaseSetup;
|
||||||
import world.bentobox.bentobox.hooks.MultiverseCoreHook;
|
import world.bentobox.bentobox.hooks.MultiverseCoreHook;
|
||||||
|
import world.bentobox.bentobox.hooks.MyWorldsHook;
|
||||||
import world.bentobox.bentobox.hooks.VaultHook;
|
import world.bentobox.bentobox.hooks.VaultHook;
|
||||||
import world.bentobox.bentobox.hooks.placeholders.PlaceholderAPIHook;
|
import world.bentobox.bentobox.hooks.placeholders.PlaceholderAPIHook;
|
||||||
import world.bentobox.bentobox.listeners.BannedCommands;
|
import world.bentobox.bentobox.listeners.BannedCommands;
|
||||||
@ -27,9 +28,9 @@ import world.bentobox.bentobox.listeners.BlockEndDragon;
|
|||||||
import world.bentobox.bentobox.listeners.DeathListener;
|
import world.bentobox.bentobox.listeners.DeathListener;
|
||||||
import world.bentobox.bentobox.listeners.JoinLeaveListener;
|
import world.bentobox.bentobox.listeners.JoinLeaveListener;
|
||||||
import world.bentobox.bentobox.listeners.PanelListenerManager;
|
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.EntityTeleportListener;
|
||||||
import world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener;
|
import world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener;
|
||||||
import world.bentobox.bentobox.listeners.StandardSpawnProtectionListener;
|
|
||||||
import world.bentobox.bentobox.managers.AddonsManager;
|
import world.bentobox.bentobox.managers.AddonsManager;
|
||||||
import world.bentobox.bentobox.managers.BlueprintsManager;
|
import world.bentobox.bentobox.managers.BlueprintsManager;
|
||||||
import world.bentobox.bentobox.managers.CommandsManager;
|
import world.bentobox.bentobox.managers.CommandsManager;
|
||||||
@ -225,6 +226,7 @@ public class BentoBox extends JavaPlugin {
|
|||||||
// Register Multiverse hook - MV loads AFTER BentoBox
|
// Register Multiverse hook - MV loads AFTER BentoBox
|
||||||
// Make sure all worlds are already registered to Multiverse.
|
// Make sure all worlds are already registered to Multiverse.
|
||||||
hooksManager.registerHook(new MultiverseCoreHook());
|
hooksManager.registerHook(new MultiverseCoreHook());
|
||||||
|
hooksManager.registerHook(new MyWorldsHook());
|
||||||
islandWorldManager.registerWorldsToMultiverse();
|
islandWorldManager.registerWorldsToMultiverse();
|
||||||
|
|
||||||
// TODO: re-enable after implementation
|
// TODO: re-enable after implementation
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package world.bentobox.bentobox;
|
package world.bentobox.bentobox;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
@ -11,8 +13,10 @@ import world.bentobox.bentobox.api.configuration.ConfigObject;
|
|||||||
import world.bentobox.bentobox.api.configuration.StoreAt;
|
import world.bentobox.bentobox.api.configuration.StoreAt;
|
||||||
import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType;
|
import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All the plugin settings are here
|
* All the plugin settings are here
|
||||||
|
*
|
||||||
* @author tastybento
|
* @author tastybento
|
||||||
*/
|
*/
|
||||||
@StoreAt(filename="config.yml") // Explicitly call out what name this should have.
|
@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("Transition options enable migration from one database type to another. Use /bbox migrate.")
|
||||||
@ConfigComment("YAML and JSON are file-based databases.")
|
@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("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("If you use MONGODB, you must also run the BSBMongo plugin (not addon).")
|
||||||
@ConfigComment("See https://github.com/tastybento/bsbMongo/releases/.")
|
@ConfigComment("See https://github.com/tastybento/bsbMongo/releases/.")
|
||||||
@ConfigEntry(path = "general.database.type", video = "https://youtu.be/FFzCk5-y7-g")
|
@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")
|
@ConfigEntry(path = "general.database.max-saved-islands-per-tick")
|
||||||
private int maxSavedIslandsPerTick = 20;
|
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.")
|
@ConfigComment("Enable SSL connection to MongoDB, MariaDB, MySQL and PostgreSQL databases.")
|
||||||
@ConfigEntry(path = "general.database.use-ssl", since = "1.12.0")
|
@ConfigEntry(path = "general.database.use-ssl", since = "1.12.0")
|
||||||
private boolean useSSL = false;
|
private boolean useSSL = false;
|
||||||
@ -118,6 +128,16 @@ public class Settings implements ConfigObject {
|
|||||||
@ConfigEntry(path = "general.database.prefix-character", since = "1.13.0")
|
@ConfigEntry(path = "general.database.prefix-character", since = "1.13.0")
|
||||||
private String databasePrefix = "";
|
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<String, String> customPoolProperties = new HashMap<>();
|
||||||
|
|
||||||
@ConfigComment("MongoDB client connection URI to override default connection options.")
|
@ConfigComment("MongoDB client connection URI to override default connection options.")
|
||||||
@ConfigComment("See: https://docs.mongodb.com/manual/reference/connection-string/")
|
@ConfigComment("See: https://docs.mongodb.com/manual/reference/connection-string/")
|
||||||
@ConfigEntry(path = "general.database.mongodb-connection-uri", since = "1.14.0")
|
@ConfigEntry(path = "general.database.mongodb-connection-uri", since = "1.14.0")
|
||||||
@ -954,6 +974,17 @@ public class Settings implements ConfigObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets maximum pool size.
|
||||||
|
*
|
||||||
|
* @return the maximum pool size
|
||||||
|
*/
|
||||||
|
public int getMaximumPoolSize()
|
||||||
|
{
|
||||||
|
return maximumPoolSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets safe spot search range.
|
* Gets safe spot search range.
|
||||||
*
|
*
|
||||||
@ -965,6 +996,39 @@ public class Settings implements ConfigObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<String, String> getCustomPoolProperties()
|
||||||
|
{
|
||||||
|
return customPoolProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets custom pool properties.
|
||||||
|
*
|
||||||
|
* @param customPoolProperties the custom pool properties
|
||||||
|
*/
|
||||||
|
public void setCustomPoolProperties(Map<String, String> customPoolProperties)
|
||||||
|
{
|
||||||
|
this.customPoolProperties = customPoolProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets safe spot search range.
|
* Sets safe spot search range.
|
||||||
*
|
*
|
||||||
|
@ -7,6 +7,7 @@ import java.net.URL;
|
|||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -33,6 +34,19 @@ public class AddonClassLoader extends URLClassLoader {
|
|||||||
private final Addon addon;
|
private final Addon addon;
|
||||||
private final AddonsManager loader;
|
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)
|
public AddonClassLoader(AddonsManager addonsManager, YamlConfiguration data, File jarFile, ClassLoader parent)
|
||||||
throws InvalidAddonInheritException,
|
throws InvalidAddonInheritException,
|
||||||
MalformedURLException,
|
MalformedURLException,
|
||||||
@ -79,8 +93,27 @@ public class AddonClassLoader extends URLClassLoader {
|
|||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public static AddonDescription asDescription(YamlConfiguration data) throws InvalidAddonDescriptionException {
|
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")))
|
.authors(Objects.requireNonNull(data.getString("authors")))
|
||||||
|
// Optional elements
|
||||||
.metrics(data.getBoolean("metrics", true))
|
.metrics(data.getBoolean("metrics", true))
|
||||||
.repository(data.getString("repository", ""));
|
.repository(data.getString("repository", ""));
|
||||||
|
|
||||||
@ -92,7 +125,7 @@ public class AddonClassLoader extends URLClassLoader {
|
|||||||
if (softDepend != null) {
|
if (softDepend != null) {
|
||||||
builder.softDependencies(Arrays.asList(softDepend.split("\\s*,\\s*")));
|
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");
|
String apiVersion = data.getString("api-version");
|
||||||
if (apiVersion != null) {
|
if (apiVersion != null) {
|
||||||
|
@ -287,7 +287,7 @@ public final class AddonDescription {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "AddonDescription [" + (name != null ? "name=" + name + ", " : "")
|
return "AddonDescription [" + "name=" + name + ", "
|
||||||
+ "version=" + version + "]";
|
+ "version=" + version + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ import java.util.Optional;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
@ -514,18 +513,6 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
|||||||
return onlyPlayer;
|
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.
|
* 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}.
|
* If this is set to {@code true}, this command will only be runnable by objects implementing {@link Player}.
|
||||||
@ -663,7 +650,7 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
|||||||
/* ------------ */
|
/* ------------ */
|
||||||
|
|
||||||
String lastArg = args.length != 0 ? args[args.length - 1] : "";
|
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 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
|||||||
return command.getSubCommands().values().stream()
|
return command.getSubCommands().values().stream()
|
||||||
.filter(cmd -> !cmd.isHidden())
|
.filter(cmd -> !cmd.isHidden())
|
||||||
.filter(cmd -> !cmd.isOnlyPlayer() || sender.isOp() || (sender instanceof Player && cmd.getPermission() != null && (cmd.getPermission().isEmpty() || sender.hasPermission(cmd.getPermission()))) )
|
.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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -83,7 +83,7 @@ public class AdminDeleteCommand extends ConfirmableCommand {
|
|||||||
// Remove them from this island (it still exists and will be deleted later)
|
// Remove them from this island (it still exists and will be deleted later)
|
||||||
getIslands().removePlayer(getWorld(), targetUUID);
|
getIslands().removePlayer(getWorld(), targetUUID);
|
||||||
if (target.isPlayer() && target.isOnline()) {
|
if (target.isPlayer() && target.isOnline()) {
|
||||||
cleanUp(user, target);
|
cleanUp(target);
|
||||||
}
|
}
|
||||||
vector = oldIsland.getCenter().toVector();
|
vector = oldIsland.getCenter().toVector();
|
||||||
getIslands().deleteIsland(oldIsland, true, targetUUID);
|
getIslands().deleteIsland(oldIsland, true, targetUUID);
|
||||||
@ -95,7 +95,7 @@ public class AdminDeleteCommand extends ConfirmableCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cleanUp(User user, User target) {
|
private void cleanUp(User target) {
|
||||||
// Remove money inventory etc.
|
// Remove money inventory etc.
|
||||||
if (getIWM().isOnLeaveResetEnderChest(getWorld())) {
|
if (getIWM().isOnLeaveResetEnderChest(getWorld())) {
|
||||||
target.getPlayer().getEnderChest().clear();
|
target.getPlayer().getEnderChest().clear();
|
||||||
@ -122,7 +122,7 @@ public class AdminDeleteCommand extends ConfirmableCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Execute commands when leaving
|
// Execute commands when leaving
|
||||||
Util.runCommands(target, getIWM().getOnLeaveCommands(getWorld()), "leave");
|
Util.runCommands(target, target.getName(), getIWM().getOnLeaveCommands(getWorld()), "leave");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -55,11 +55,11 @@ public class AdminDeleteHomesCommand extends ConfirmableCommand {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Confirm
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean deleteHomes(User user, UUID targetUUID, Island island) {
|
private boolean deleteHomes(User user, Island island) {
|
||||||
island.removeHomes();
|
island.removeHomes();
|
||||||
user.sendMessage("general.success");
|
user.sendMessage("general.success");
|
||||||
return true;
|
return true;
|
||||||
|
@ -3,7 +3,6 @@ package world.bentobox.bentobox.api.commands.admin;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@ -98,7 +97,7 @@ public class AdminGetrankCommand extends CompositeCommand {
|
|||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
String lastArg = args.get(args.size() - 1);
|
String lastArg = args.get(args.size() - 1);
|
||||||
List<String> options = Bukkit.getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
|
List<String> options = Bukkit.getOnlinePlayers().stream().map(Player::getName).toList();
|
||||||
return Optional.of(Util.tabLimit(options, lastArg));
|
return Optional.of(Util.tabLimit(options, lastArg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package world.bentobox.bentobox.api.commands.admin;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||||
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
|
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
|
||||||
@ -26,7 +25,7 @@ public class AdminResetFlagsCommand extends ConfirmableCommand {
|
|||||||
super(parent, "resetflags");
|
super(parent, "resetflags");
|
||||||
options = getPlugin().getFlagsManager().getFlags().stream()
|
options = getPlugin().getFlagsManager().getFlags().stream()
|
||||||
.filter(f -> f.getType().equals(Type.PROTECTION) || f.getType().equals(Type.SETTING))
|
.filter(f -> f.getType().equals(Type.PROTECTION) || f.getType().equals(Type.SETTING))
|
||||||
.map(Flag::getID).collect(Collectors.toList());
|
.map(Flag::getID).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
package world.bentobox.bentobox.api.commands.admin;
|
package world.bentobox.bentobox.api.commands.admin;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||||
import world.bentobox.bentobox.api.user.User;
|
import world.bentobox.bentobox.api.user.User;
|
||||||
|
@ -50,7 +50,7 @@ public class AdminSetProtectionCenterCommand extends ConfirmableCommand
|
|||||||
public boolean canExecute(User user, String label, List<String> args) {
|
public boolean canExecute(User user, String label, List<String> args) {
|
||||||
if (args.size() == 3) {
|
if (args.size() == 3) {
|
||||||
// Get location
|
// Get location
|
||||||
targetLoc = getLocation(user, args);
|
targetLoc = getLocation(args);
|
||||||
} else {
|
} else {
|
||||||
targetLoc = new Location(getWorld(), user.getLocation().getBlockX(), user.getLocation().getBlockY(), user.getLocation().getBlockZ());
|
targetLoc = new Location(getWorld(), user.getLocation().getBlockX(), user.getLocation().getBlockY(), user.getLocation().getBlockZ());
|
||||||
}
|
}
|
||||||
@ -67,7 +67,7 @@ public class AdminSetProtectionCenterCommand extends ConfirmableCommand
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Location getLocation(User user, List<String> args) {
|
private Location getLocation(List<String> args) {
|
||||||
try {
|
try {
|
||||||
int x = Integer.parseInt(args.get(0));
|
int x = Integer.parseInt(args.get(0));
|
||||||
int y = Integer.parseInt(args.get(1));
|
int y = Integer.parseInt(args.get(1));
|
||||||
|
@ -4,7 +4,6 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
@ -140,7 +139,7 @@ public class AdminSetrankCommand extends CompositeCommand {
|
|||||||
return Optional.of(getPlugin().getRanksManager().getRanks()
|
return Optional.of(getPlugin().getRanksManager().getRanks()
|
||||||
.entrySet().stream()
|
.entrySet().stream()
|
||||||
.filter(entry -> entry.getValue() > RanksManager.VISITOR_RANK)
|
.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
|
// Return the player names again for the optional island owner argument
|
||||||
|
@ -8,7 +8,6 @@ import java.util.Locale;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
import org.eclipse.jdt.annotation.NonNull;
|
||||||
@ -88,12 +87,10 @@ public class AdminSettingsCommand extends CompositeCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean getIsland(User user, List<String> args) {
|
private boolean getIsland(User user, List<String> args) {
|
||||||
if (args.get(0).equalsIgnoreCase(SPAWN_ISLAND)) {
|
if (args.get(0).equalsIgnoreCase(SPAWN_ISLAND) && getIslands().getSpawn(getWorld()).isPresent()) {
|
||||||
if (getIslands().getSpawn(getWorld()).isPresent()) {
|
|
||||||
island = getIslands().getSpawn(getWorld()).get();
|
island = getIslands().getSpawn(getWorld()).get();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Get target player
|
// Get target player
|
||||||
@Nullable UUID targetUUID = Util.getUUID(args.get(0));
|
@Nullable UUID targetUUID = Util.getUUID(args.get(0));
|
||||||
if (targetUUID == null) {
|
if (targetUUID == null) {
|
||||||
@ -192,19 +189,18 @@ public class AdminSettingsCommand extends CompositeCommand {
|
|||||||
// Command line setting
|
// Command line setting
|
||||||
flag.ifPresent(f -> {
|
flag.ifPresent(f -> {
|
||||||
switch (f.getType()) {
|
switch (f.getType()) {
|
||||||
case PROTECTION:
|
case PROTECTION -> {
|
||||||
island.setFlag(f, rank);
|
island.setFlag(f, rank);
|
||||||
getIslands().save(island);
|
getIslands().save(island);
|
||||||
break;
|
}
|
||||||
case SETTING:
|
case SETTING -> {
|
||||||
island.setSettingsFlag(f, activeState);
|
island.setSettingsFlag(f, activeState);
|
||||||
getIslands().save(island);
|
getIslands().save(island);
|
||||||
break;
|
}
|
||||||
case WORLD_SETTING:
|
case WORLD_SETTING -> f.setSetting(getWorld(), activeState);
|
||||||
f.setSetting(getWorld(), activeState);
|
default -> {
|
||||||
break;
|
// Do nothing
|
||||||
default:
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
user.sendMessage("general.success");
|
user.sendMessage("general.success");
|
||||||
@ -270,7 +266,7 @@ public class AdminSettingsCommand extends CompositeCommand {
|
|||||||
.getRanks().entrySet().stream()
|
.getRanks().entrySet().stream()
|
||||||
.filter(en -> en.getValue() > RanksManager.BANNED_RANK && en.getValue() <= RanksManager.OWNER_RANK)
|
.filter(en -> en.getValue() > RanksManager.BANNED_RANK && en.getValue() <= RanksManager.OWNER_RANK)
|
||||||
.map(Entry::getKey)
|
.map(Entry::getKey)
|
||||||
.map(user::getTranslation).collect(Collectors.toList());
|
.map(user::getTranslation).toList();
|
||||||
case SETTING -> Arrays.asList(active, disabled);
|
case SETTING -> Arrays.asList(active, disabled);
|
||||||
default -> Collections.<String>emptyList();
|
default -> Collections.<String>emptyList();
|
||||||
}).orElse(Collections.emptyList());
|
}).orElse(Collections.emptyList());
|
||||||
|
@ -9,7 +9,12 @@ import world.bentobox.bentobox.api.commands.admin.deaths.AdminDeathsCommand;
|
|||||||
import world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand;
|
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.range.AdminRangeCommand;
|
||||||
import world.bentobox.bentobox.api.commands.admin.resets.AdminResetsCommand;
|
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.localization.TextVariables;
|
||||||
import world.bentobox.bentobox.api.user.User;
|
import world.bentobox.bentobox.api.user.User;
|
||||||
|
|
||||||
@ -25,7 +30,7 @@ public abstract class DefaultAdminCommand extends CompositeCommand {
|
|||||||
*
|
*
|
||||||
* @param addon - GameMode addon
|
* @param addon - GameMode addon
|
||||||
*/
|
*/
|
||||||
public DefaultAdminCommand(GameModeAddon addon) {
|
protected DefaultAdminCommand(GameModeAddon addon) {
|
||||||
// Register command with alias from config.
|
// Register command with alias from config.
|
||||||
super(addon,
|
super(addon,
|
||||||
addon.getWorldSettings().getAdminCommandAliases().split(" ")[0],
|
addon.getWorldSettings().getAdminCommandAliases().split(" ")[0],
|
||||||
|
@ -2,7 +2,6 @@ package world.bentobox.bentobox.api.commands.admin.blueprints;
|
|||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
|
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
|
||||||
|
@ -2,13 +2,11 @@ package world.bentobox.bentobox.api.commands.admin.blueprints;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
|
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
|
||||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||||
import world.bentobox.bentobox.api.user.User;
|
import world.bentobox.bentobox.api.user.User;
|
||||||
import world.bentobox.bentobox.blueprints.Blueprint;
|
import world.bentobox.bentobox.blueprints.Blueprint;
|
||||||
import world.bentobox.bentobox.blueprints.BlueprintClipboard;
|
|
||||||
import world.bentobox.bentobox.managers.BlueprintsManager;
|
import world.bentobox.bentobox.managers.BlueprintsManager;
|
||||||
import world.bentobox.bentobox.util.Util;
|
import world.bentobox.bentobox.util.Util;
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ public class AdminBlueprintSaveCommand extends ConfirmableCommand
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clipboard.getBlueprint().getBedrock() == null)
|
if (clipboard.getBlueprint() != null && clipboard.getBlueprint().getBedrock() == null)
|
||||||
{
|
{
|
||||||
// Bedrock is required for all blueprints.
|
// Bedrock is required for all blueprints.
|
||||||
user.sendMessage("commands.admin.blueprint.bedrock-required");
|
user.sendMessage("commands.admin.blueprint.bedrock-required");
|
||||||
|
@ -17,8 +17,10 @@ import world.bentobox.bentobox.database.objects.Island;
|
|||||||
*/
|
*/
|
||||||
public class NamePrompt extends StringPrompt {
|
public class NamePrompt extends StringPrompt {
|
||||||
|
|
||||||
private @NonNull final Island island;
|
@NonNull
|
||||||
private @NonNull final User user;
|
private final Island island;
|
||||||
|
@NonNull
|
||||||
|
private final User user;
|
||||||
private final String oldName;
|
private final String oldName;
|
||||||
private final BentoBox plugin;
|
private final BentoBox plugin;
|
||||||
|
|
||||||
@ -30,7 +32,8 @@ public class NamePrompt extends StringPrompt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull String getPromptText(@NonNull ConversationContext context) {
|
@NonNull
|
||||||
|
public String getPromptText(@NonNull ConversationContext context) {
|
||||||
return user.getTranslation("commands.island.renamehome.enter-new-name");
|
return user.getTranslation("commands.island.renamehome.enter-new-name");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,10 +99,10 @@ public class AdminRangeDisplayCommand extends CompositeCommand {
|
|||||||
// Draw 3 "stages" (one line below, at and above player's y coordinate)
|
// Draw 3 "stages" (one line below, at and above player's y coordinate)
|
||||||
for (int stage = -1 ; stage <= 1 ; stage++) {
|
for (int stage = -1 ; stage <= 1 ; stage++) {
|
||||||
for (int i = -range ; i <= range ; i++) {
|
for (int i = -range ; i <= range ; i++) {
|
||||||
user.spawnParticle(particle, dustOptions, center.getBlockX() + i, playerY + stage, center.getBlockZ() + range);
|
user.spawnParticle(particle, dustOptions, (double)center.getBlockX() + i, (double)playerY + stage, (double)center.getBlockZ() + range);
|
||||||
user.spawnParticle(particle, dustOptions, center.getBlockX() + i, playerY + stage, center.getBlockZ() - range);
|
user.spawnParticle(particle, dustOptions, (double)center.getBlockX() + i, (double)playerY + stage, (double)center.getBlockZ() - range);
|
||||||
user.spawnParticle(particle, dustOptions, center.getBlockX() + range, playerY + stage, center.getBlockZ() + i);
|
user.spawnParticle(particle, dustOptions, (double)center.getBlockX() + range, (double)playerY + stage, (double)center.getBlockZ() + i);
|
||||||
user.spawnParticle(particle, dustOptions, center.getBlockX() - range, playerY + stage, center.getBlockZ() + i);
|
user.spawnParticle(particle, dustOptions, (double)center.getBlockX() - range, (double)playerY + stage, (double)center.getBlockZ() + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import java.util.List;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
@ -142,7 +141,7 @@ public class IslandBanCommand extends CompositeCommand {
|
|||||||
.filter(p -> !p.getUniqueId().equals(user.getUniqueId()))
|
.filter(p -> !p.getUniqueId().equals(user.getUniqueId()))
|
||||||
.filter(p -> !island.isBanned(p.getUniqueId()))
|
.filter(p -> !island.isBanned(p.getUniqueId()))
|
||||||
.filter(p -> user.getPlayer().canSee(p))
|
.filter(p -> user.getPlayer().canSee(p))
|
||||||
.map(Player::getName).collect(Collectors.toList());
|
.map(Player::getName).toList();
|
||||||
return Optional.of(Util.tabLimit(options, lastArg));
|
return Optional.of(Util.tabLimit(options, lastArg));
|
||||||
} else {
|
} else {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
|
@ -3,7 +3,6 @@ package world.bentobox.bentobox.api.commands.island;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||||
@ -57,7 +56,7 @@ public class IslandBanlistCommand extends CompositeCommand {
|
|||||||
// Title
|
// Title
|
||||||
user.sendMessage("commands.island.banlist.the-following");
|
user.sendMessage("commands.island.banlist.the-following");
|
||||||
// Create a nicely formatted list
|
// Create a nicely formatted list
|
||||||
List<String> names = island.getBanned().stream().map(u -> getPlayers().getName(u)).sorted().collect(Collectors.toList());
|
List<String> names = island.getBanned().stream().map(u -> getPlayers().getName(u)).sorted().toList();
|
||||||
List<String> lines = new ArrayList<>();
|
List<String> lines = new ArrayList<>();
|
||||||
StringBuilder line = new StringBuilder();
|
StringBuilder line = new StringBuilder();
|
||||||
// Put the names into lines of no more than 40 characters long, separated by commas
|
// Put the names into lines of no more than 40 characters long, separated by commas
|
||||||
|
@ -84,9 +84,9 @@ public class IslandDeletehomeCommand extends ConfirmableCommand {
|
|||||||
@Override
|
@Override
|
||||||
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
|
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
|
||||||
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
|
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
|
||||||
Island island = getIslands().getIsland(getWorld(), user.getUniqueId());
|
Island is = getIslands().getIsland(getWorld(), user.getUniqueId());
|
||||||
if (island != null) {
|
if (is != null) {
|
||||||
return Optional.of(Util.tabLimit(new ArrayList<>(island.getHomes().keySet()), lastArg));
|
return Optional.of(Util.tabLimit(new ArrayList<>(is.getHomes().keySet()), lastArg));
|
||||||
} else {
|
} else {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import java.util.List;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
@ -156,7 +155,7 @@ public class IslandExpelCommand extends CompositeCommand {
|
|||||||
.filter(p -> !p.isOp()) // Not op
|
.filter(p -> !p.isOp()) // Not op
|
||||||
.filter(p -> !p.hasPermission(this.getPermissionPrefix() + "admin.noexpel"))
|
.filter(p -> !p.hasPermission(this.getPermissionPrefix() + "admin.noexpel"))
|
||||||
.filter(p -> !p.hasPermission(this.getPermissionPrefix() + "mod.bypassexpel"))
|
.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) : "";
|
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
|
||||||
return Optional.of(Util.tabLimit(options, lastArg));
|
return Optional.of(Util.tabLimit(options, lastArg));
|
||||||
|
@ -55,14 +55,12 @@ public class IslandGoCommand extends DelayedTeleportCommand {
|
|||||||
user.sendMessage(Flags.PREVENT_TELEPORT_WHEN_FALLING.getHintReference());
|
user.sendMessage(Flags.PREVENT_TELEPORT_WHEN_FALLING.getHintReference());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!args.isEmpty()) {
|
if (!args.isEmpty() && !getIslands().isHomeLocation(island, String.join(" ", args))) {
|
||||||
if (!getIslands().isHomeLocation(island, String.join(" ", args))) {
|
|
||||||
user.sendMessage("commands.island.go.unknown-home");
|
user.sendMessage("commands.island.go.unknown-home");
|
||||||
user.sendMessage("commands.island.sethome.homes-are");
|
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));
|
island.getHomes().keySet().stream().filter(s -> !s.isEmpty()).forEach(s -> user.sendMessage("commands.island.sethome.home-list-syntax", TextVariables.NAME, s));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,9 +87,9 @@ public class IslandRenamehomeCommand extends ConfirmableCommand {
|
|||||||
@Override
|
@Override
|
||||||
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
|
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
|
||||||
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
|
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
|
||||||
Island island = getIslands().getIsland(getWorld(), user.getUniqueId());
|
Island is = getIslands().getIsland(getWorld(), user.getUniqueId());
|
||||||
if (island != null) {
|
if (is != null) {
|
||||||
return Optional.of(Util.tabLimit(new ArrayList<>(island.getHomes().keySet()), lastArg));
|
return Optional.of(Util.tabLimit(new ArrayList<>(is.getHomes().keySet()), lastArg));
|
||||||
} else {
|
} else {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
@ -187,7 +187,7 @@ public class IslandResetCommand extends ConfirmableCommand {
|
|||||||
getIslands().removePlayer(getWorld(), memberUUID);
|
getIslands().removePlayer(getWorld(), memberUUID);
|
||||||
|
|
||||||
// Clean player
|
// Clean player
|
||||||
getPlayers().cleanLeavingPlayer(getWorld(), member, false);
|
getPlayers().cleanLeavingPlayer(getWorld(), member, false, island);
|
||||||
|
|
||||||
// Fire event
|
// Fire event
|
||||||
TeamEvent.builder()
|
TeamEvent.builder()
|
||||||
|
@ -4,7 +4,6 @@ import java.util.List;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
@ -112,7 +111,7 @@ public class IslandUnbanCommand extends CompositeCommand {
|
|||||||
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
|
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
|
||||||
Island island = getIslands().getIsland(getWorld(), user.getUniqueId());
|
Island island = getIslands().getIsland(getWorld(), user.getUniqueId());
|
||||||
if (island != null) {
|
if (island != null) {
|
||||||
List<String> options = island.getBanned().stream().map(getPlayers()::getName).collect(Collectors.toList());
|
List<String> options = island.getBanned().stream().map(getPlayers()::getName).toList();
|
||||||
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
|
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
|
||||||
return Optional.of(Util.tabLimit(options, lastArg));
|
return Optional.of(Util.tabLimit(options, lastArg));
|
||||||
} else {
|
} else {
|
||||||
|
@ -7,7 +7,6 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
@ -91,12 +90,11 @@ public class IslandTeamCommand extends CompositeCommand {
|
|||||||
|
|
||||||
private void showMembers(Island island, User user) {
|
private void showMembers(Island island, User user) {
|
||||||
// Gather online members
|
// Gather online members
|
||||||
List<UUID> onlineMembers = island
|
long count = island
|
||||||
.getMemberSet(RanksManager.MEMBER_RANK)
|
.getMemberSet(RanksManager.MEMBER_RANK)
|
||||||
.stream()
|
.stream()
|
||||||
.filter(uuid -> Bukkit.getOfflinePlayer(uuid)
|
.filter(uuid -> Util.getOnlinePlayerList(user).contains(Bukkit.getOfflinePlayer(uuid).getName()))
|
||||||
.isOnline())
|
.count();
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
// List of ranks that we will loop through
|
// 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};
|
Integer[] ranks = new Integer[]{RanksManager.OWNER_RANK, RanksManager.SUB_OWNER_RANK, RanksManager.MEMBER_RANK, RanksManager.TRUSTED_RANK, RanksManager.COOP_RANK};
|
||||||
@ -105,11 +103,11 @@ public class IslandTeamCommand extends CompositeCommand {
|
|||||||
user.sendMessage("commands.island.team.info.header",
|
user.sendMessage("commands.island.team.info.header",
|
||||||
"[max]", String.valueOf(getIslands().getMaxMembers(island, RanksManager.MEMBER_RANK)),
|
"[max]", String.valueOf(getIslands().getMaxMembers(island, RanksManager.MEMBER_RANK)),
|
||||||
"[total]", String.valueOf(island.getMemberSet().size()),
|
"[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
|
// We now need to get all online "members" of the island - incl. Trusted and coop
|
||||||
onlineMembers = island.getMemberSet(RanksManager.COOP_RANK).stream()
|
List<UUID> onlineMembers = island.getMemberSet(RanksManager.COOP_RANK).stream()
|
||||||
.filter(uuid -> Util.getOnlinePlayerList(user).contains(Bukkit.getOfflinePlayer(uuid).getName())).collect(Collectors.toList());
|
.filter(uuid -> Util.getOnlinePlayerList(user).contains(Bukkit.getOfflinePlayer(uuid).getName())).toList();
|
||||||
|
|
||||||
for (int rank : ranks) {
|
for (int rank : ranks) {
|
||||||
Set<UUID> players = island.getMemberSet(rank, false);
|
Set<UUID> players = island.getMemberSet(rank, false);
|
||||||
@ -123,6 +121,12 @@ public class IslandTeamCommand extends CompositeCommand {
|
|||||||
TextVariables.RANK, user.getTranslation(getPlugin().getRanksManager().getRank(rank)),
|
TextVariables.RANK, user.getTranslation(getPlugin().getRanksManager().getRank(rank)),
|
||||||
TextVariables.NUMBER, String.valueOf(island.getMemberSet(rank, false).size()));
|
TextVariables.NUMBER, String.valueOf(island.getMemberSet(rank, false).size()));
|
||||||
}
|
}
|
||||||
|
displayOnOffline(user, rank, island, onlineMembers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void displayOnOffline(User user, int rank, Island island, List<UUID> onlineMembers) {
|
||||||
for (UUID member : island.getMemberSet(rank, false)) {
|
for (UUID member : island.getMemberSet(rank, false)) {
|
||||||
OfflinePlayer offlineMember = Bukkit.getOfflinePlayer(member);
|
OfflinePlayer offlineMember = Bukkit.getOfflinePlayer(member);
|
||||||
if (onlineMembers.contains(member)) {
|
if (onlineMembers.contains(member)) {
|
||||||
@ -162,8 +166,7 @@ public class IslandTeamCommand extends CompositeCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean fireEvent(User user) {
|
private boolean fireEvent(User user) {
|
||||||
|
@ -96,7 +96,6 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
|
|||||||
// Remove the invite
|
// Remove the invite
|
||||||
itc.removeInvite(playerUUID);
|
itc.removeInvite(playerUUID);
|
||||||
User inviter = User.getInstance(invite.getInviter());
|
User inviter = User.getInstance(invite.getInviter());
|
||||||
if (inviter != null) {
|
|
||||||
Island island = getIslands().getIsland(getWorld(), inviter);
|
Island island = getIslands().getIsland(getWorld(), inviter);
|
||||||
if (island != null) {
|
if (island != null) {
|
||||||
if (island.getMemberSet(RanksManager.TRUSTED_RANK, false).size() > getIslands().getMaxMembers(island, RanksManager.TRUSTED_RANK)) {
|
if (island.getMemberSet(RanksManager.TRUSTED_RANK, false).size() > getIslands().getMaxMembers(island, RanksManager.TRUSTED_RANK)) {
|
||||||
@ -111,7 +110,10 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
|
|||||||
.reason(IslandEvent.Reason.RANK_CHANGE)
|
.reason(IslandEvent.Reason.RANK_CHANGE)
|
||||||
.rankChange(island.getRank(user), RanksManager.TRUSTED_RANK)
|
.rankChange(island.getRank(user), RanksManager.TRUSTED_RANK)
|
||||||
.build();
|
.build();
|
||||||
|
if (inviter.isOnline()) {
|
||||||
inviter.sendMessage("commands.island.team.trust.success", TextVariables.NAME, user.getName());
|
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());
|
user.sendMessage("commands.island.team.trust.you-are-trusted", TextVariables.NAME, inviter.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,7 +123,6 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
|
|||||||
// Remove the invite
|
// Remove the invite
|
||||||
itc.removeInvite(playerUUID);
|
itc.removeInvite(playerUUID);
|
||||||
User inviter = User.getInstance(invite.getInviter());
|
User inviter = User.getInstance(invite.getInviter());
|
||||||
if (inviter != null) {
|
|
||||||
Island island = getIslands().getIsland(getWorld(), inviter);
|
Island island = getIslands().getIsland(getWorld(), inviter);
|
||||||
if (island != null) {
|
if (island != null) {
|
||||||
if (island.getMemberSet(RanksManager.COOP_RANK, false).size() > getIslands().getMaxMembers(island, RanksManager.COOP_RANK)) {
|
if (island.getMemberSet(RanksManager.COOP_RANK, false).size() > getIslands().getMaxMembers(island, RanksManager.COOP_RANK)) {
|
||||||
@ -136,7 +137,10 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
|
|||||||
.reason(IslandEvent.Reason.RANK_CHANGE)
|
.reason(IslandEvent.Reason.RANK_CHANGE)
|
||||||
.rankChange(island.getRank(user), RanksManager.COOP_RANK)
|
.rankChange(island.getRank(user), RanksManager.COOP_RANK)
|
||||||
.build();
|
.build();
|
||||||
|
if (inviter.isOnline()) {
|
||||||
inviter.sendMessage("commands.island.team.coop.success", TextVariables.NAME, user.getName());
|
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());
|
user.sendMessage("commands.island.team.coop.you-are-a-coop-member", TextVariables.NAME, inviter.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -153,7 +157,7 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
|
|||||||
user.sendMessage(INVALID_INVITE);
|
user.sendMessage(INVALID_INVITE);
|
||||||
return;
|
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");
|
user.sendMessage("commands.island.team.invite.errors.island-is-full");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -172,6 +176,10 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
|
|||||||
// Put player back into normal mode
|
// Put player back into normal mode
|
||||||
user.setGameMode(getIWM().getDefaultGameMode(getWorld()));
|
user.setGameMode(getIWM().getDefaultGameMode(getWorld()));
|
||||||
|
|
||||||
|
// Execute commands
|
||||||
|
String ownerName = this.getPlayers().getName(teamIsland.getOwner());
|
||||||
|
Util.runCommands(user, ownerName, getIWM().getOnJoinCommands(getWorld()), "join");
|
||||||
|
|
||||||
});
|
});
|
||||||
// Reset deaths
|
// Reset deaths
|
||||||
if (getIWM().isTeamJoinDeathReset(getWorld())) {
|
if (getIWM().isTeamJoinDeathReset(getWorld())) {
|
||||||
@ -179,7 +187,7 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
|
|||||||
}
|
}
|
||||||
user.sendMessage("commands.island.team.invite.accept.you-joined-island", TextVariables.LABEL, getTopLabel());
|
user.sendMessage("commands.island.team.invite.accept.you-joined-island", TextVariables.LABEL, getTopLabel());
|
||||||
User inviter = User.getInstance(invite.getInviter());
|
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());
|
inviter.sendMessage("commands.island.team.invite.accept.name-joined-your-island", TextVariables.NAME, user.getName());
|
||||||
}
|
}
|
||||||
getIslands().save(teamIsland);
|
getIslands().save(teamIsland);
|
||||||
@ -224,7 +232,5 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
|
|||||||
user.getPlayer().setTotalExperience(0);
|
user.getPlayer().setTotalExperience(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute commands
|
|
||||||
Util.runCommands(user, getIWM().getOnJoinCommands(getWorld()), "join");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ public class IslandTeamInviteCommand extends CompositeCommand {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Check for space on team
|
// 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");
|
user.sendMessage("commands.island.team.invite.errors.island-is-full");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import java.util.List;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
@ -103,7 +102,7 @@ public class IslandTeamKickCommand extends ConfirmableCommand {
|
|||||||
|
|
||||||
getIslands().removePlayer(getWorld(), targetUUID);
|
getIslands().removePlayer(getWorld(), targetUUID);
|
||||||
// Clean the target player
|
// 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());
|
user.sendMessage("commands.island.team.kick.success", TextVariables.NAME, target.getName());
|
||||||
IslandEvent.builder()
|
IslandEvent.builder()
|
||||||
@ -131,7 +130,7 @@ public class IslandTeamKickCommand extends ConfirmableCommand {
|
|||||||
List<String> options = island.getMemberSet().stream()
|
List<String> options = island.getMemberSet().stream()
|
||||||
.filter(uuid -> island.getRank(uuid) >= RanksManager.MEMBER_RANK)
|
.filter(uuid -> island.getRank(uuid) >= RanksManager.MEMBER_RANK)
|
||||||
.map(Bukkit::getOfflinePlayer)
|
.map(Bukkit::getOfflinePlayer)
|
||||||
.map(OfflinePlayer::getName).collect(Collectors.toList());
|
.map(OfflinePlayer::getName).toList();
|
||||||
|
|
||||||
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
|
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
|
||||||
return Optional.of(Util.tabLimit(options, lastArg));
|
return Optional.of(Util.tabLimit(options, lastArg));
|
||||||
|
@ -82,7 +82,7 @@ public class IslandTeamLeaveCommand extends ConfirmableCommand {
|
|||||||
}
|
}
|
||||||
getIslands().setLeaveTeam(getWorld(), user.getUniqueId());
|
getIslands().setLeaveTeam(getWorld(), user.getUniqueId());
|
||||||
// Clean the player
|
// Clean the player
|
||||||
getPlayers().cleanLeavingPlayer(getWorld(), user, false);
|
getPlayers().cleanLeavingPlayer(getWorld(), user, false, island);
|
||||||
|
|
||||||
// Add cooldown for this player and target
|
// Add cooldown for this player and target
|
||||||
if (getSettings().getInviteCooldown() > 0 && getParent() != null) {
|
if (getSettings().getInviteCooldown() > 0 && getParent() != null) {
|
||||||
|
@ -3,7 +3,6 @@ package world.bentobox.bentobox.api.commands.island.team;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
@ -125,7 +124,7 @@ public class IslandTeamPromoteCommand extends CompositeCommand {
|
|||||||
if (island != null) {
|
if (island != null) {
|
||||||
List<String> options = island.getMemberSet().stream()
|
List<String> options = island.getMemberSet().stream()
|
||||||
.map(Bukkit::getOfflinePlayer)
|
.map(Bukkit::getOfflinePlayer)
|
||||||
.map(OfflinePlayer::getName).collect(Collectors.toList());
|
.map(OfflinePlayer::getName).toList();
|
||||||
|
|
||||||
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
|
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
|
||||||
return Optional.of(Util.tabLimit(options, lastArg));
|
return Optional.of(Util.tabLimit(options, lastArg));
|
||||||
|
@ -4,7 +4,6 @@ import java.util.List;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
@ -114,7 +113,7 @@ public class IslandTeamUncoopCommand extends CompositeCommand {
|
|||||||
List<String> options = island.getMembers().entrySet().stream()
|
List<String> options = island.getMembers().entrySet().stream()
|
||||||
.filter(e -> e.getValue() == RanksManager.COOP_RANK)
|
.filter(e -> e.getValue() == RanksManager.COOP_RANK)
|
||||||
.map(e -> Bukkit.getOfflinePlayer(e.getKey()))
|
.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) : "";
|
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
|
||||||
return Optional.of(Util.tabLimit(options, lastArg));
|
return Optional.of(Util.tabLimit(options, lastArg));
|
||||||
} else {
|
} else {
|
||||||
|
@ -4,7 +4,6 @@ import java.util.List;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
@ -114,7 +113,7 @@ public class IslandTeamUntrustCommand extends CompositeCommand {
|
|||||||
List<String> options = island.getMembers().entrySet().stream()
|
List<String> options = island.getMembers().entrySet().stream()
|
||||||
.filter(e -> e.getValue() == RanksManager.TRUSTED_RANK)
|
.filter(e -> e.getValue() == RanksManager.TRUSTED_RANK)
|
||||||
.map(e -> Bukkit.getOfflinePlayer(e.getKey()))
|
.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) : "";
|
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
|
||||||
return Optional.of(Util.tabLimit(options, lastArg));
|
return Optional.of(Util.tabLimit(options, lastArg));
|
||||||
} else {
|
} else {
|
||||||
|
@ -32,12 +32,12 @@ public interface WorldSettings extends ConfigObject {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return default rank settings for new islands
|
* @return default rank settings for new islands
|
||||||
* @deprecated since 1.21
|
* @deprecated Map of Flag, Integer does not allow to load other plugin/addon flags.
|
||||||
* 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.
|
* It cannot be replaced with Map of String, Integer due to compatibility issues.
|
||||||
* @see WorldSettings#getDefaultIslandFlagNames()
|
* @see WorldSettings#getDefaultIslandFlagNames()
|
||||||
|
* @since 1.21.0
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated(since="1.21.0", forRemoval=true)
|
||||||
Map<Flag, Integer> getDefaultIslandFlags();
|
Map<Flag, Integer> getDefaultIslandFlags();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,12 +57,12 @@ public interface WorldSettings extends ConfigObject {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return default settings for new
|
* @return default settings for new
|
||||||
* @deprecated since 1.21
|
* @deprecated Map of Flag, Integer does not allow to load other plugin/addon flags.
|
||||||
* 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.
|
* It cannot be replaced with Map of String, Integer due to compatibility issues.
|
||||||
* @see WorldSettings#getDefaultIslandSettingNames()
|
* @see WorldSettings#getDefaultIslandSettingNames()
|
||||||
|
* @since 1.21.0
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated(since="1.21.0", forRemoval=true)
|
||||||
Map<Flag, Integer> getDefaultIslandSettings();
|
Map<Flag, Integer> getDefaultIslandSettings();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,7 +70,7 @@ public interface WorldSettings extends ConfigObject {
|
|||||||
* This is necessary so users could specify any flag names in settings file from other plugins and addons.
|
* 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.
|
* Otherwise, Flag reader would mark flag as invalid and remove it.
|
||||||
* Default implementation is compatibility layer so GameModes that are not upgraded still works.
|
* 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.
|
* @return default settings for new islands.
|
||||||
*/
|
*/
|
||||||
default Map<String, Integer> getDefaultIslandSettingNames()
|
default Map<String, Integer> getDefaultIslandSettingNames()
|
||||||
@ -288,6 +288,8 @@ public interface WorldSettings extends ConfigObject {
|
|||||||
* Available placeholders for the commands are the following:
|
* Available placeholders for the commands are the following:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@code [player]}: name of the player</li>
|
* <li>{@code [player]}: name of the player</li>
|
||||||
|
* <li>{@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</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* <br/>
|
* <br/>
|
||||||
* Here are some examples of valid commands to execute:
|
* Here are some examples of valid commands to execute:
|
||||||
@ -345,6 +347,8 @@ public interface WorldSettings extends ConfigObject {
|
|||||||
* Available placeholders for the commands are the following:
|
* Available placeholders for the commands are the following:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@code [player]}: name of the player</li>
|
* <li>{@code [player]}: name of the player</li>
|
||||||
|
* <li>{@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</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* <br/>
|
* <br/>
|
||||||
* Here are some examples of valid commands to execute:
|
* Here are some examples of valid commands to execute:
|
||||||
@ -363,6 +367,22 @@ public interface WorldSettings extends ConfigObject {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of commands that should be executed when the player respawns after death if {@link Flags#ISLAND_RESPAWN} is true.<br/>
|
* Returns a list of commands that should be executed when the player respawns after death if {@link Flags#ISLAND_RESPAWN} is true.<br/>
|
||||||
|
* These commands are executed by the console, unless otherwise stated using the {@code [SUDO]} prefix, in which case they are executed by the player.<br/>
|
||||||
|
* <br/>
|
||||||
|
* Available placeholders for the commands are the following:
|
||||||
|
* <ul>
|
||||||
|
* <li>{@code [player]}: name of the player</li>
|
||||||
|
* <li>{@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</li>
|
||||||
|
* </ul>
|
||||||
|
* <br/>
|
||||||
|
* Here are some examples of valid commands to execute:
|
||||||
|
* <ul>
|
||||||
|
* <li>{@code "[SUDO] bbox version"}</li>
|
||||||
|
* <li>{@code "bsbadmin deaths set [player] 0"}</li>
|
||||||
|
* </ul>
|
||||||
|
* <br/>
|
||||||
|
* Note that player-executed commands might not work, as these commands can be run with said player being offline.
|
||||||
* @return a list of commands.
|
* @return a list of commands.
|
||||||
* @since 1.14.0
|
* @since 1.14.0
|
||||||
* @see #getOnJoinCommands()
|
* @see #getOnJoinCommands()
|
||||||
|
@ -53,8 +53,8 @@ public class Flag implements Comparable<Flag> {
|
|||||||
*/
|
*/
|
||||||
WORLD_SETTING(Material.GRASS_BLOCK);
|
WORLD_SETTING(Material.GRASS_BLOCK);
|
||||||
|
|
||||||
private @NonNull
|
@NonNull
|
||||||
final Material icon;
|
private final Material icon;
|
||||||
|
|
||||||
Type(@NonNull Material icon) {
|
Type(@NonNull Material icon) {
|
||||||
this.icon = icon;
|
this.icon = icon;
|
||||||
|
@ -95,8 +95,8 @@ public abstract class FlagListener implements Listener {
|
|||||||
* @param string - translation reference
|
* @param string - translation reference
|
||||||
*/
|
*/
|
||||||
public void noGo(@NonNull Event e, @NonNull Flag flag, boolean silent, String string) {
|
public void noGo(@NonNull Event e, @NonNull Flag flag, boolean silent, String string) {
|
||||||
if (e instanceof Cancellable) {
|
if (e instanceof Cancellable cancellable) {
|
||||||
((Cancellable)e).setCancelled(true);
|
cancellable.setCancelled(true);
|
||||||
}
|
}
|
||||||
if (user != null && !silent) {
|
if (user != null && !silent) {
|
||||||
user.notify(string, TextVariables.DESCRIPTION, user.getTranslation(flag.getHintReference()));
|
user.notify(string, TextVariables.DESCRIPTION, user.getTranslation(flag.getHintReference()));
|
||||||
@ -128,7 +128,7 @@ public abstract class FlagListener implements Listener {
|
|||||||
// Set user
|
// Set user
|
||||||
user = player == null ? null : User.getInstance(player);
|
user = player == null ? null : User.getInstance(player);
|
||||||
if (loc == null) {
|
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);
|
report(user, e, user.getLocation(), flag, Why.NULL_LOCATION);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -144,13 +144,7 @@ public abstract class FlagListener implements Listener {
|
|||||||
Optional<Island> island = getIslands().getProtectedIslandAt(loc);
|
Optional<Island> island = getIslands().getProtectedIslandAt(loc);
|
||||||
// Handle Settings Flag
|
// Handle Settings Flag
|
||||||
if (flag.getType().equals(Flag.Type.SETTING)) {
|
if (flag.getType().equals(Flag.Type.SETTING)) {
|
||||||
// If the island exists, return the setting, otherwise return the default setting for this flag
|
return processSetting(flag, island, e, loc);
|
||||||
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()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Protection flag
|
// Protection flag
|
||||||
@ -169,31 +163,14 @@ public abstract class FlagListener implements Listener {
|
|||||||
|
|
||||||
// Handle World Settings
|
// Handle World Settings
|
||||||
if (flag.getType().equals(Flag.Type.WORLD_SETTING)) {
|
if (flag.getType().equals(Flag.Type.WORLD_SETTING)) {
|
||||||
if (flag.isSetForWorld(loc.getWorld())) {
|
return processWorldSetting(flag, loc, e, silent);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the plugin is set in User (required for testing)
|
// Check if the plugin is set in User (required for testing)
|
||||||
User.setPlugin(plugin);
|
User.setPlugin(plugin);
|
||||||
|
|
||||||
if (island.isPresent()) {
|
if (island.isPresent()) {
|
||||||
// If it is not allowed on the island, "bypass island" moderators can do anything
|
return processBypass(flag, island.get(), e, loc, silent);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
// The player is in the world, but not on an island, so general world settings apply
|
// The player is in the world, but not on an island, so general world settings apply
|
||||||
if (flag.isSetForWorld(loc.getWorld())) {
|
if (flag.isSetForWorld(loc.getWorld())) {
|
||||||
@ -206,6 +183,41 @@ public abstract class FlagListener implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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> 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
|
* Report why something did or did not happen for the admin why command
|
||||||
* @param user user involved
|
* @param user user involved
|
||||||
@ -229,7 +241,7 @@ public abstract class FlagListener implements Listener {
|
|||||||
.filter(p -> getPlugin().equals(p.getOwningPlugin())).findFirst().map(MetadataValue::asString).orElse("");
|
.filter(p -> getPlugin().equals(p.getOwningPlugin())).findFirst().map(MetadataValue::asString).orElse("");
|
||||||
if (!issuerUUID.isEmpty()) {
|
if (!issuerUUID.isEmpty()) {
|
||||||
User issuer = User.getInstance(UUID.fromString(issuerUUID));
|
User issuer = User.getInstance(UUID.fromString(issuerUUID));
|
||||||
if (issuer != null && issuer.isPlayer()) {
|
if (issuer.isPlayer()) {
|
||||||
user.sendRawMessage(whyEvent);
|
user.sendRawMessage(whyEvent);
|
||||||
user.sendRawMessage(whyBypass);
|
user.sendRawMessage(whyBypass);
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
package world.bentobox.bentobox.api.flags.clicklisteners;
|
package world.bentobox.bentobox.api.flags.clicklisteners;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
import org.bukkit.event.inventory.ClickType;
|
import org.bukkit.event.inventory.ClickType;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import world.bentobox.bentobox.BentoBox;
|
import world.bentobox.bentobox.BentoBox;
|
||||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||||
import world.bentobox.bentobox.api.events.flags.FlagProtectionChangeEvent;
|
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.localization.TextVariables;
|
||||||
import world.bentobox.bentobox.api.panels.Panel;
|
import world.bentobox.bentobox.api.panels.Panel;
|
||||||
import world.bentobox.bentobox.api.panels.PanelItem;
|
import world.bentobox.bentobox.api.panels.PanelItem;
|
||||||
@ -57,13 +58,13 @@ public class CycleClick implements PanelItem.ClickHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
// This click listener is used with TabbedPanel and SettingsTabs only
|
||||||
TabbedPanel tp = (TabbedPanel)panel;
|
TabbedPanel tp = (TabbedPanel)panel;
|
||||||
SettingsTab st = (SettingsTab)tp.getActiveTab();
|
SettingsTab st = (SettingsTab)tp.getActiveTab();
|
||||||
// Get the island for this tab
|
// Get the island for this tab
|
||||||
island = st.getIsland();
|
island = st.getIsland();
|
||||||
this.user = user;
|
this.user = user2;
|
||||||
changeOccurred = false;
|
changeOccurred = false;
|
||||||
// Permission prefix
|
// Permission prefix
|
||||||
String prefix = plugin.getIWM().getPermissionPrefix(Util.getWorld(user.getWorld()));
|
String prefix = plugin.getIWM().getPermissionPrefix(Util.getWorld(user.getWorld()));
|
||||||
@ -85,6 +86,35 @@ public class CycleClick implements PanelItem.ClickHandler {
|
|||||||
// Rank
|
// Rank
|
||||||
int currentRank = island.getFlag(flag);
|
int currentRank = island.getFlag(flag);
|
||||||
if (click.equals(ClickType.LEFT)) {
|
if (click.equals(ClickType.LEFT)) {
|
||||||
|
leftClick(flag, rm, currentRank);
|
||||||
|
|
||||||
|
} else if (click.equals(ClickType.RIGHT)) {
|
||||||
|
rightClick(flag, rm, currentRank);
|
||||||
|
|
||||||
|
} else if (click.equals(ClickType.SHIFT_LEFT) && user2.isOp()) {
|
||||||
|
leftShiftClick(flag);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void leftClick(Flag flag, RanksManager rm, int currentRank) {
|
||||||
if (currentRank >= maxRank) {
|
if (currentRank >= maxRank) {
|
||||||
island.setFlag(flag, minRank);
|
island.setFlag(flag, minRank);
|
||||||
} else {
|
} else {
|
||||||
@ -99,7 +129,10 @@ public class CycleClick implements PanelItem.ClickHandler {
|
|||||||
// Fire events for all subflags as well
|
// Fire events for all subflags as well
|
||||||
flag.getSubflags().forEach(subflag -> Bukkit.getPluginManager().callEvent(new FlagProtectionChangeEvent(island, user.getUniqueId(), subflag, island.getFlag(subflag))));
|
flag.getSubflags().forEach(subflag -> Bukkit.getPluginManager().callEvent(new FlagProtectionChangeEvent(island, user.getUniqueId(), subflag, island.getFlag(subflag))));
|
||||||
}
|
}
|
||||||
} else if (click.equals(ClickType.RIGHT)) {
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void rightClick(Flag flag, RanksManager rm, int currentRank) {
|
||||||
if (currentRank <= minRank) {
|
if (currentRank <= minRank) {
|
||||||
island.setFlag(flag, maxRank);
|
island.setFlag(flag, maxRank);
|
||||||
} else {
|
} else {
|
||||||
@ -114,7 +147,10 @@ public class CycleClick implements PanelItem.ClickHandler {
|
|||||||
// Fire events for all subflags as well
|
// Fire events for all subflags as well
|
||||||
flag.getSubflags().forEach(subflag -> Bukkit.getPluginManager().callEvent(new FlagProtectionChangeEvent(island, user.getUniqueId(), subflag, island.getFlag(subflag))));
|
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()) {
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void leftShiftClick(Flag flag) {
|
||||||
if (!plugin.getIWM().getHiddenFlags(user.getWorld()).contains(flag.getID())) {
|
if (!plugin.getIWM().getHiddenFlags(user.getWorld()).contains(flag.getID())) {
|
||||||
plugin.getIWM().getHiddenFlags(user.getWorld()).add(flag.getID());
|
plugin.getIWM().getHiddenFlags(user.getWorld()).add(flag.getID());
|
||||||
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_GLASS_BREAK, 1F, 1F);
|
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_GLASS_BREAK, 1F, 1F);
|
||||||
@ -124,22 +160,7 @@ public class CycleClick implements PanelItem.ClickHandler {
|
|||||||
}
|
}
|
||||||
// Save changes
|
// Save changes
|
||||||
plugin.getIWM().getAddon(user.getWorld()).ifPresent(GameModeAddon::saveWorldSettings);
|
plugin.getIWM().getAddon(user.getWorld()).ifPresent(GameModeAddon::saveWorldSettings);
|
||||||
}
|
|
||||||
});
|
|
||||||
} 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",
|
|
||||||
TextVariables.RANK,
|
|
||||||
user.getTranslation(plugin.getRanksManager().getRank(Objects.requireNonNull(island).getRank(user))));
|
|
||||||
}
|
|
||||||
|
|
||||||
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_METAL_HIT, 1F, 1F);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
package world.bentobox.bentobox.api.flags.clicklisteners;
|
package world.bentobox.bentobox.api.flags.clicklisteners;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
import org.bukkit.event.inventory.ClickType;
|
import org.bukkit.event.inventory.ClickType;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import world.bentobox.bentobox.BentoBox;
|
import world.bentobox.bentobox.BentoBox;
|
||||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||||
import world.bentobox.bentobox.api.events.flags.FlagSettingChangeEvent;
|
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.localization.TextVariables;
|
||||||
import world.bentobox.bentobox.api.panels.Panel;
|
import world.bentobox.bentobox.api.panels.Panel;
|
||||||
import world.bentobox.bentobox.api.panels.PanelItem.ClickHandler;
|
import world.bentobox.bentobox.api.panels.PanelItem.ClickHandler;
|
||||||
@ -60,18 +61,7 @@ public class IslandToggleClick implements ClickHandler {
|
|||||||
{
|
{
|
||||||
if (click.equals(ClickType.SHIFT_LEFT) && user.isOp())
|
if (click.equals(ClickType.SHIFT_LEFT) && user.isOp())
|
||||||
{
|
{
|
||||||
if (!plugin.getIWM().getHiddenFlags(user.getWorld()).contains(flag.getID()))
|
shiftLeftClick(user, flag);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -82,6 +72,16 @@ public class IslandToggleClick implements ClickHandler {
|
|||||||
user.notify("protection.panel.flag-item.setting-cooldown");
|
user.notify("protection.panel.flag-item.setting-cooldown");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
toggleFlag(user, flag, island);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
reportError(user, island);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void toggleFlag(User user, Flag flag, Island island) {
|
||||||
// Toggle flag
|
// Toggle flag
|
||||||
island.toggleFlag(flag);
|
island.toggleFlag(flag);
|
||||||
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1F, 1F);
|
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1F, 1F);
|
||||||
@ -102,9 +102,10 @@ public class IslandToggleClick implements ClickHandler {
|
|||||||
subflag,
|
subflag,
|
||||||
island.isAllowed(subflag))));
|
island.isAllowed(subflag))));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
} else {
|
private void reportError(User user, Island island) {
|
||||||
if (island == null) {
|
if (island == null) {
|
||||||
user.sendMessage("general.errors.not-on-island");
|
user.sendMessage("general.errors.not-on-island");
|
||||||
} else {
|
} else {
|
||||||
@ -115,7 +116,22 @@ public class IslandToggleClick implements ClickHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_METAL_HIT, 1F, 1F);
|
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_METAL_HIT, 1F, 1F);
|
||||||
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,22 +36,22 @@ public class MetaDataValue {
|
|||||||
* @param value the value assigned to this metadata value
|
* @param value the value assigned to this metadata value
|
||||||
*/
|
*/
|
||||||
public MetaDataValue(@NonNull Object value) {
|
public MetaDataValue(@NonNull Object value) {
|
||||||
if (value instanceof Integer) {
|
if (value instanceof Integer i) {
|
||||||
intValue = (int)value;
|
intValue = i;
|
||||||
} else if (value instanceof Float) {
|
} else if (value instanceof Float f) {
|
||||||
floatValue = (float)value;
|
floatValue = f;
|
||||||
} else if (value instanceof Double) {
|
} else if (value instanceof Double d) {
|
||||||
doubleValue = (double)value;
|
doubleValue = d;
|
||||||
} else if (value instanceof Long) {
|
} else if (value instanceof Long l) {
|
||||||
longValue = (long)value;
|
longValue = l;
|
||||||
} else if (value instanceof Short) {
|
} else if (value instanceof Short s) {
|
||||||
shortValue = (short)value;
|
shortValue = s;
|
||||||
} else if (value instanceof Byte) {
|
} else if (value instanceof Byte b) {
|
||||||
byteValue = (byte)value;
|
byteValue = b;
|
||||||
} else if (value instanceof Boolean) {
|
} else if (value instanceof Boolean bo) {
|
||||||
booleanValue = (boolean)value;
|
booleanValue = bo;
|
||||||
} else if (value instanceof String) {
|
} else if (value instanceof String st) {
|
||||||
stringValue = (String)value;
|
stringValue = st;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ public interface Tab {
|
|||||||
String getName();
|
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
|
* @return a list of items in slot order
|
||||||
*/
|
*/
|
||||||
List<@Nullable PanelItem> getPanelItems();
|
List<@Nullable PanelItem> getPanelItems();
|
||||||
|
@ -31,8 +31,8 @@ public class TabbedPanel extends Panel implements PanelListener {
|
|||||||
private static final String PROTECTION_PANEL = "protection.panel.";
|
private static final String PROTECTION_PANEL = "protection.panel.";
|
||||||
private static final long ITEMS_PER_PAGE = 36;
|
private static final long ITEMS_PER_PAGE = 36;
|
||||||
private final TabbedPanelBuilder tpb;
|
private final TabbedPanelBuilder tpb;
|
||||||
private @NonNull
|
@NonNull
|
||||||
final BentoBox plugin = BentoBox.getInstance();
|
private final BentoBox plugin = BentoBox.getInstance();
|
||||||
private int activeTab;
|
private int activeTab;
|
||||||
private int activePage;
|
private int activePage;
|
||||||
private boolean closed;
|
private boolean closed;
|
||||||
|
@ -96,11 +96,11 @@ public class TemplatedPanel extends Panel
|
|||||||
{
|
{
|
||||||
for (int k = 0; k < this.panelTemplate.content()[i].length; k++)
|
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);
|
int counter = this.typeSlotMap.computeIfAbsent(type, key -> 0);
|
||||||
this.typeSlotMap.put(type, counter + 1);
|
this.typeSlotMap.put(type, counter + 1);
|
||||||
@ -226,11 +226,11 @@ public class TemplatedPanel extends Panel
|
|||||||
// Analyze the template
|
// Analyze the template
|
||||||
for (int i = 0; i < 5; i++)
|
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);
|
int counter = this.typeSlotMap.computeIfAbsent(type, key -> 0);
|
||||||
this.typeSlotMap.put(type, counter + 1);
|
this.typeSlotMap.put(type, counter + 1);
|
||||||
@ -289,11 +289,11 @@ public class TemplatedPanel extends Panel
|
|||||||
{
|
{
|
||||||
for (int k = 0; k < 3; k++)
|
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);
|
int counter = this.typeSlotMap.computeIfAbsent(type, key -> 0);
|
||||||
this.typeSlotMap.put(type, counter + 1);
|
this.typeSlotMap.put(type, counter + 1);
|
||||||
@ -354,41 +354,41 @@ public class TemplatedPanel extends Panel
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method passes button creation from given record template.
|
* 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.
|
* @return PanelItem of the template, otherwise null.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@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.
|
// Immediate exit if record is null.
|
||||||
return 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.
|
// 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
|
else
|
||||||
{
|
{
|
||||||
PanelItemBuilder itemBuilder = new PanelItemBuilder();
|
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
|
// If there are generic click handlers that could be added, then this is a place
|
||||||
@ -402,19 +402,19 @@ public class TemplatedPanel extends Panel
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method passes button to the type creator, if that exists.
|
* 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.
|
* @return PanelItem of the button created by typeCreator, otherwise null.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private PanelItem makeAddonButton(@NonNull ItemTemplateRecord record)
|
private PanelItem makeAddonButton(@NonNull ItemTemplateRecord rec)
|
||||||
{
|
{
|
||||||
// Get object type.
|
// Get object type.
|
||||||
String type = String.valueOf(record.dataMap().getOrDefault("type", ""));
|
String type = String.valueOf(rec.dataMap().getOrDefault("type", ""));
|
||||||
|
|
||||||
if (!this.typeCreators.containsKey(type))
|
if (!this.typeCreators.containsKey(type))
|
||||||
{
|
{
|
||||||
// There are no object with a given type.
|
// There are no object with a given type.
|
||||||
return this.makeFallBack(record.fallback());
|
return this.makeFallBack(rec.fallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
BiFunction<ItemTemplateRecord, ItemSlot, PanelItem> buttonBuilder = this.typeCreators.get(type);
|
BiFunction<ItemTemplateRecord, ItemSlot, PanelItem> buttonBuilder = this.typeCreators.get(type);
|
||||||
@ -426,48 +426,48 @@ public class TemplatedPanel extends Panel
|
|||||||
this.typeIndex.put(type, itemSlot.nextItemSlot());
|
this.typeIndex.put(type, itemSlot.nextItemSlot());
|
||||||
|
|
||||||
// Try to get next object.
|
// Try to get next object.
|
||||||
PanelItem item = buttonBuilder.apply(record, itemSlot);
|
PanelItem item = buttonBuilder.apply(rec, itemSlot);
|
||||||
return item == null ? this.makeFallBack(record.fallback()) : item;
|
return item == null ? this.makeFallBack(rec.fallback()) : item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method creates a fall back button for given record.
|
* 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.
|
* @return PanelItem if fallback was creates successfully, otherwise null.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@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.
|
* 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.
|
* @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();
|
PanelItemBuilder itemBuilder = new PanelItemBuilder();
|
||||||
|
|
||||||
// Read icon only if it is not null.
|
// 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.
|
// 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.
|
// 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.
|
// Click Handlers are managed by custom addon buttons.
|
||||||
|
@ -8,7 +8,11 @@ package world.bentobox.bentobox.api.panels.builders;
|
|||||||
|
|
||||||
|
|
||||||
import java.io.File;
|
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 java.util.function.BiFunction;
|
||||||
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
@ -19,7 +19,6 @@ import org.eclipse.jdt.annotation.Nullable;
|
|||||||
|
|
||||||
import world.bentobox.bentobox.api.panels.reader.ItemTemplateRecord.ActionRecords;
|
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.
|
* This Record contains all necessary information about Item Template that can be used to craft panel item.
|
||||||
*
|
*
|
||||||
|
@ -17,7 +17,6 @@ import org.eclipse.jdt.annotation.Nullable;
|
|||||||
import world.bentobox.bentobox.api.panels.Panel;
|
import world.bentobox.bentobox.api.panels.Panel;
|
||||||
import world.bentobox.bentobox.api.panels.reader.PanelTemplateRecord.TemplateItem;
|
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.
|
* This is template object for the panel reader. It contains data that can exist in the panel.
|
||||||
* PanelBuilder will use this to build panel.
|
* PanelBuilder will use this to build panel.
|
||||||
@ -98,10 +97,9 @@ public record PanelTemplateRecord(Panel.Type type,
|
|||||||
if (this == obj) {
|
if (this == obj) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!(obj instanceof PanelTemplateRecord)) {
|
if (!(obj instanceof PanelTemplateRecord other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
PanelTemplateRecord other = (PanelTemplateRecord) obj;
|
|
||||||
return Objects.equals(background, other.background) && Objects.equals(border, other.border)
|
return Objects.equals(background, other.background) && Objects.equals(border, other.border)
|
||||||
&& Arrays.deepEquals(content, other.content) && Arrays.equals(forcedRows, other.forcedRows)
|
&& Arrays.deepEquals(content, other.content) && Arrays.equals(forcedRows, other.forcedRows)
|
||||||
&& Objects.equals(title, other.title) && type == other.type;
|
&& Objects.equals(title, other.title) && type == other.type;
|
||||||
|
@ -6,6 +6,12 @@
|
|||||||
|
|
||||||
package world.bentobox.bentobox.api.panels.reader;
|
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.Material;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.bukkit.configuration.InvalidConfigurationException;
|
import org.bukkit.configuration.InvalidConfigurationException;
|
||||||
@ -14,12 +20,6 @@ import org.bukkit.event.inventory.ClickType;
|
|||||||
import org.eclipse.jdt.annotation.NonNull;
|
import org.eclipse.jdt.annotation.NonNull;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
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 com.google.common.base.Enums;
|
||||||
|
|
||||||
import world.bentobox.bentobox.api.panels.Panel;
|
import world.bentobox.bentobox.api.panels.Panel;
|
||||||
@ -49,6 +49,14 @@ public class TemplateReader
|
|||||||
private static final String TYPE = "type";
|
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.
|
* Read template panel panel template record.
|
||||||
*
|
*
|
||||||
@ -95,7 +103,7 @@ public class TemplateReader
|
|||||||
return TemplateReader.loadedPanels.get(panelKey);
|
return TemplateReader.loadedPanels.get(panelKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelTemplateRecord record;
|
PanelTemplateRecord rec;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -103,16 +111,16 @@ public class TemplateReader
|
|||||||
YamlConfiguration config = new YamlConfiguration();
|
YamlConfiguration config = new YamlConfiguration();
|
||||||
config.load(file);
|
config.load(file);
|
||||||
// Read panel
|
// Read panel
|
||||||
record = readPanelTemplate(config.getConfigurationSection(panelName));
|
rec = readPanelTemplate(config.getConfigurationSection(panelName));
|
||||||
// Put panel into memory
|
// Put panel into memory
|
||||||
TemplateReader.loadedPanels.put(panelKey, record);
|
TemplateReader.loadedPanels.put(panelKey, rec);
|
||||||
}
|
}
|
||||||
catch (IOException | InvalidConfigurationException e)
|
catch (IOException | InvalidConfigurationException e)
|
||||||
{
|
{
|
||||||
record = null;
|
rec = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return record;
|
return rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import java.util.Map;
|
|||||||
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
import org.eclipse.jdt.annotation.NonNull;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||||
import world.bentobox.bentobox.api.placeholders.PlaceholderReplacer;
|
import world.bentobox.bentobox.api.placeholders.PlaceholderReplacer;
|
||||||
@ -42,9 +43,9 @@ abstract class BasicPlaceholderExpansion extends PlaceholderExpansion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String onPlaceholderRequest(Player p, @NonNull String placeholder) {
|
public String onPlaceholderRequest(@Nullable Player p, @NonNull String placeholder) {
|
||||||
if (placeholders.containsKey(placeholder) && p != null) {
|
if (placeholders.containsKey(placeholder)) {
|
||||||
return placeholders.get(placeholder).onReplace(User.getInstance(p));
|
return placeholders.get(placeholder).onReplace(p != null ? User.getInstance(p) : null);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package world.bentobox.bentobox.api.user;
|
package world.bentobox.bentobox.api.user;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.EnumMap;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -8,7 +10,6 @@ import java.util.Objects;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.apache.commons.lang.math.NumberUtils;
|
import org.apache.commons.lang.math.NumberUtils;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
@ -17,6 +18,7 @@ import org.bukkit.GameMode;
|
|||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.Particle;
|
import org.bukkit.Particle;
|
||||||
|
import org.bukkit.Particle.DustTransition;
|
||||||
import org.bukkit.Vibration;
|
import org.bukkit.Vibration;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
@ -54,6 +56,26 @@ public class User implements MetaDataAble {
|
|||||||
|
|
||||||
private static final Map<UUID, User> users = new HashMap<>();
|
private static final Map<UUID, User> users = new HashMap<>();
|
||||||
|
|
||||||
|
// Used for particle validation
|
||||||
|
private static final Map<Particle, Class<?>> VALIDATION_CHECK;
|
||||||
|
static {
|
||||||
|
Map<Particle, Class<?>> 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
|
* Clears all users from the user list
|
||||||
*/
|
*/
|
||||||
@ -89,7 +111,8 @@ public class User implements MetaDataAble {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
* @param uuid - UUID
|
||||||
* @return user - user
|
* @return user - user
|
||||||
*/
|
*/
|
||||||
@ -98,7 +121,7 @@ public class User implements MetaDataAble {
|
|||||||
if (users.containsKey(uuid)) {
|
if (users.containsKey(uuid)) {
|
||||||
return users.get(uuid);
|
return users.get(uuid);
|
||||||
}
|
}
|
||||||
// Return player, or null if they are not online
|
// Return a user instance
|
||||||
return new User(uuid);
|
return new User(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,8 +340,6 @@ public class User implements MetaDataAble {
|
|||||||
// If requester is console, then return the default value
|
// If requester is console, then return the default value
|
||||||
if (!isPlayer()) return defaultValue;
|
if (!isPlayer()) return defaultValue;
|
||||||
|
|
||||||
int value = 0;
|
|
||||||
|
|
||||||
// If there is a dot at the end of the permissionPrefix, remove it
|
// If there is a dot at the end of the permissionPrefix, remove it
|
||||||
if (permissionPrefix.endsWith(".")) {
|
if (permissionPrefix.endsWith(".")) {
|
||||||
permissionPrefix = permissionPrefix.substring(0, permissionPrefix.length()-1);
|
permissionPrefix = permissionPrefix.substring(0, permissionPrefix.length()-1);
|
||||||
@ -330,10 +351,16 @@ public class User implements MetaDataAble {
|
|||||||
.filter(PermissionAttachmentInfo::getValue) // Must be a positive permission, not a negative one
|
.filter(PermissionAttachmentInfo::getValue) // Must be a positive permission, not a negative one
|
||||||
.map(PermissionAttachmentInfo::getPermission)
|
.map(PermissionAttachmentInfo::getPermission)
|
||||||
.filter(permission -> permission.startsWith(permPrefix))
|
.filter(permission -> permission.startsWith(permPrefix))
|
||||||
.collect(Collectors.toList());
|
.toList();
|
||||||
|
|
||||||
if (permissions.isEmpty()) return defaultValue;
|
if (permissions.isEmpty()) return defaultValue;
|
||||||
|
|
||||||
|
return iteratePerms(permissions, permPrefix, defaultValue);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private int iteratePerms(List<String> permissions, String permPrefix, int defaultValue) {
|
||||||
|
int value = 0;
|
||||||
for (String permission : permissions) {
|
for (String permission : permissions) {
|
||||||
if (permission.contains(permPrefix + "*")) {
|
if (permission.contains(permPrefix + "*")) {
|
||||||
// 'Star' permission
|
// 'Star' permission
|
||||||
@ -403,21 +430,27 @@ public class User implements MetaDataAble {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String translate(String addonPrefix, 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);
|
String translation = plugin.getLocalesManager().get(this, addonPrefix + reference);
|
||||||
|
|
||||||
if (translation == null) {
|
if (translation == null) {
|
||||||
|
// No luck, try to get the generic translation
|
||||||
translation = plugin.getLocalesManager().get(this, reference);
|
translation = plugin.getLocalesManager().get(this, reference);
|
||||||
if (translation == null) {
|
if (translation == null) {
|
||||||
// If no translation has been found, return the reference for debug purposes.
|
// Nothing found. Replace vars (probably will do nothing) and return
|
||||||
return reference;
|
return replaceVars(reference, variables);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a prefix, just gather and return the translation
|
// If this is a prefix, just gather and return the translation
|
||||||
if (reference.startsWith("prefixes.")) {
|
if (!reference.startsWith("prefixes.")) {
|
||||||
return translation;
|
|
||||||
} else {
|
|
||||||
// Replace the prefixes
|
// Replace the prefixes
|
||||||
|
return replacePrefixes(translation, variables);
|
||||||
|
}
|
||||||
|
return translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String replacePrefixes(String translation, String[] variables) {
|
||||||
for (String prefix : plugin.getLocalesManager().getAvailablePrefixes(this)) {
|
for (String prefix : plugin.getLocalesManager().getAvailablePrefixes(this)) {
|
||||||
String prefixTranslation = getTranslation("prefixes." + prefix);
|
String prefixTranslation = getTranslation("prefixes." + prefix);
|
||||||
// Replace the [gamemode] text variable
|
// Replace the [gamemode] text variable
|
||||||
@ -440,9 +473,25 @@ public class User implements MetaDataAble {
|
|||||||
if (player != null) {
|
if (player != null) {
|
||||||
translation = plugin.getPlaceholdersManager().replacePlaceholders(player, translation);
|
translation = plugin.getPlaceholdersManager().replacePlaceholders(player, translation);
|
||||||
}
|
}
|
||||||
|
|
||||||
return translation;
|
return 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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 class User implements MetaDataAble {
|
|||||||
* @param y Y coordinate of the particle to display.
|
* @param y Y coordinate of the particle to display.
|
||||||
* @param z Z 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.
|
Class<?> expectedClass = VALIDATION_CHECK.get(particle);
|
||||||
switch (particle)
|
if (expectedClass == null) throw new IllegalArgumentException("Unexpected value: " + particle);
|
||||||
{
|
|
||||||
case REDSTONE ->
|
if (!(expectedClass.isInstance(dustOptions))) {
|
||||||
{
|
throw new IllegalArgumentException("A non-null " + expectedClass.getSimpleName() + " must be provided when using Particle." + particle + " as particle.");
|
||||||
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.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this particle is beyond the viewing distance of the server
|
// Check if this particle is beyond the viewing distance of the server
|
||||||
if (this.player != null &&
|
if (this.player != null
|
||||||
this.player.getLocation().toVector().distanceSquared(new Vector(x, y, z)) <
|
&& this.player.getLocation().toVector().distanceSquared(new Vector(x, y, z)) <
|
||||||
(Bukkit.getServer().getViewDistance() * 256 * Bukkit.getServer().getViewDistance()))
|
(Bukkit.getServer().getViewDistance() * 256 * Bukkit.getServer().getViewDistance()))
|
||||||
{
|
{
|
||||||
if (particle.equals(Particle.REDSTONE))
|
if (particle.equals(Particle.REDSTONE))
|
||||||
@ -678,6 +673,7 @@ public class User implements MetaDataAble {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// This will never be called unless the value in VALIDATION_CHECK is null in the future
|
||||||
player.spawnParticle(particle, x, y, z, 1);
|
player.spawnParticle(particle, x, y, z, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package world.bentobox.bentobox.blueprints;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
@ -8,7 +8,6 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
@ -138,7 +137,7 @@ public class BlueprintClipboard {
|
|||||||
.filter(e -> new Vector(Math.rint(e.getLocation().getX()),
|
.filter(e -> new Vector(Math.rint(e.getLocation().getX()),
|
||||||
Math.rint(e.getLocation().getY()),
|
Math.rint(e.getLocation().getY()),
|
||||||
Math.rint(e.getLocation().getZ())).equals(v))
|
Math.rint(e.getLocation().getZ())).equals(v))
|
||||||
.collect(Collectors.toList());
|
.toList();
|
||||||
if (copyBlock(v.toLocation(world), copyAir, copyBiome, ents)) {
|
if (copyBlock(v.toLocation(world), copyAir, copyBiome, ents)) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
@ -288,19 +287,17 @@ public class BlueprintClipboard {
|
|||||||
if (entity instanceof Villager villager) {
|
if (entity instanceof Villager villager) {
|
||||||
setVillager(villager, bpe);
|
setVillager(villager, bpe);
|
||||||
}
|
}
|
||||||
if (entity instanceof Colorable c) {
|
if (entity instanceof Colorable c && c.getColor() != null) {
|
||||||
if (c.getColor() != null) {
|
|
||||||
bpe.setColor(c.getColor());
|
bpe.setColor(c.getColor());
|
||||||
}
|
}
|
||||||
|
if (entity instanceof Tameable tameable) {
|
||||||
|
bpe.setTamed(tameable.isTamed());
|
||||||
}
|
}
|
||||||
if (entity instanceof Tameable) {
|
if (entity instanceof ChestedHorse chestedHorse) {
|
||||||
bpe.setTamed(((Tameable)entity).isTamed());
|
bpe.setChest(chestedHorse.isCarryingChest());
|
||||||
}
|
|
||||||
if (entity instanceof ChestedHorse) {
|
|
||||||
bpe.setChest(((ChestedHorse)entity).isCarryingChest());
|
|
||||||
}
|
}
|
||||||
// Only set if child. Most animals are adults
|
// 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);
|
bpe.setAdult(false);
|
||||||
}
|
}
|
||||||
if (entity instanceof AbstractHorse horse) {
|
if (entity instanceof AbstractHorse horse) {
|
||||||
|
@ -1,5 +1,17 @@
|
|||||||
package world.bentobox.bentobox.blueprints;
|
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.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
@ -7,6 +19,7 @@ import org.bukkit.scheduler.BukkitTask;
|
|||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
import org.eclipse.jdt.annotation.NonNull;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
import world.bentobox.bentobox.BentoBox;
|
import world.bentobox.bentobox.BentoBox;
|
||||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||||
import world.bentobox.bentobox.api.user.User;
|
import world.bentobox.bentobox.api.user.User;
|
||||||
@ -16,12 +29,6 @@ import world.bentobox.bentobox.database.objects.Island;
|
|||||||
import world.bentobox.bentobox.nms.PasteHandler;
|
import world.bentobox.bentobox.nms.PasteHandler;
|
||||||
import world.bentobox.bentobox.util.Util;
|
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
|
* This class pastes the clipboard it is given
|
||||||
* @author tastybento
|
* @author tastybento
|
||||||
@ -77,10 +84,10 @@ public class BlueprintPaster {
|
|||||||
private final Island island;
|
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 plugin - BentoBox
|
||||||
* @param clipboard - clipboard to paste
|
* @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) {
|
public BlueprintPaster(@NonNull BentoBox plugin, @NonNull BlueprintClipboard clipboard, @NonNull Location location) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
@ -90,9 +97,6 @@ public class BlueprintPaster {
|
|||||||
this.location = location;
|
this.location = location;
|
||||||
this.world = location.getWorld();
|
this.world = location.getWorld();
|
||||||
this.island = null;
|
this.island = null;
|
||||||
|
|
||||||
// Paste
|
|
||||||
paste();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -151,20 +155,71 @@ public class BlueprintPaster {
|
|||||||
|
|
||||||
final int pasteSpeed = plugin.getSettings().getPasteSpeed();
|
final int pasteSpeed = plugin.getSettings().getPasteSpeed();
|
||||||
|
|
||||||
long timer = System.currentTimeMillis();
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
if (pasteState.equals(PasteState.CHUNK_LOAD)) {
|
if (pasteState.equals(PasteState.CHUNK_LOAD)) {
|
||||||
pasteState = PasteState.CHUNK_LOADING;
|
loadChunk();
|
||||||
// Load chunk
|
|
||||||
currentTask = Util.getChunkAtAsync(location).thenRun(() -> {
|
|
||||||
pasteState = PasteState.BLOCKS;
|
|
||||||
long duration = System.currentTimeMillis() - timer;
|
|
||||||
if (duration > chunkLoadTime) {
|
|
||||||
chunkLoadTime = duration;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else if (pasteState.equals(PasteState.BLOCKS) || pasteState.equals(PasteState.ATTACHMENTS)) {
|
else if (pasteState.equals(PasteState.BLOCKS) || pasteState.equals(PasteState.ATTACHMENTS)) {
|
||||||
|
pasteBlocks(bits, count, owner, pasteSpeed);
|
||||||
|
}
|
||||||
|
else if (pasteState.equals(PasteState.ENTITIES)) {
|
||||||
|
pasteEntities(bits, count, owner, pasteSpeed);
|
||||||
|
}
|
||||||
|
else if (pasteState.equals(PasteState.DONE)) {
|
||||||
|
// All done. Cancel task
|
||||||
|
cancelTask(result);
|
||||||
|
} else if (pasteState.equals(PasteState.CANCEL)) {
|
||||||
|
// This state makes sure the follow-on task only ever runs once
|
||||||
|
pastingTask.cancel();
|
||||||
|
result.complete(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelTask(CompletableFuture<Boolean> 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<User> owner, int pasteSpeed) {
|
||||||
|
if (bits.it3().hasNext()) {
|
||||||
|
Map<Location, List<BlueprintEntity>> entityMap = new HashMap<>();
|
||||||
|
// Paste entities
|
||||||
|
while (count < pasteSpeed) {
|
||||||
|
if (!bits.it3().hasNext()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Entry<Vector, List<BlueprintEntity>> 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<BlueprintEntity> 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<User> owner, int pasteSpeed) {
|
||||||
Iterator<Entry<Vector, BlueprintBlock>> it = pasteState.equals(PasteState.BLOCKS) ? bits.it : bits.it2;
|
Iterator<Entry<Vector, BlueprintBlock>> it = pasteState.equals(PasteState.BLOCKS) ? bits.it : bits.it2;
|
||||||
if (it.hasNext()) {
|
if (it.hasNext()) {
|
||||||
Map<Location, BlueprintBlock> blockMap = new HashMap<>();
|
Map<Location, BlueprintBlock> blockMap = new HashMap<>();
|
||||||
@ -198,53 +253,21 @@ public class BlueprintPaster {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (pasteState.equals(PasteState.ENTITIES)) {
|
|
||||||
if (bits.it3().hasNext()) {
|
|
||||||
Map<Location, List<BlueprintEntity>> entityMap = new HashMap<>();
|
|
||||||
// Paste entities
|
|
||||||
while (count < pasteSpeed) {
|
|
||||||
if (!bits.it3().hasNext()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Entry<Vector, List<BlueprintEntity>> 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<BlueprintEntity> 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));
|
private void loadChunk() {
|
||||||
}
|
long timer = System.currentTimeMillis();
|
||||||
}
|
pasteState = PasteState.CHUNK_LOADING;
|
||||||
else if (pasteState.equals(PasteState.DONE)) {
|
// Load chunk
|
||||||
// All done. Cancel task
|
currentTask = Util.getChunkAtAsync(location).thenRun(() -> {
|
||||||
// Set pos1 and 2 if this was a clipboard paste
|
pasteState = PasteState.BLOCKS;
|
||||||
if (island == null && clipboard != null) {
|
long duration = System.currentTimeMillis() - timer;
|
||||||
clipboard.setPos1(pos1);
|
if (duration > chunkLoadTime) {
|
||||||
clipboard.setPos2(pos2);
|
chunkLoadTime = duration;
|
||||||
}
|
|
||||||
pasteState = PasteState.CANCEL;
|
|
||||||
result.complete(true);
|
|
||||||
} else if (pasteState.equals(PasteState.CANCEL)) {
|
|
||||||
// This state makes sure the follow-on task only ever runs once
|
|
||||||
pastingTask.cancel();
|
|
||||||
result.complete(true);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tellOwner(User user, int blocksSize, int attachedSize, int entitiesSize, int pasteSpeed) {
|
private void tellOwner(User user, int blocksSize, int attachedSize, int entitiesSize, int pasteSpeed) {
|
||||||
|
@ -8,7 +8,6 @@ import org.bukkit.entity.Player;
|
|||||||
import org.eclipse.jdt.annotation.NonNull;
|
import org.eclipse.jdt.annotation.NonNull;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
import world.bentobox.bentobox.BentoBox;
|
|
||||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||||
import world.bentobox.bentobox.api.user.User;
|
import world.bentobox.bentobox.api.user.User;
|
||||||
import world.bentobox.bentobox.blueprints.Blueprint;
|
import world.bentobox.bentobox.blueprints.Blueprint;
|
||||||
|
@ -3,7 +3,6 @@ package world.bentobox.bentobox.blueprints.dataobjects;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
@ -99,12 +99,11 @@ public class Database<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
* @param instance to save
|
||||||
* @return true - always.
|
* @return true - always.
|
||||||
* @deprecated As of 1.13.0. Use {@link #saveObjectAsync(Object)}.
|
* @since 1.13.0
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public boolean saveObject(T instance) {
|
public boolean saveObject(T instance) {
|
||||||
saveObjectAsync(instance).thenAccept(r -> {
|
saveObjectAsync(instance).thenAccept(r -> {
|
||||||
if (Boolean.FALSE.equals(r)) logger.severe(() -> "Could not save object to database!");
|
if (Boolean.FALSE.equals(r)) logger.severe(() -> "Could not save object to database!");
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
package world.bentobox.bentobox.database;
|
package world.bentobox.bentobox.database;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type Database connection settings.
|
||||||
|
*/
|
||||||
public class DatabaseConnectionSettingsImpl {
|
public class DatabaseConnectionSettingsImpl {
|
||||||
private String host;
|
private String host;
|
||||||
private int port;
|
private int port;
|
||||||
@ -14,6 +22,18 @@ public class DatabaseConnectionSettingsImpl {
|
|||||||
*/
|
*/
|
||||||
private boolean useSSL;
|
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<String, String> extraProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hosts database settings
|
* Hosts database settings
|
||||||
* @param host - database host
|
* @param host - database host
|
||||||
@ -21,16 +41,78 @@ public class DatabaseConnectionSettingsImpl {
|
|||||||
* @param databaseName - database name
|
* @param databaseName - database name
|
||||||
* @param username - username
|
* @param username - username
|
||||||
* @param password - password
|
* @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) {
|
public record DatabaseSettings(String host,
|
||||||
this.host = host;
|
int port,
|
||||||
this.port = port;
|
String databaseName,
|
||||||
this.databaseName = databaseName;
|
String username,
|
||||||
this.username = username;
|
String password,
|
||||||
this.password = password;
|
boolean useSSL,
|
||||||
this.useSSL = useSSL;
|
int maxConnections,
|
||||||
|
Map<String, String> 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
|
* @return the host
|
||||||
*/
|
*/
|
||||||
@ -117,4 +199,48 @@ public class DatabaseConnectionSettingsImpl {
|
|||||||
public void setUseSSL(boolean useSSL) {
|
public void setUseSSL(boolean useSSL) {
|
||||||
this.useSSL = 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<String, String> getExtraProperties()
|
||||||
|
{
|
||||||
|
return extraProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets extra properties.
|
||||||
|
*
|
||||||
|
* @param extraProperties the extra properties
|
||||||
|
*/
|
||||||
|
public void setExtraProperties(Map<String, String> extraProperties)
|
||||||
|
{
|
||||||
|
this.extraProperties = extraProperties;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,10 +45,5 @@ public interface DatabaseConnector {
|
|||||||
* @return true if it exists
|
* @return true if it exists
|
||||||
*/
|
*/
|
||||||
boolean uniqueIdExists(String tableName, String key);
|
boolean uniqueIdExists(String tableName, String key);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,6 @@ import world.bentobox.bentobox.database.json.adapters.LocationTypeAdapter;
|
|||||||
import world.bentobox.bentobox.database.json.adapters.PotionEffectTypeAdapter;
|
import world.bentobox.bentobox.database.json.adapters.PotionEffectTypeAdapter;
|
||||||
import world.bentobox.bentobox.database.json.adapters.VectorTypeAdapter;
|
import world.bentobox.bentobox.database.json.adapters.VectorTypeAdapter;
|
||||||
import world.bentobox.bentobox.database.json.adapters.WorldTypeAdapter;
|
import world.bentobox.bentobox.database.json.adapters.WorldTypeAdapter;
|
||||||
import world.bentobox.bentobox.versions.ServerCompatibility;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,7 +21,7 @@ public final class EnumTypeAdapter<T extends Enum<T>> extends TypeAdapter<T> {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bimap to store name <-> enum references
|
* Bimap to store name,enum pair references
|
||||||
*/
|
*/
|
||||||
private final BiMap<String, T> enumMap = HashBiMap.create();
|
private final BiMap<String, T> enumMap = HashBiMap.create();
|
||||||
|
|
||||||
|
@ -24,8 +24,9 @@ public class LocationTypeAdapter extends TypeAdapter<Location> {
|
|||||||
out.value(location.getX());
|
out.value(location.getX());
|
||||||
out.value(location.getY());
|
out.value(location.getY());
|
||||||
out.value(location.getZ());
|
out.value(location.getZ());
|
||||||
out.value(location.getYaw());
|
// This is required for 1.19-1.19.2 compatibility.
|
||||||
out.value(location.getPitch());
|
out.value((double) location.getYaw());
|
||||||
|
out.value((double) location.getPitch());
|
||||||
out.endArray();
|
out.endArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,9 +5,6 @@ import com.google.gson.annotations.Expose;
|
|||||||
/**
|
/**
|
||||||
* Record for bonus ranges
|
* Record for bonus ranges
|
||||||
* @author tastybento
|
* @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 {
|
public class BonusRangeRecord {
|
||||||
@Expose
|
@Expose
|
||||||
@ -17,9 +14,9 @@ public class BonusRangeRecord {
|
|||||||
@Expose
|
@Expose
|
||||||
private String message;
|
private String message;
|
||||||
/**
|
/**
|
||||||
* @param uniqueId
|
* @param uniqueId an id to identify this bonus
|
||||||
* @param range
|
* @param range the additional bonus range
|
||||||
* @param message
|
* @param message the reference key to a locale message related to this bonus. May be blank.
|
||||||
*/
|
*/
|
||||||
public BonusRangeRecord(String uniqueId, int range, String message) {
|
public BonusRangeRecord(String uniqueId, int range, String message) {
|
||||||
this.uniqueId = uniqueId;
|
this.uniqueId = uniqueId;
|
||||||
|
@ -16,9 +16,9 @@ import java.util.UUID;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.GameMode;
|
|
||||||
import org.bukkit.World.Environment;
|
import org.bukkit.World.Environment;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.util.BoundingBox;
|
import org.bukkit.util.BoundingBox;
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package world.bentobox.bentobox.database.objects.adapters;
|
package world.bentobox.bentobox.database.objects.adapters;
|
||||||
|
|
||||||
|
|
||||||
import org.bukkit.configuration.MemorySection;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
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.
|
* This Serializer migrates Map of String, Boolean to Map of String, Integer in serialization process.
|
||||||
@ -35,7 +36,7 @@ public class FlagBooleanSerializer implements AdapterInterface<Map<String, Integ
|
|||||||
{
|
{
|
||||||
for (Entry<String, Boolean> en : ((Map<String, Boolean>) object).entrySet())
|
for (Entry<String, Boolean> en : ((Map<String, Boolean>) object).entrySet())
|
||||||
{
|
{
|
||||||
result.put(en.getKey(), en.getValue() ? 0 : -1);
|
result.put(en.getKey(), Boolean.TRUE.equals(en.getValue()) ? 0 : -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ public class FlagSerializer2 implements AdapterInterface<Map<Flag, Integer>, Map
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (Entry<String, Boolean> en : ((Map<String, Boolean>)object).entrySet()) {
|
for (Entry<String, Boolean> en : ((Map<String, Boolean>)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;
|
return result;
|
||||||
|
@ -9,34 +9,44 @@ import world.bentobox.bentobox.database.objects.Table;
|
|||||||
* @author tastybento
|
* @author tastybento
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class SQLConfiguration {
|
public class SQLConfiguration
|
||||||
|
{
|
||||||
private String loadObjectSQL;
|
private String loadObjectSQL;
|
||||||
|
|
||||||
private String saveObjectSQL;
|
private String saveObjectSQL;
|
||||||
|
|
||||||
private String deleteObjectSQL;
|
private String deleteObjectSQL;
|
||||||
|
|
||||||
private String objectExistsSQL;
|
private String objectExistsSQL;
|
||||||
|
|
||||||
private String schemaSQL;
|
private String schemaSQL;
|
||||||
|
|
||||||
private String loadObjectsSQL;
|
private String loadObjectsSQL;
|
||||||
|
|
||||||
private String renameTableSQL;
|
private String renameTableSQL;
|
||||||
|
|
||||||
private final String tableName;
|
private final String tableName;
|
||||||
|
|
||||||
private final boolean renameRequired;
|
private final boolean renameRequired;
|
||||||
|
|
||||||
private final String oldTableName;
|
private final String oldTableName;
|
||||||
|
|
||||||
public <T> SQLConfiguration(BentoBox plugin, Class<T> type) {
|
|
||||||
|
public <T> SQLConfiguration(BentoBox plugin, Class<T> type)
|
||||||
|
{
|
||||||
// Set the table name
|
// Set the table name
|
||||||
oldTableName = plugin.getSettings().getDatabasePrefix() + type.getCanonicalName();
|
this.oldTableName = plugin.getSettings().getDatabasePrefix() + type.getCanonicalName();
|
||||||
this.tableName = plugin.getSettings().getDatabasePrefix() +
|
this.tableName = plugin.getSettings().getDatabasePrefix() +
|
||||||
(type.getAnnotation(Table.class) == null ?
|
(type.getAnnotation(Table.class) == null ? type.getCanonicalName() : type.getAnnotation(Table.class).name());
|
||||||
type.getCanonicalName()
|
|
||||||
: type.getAnnotation(Table.class).name());
|
|
||||||
// Only rename if there is a specific Table annotation
|
// Only rename if there is a specific Table annotation
|
||||||
renameRequired = !tableName.equals(oldTableName);
|
this.renameRequired = !this.tableName.equals(this.oldTableName);
|
||||||
schema("CREATE TABLE IF NOT EXISTS `[tableName]` (json JSON, uniqueId VARCHAR(255) GENERATED ALWAYS AS (json->\"$.uniqueId\"), UNIQUE INDEX i (uniqueId) )");
|
this.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]`");
|
this.loadObjects("SELECT `json` FROM `[tableName]`");
|
||||||
loadObject("SELECT `json` FROM `[tableName]` WHERE uniqueId = ? LIMIT 1");
|
this.loadObject("SELECT `json` FROM `[tableName]` WHERE uniqueId = ? LIMIT 1");
|
||||||
saveObject("INSERT INTO `[tableName]` (json) VALUES (?) ON DUPLICATE KEY UPDATE json = ?");
|
this.saveObject("INSERT INTO `[tableName]` (json) VALUES (?) ON DUPLICATE KEY UPDATE json = ?");
|
||||||
deleteObject("DELETE FROM `[tableName]` WHERE uniqueId = ?");
|
this.deleteObject("DELETE FROM `[tableName]` WHERE uniqueId = ?");
|
||||||
objectExists("SELECT IF ( EXISTS( SELECT * FROM `[tableName]` WHERE `uniqueId` = ?), 1, 0)");
|
this.objectExists("SELECT IF ( EXISTS( SELECT * FROM `[tableName]` WHERE `uniqueId` = ?), 1, 0)");
|
||||||
renameTable("SELECT Count(*) INTO @exists " +
|
this.renameTable("SELECT Count(*) INTO @exists " +
|
||||||
"FROM information_schema.tables " +
|
"FROM information_schema.tables " +
|
||||||
"WHERE table_schema = '" + plugin.getSettings().getDatabaseName() + "' " +
|
"WHERE table_schema = '" + plugin.getSettings().getDatabaseName() + "' " +
|
||||||
"AND table_type = 'BASE TABLE' " +
|
"AND table_type = 'BASE TABLE' " +
|
||||||
@ -46,48 +56,66 @@ public class SQLConfiguration {
|
|||||||
"EXECUTE stmt;");
|
"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
|
* By default, use quotes around the unique ID in the SQL statement
|
||||||
*/
|
*/
|
||||||
private boolean useQuotes = true;
|
private boolean useQuotes = true;
|
||||||
|
|
||||||
public SQLConfiguration loadObject(String string) {
|
|
||||||
|
public SQLConfiguration loadObject(String string)
|
||||||
|
{
|
||||||
this.loadObjectSQL = string.replaceFirst(TABLE_NAME, tableName);
|
this.loadObjectSQL = string.replaceFirst(TABLE_NAME, tableName);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SQLConfiguration saveObject(String string) {
|
|
||||||
|
public SQLConfiguration saveObject(String string)
|
||||||
|
{
|
||||||
this.saveObjectSQL = string.replaceFirst(TABLE_NAME, tableName);
|
this.saveObjectSQL = string.replaceFirst(TABLE_NAME, tableName);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SQLConfiguration deleteObject(String string) {
|
|
||||||
|
public SQLConfiguration deleteObject(String string)
|
||||||
|
{
|
||||||
this.deleteObjectSQL = string.replaceFirst(TABLE_NAME, tableName);
|
this.deleteObjectSQL = string.replaceFirst(TABLE_NAME, tableName);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SQLConfiguration objectExists(String string) {
|
|
||||||
|
public SQLConfiguration objectExists(String string)
|
||||||
|
{
|
||||||
this.objectExistsSQL = string.replaceFirst(TABLE_NAME, tableName);
|
this.objectExistsSQL = string.replaceFirst(TABLE_NAME, tableName);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SQLConfiguration schema(String string) {
|
|
||||||
|
public SQLConfiguration schema(String string)
|
||||||
|
{
|
||||||
this.schemaSQL = string.replaceFirst(TABLE_NAME, tableName);
|
this.schemaSQL = string.replaceFirst(TABLE_NAME, tableName);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SQLConfiguration loadObjects(String string) {
|
|
||||||
|
public SQLConfiguration loadObjects(String string)
|
||||||
|
{
|
||||||
this.loadObjectsSQL = string.replaceFirst(TABLE_NAME, tableName);
|
this.loadObjectsSQL = string.replaceFirst(TABLE_NAME, tableName);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SQLConfiguration renameTable(String string) {
|
|
||||||
|
public SQLConfiguration renameTable(String string)
|
||||||
|
{
|
||||||
this.renameTableSQL = string.replace(TABLE_NAME, tableName).replace("\\[oldTableName\\]", oldTableName);
|
this.renameTableSQL = string.replace(TABLE_NAME, tableName).replace("\\[oldTableName\\]", oldTableName);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SQLConfiguration setUseQuotes(boolean b) {
|
|
||||||
|
public SQLConfiguration setUseQuotes(boolean b)
|
||||||
|
{
|
||||||
this.useQuotes = b;
|
this.useQuotes = b;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -96,71 +124,95 @@ public class SQLConfiguration {
|
|||||||
/**
|
/**
|
||||||
* @return the loadObjectSQL
|
* @return the loadObjectSQL
|
||||||
*/
|
*/
|
||||||
public String getLoadObjectSQL() {
|
public String getLoadObjectSQL()
|
||||||
|
{
|
||||||
return loadObjectSQL;
|
return loadObjectSQL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the saveObjectSQL
|
* @return the saveObjectSQL
|
||||||
*/
|
*/
|
||||||
public String getSaveObjectSQL() {
|
public String getSaveObjectSQL()
|
||||||
|
{
|
||||||
return saveObjectSQL;
|
return saveObjectSQL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the deleteObjectSQL
|
* @return the deleteObjectSQL
|
||||||
*/
|
*/
|
||||||
public String getDeleteObjectSQL() {
|
public String getDeleteObjectSQL()
|
||||||
|
{
|
||||||
return deleteObjectSQL;
|
return deleteObjectSQL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the objectExistsSQL
|
* @return the objectExistsSQL
|
||||||
*/
|
*/
|
||||||
public String getObjectExistsSQL() {
|
public String getObjectExistsSQL()
|
||||||
|
{
|
||||||
return objectExistsSQL;
|
return objectExistsSQL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the schemaSQL
|
* @return the schemaSQL
|
||||||
*/
|
*/
|
||||||
public String getSchemaSQL() {
|
public String getSchemaSQL()
|
||||||
|
{
|
||||||
return schemaSQL;
|
return schemaSQL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the loadItSQL
|
* @return the loadItSQL
|
||||||
*/
|
*/
|
||||||
public String getLoadObjectsSQL() {
|
public String getLoadObjectsSQL()
|
||||||
|
{
|
||||||
return loadObjectsSQL;
|
return loadObjectsSQL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the renameTableSQL
|
* @return the renameTableSQL
|
||||||
*/
|
*/
|
||||||
public String getRenameTableSQL() {
|
public String getRenameTableSQL()
|
||||||
|
{
|
||||||
return renameTableSQL;
|
return renameTableSQL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the tableName
|
* @return the tableName
|
||||||
*/
|
*/
|
||||||
public String getTableName() {
|
public String getTableName()
|
||||||
|
{
|
||||||
return tableName;
|
return tableName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the oldName
|
* @return the oldName
|
||||||
*/
|
*/
|
||||||
public String getOldTableName() {
|
public String getOldTableName()
|
||||||
|
{
|
||||||
return oldTableName;
|
return oldTableName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean renameRequired() {
|
|
||||||
|
public boolean renameRequired()
|
||||||
|
{
|
||||||
return renameRequired;
|
return renameRequired;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the useQuotes
|
* @return the useQuotes
|
||||||
*/
|
*/
|
||||||
public boolean isUseQuotes() {
|
public boolean isUseQuotes()
|
||||||
|
{
|
||||||
return useQuotes;
|
return useQuotes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package world.bentobox.bentobox.database.sql;
|
package world.bentobox.bentobox.database.sql;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.DriverManager;
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -9,64 +8,136 @@ import java.util.Set;
|
|||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
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.DatabaseConnectionSettingsImpl;
|
||||||
import world.bentobox.bentobox.database.DatabaseConnector;
|
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;
|
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<Class<?>> types = new HashSet<>();
|
protected static Set<Class<?>> 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.dbSettings = dbSettings;
|
||||||
this.connectionUrl = connectionUrl;
|
this.connectionUrl = connectionUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns connection url of database.
|
||||||
|
* @return Database connection url.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getConnectionUrl() {
|
public String getConnectionUrl()
|
||||||
|
{
|
||||||
return connectionUrl;
|
return connectionUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
@NonNull
|
@NonNull
|
||||||
public String getUniqueId(String tableName) {
|
public String getUniqueId(String tableName)
|
||||||
|
{
|
||||||
// Not used
|
// Not used
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean uniqueIdExists(String tableName, String key) {
|
public boolean uniqueIdExists(String tableName, String key)
|
||||||
|
{
|
||||||
// Not used
|
// Not used
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void closeConnection(Class<?> type) {
|
public void closeConnection(Class<?> type)
|
||||||
|
{
|
||||||
types.remove(type);
|
types.remove(type);
|
||||||
if (types.isEmpty() && connection != null) {
|
|
||||||
try {
|
if (types.isEmpty())
|
||||||
connection.close();
|
{
|
||||||
|
dataSource.close();
|
||||||
Bukkit.getLogger().info("Closed database connection");
|
Bukkit.getLogger().info("Closed database connection");
|
||||||
} catch (SQLException e) {
|
|
||||||
Bukkit.getLogger().severe("Could not close database connection");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method creates config that is used to create HikariDataSource.
|
||||||
|
* @return HikariConfig object.
|
||||||
|
*/
|
||||||
|
public abstract HikariConfig createConfig();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object createConnection(Class<?> type) {
|
public Object createConnection(Class<?> type)
|
||||||
|
{
|
||||||
types.add(type);
|
types.add(type);
|
||||||
|
|
||||||
// Only make one connection to the database
|
// Only make one connection to the database
|
||||||
if (connection == null) {
|
if (dataSource == null)
|
||||||
try {
|
{
|
||||||
connection = DriverManager.getConnection(connectionUrl, dbSettings.getUsername(), dbSettings.getPassword());
|
try
|
||||||
} catch (SQLException e) {
|
{
|
||||||
|
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());
|
Bukkit.getLogger().severe("Could not connect to the database! " + e.getMessage());
|
||||||
|
dataSource = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return dataSource;
|
||||||
|
}
|
||||||
}
|
}
|
@ -11,6 +11,8 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
import org.eclipse.jdt.annotation.NonNull;
|
||||||
|
|
||||||
@ -31,246 +33,413 @@ import world.bentobox.bentobox.database.objects.DataObject;
|
|||||||
*
|
*
|
||||||
* @param <T>
|
* @param <T>
|
||||||
*/
|
*/
|
||||||
public class SQLDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
|
public class SQLDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T>
|
||||||
|
{
|
||||||
protected static final String COULD_NOT_LOAD_OBJECTS = "Could not load objects ";
|
protected static final String COULD_NOT_LOAD_OBJECTS = "Could not load objects ";
|
||||||
protected static final String COULD_NOT_LOAD_OBJECT = "Could not load object ";
|
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
|
* SQL configuration
|
||||||
*/
|
*/
|
||||||
private SQLConfiguration sqlConfig;
|
private SQLConfiguration sqlConfig;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the connection to the database and creation of the initial database schema (tables) for
|
* Handles the connection to the database and creation of the initial database schema (tables) for
|
||||||
* the class that will be stored.
|
* the class that will be stored.
|
||||||
* @param plugin - plugin object
|
* @param plugin - plugin object
|
||||||
* @param type - the type of class to be stored in the database. Must inherit DataObject
|
* @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
|
* @param sqlConfiguration - SQL configuration
|
||||||
*/
|
*/
|
||||||
protected SQLDatabaseHandler(BentoBox plugin, Class<T> type, DatabaseConnector dbConnecter, SQLConfiguration sqlConfiguration) {
|
protected SQLDatabaseHandler(BentoBox plugin, Class<T> type, DatabaseConnector databaseConnector, SQLConfiguration sqlConfiguration)
|
||||||
super(plugin, type, dbConnecter);
|
{
|
||||||
|
super(plugin, type, databaseConnector);
|
||||||
this.sqlConfig = sqlConfiguration;
|
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
|
// Check if the table exists in the database and if not, create it
|
||||||
createSchema();
|
this.createSchema();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the sqlConfig
|
* @return the sqlConfig
|
||||||
*/
|
*/
|
||||||
public SQLConfiguration getSqlConfig() {
|
public SQLConfiguration getSqlConfig()
|
||||||
|
{
|
||||||
return sqlConfig;
|
return sqlConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param sqlConfig the sqlConfig to set
|
* @param sqlConfig the sqlConfig to set
|
||||||
*/
|
*/
|
||||||
public void setSqlConfig(SQLConfiguration sqlConfig) {
|
public void setSqlConfig(SQLConfiguration sqlConfig)
|
||||||
|
{
|
||||||
this.sqlConfig = sqlConfig;
|
this.sqlConfig = sqlConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the table in the database if it doesn't exist already
|
* Creates the table in the database if it doesn't exist already
|
||||||
*/
|
*/
|
||||||
protected void createSchema() {
|
protected void createSchema()
|
||||||
if (sqlConfig.renameRequired()) {
|
{
|
||||||
|
if (this.sqlConfig.renameRequired())
|
||||||
|
{
|
||||||
// Transition from the old table name
|
// Transition from the old table name
|
||||||
String sql = sqlConfig.getRenameTableSQL().replace("[oldTableName]", sqlConfig.getOldTableName()).replace("[tableName]", sqlConfig.getTableName());
|
String sql = this.sqlConfig.getRenameTableSQL().
|
||||||
try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
|
replace("[oldTableName]", this.sqlConfig.getOldTableName()).
|
||||||
pstmt.execute();
|
replace("[tableName]", this.sqlConfig.getTableName());
|
||||||
} catch (SQLException e) {
|
|
||||||
plugin.logError("Could not rename " + sqlConfig.getOldTableName() + " for data object " + dataObject.getCanonicalName() + " " + e.getMessage());
|
try (Connection connection = this.dataSource.getConnection();
|
||||||
|
PreparedStatement preparedStatement = connection.prepareStatement(sql))
|
||||||
|
{
|
||||||
|
preparedStatement.execute();
|
||||||
}
|
}
|
||||||
}
|
catch (SQLException e)
|
||||||
// Prepare and execute the database statements
|
{
|
||||||
try (PreparedStatement pstmt = connection.prepareStatement(sqlConfig.getSchemaSQL())) {
|
this.plugin.logError("Could not rename " + this.sqlConfig.getOldTableName() + " for data object " +
|
||||||
pstmt.execute();
|
this.dataObject.getCanonicalName() + " " + e.getMessage());
|
||||||
} catch (SQLException e) {
|
|
||||||
plugin.logError("Problem trying to create schema for data object " + dataObject.getCanonicalName() + " " + e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// Prepare and execute the database statements
|
||||||
public List<T> loadObjects() {
|
try (Connection connection = this.dataSource.getConnection();
|
||||||
try (Statement preparedStatement = connection.createStatement()) {
|
PreparedStatement preparedStatement = connection.prepareStatement(this.sqlConfig.getSchemaSQL()))
|
||||||
return loadIt(preparedStatement);
|
{
|
||||||
} catch (SQLException e) {
|
preparedStatement.execute();
|
||||||
plugin.logError(COULD_NOT_LOAD_OBJECTS + e.getMessage());
|
|
||||||
}
|
}
|
||||||
|
catch (SQLException e)
|
||||||
|
{
|
||||||
|
this.plugin.logError("Problem trying to create schema for data object " +
|
||||||
|
this.dataObject.getCanonicalName() + " " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<T> 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();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<T> loadIt(Statement preparedStatement) {
|
|
||||||
|
/**
|
||||||
|
* This method loads objects based on results provided by prepared statement.
|
||||||
|
* @param preparedStatement Statement from database.
|
||||||
|
* @return List of object <T> from database.
|
||||||
|
*/
|
||||||
|
private List<T> loadIt(Statement preparedStatement)
|
||||||
|
{
|
||||||
List<T> list = new ArrayList<>();
|
List<T> list = new ArrayList<>();
|
||||||
try (ResultSet resultSet = preparedStatement.executeQuery(sqlConfig.getLoadObjectsSQL())) {
|
|
||||||
|
try (ResultSet resultSet = preparedStatement.executeQuery(this.sqlConfig.getLoadObjectsSQL()))
|
||||||
|
{
|
||||||
// Load all the results
|
// Load all the results
|
||||||
Gson gson = getGson();
|
Gson gson = this.getGson();
|
||||||
while (resultSet.next()) {
|
|
||||||
|
while (resultSet.next())
|
||||||
|
{
|
||||||
String json = resultSet.getString("json");
|
String json = resultSet.getString("json");
|
||||||
if (json != null) {
|
|
||||||
try {
|
if (json != null)
|
||||||
T gsonResult = gson.fromJson(json, dataObject);
|
{
|
||||||
if (gsonResult != null) {
|
getGsonResultSet(gson, json, list);
|
||||||
list.add(gsonResult);
|
|
||||||
}
|
|
||||||
} catch (JsonSyntaxException ex) {
|
|
||||||
plugin.logError(COULD_NOT_LOAD_OBJECT + ex.getMessage());
|
|
||||||
plugin.logError(json);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
catch (Exception e)
|
||||||
plugin.logError(COULD_NOT_LOAD_OBJECTS + e.getMessage());
|
{
|
||||||
|
this.plugin.logError(COULD_NOT_LOAD_OBJECTS + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void getGsonResultSet(Gson gson, String json, List<T> 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
|
@Override
|
||||||
public T loadObject(@NonNull String uniqueId) {
|
public T loadObject(@NonNull String uniqueId)
|
||||||
try (PreparedStatement preparedStatement = connection.prepareStatement(sqlConfig.getLoadObjectSQL())) {
|
{
|
||||||
|
T result = null;
|
||||||
|
try (Connection connection = this.dataSource.getConnection();
|
||||||
|
PreparedStatement preparedStatement = connection.prepareStatement(this.sqlConfig.getLoadObjectSQL()))
|
||||||
|
{
|
||||||
// UniqueId needs to be placed in quotes?
|
// UniqueId needs to be placed in quotes?
|
||||||
preparedStatement.setString(1, this.sqlConfig.isUseQuotes() ? "\"" + uniqueId + "\"" : uniqueId);
|
preparedStatement.setString(1, this.sqlConfig.isUseQuotes() ? "\"" + uniqueId + "\"" : uniqueId);
|
||||||
try (ResultSet resultSet = preparedStatement.executeQuery()) {
|
result = getObject(uniqueId, preparedStatement);
|
||||||
if (resultSet.next()) {
|
}
|
||||||
|
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
|
// If there is a result, we only want/need the first one
|
||||||
Gson gson = getGson();
|
Gson gson = this.getGson();
|
||||||
return gson.fromJson(resultSet.getString("json"), dataObject);
|
return gson.fromJson(resultSet.getString("json"), this.dataObject);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
plugin.logError(COULD_NOT_LOAD_OBJECT + uniqueId + " " + e.getMessage());
|
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
catch (Exception e)
|
||||||
plugin.logError(COULD_NOT_LOAD_OBJECT + uniqueId + " " + e.getMessage());
|
{
|
||||||
|
this.plugin.logError(COULD_NOT_LOAD_OBJECT + uniqueId + " " + e.getMessage());
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Boolean> saveObject(T instance) {
|
public CompletableFuture<Boolean> saveObject(T instance)
|
||||||
|
{
|
||||||
CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();
|
CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();
|
||||||
|
|
||||||
// Null check
|
// Null check
|
||||||
if (instance == null) {
|
if (instance == null)
|
||||||
plugin.logError("SQL database request to store a null. ");
|
{
|
||||||
|
this.plugin.logError("SQL database request to store a null. ");
|
||||||
completableFuture.complete(false);
|
completableFuture.complete(false);
|
||||||
return completableFuture;
|
return completableFuture;
|
||||||
}
|
}
|
||||||
if (!(instance instanceof DataObject)) {
|
|
||||||
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()) {
|
|
||||||
// Async
|
|
||||||
processQueue.add(() -> store(completableFuture, instance.getClass().getName(), toStore, sqlConfig.getSaveObjectSQL(), true));
|
|
||||||
} else {
|
|
||||||
// Sync
|
|
||||||
store(completableFuture, instance.getClass().getName(), toStore, sqlConfig.getSaveObjectSQL(), false);
|
|
||||||
}
|
|
||||||
return completableFuture;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void store(CompletableFuture<Boolean> completableFuture, String name, String toStore, String sb, boolean async) {
|
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 = this.getGson().toJson(instance);
|
||||||
|
|
||||||
|
if (this.plugin.isEnabled())
|
||||||
|
{
|
||||||
|
// Async
|
||||||
|
this.processQueue.add(() -> store(completableFuture,
|
||||||
|
instance.getClass().getName(),
|
||||||
|
toStore,
|
||||||
|
this.sqlConfig.getSaveObjectSQL(),
|
||||||
|
true));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Sync
|
||||||
|
this.store(completableFuture, instance.getClass().getName(), toStore, this.sqlConfig.getSaveObjectSQL(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return completableFuture;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<Boolean> completableFuture, String name, String toStore, String storeSQL, boolean async)
|
||||||
|
{
|
||||||
// Do not save anything if plug is disabled and this was an async request
|
// Do not save anything if plug is disabled and this was an async request
|
||||||
if (async && !plugin.isEnabled()) return;
|
if (async && !this.plugin.isEnabled())
|
||||||
try (PreparedStatement preparedStatement = connection.prepareStatement(sb)) {
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (Connection connection = this.dataSource.getConnection();
|
||||||
|
PreparedStatement preparedStatement = connection.prepareStatement(storeSQL))
|
||||||
|
{
|
||||||
preparedStatement.setString(1, toStore);
|
preparedStatement.setString(1, toStore);
|
||||||
preparedStatement.setString(2, toStore);
|
preparedStatement.setString(2, toStore);
|
||||||
preparedStatement.execute();
|
preparedStatement.execute();
|
||||||
completableFuture.complete(true);
|
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);
|
completableFuture.complete(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see world.bentobox.bentobox.database.AbstractDatabaseHandler#deleteID(java.lang.String)
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void deleteID(String uniqueId) {
|
public void deleteID(String uniqueId)
|
||||||
processQueue.add(() -> delete(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?
|
// UniqueId needs to be placed in quotes?
|
||||||
preparedStatement.setString(1, this.sqlConfig.isUseQuotes() ? "\"" + uniqueId + "\"" : uniqueId);
|
preparedStatement.setString(1, this.sqlConfig.isUseQuotes() ? "\"" + uniqueId + "\"" : uniqueId);
|
||||||
preparedStatement.execute();
|
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
|
@Override
|
||||||
public void deleteObject(T instance) {
|
public void deleteObject(T instance)
|
||||||
|
{
|
||||||
// Null check
|
// Null check
|
||||||
if (instance == null) {
|
if (instance == null)
|
||||||
plugin.logError("SQL database request to delete a null.");
|
{
|
||||||
|
this.plugin.logError("SQL database request to delete a null.");
|
||||||
return;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
Method getUniqueId = dataObject.getMethod("getUniqueId");
|
try
|
||||||
deleteID((String) getUniqueId.invoke(instance));
|
{
|
||||||
} catch (Exception e) {
|
Method getUniqueId = this.dataObject.getMethod("getUniqueId");
|
||||||
plugin.logError("Could not delete object " + instance.getClass().getName() + " " + e.getMessage());
|
this.deleteID((String) getUniqueId.invoke(instance));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
this.plugin.logError("Could not delete object " + instance.getClass().getName() + " " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean objectExists(String uniqueId) {
|
public boolean objectExists(String uniqueId)
|
||||||
|
{
|
||||||
// Query to see if this key exists
|
// 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?
|
// UniqueId needs to be placed in quotes?
|
||||||
preparedStatement.setString(1, this.sqlConfig.isUseQuotes() ? "\"" + uniqueId + "\"" : uniqueId);
|
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);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close()
|
||||||
shutdown = true;
|
{
|
||||||
|
this.shutdown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the connection
|
|
||||||
*/
|
|
||||||
public Connection getConnection() {
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param connection the connection to set
|
* Sets data source of database.
|
||||||
* @return true if connection is not null
|
*
|
||||||
|
* @param dataSource the data source
|
||||||
|
* @return {@code true} if data source is set, {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean setConnection(Connection connection) {
|
public boolean setDataSource(DataSource dataSource)
|
||||||
if (connection == null) {
|
{
|
||||||
plugin.logError("Could not connect to the database. Are the credentials in the config.yml file correct?");
|
if (dataSource == null)
|
||||||
plugin.logWarning("Disabling the plugin...");
|
{
|
||||||
Bukkit.getPluginManager().disablePlugin(plugin);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
this.connection = connection;
|
this.dataSource = dataSource;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,26 +9,34 @@ import world.bentobox.bentobox.database.DatabaseSetup;
|
|||||||
* @author barpec12
|
* @author barpec12
|
||||||
* @since 1.1
|
* @since 1.1
|
||||||
*/
|
*/
|
||||||
public class MariaDBDatabase implements DatabaseSetup {
|
public class MariaDBDatabase implements DatabaseSetup
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* MariaDB Database Connector.
|
||||||
|
*/
|
||||||
private MariaDBDatabaseConnector connector;
|
private MariaDBDatabaseConnector connector;
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see world.bentobox.bentobox.database.DatabaseSetup#getHandler(java.lang.Class)
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <T> AbstractDatabaseHandler<T> getHandler(Class<T> type) {
|
public <T> AbstractDatabaseHandler<T> getHandler(Class<T> type)
|
||||||
|
{
|
||||||
BentoBox plugin = BentoBox.getInstance();
|
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().getDatabaseHost(),
|
||||||
plugin.getSettings().getDatabasePort(),
|
plugin.getSettings().getDatabasePort(),
|
||||||
plugin.getSettings().getDatabaseName(),
|
plugin.getSettings().getDatabaseName(),
|
||||||
plugin.getSettings().getDatabaseUsername(),
|
plugin.getSettings().getDatabaseUsername(),
|
||||||
plugin.getSettings().getDatabasePassword(),
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package world.bentobox.bentobox.database.sql.mariadb;
|
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.DatabaseConnectionSettingsImpl;
|
||||||
import world.bentobox.bentobox.database.sql.SQLDatabaseConnector;
|
import world.bentobox.bentobox.database.sql.SQLDatabaseConnector;
|
||||||
|
|
||||||
@ -7,15 +11,45 @@ import world.bentobox.bentobox.database.sql.SQLDatabaseConnector;
|
|||||||
* @author barpec12
|
* @author barpec12
|
||||||
* @since 1.1
|
* @since 1.1
|
||||||
*/
|
*/
|
||||||
public class MariaDBDatabaseConnector extends SQLDatabaseConnector {
|
public class MariaDBDatabaseConnector extends SQLDatabaseConnector
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Class for MariaDB database connections using the settings provided
|
* Class for MariaDB database connections using the settings provided
|
||||||
* @param dbSettings - database settings
|
* @param dbSettings - database settings
|
||||||
*/
|
*/
|
||||||
MariaDBDatabaseConnector(DatabaseConnectionSettingsImpl dbSettings) {
|
MariaDBDatabaseConnector(@NonNull DatabaseConnectionSettingsImpl dbSettings)
|
||||||
super(dbSettings, "jdbc:mysql://" + dbSettings.getHost() + ":" + dbSettings.getPort() + "/" + dbSettings.getDatabaseName()
|
{
|
||||||
+ "?autoReconnect=true&useSSL=" + dbSettings.isUseSSL() + "&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8");
|
// 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,8 @@ import world.bentobox.bentobox.database.sql.SQLDatabaseHandler;
|
|||||||
*
|
*
|
||||||
* @param <T>
|
* @param <T>
|
||||||
*/
|
*/
|
||||||
public class MariaDBDatabaseHandler<T> extends SQLDatabaseHandler<T> {
|
public class MariaDBDatabaseHandler<T> extends SQLDatabaseHandler<T>
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Handles the connection to the database and creation of the initial database schema (tables) for
|
* Handles the connection to the database and creation of the initial database schema (tables) for
|
||||||
* the class that will be stored.
|
* the class that will be stored.
|
||||||
@ -22,9 +22,11 @@ public class MariaDBDatabaseHandler<T> extends SQLDatabaseHandler<T> {
|
|||||||
* @param type - the type of class to be stored in the database. Must inherit DataObject
|
* @param type - the type of class to be stored in the database. Must inherit DataObject
|
||||||
* @param databaseConnector - authentication details for the database
|
* @param databaseConnector - authentication details for the database
|
||||||
*/
|
*/
|
||||||
MariaDBDatabaseHandler(BentoBox plugin, Class<T> type, DatabaseConnector databaseConnector) {
|
MariaDBDatabaseHandler(BentoBox plugin, Class<T> type, DatabaseConnector databaseConnector)
|
||||||
super(plugin, type, databaseConnector,
|
{
|
||||||
new SQLConfiguration(plugin, type)
|
super(plugin,
|
||||||
.schema("CREATE TABLE IF NOT EXISTS `[tableName]` (json JSON, uniqueId VARCHAR(255) GENERATED ALWAYS AS (JSON_EXTRACT(json, \"$.uniqueId\")), UNIQUE INDEX i (uniqueId))"));
|
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))"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,27 +5,34 @@ import world.bentobox.bentobox.database.AbstractDatabaseHandler;
|
|||||||
import world.bentobox.bentobox.database.DatabaseConnectionSettingsImpl;
|
import world.bentobox.bentobox.database.DatabaseConnectionSettingsImpl;
|
||||||
import world.bentobox.bentobox.database.DatabaseSetup;
|
import world.bentobox.bentobox.database.DatabaseSetup;
|
||||||
|
|
||||||
public class MySQLDatabase implements DatabaseSetup {
|
public class MySQLDatabase implements DatabaseSetup
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* MySQL Database Connector
|
||||||
|
*/
|
||||||
private MySQLDatabaseConnector connector;
|
private MySQLDatabaseConnector connector;
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see world.bentobox.bentobox.database.DatabaseSetup#getHandler(java.lang.Class)
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <T> AbstractDatabaseHandler<T> getHandler(Class<T> type) {
|
public <T> AbstractDatabaseHandler<T> getHandler(Class<T> type)
|
||||||
|
{
|
||||||
BentoBox plugin = BentoBox.getInstance();
|
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().getDatabaseHost(),
|
||||||
plugin.getSettings().getDatabasePort(),
|
plugin.getSettings().getDatabasePort(),
|
||||||
plugin.getSettings().getDatabaseName(),
|
plugin.getSettings().getDatabaseName(),
|
||||||
plugin.getSettings().getDatabaseUsername(),
|
plugin.getSettings().getDatabaseUsername(),
|
||||||
plugin.getSettings().getDatabasePassword(),
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,56 @@
|
|||||||
package world.bentobox.bentobox.database.sql.mysql;
|
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.DatabaseConnectionSettingsImpl;
|
||||||
import world.bentobox.bentobox.database.sql.SQLDatabaseConnector;
|
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
|
* Class for MySQL database connections using the settings provided
|
||||||
|
*
|
||||||
* @param dbSettings - database settings
|
* @param dbSettings - database settings
|
||||||
*/
|
*/
|
||||||
MySQLDatabaseConnector(DatabaseConnectionSettingsImpl dbSettings) {
|
MySQLDatabaseConnector(@NonNull DatabaseConnectionSettingsImpl dbSettings)
|
||||||
super(dbSettings, "jdbc:mysql://" + dbSettings.getHost() + ":" + dbSettings.getPort() + "/" + dbSettings.getDatabaseName()
|
{
|
||||||
+ "?autoReconnect=true&useSSL=" + dbSettings.isUseSSL() + "&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8");
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,17 +13,21 @@ import world.bentobox.bentobox.database.sql.SQLDatabaseHandler;
|
|||||||
*
|
*
|
||||||
* @param <T>
|
* @param <T>
|
||||||
*/
|
*/
|
||||||
public class MySQLDatabaseHandler<T> extends SQLDatabaseHandler<T> {
|
public class MySQLDatabaseHandler<T> extends SQLDatabaseHandler<T>
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Handles the connection to the database and creation of the initial database schema (tables) for
|
* Handles the connection to the database and creation of the initial database schema (tables) for the class that
|
||||||
* the class that will be stored.
|
* will be stored.
|
||||||
|
*
|
||||||
* @param plugin - plugin object
|
* @param plugin - plugin object
|
||||||
* @param type - the type of class to be stored in the database. Must inherit DataObject
|
* @param type - the type of class to be stored in the database. Must inherit DataObject
|
||||||
* @param dbConnecter - authentication details for the database
|
* @param dbConnecter - authentication details for the database
|
||||||
*/
|
*/
|
||||||
MySQLDatabaseHandler(BentoBox plugin, Class<T> type, DatabaseConnector dbConnecter) {
|
MySQLDatabaseHandler(BentoBox plugin, Class<T> 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"));
|
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"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,23 +9,34 @@ import world.bentobox.bentobox.database.DatabaseSetup;
|
|||||||
* @since 1.6.0
|
* @since 1.6.0
|
||||||
* @author Poslovitch
|
* @author Poslovitch
|
||||||
*/
|
*/
|
||||||
public class PostgreSQLDatabase implements DatabaseSetup {
|
public class PostgreSQLDatabase implements DatabaseSetup
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* PostgreSQL Database Connector.
|
||||||
|
*/
|
||||||
PostgreSQLDatabaseConnector connector;
|
PostgreSQLDatabaseConnector connector;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <T> AbstractDatabaseHandler<T> getHandler(Class<T> dataObjectClass) {
|
public <T> AbstractDatabaseHandler<T> getHandler(Class<T> dataObjectClass)
|
||||||
|
{
|
||||||
BentoBox plugin = BentoBox.getInstance();
|
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().getDatabaseHost(),
|
||||||
plugin.getSettings().getDatabasePort(),
|
plugin.getSettings().getDatabasePort(),
|
||||||
plugin.getSettings().getDatabaseName(),
|
plugin.getSettings().getDatabaseName(),
|
||||||
plugin.getSettings().getDatabaseUsername(),
|
plugin.getSettings().getDatabaseUsername(),
|
||||||
plugin.getSettings().getDatabasePassword(),
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,54 @@
|
|||||||
package world.bentobox.bentobox.database.sql.postgresql;
|
package world.bentobox.bentobox.database.sql.postgresql;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
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.DatabaseConnectionSettingsImpl;
|
||||||
import world.bentobox.bentobox.database.sql.SQLDatabaseConnector;
|
import world.bentobox.bentobox.database.sql.SQLDatabaseConnector;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 1.6.0
|
* @since 1.6.0
|
||||||
* @author Poslovitch
|
* @author Poslovitch
|
||||||
*/
|
*/
|
||||||
public class PostgreSQLDatabaseConnector extends SQLDatabaseConnector {
|
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for PostgreSQL database connections using the settings provided
|
* Class for PostgreSQL database connections using the settings provided
|
||||||
|
*
|
||||||
* @param dbSettings - database settings
|
* @param dbSettings - database settings
|
||||||
*/
|
*/
|
||||||
PostgreSQLDatabaseConnector(@NonNull DatabaseConnectionSettingsImpl dbSettings) {
|
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");
|
// 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package world.bentobox.bentobox.database.sql.postgresql;
|
package world.bentobox.bentobox.database.sql.postgresql;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
@ -19,70 +20,86 @@ import world.bentobox.bentobox.database.sql.SQLDatabaseHandler;
|
|||||||
* @since 1.11.0
|
* @since 1.11.0
|
||||||
* @author tastybento
|
* @author tastybento
|
||||||
*/
|
*/
|
||||||
public class PostgreSQLDatabaseHandler<T> extends SQLDatabaseHandler<T> {
|
public class PostgreSQLDatabaseHandler<T> extends SQLDatabaseHandler<T>
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param plugin BentoBox plugin
|
* @param plugin BentoBox plugin
|
||||||
* @param type The type of the objects that should be created and filled with
|
* @param type The type of the objects that should be created and filled with values from the database or inserted
|
||||||
* values from the database or inserted into the database
|
* into the database
|
||||||
* @param databaseConnector Contains the settings to create a connection to the database
|
* @param databaseConnector Contains the settings to create a connection to the database
|
||||||
*/
|
*/
|
||||||
PostgreSQLDatabaseHandler(BentoBox plugin, Class<T> type, DatabaseConnector databaseConnector) {
|
PostgreSQLDatabaseHandler(BentoBox plugin, Class<T> type, DatabaseConnector databaseConnector)
|
||||||
super(plugin, type, databaseConnector, new SQLConfiguration(plugin, type)
|
{
|
||||||
|
super(plugin,
|
||||||
|
type,
|
||||||
|
databaseConnector,
|
||||||
|
new SQLConfiguration(plugin, type).
|
||||||
// Set uniqueid as the primary key (index). Postgresql convention is to use lower case field names
|
// 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.
|
// 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)")
|
schema("CREATE TABLE IF NOT EXISTS \"[tableName]\" (uniqueid VARCHAR PRIMARY KEY, json jsonb NOT NULL)").
|
||||||
.loadObject("SELECT * FROM \"[tableName]\" WHERE uniqueid = ? LIMIT 1")
|
loadObject("SELECT * FROM \"[tableName]\" WHERE uniqueid = ? LIMIT 1").
|
||||||
.deleteObject("DELETE FROM \"[tableName]\" WHERE uniqueid = ?")
|
deleteObject("DELETE FROM \"[tableName]\" WHERE uniqueid = ?").
|
||||||
// uniqueId has to be added into the row explicitly so we need to override the saveObject method
|
// 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
|
// 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.
|
// This is the Postgresql version of UPSERT.
|
||||||
+ "ON CONFLICT (uniqueid) "
|
+ "ON CONFLICT (uniqueid) DO UPDATE SET json = cast(? as json)").
|
||||||
+ "DO UPDATE SET json = cast(? as json)")
|
loadObjects("SELECT json FROM \"[tableName]\"").
|
||||||
.loadObjects("SELECT json FROM \"[tableName]\"")
|
|
||||||
// Postgres exists function returns true or false natively
|
// Postgres exists function returns true or false natively
|
||||||
.objectExists("SELECT EXISTS(SELECT * FROM \"[tableName]\" WHERE uniqueid = ?)")
|
objectExists("SELECT EXISTS(SELECT * FROM \"[tableName]\" WHERE uniqueid = ?)").
|
||||||
.renameTable("ALTER TABLE IF EXISTS \"[oldTableName]\" RENAME TO \"[tableName]\"")
|
renameTable("ALTER TABLE IF EXISTS \"[oldTableName]\" RENAME TO \"[tableName]\"").
|
||||||
.setUseQuotes(false)
|
setUseQuotes(false)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see world.bentobox.bentobox.database.sql.SQLDatabaseHandler#saveObject(java.lang.Object)
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Boolean> saveObject(T instance) {
|
public CompletableFuture<Boolean> saveObject(T instance)
|
||||||
|
{
|
||||||
CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();
|
CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();
|
||||||
|
|
||||||
// Null check
|
// Null check
|
||||||
if (instance == null) {
|
if (instance == null)
|
||||||
plugin.logError("PostgreSQL database request to store a null. ");
|
{
|
||||||
|
this.plugin.logError("PostgreSQL database request to store a null. ");
|
||||||
completableFuture.complete(false);
|
completableFuture.complete(false);
|
||||||
return completableFuture;
|
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);
|
completableFuture.complete(false);
|
||||||
return completableFuture;
|
return completableFuture;
|
||||||
}
|
}
|
||||||
Gson gson = getGson();
|
|
||||||
|
Gson gson = this.getGson();
|
||||||
String toStore = gson.toJson(instance);
|
String toStore = gson.toJson(instance);
|
||||||
String uniqueId = ((DataObject) instance).getUniqueId();
|
String uniqueId = ((DataObject) instance).getUniqueId();
|
||||||
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, uniqueId); // INSERT
|
preparedStatement.setString(1, uniqueId); // INSERT
|
||||||
preparedStatement.setString(2, toStore); // INSERT
|
preparedStatement.setString(2, toStore); // INSERT
|
||||||
preparedStatement.setString(3, toStore); // ON CONFLICT
|
preparedStatement.setString(3, toStore); // ON CONFLICT
|
||||||
preparedStatement.execute();
|
preparedStatement.execute();
|
||||||
completableFuture.complete(true);
|
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);
|
completableFuture.complete(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return completableFuture;
|
return completableFuture;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,51 @@
|
|||||||
package world.bentobox.bentobox.database.sql.sqlite;
|
package world.bentobox.bentobox.database.sql.sqlite;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
import world.bentobox.bentobox.BentoBox;
|
import world.bentobox.bentobox.BentoBox;
|
||||||
import world.bentobox.bentobox.database.AbstractDatabaseHandler;
|
import world.bentobox.bentobox.database.AbstractDatabaseHandler;
|
||||||
import world.bentobox.bentobox.database.DatabaseSetup;
|
import world.bentobox.bentobox.database.DatabaseSetup;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 1.6.0
|
* @since 1.6.0
|
||||||
* @author Poslovitch
|
* @author Poslovitch
|
||||||
*/
|
*/
|
||||||
public class SQLiteDatabase implements DatabaseSetup {
|
public class SQLiteDatabase implements DatabaseSetup
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Database file name.
|
||||||
|
*/
|
||||||
|
private static final String DATABASE_FOLDER_NAME = "database";
|
||||||
|
|
||||||
private final SQLiteDatabaseConnector connector = new SQLiteDatabaseConnector(BentoBox.getInstance());
|
/**
|
||||||
|
* SQLite Database Connector.
|
||||||
|
*/
|
||||||
|
private SQLiteDatabaseConnector connector;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <T> AbstractDatabaseHandler<T> getHandler(Class<T> dataObjectClass) {
|
public <T> AbstractDatabaseHandler<T> getHandler(Class<T> dataObjectClass)
|
||||||
return new SQLiteDatabaseHandler<>(BentoBox.getInstance(), dataObjectClass, connector);
|
{
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,48 +1,37 @@
|
|||||||
package world.bentobox.bentobox.database.sql.sqlite;
|
package world.bentobox.bentobox.database.sql.sqlite;
|
||||||
|
|
||||||
import java.io.File;
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
import java.sql.DriverManager;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
|
||||||
|
|
||||||
import world.bentobox.bentobox.BentoBox;
|
|
||||||
import world.bentobox.bentobox.database.sql.SQLDatabaseConnector;
|
import world.bentobox.bentobox.database.sql.SQLDatabaseConnector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 1.6.0
|
* @since 1.6.0
|
||||||
* @author Poslovitch
|
* @author Poslovitch
|
||||||
*/
|
*/
|
||||||
public class SQLiteDatabaseConnector extends SQLDatabaseConnector {
|
public class SQLiteDatabaseConnector extends SQLDatabaseConnector
|
||||||
|
{
|
||||||
private static final String DATABASE_FOLDER_NAME = "database";
|
/**
|
||||||
|
* Default constructor.
|
||||||
SQLiteDatabaseConnector(@NonNull BentoBox plugin) {
|
*/
|
||||||
super(null, ""); // Not used by SQLite
|
SQLiteDatabaseConnector(String connectionUrl)
|
||||||
File dataFolder = new File(plugin.getDataFolder(), DATABASE_FOLDER_NAME);
|
{
|
||||||
if (!dataFolder.exists() && !dataFolder.mkdirs()) {
|
super(null, connectionUrl);
|
||||||
BentoBox.getInstance().logError("Could not create database folder!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
connectionUrl = "jdbc:sqlite:" + dataFolder.getAbsolutePath() + File.separator + "database.db";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/**
|
||||||
* @see world.bentobox.bentobox.database.sql.SQLDatabaseConnector#createConnection(java.lang.Class)
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object createConnection(Class<?> type) {
|
public HikariConfig createConfig()
|
||||||
types.add(type);
|
{
|
||||||
// Only make one connection at a time
|
HikariConfig config = new HikariConfig();
|
||||||
if (connection == null) {
|
config.setDataSourceClassName("org.sqlite.SQLiteDataSource");
|
||||||
try {
|
config.setPoolName("BentoBox SQLite Pool");
|
||||||
connection = DriverManager.getConnection(connectionUrl);
|
config.addDataSourceProperty("encoding", "UTF-8");
|
||||||
} catch (SQLException e) {
|
config.addDataSourceProperty("url", this.connectionUrl);
|
||||||
Bukkit.getLogger().severe("Could not connect to the database! " + e.getMessage());
|
config.setMaximumPoolSize(100);
|
||||||
}
|
|
||||||
}
|
return config;
|
||||||
return connection;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package world.bentobox.bentobox.database.sql.sqlite;
|
package world.bentobox.bentobox.database.sql.sqlite;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@ -17,23 +18,24 @@ import world.bentobox.bentobox.database.sql.SQLDatabaseHandler;
|
|||||||
* @since 1.6.0
|
* @since 1.6.0
|
||||||
* @author Poslovitch, tastybento
|
* @author Poslovitch, tastybento
|
||||||
*/
|
*/
|
||||||
public class SQLiteDatabaseHandler<T> extends SQLDatabaseHandler<T> {
|
public class SQLiteDatabaseHandler<T> extends SQLDatabaseHandler<T>
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param plugin BentoBox plugin
|
* @param plugin BentoBox plugin
|
||||||
* @param type The type of the objects that should be created and filled with
|
* @param type The type of the objects that should be created and filled with values from the database or inserted
|
||||||
* values from the database or inserted into the database
|
* into the database
|
||||||
* @param databaseConnector Contains the settings to create a connection to the database
|
* @param databaseConnector Contains the settings to create a connection to the database
|
||||||
*/
|
*/
|
||||||
protected SQLiteDatabaseHandler(BentoBox plugin, Class<T> type, DatabaseConnector databaseConnector) {
|
protected SQLiteDatabaseHandler(BentoBox plugin, Class<T> 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)")
|
super(plugin, type, databaseConnector, new SQLConfiguration(plugin, type).
|
||||||
.saveObject("INSERT INTO `[tableName]` (json, uniqueId) VALUES (?, ?) ON CONFLICT(uniqueId) DO UPDATE SET json = ?")
|
schema("CREATE TABLE IF NOT EXISTS `[tableName]` (json JSON, uniqueId VARCHAR(255) NOT NULL PRIMARY KEY)").
|
||||||
.objectExists("SELECT EXISTS (SELECT 1 FROM `[tableName]` WHERE `uniqueId` = ?)")
|
saveObject("INSERT INTO `[tableName]` (json, uniqueId) VALUES (?, ?) ON CONFLICT(uniqueId) DO UPDATE SET json = ?").
|
||||||
.renameTable("ALTER TABLE `[oldTableName]` RENAME TO `[tableName]`")
|
objectExists("SELECT EXISTS (SELECT 1 FROM `[tableName]` WHERE `uniqueId` = ?)").
|
||||||
.setUseQuotes(false)
|
renameTable("ALTER TABLE `[oldTableName]` RENAME TO `[tableName]`").
|
||||||
|
setUseQuotes(false)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,70 +44,115 @@ public class SQLiteDatabaseHandler<T> extends SQLDatabaseHandler<T> {
|
|||||||
* Creates the table in the database if it doesn't exist already
|
* Creates the table in the database if it doesn't exist already
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void createSchema() {
|
protected void createSchema()
|
||||||
if (getSqlConfig().renameRequired()) {
|
{
|
||||||
|
if (this.getSqlConfig().renameRequired())
|
||||||
|
{
|
||||||
// SQLite does not have a rename if exists command so we have to manually check if the old table exists
|
// 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)";
|
String sql = "SELECT EXISTS (SELECT 1 FROM sqlite_master WHERE type='table' AND name='" +
|
||||||
try (PreparedStatement pstmt = getConnection().prepareStatement(sql)) {
|
this.getSqlConfig().getOldTableName() + "' COLLATE NOCASE)";
|
||||||
rename(pstmt);
|
|
||||||
} catch (SQLException e) {
|
try (Connection connection = this.dataSource.getConnection();
|
||||||
plugin.logError("Could not check if " + getSqlConfig().getOldTableName() + " exists for data object " + dataObject.getCanonicalName() + " " + e.getMessage());
|
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
|
// Prepare and execute the database statements
|
||||||
try (PreparedStatement pstmt = getConnection().prepareStatement(getSqlConfig().getSchemaSQL())) {
|
try (Connection connection = this.dataSource.getConnection();
|
||||||
pstmt.execute();
|
PreparedStatement preparedStatement = connection.prepareStatement(this.getSqlConfig().getSchemaSQL()))
|
||||||
} catch (SQLException e) {
|
{
|
||||||
plugin.logError("Problem trying to create schema for data object " + dataObject.getCanonicalName() + " " + e.getMessage());
|
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()) {
|
private void rename(PreparedStatement pstmt)
|
||||||
if (resultSet.next() && resultSet.getBoolean(1)) {
|
{
|
||||||
|
try (ResultSet resultSet = pstmt.executeQuery())
|
||||||
|
{
|
||||||
|
if (resultSet.next() && resultSet.getBoolean(1))
|
||||||
|
{
|
||||||
// Transition from the old table name
|
// Transition from the old table name
|
||||||
String sql = getSqlConfig().getRenameTableSQL().replace("[oldTableName]", getSqlConfig().getOldTableName().replace("[tableName]", getSqlConfig().getTableName()));
|
String sql = this.getSqlConfig().getRenameTableSQL().replace("[oldTableName]",
|
||||||
try (PreparedStatement pstmt2 = getConnection().prepareStatement(sql)) {
|
this.getSqlConfig().getOldTableName().replace("[tableName]", this.getSqlConfig().getTableName()));
|
||||||
pstmt2.execute();
|
|
||||||
} catch (SQLException e) {
|
executeStatement(sql);
|
||||||
plugin.logError("Could not rename " + getSqlConfig().getOldTableName() + " for data object " + dataObject.getCanonicalName() + " " + e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
catch (Exception ex)
|
||||||
plugin.logError("Could not check if " + getSqlConfig().getOldTableName() + " exists for data object " + dataObject.getCanonicalName() + " " + ex.getMessage());
|
{
|
||||||
|
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
|
@Override
|
||||||
public CompletableFuture<Boolean> saveObject(T instance) {
|
public CompletableFuture<Boolean> saveObject(T instance)
|
||||||
|
{
|
||||||
CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();
|
CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();
|
||||||
|
|
||||||
// Null check
|
// Null check
|
||||||
if (instance == null) {
|
if (instance == null)
|
||||||
plugin.logError("SQLite database request to store a null. ");
|
{
|
||||||
|
this.plugin.logError("SQLite database request to store a null. ");
|
||||||
completableFuture.complete(false);
|
completableFuture.complete(false);
|
||||||
return completableFuture;
|
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);
|
completableFuture.complete(false);
|
||||||
return completableFuture;
|
return completableFuture;
|
||||||
}
|
}
|
||||||
Gson gson = getGson();
|
|
||||||
|
Gson gson = this.getGson();
|
||||||
String toStore = gson.toJson(instance);
|
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(1, toStore);
|
||||||
preparedStatement.setString(2, ((DataObject) instance).getUniqueId());
|
preparedStatement.setString(2, ((DataObject) instance).getUniqueId());
|
||||||
preparedStatement.setString(3, toStore);
|
preparedStatement.setString(3, toStore);
|
||||||
preparedStatement.execute();
|
preparedStatement.execute();
|
||||||
completableFuture.complete(true);
|
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);
|
completableFuture.complete(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return completableFuture;
|
return completableFuture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -25,8 +25,6 @@ import org.bukkit.configuration.InvalidConfigurationException;
|
|||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
import org.eclipse.jdt.annotation.NonNull;
|
||||||
|
|
||||||
import com.google.common.base.Charsets;
|
|
||||||
|
|
||||||
import world.bentobox.bentobox.BentoBox;
|
import world.bentobox.bentobox.BentoBox;
|
||||||
import world.bentobox.bentobox.database.DatabaseConnector;
|
import world.bentobox.bentobox.database.DatabaseConnector;
|
||||||
|
|
||||||
@ -100,11 +98,14 @@ public class YamlDatabaseConnector implements DatabaseConnector {
|
|||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(yamlFile), StandardCharsets.UTF_8))){
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(yamlFile), StandardCharsets.UTF_8))){
|
||||||
File temp = File.createTempFile("file", ".tmp", yamlFile.getParentFile());
|
File temp = File.createTempFile("file", ".tmp", yamlFile.getParentFile());
|
||||||
writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(temp), StandardCharsets.UTF_8));
|
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", "");
|
line = line.replace("!!java.util.UUID", "");
|
||||||
writer.println(line);
|
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?");
|
plugin.logError("Could not rename fixed Island object. Are the writing permissions correctly setup?");
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -123,7 +124,7 @@ public class YamlDatabaseConnector implements DatabaseConnector {
|
|||||||
if (!tableFolder.exists()) {
|
if (!tableFolder.exists()) {
|
||||||
tableFolder.mkdirs();
|
tableFolder.mkdirs();
|
||||||
}
|
}
|
||||||
try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8)) {
|
try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) {
|
||||||
writer.write(data);
|
writer.write(data);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
plugin.logError("Could not save yml file: " + tableName + " " + fileName + " " + e.getMessage());
|
plugin.logError("Could not save yml file: " + tableName + " " + fileName + " " + e.getMessage());
|
||||||
@ -151,9 +152,8 @@ public class YamlDatabaseConnector implements DatabaseConnector {
|
|||||||
for (Entry<String, String> e : commentMap.entrySet()) {
|
for (Entry<String, String> e : commentMap.entrySet()) {
|
||||||
if (nextLine.contains(e.getKey())) {
|
if (nextLine.contains(e.getKey())) {
|
||||||
// We want the comment to start at the same level as the entry
|
// 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();
|
e.getValue();
|
||||||
nextLine = commentLine;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,9 +316,9 @@ public class YamlDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
|||||||
// There could be more than one argument, so step through them
|
// There could be more than one argument, so step through them
|
||||||
for (Type genericParameterType : genericParameterTypes) {
|
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 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
|
// Get the actual type arguments of the parameter
|
||||||
Type[] parameters = ((ParameterizedType)genericParameterType).getActualTypeArguments();
|
Type[] parameters = pt.getActualTypeArguments();
|
||||||
result.addAll(Arrays.asList(parameters));
|
result.addAll(Arrays.asList(parameters));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -338,13 +338,11 @@ public class YamlDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
|||||||
// Null check
|
// Null check
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
plugin.logError("YAML database request to store a null.");
|
plugin.logError("YAML database request to store a null.");
|
||||||
completableFuture.complete(false);
|
return CompletableFuture.completedFuture(false);
|
||||||
return completableFuture;
|
|
||||||
}
|
}
|
||||||
if (!(instance instanceof DataObject)) {
|
if (!(instance instanceof DataObject)) {
|
||||||
plugin.logError("This class is not a DataObject: " + instance.getClass().getName());
|
plugin.logError("This class is not a DataObject: " + instance.getClass().getName());
|
||||||
completableFuture.complete(false);
|
return CompletableFuture.completedFuture(false);
|
||||||
return completableFuture;
|
|
||||||
}
|
}
|
||||||
// This is the Yaml Configuration that will be used and saved at the end
|
// This is the Yaml Configuration that will be used and saved at the end
|
||||||
YamlConfiguration config = new YamlConfiguration();
|
YamlConfiguration config = new YamlConfiguration();
|
||||||
@ -396,9 +394,7 @@ public class YamlDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
|||||||
handleConfigEntryComments(configEntry, config, yamlComments, parent);
|
handleConfigEntryComments(configEntry, config, yamlComments, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkAdapter(field, config, storageLocation, value)) {
|
if (!checkAdapter(field, config, storageLocation, value)) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Set the filename if it has not be set already
|
// Set the filename if it has not be set already
|
||||||
if (filename.isEmpty() && method.getName().equals("getUniqueId")) {
|
if (filename.isEmpty() && method.getName().equals("getUniqueId")) {
|
||||||
// Save the name for when the file is saved
|
// Save the name for when the file is saved
|
||||||
@ -414,6 +410,7 @@ public class YamlDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
|||||||
config.set(storageLocation, serialize(value));
|
config.set(storageLocation, serialize(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// If the filename has not been set by now then we have a problem
|
// If the filename has not been set by now then we have a problem
|
||||||
if (filename.isEmpty()) {
|
if (filename.isEmpty()) {
|
||||||
throw new IllegalArgumentException("No uniqueId in class");
|
throw new IllegalArgumentException("No uniqueId in class");
|
||||||
@ -469,6 +466,16 @@ public class YamlDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an adapter is to be used. If so, it is used and true returned, if not, fase is returned
|
||||||
|
* @param field Field
|
||||||
|
* @param config Yaml Config
|
||||||
|
* @param storageLocation Storage location
|
||||||
|
* @param value Value
|
||||||
|
* @return true if adapater used
|
||||||
|
* @throws IllegalAccessException exception
|
||||||
|
* @throws InvocationTargetException exception
|
||||||
|
*/
|
||||||
private boolean checkAdapter(Field field, YamlConfiguration config, String storageLocation, Object value) throws IllegalAccessException, InvocationTargetException {
|
private boolean checkAdapter(Field field, YamlConfiguration config, String storageLocation, Object value) throws IllegalAccessException, InvocationTargetException {
|
||||||
Adapter adapterNotation = field.getAnnotation(Adapter.class);
|
Adapter adapterNotation = field.getAnnotation(Adapter.class);
|
||||||
if (adapterNotation != null && AdapterInterface.class.isAssignableFrom(adapterNotation.value())) {
|
if (adapterNotation != null && AdapterInterface.class.isAssignableFrom(adapterNotation.value())) {
|
||||||
|
@ -14,7 +14,7 @@ import world.bentobox.bentobox.api.hooks.Hook;
|
|||||||
*
|
*
|
||||||
* @author Poslovitch
|
* @author Poslovitch
|
||||||
*/
|
*/
|
||||||
public class MultiverseCoreHook extends Hook {
|
public class MultiverseCoreHook extends Hook implements WorldManagementHook {
|
||||||
|
|
||||||
private static final String MULTIVERSE_SET_GENERATOR = "mv modify set generator ";
|
private static final String MULTIVERSE_SET_GENERATOR = "mv modify set generator ";
|
||||||
private static final String MULTIVERSE_IMPORT = "mv import ";
|
private static final String MULTIVERSE_IMPORT = "mv import ";
|
||||||
@ -28,6 +28,7 @@ public class MultiverseCoreHook extends Hook {
|
|||||||
* @param world - world to register
|
* @param world - world to register
|
||||||
* @param islandWorld - if true, then this is an island world
|
* @param islandWorld - if true, then this is an island world
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void registerWorld(World world, boolean islandWorld) {
|
public void registerWorld(World world, boolean islandWorld) {
|
||||||
if (islandWorld) {
|
if (islandWorld) {
|
||||||
// Only register generator if one is defined in the addon (is not null)
|
// Only register generator if one is defined in the addon (is not null)
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
package world.bentobox.bentobox.hooks;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
import com.bergerkiller.bukkit.mw.WorldConfigStore;
|
||||||
|
|
||||||
|
import world.bentobox.bentobox.BentoBox;
|
||||||
|
import world.bentobox.bentobox.api.hooks.Hook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides implementation and interfacing to interact with MyWorlds.
|
||||||
|
*
|
||||||
|
* @author bergerkiller (Irmo van den Berge)
|
||||||
|
*/
|
||||||
|
public class MyWorldsHook extends Hook implements WorldManagementHook {
|
||||||
|
|
||||||
|
public MyWorldsHook() {
|
||||||
|
super("My_Worlds", Material.FILLED_MAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the world with MyWorlds
|
||||||
|
*
|
||||||
|
* @param world - world to register
|
||||||
|
* @param islandWorld - if true, then this is an island world
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void registerWorld(World world, boolean islandWorld) {
|
||||||
|
if (islandWorld) {
|
||||||
|
// Only register generator if one is defined in the addon (is not null)
|
||||||
|
boolean hasGenerator = BentoBox.getInstance().getIWM().getAddon(world).map(gm -> gm.getDefaultWorldGenerator(world.getName(), "") != null).orElse(false);
|
||||||
|
setUseBentoboxGenerator(world, hasGenerator);
|
||||||
|
} else {
|
||||||
|
// Set the generator to null - this will remove any previous registration
|
||||||
|
setUseBentoboxGenerator(world, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUseBentoboxGenerator(World world, boolean hasGenerator) {
|
||||||
|
String name = hasGenerator ? BentoBox.getInstance().getName() : null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
WorldConfigStore.get(world).setChunkGeneratorName(name);
|
||||||
|
|
||||||
|
// Alternative Reflection way to do it, if a MyWorlds dependency isn't available at
|
||||||
|
// compile time.
|
||||||
|
/*
|
||||||
|
// WorldConfigStore -> public static WorldConfig get(World world);
|
||||||
|
Object worldConfig = Class.forName("com.bergerkiller.bukkit.mw.WorldConfigStore")
|
||||||
|
.getMethod("get", World.class)
|
||||||
|
.invoke(null, world);
|
||||||
|
|
||||||
|
// WorldConfig -> public void setChunkGeneratorName(String name);
|
||||||
|
Class.forName("com.bergerkiller.bukkit.mw.WorldConfig")
|
||||||
|
.getMethod("setChunkGeneratorName", String.class)
|
||||||
|
.invoke(worldConfig, name);
|
||||||
|
*/
|
||||||
|
} catch (Exception t) {
|
||||||
|
BentoBox.getInstance().logError("Failed to register world " + world.getName() + " with MyWorlds " + t.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hook() {
|
||||||
|
return true; // The hook process shouldn't fail
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFailureCause() {
|
||||||
|
return null; // The hook process shouldn't fail
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package world.bentobox.bentobox.hooks;
|
||||||
|
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook for a type of Multi-World management plugin that must be made
|
||||||
|
* aware of the correct configuration of a BentoBox World.
|
||||||
|
*
|
||||||
|
* @author bergerkiller (Irmo van den Berge)
|
||||||
|
*/
|
||||||
|
public interface WorldManagementHook {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the world with the World Management hook
|
||||||
|
*
|
||||||
|
* @param world - world to register
|
||||||
|
* @param islandWorld - if true, then this is an island world
|
||||||
|
*/
|
||||||
|
void registerWorld(World world, boolean islandWorld);
|
||||||
|
}
|
@ -9,6 +9,7 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
import org.eclipse.jdt.annotation.NonNull;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPI;
|
import me.clip.placeholderapi.PlaceholderAPI;
|
||||||
import world.bentobox.bentobox.BentoBox;
|
import world.bentobox.bentobox.BentoBox;
|
||||||
@ -69,12 +70,12 @@ public class PlaceholderAPIHook extends PlaceholderHook {
|
|||||||
@Override
|
@Override
|
||||||
public void registerPlaceholder(@NonNull Addon addon, @NonNull String placeholder, @NonNull PlaceholderReplacer replacer) {
|
public void registerPlaceholder(@NonNull Addon addon, @NonNull String placeholder, @NonNull PlaceholderReplacer replacer) {
|
||||||
// Check if the addon expansion does not exist
|
// Check if the addon expansion does not exist
|
||||||
if (!addonsExpansions.containsKey(addon)) {
|
addonsExpansions.computeIfAbsent(addon, k -> {
|
||||||
AddonPlaceholderExpansion addonPlaceholderExpansion = new AddonPlaceholderExpansion(addon);
|
AddonPlaceholderExpansion addonPlaceholderExpansion = new AddonPlaceholderExpansion(addon);
|
||||||
addonPlaceholderExpansion.register();
|
addonPlaceholderExpansion.register();
|
||||||
addonsExpansions.put(addon, addonPlaceholderExpansion);
|
this.addonPlaceholders.computeIfAbsent(addon, kk -> new HashSet<>()).add(placeholder);
|
||||||
this.addonPlaceholders.computeIfAbsent(addon, k -> new HashSet<>()).add(placeholder);
|
return addonPlaceholderExpansion;
|
||||||
}
|
});
|
||||||
addonsExpansions.get(addon).registerPlaceholder(placeholder, replacer);
|
addonsExpansions.get(addon).registerPlaceholder(placeholder, replacer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +110,10 @@ public class PlaceholderAPIHook extends PlaceholderHook {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@NonNull
|
@NonNull
|
||||||
public String replacePlaceholders(@NonNull Player player, @NonNull String string) {
|
public String replacePlaceholders(@Nullable Player player, @NonNull String string) {
|
||||||
|
if (player == null) {
|
||||||
|
return PlaceholderAPI.setPlaceholders(player, removeGMPlaceholder(string));
|
||||||
|
}
|
||||||
// Transform [gamemode] in string to the game mode description name, or remove it for the default replacement
|
// Transform [gamemode] in string to the game mode description name, or remove it for the default replacement
|
||||||
String newString = BentoBox.getInstance().getIWM().getAddon(player.getWorld()).map(gm ->
|
String newString = BentoBox.getInstance().getIWM().getAddon(player.getWorld()).map(gm ->
|
||||||
string.replace(TextVariables.GAMEMODE, gm.getDescription().getName().toLowerCase())
|
string.replace(TextVariables.GAMEMODE, gm.getDescription().getName().toLowerCase())
|
||||||
|
@ -16,6 +16,7 @@ import org.bukkit.event.player.PlayerChangedWorldEvent;
|
|||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
import org.eclipse.jdt.annotation.NonNull;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
import world.bentobox.bentobox.BentoBox;
|
import world.bentobox.bentobox.BentoBox;
|
||||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||||
@ -49,7 +50,8 @@ public class JoinLeaveListener implements Listener {
|
|||||||
User.removePlayer(event.getPlayer());
|
User.removePlayer(event.getPlayer());
|
||||||
|
|
||||||
User user = User.getInstance(event.getPlayer());
|
User user = User.getInstance(event.getPlayer());
|
||||||
if (user == null || user.getUniqueId() == null) {
|
if (!user.isPlayer() || user.getUniqueId() == null) {
|
||||||
|
// This should never be the case, but it might be caused by some fake player plugins
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
UUID playerUUID = event.getPlayer().getUniqueId();
|
UUID playerUUID = event.getPlayer().getUniqueId();
|
||||||
@ -142,7 +144,7 @@ public class JoinLeaveListener implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This event will clean players inventor
|
* This event will clean players inventory
|
||||||
* @param event SwitchWorld event.
|
* @param event SwitchWorld event.
|
||||||
*/
|
*/
|
||||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
@ -161,8 +163,8 @@ public class JoinLeaveListener implements Listener {
|
|||||||
* @param world World where cleaning must occur.
|
* @param world World where cleaning must occur.
|
||||||
* @param user Targeted user.
|
* @param user Targeted user.
|
||||||
*/
|
*/
|
||||||
private void clearPlayersInventory(World world, @NonNull User user) {
|
private void clearPlayersInventory(@Nullable World world, @NonNull User user) {
|
||||||
if (user.getUniqueId() == null) return;
|
if (user.getUniqueId() == null || world == null) return;
|
||||||
// Clear inventory if required
|
// Clear inventory if required
|
||||||
Players playerData = players.getPlayer(user.getUniqueId());
|
Players playerData = players.getPlayer(user.getUniqueId());
|
||||||
|
|
||||||
|
@ -18,7 +18,9 @@ import world.bentobox.bentobox.database.objects.Island;
|
|||||||
* Abstracts PlayerPortalEvent and EntityPortalEvent
|
* Abstracts PlayerPortalEvent and EntityPortalEvent
|
||||||
* @author tastybento
|
* @author tastybento
|
||||||
* @deprecated replaced not used in new listeners.
|
* @deprecated replaced not used in new listeners.
|
||||||
|
* @since 1.12.1
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since="1.21.0", forRemoval=true)
|
||||||
public class PlayerEntityPortalEvent {
|
public class PlayerEntityPortalEvent {
|
||||||
|
|
||||||
private final EntityPortalEvent epe;
|
private final EntityPortalEvent epe;
|
||||||
|
@ -43,8 +43,9 @@ import world.bentobox.bentobox.util.teleport.SafeSpotTeleport;
|
|||||||
* @deprecated replaced by better listeners.
|
* @deprecated replaced by better listeners.
|
||||||
* @see world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener
|
* @see world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener
|
||||||
* @see world.bentobox.bentobox.listeners.teleports.EntityTeleportListener
|
* @see world.bentobox.bentobox.listeners.teleports.EntityTeleportListener
|
||||||
|
* @since 1.12.1
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated(since="1.21.0", forRemoval=true)
|
||||||
public class PortalTeleportationListener implements Listener {
|
public class PortalTeleportationListener implements Listener {
|
||||||
|
|
||||||
private final BentoBox plugin;
|
private final BentoBox plugin;
|
||||||
@ -148,7 +149,7 @@ public class PortalTeleportationListener implements Listener {
|
|||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,9 +269,8 @@ public class PortalTeleportationListener implements Listener {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Location toLocation = e.getIsland().map(island -> island.getSpawnPoint(env)).
|
Location toLocation = Objects.requireNonNullElse(e.getIsland().map(island -> island.getSpawnPoint(env)).
|
||||||
orElse(e.getFrom().toVector().toLocation(toWorld));
|
orElse(e.getFrom().toVector().toLocation(toWorld)), e.getFrom().toVector().toLocation(toWorld));
|
||||||
|
|
||||||
// Limit Y to the min/max world height.
|
// Limit Y to the min/max world height.
|
||||||
toLocation.setY(Math.max(Math.min(toLocation.getY(), toWorld.getMaxHeight()), toWorld.getMinHeight()));
|
toLocation.setY(Math.max(Math.min(toLocation.getY(), toWorld.getMaxHeight()), toWorld.getMinHeight()));
|
||||||
|
|
||||||
@ -438,9 +438,9 @@ public class PortalTeleportationListener implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// From standard nether or end
|
// From standard nether or end
|
||||||
else if (e.getEntity() instanceof Player){
|
else if (e.getEntity() instanceof Player player){
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
plugin.getIslands().homeTeleportAsync(overWorld, (Player)e.getEntity());
|
plugin.getIslands().homeTeleportAsync(overWorld, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
@ -39,7 +38,7 @@ public class GeoMobLimitTab implements Tab, ClickHandler {
|
|||||||
.filter(EntityType::isAlive)
|
.filter(EntityType::isAlive)
|
||||||
.filter(t -> !(t.equals(EntityType.PLAYER) || t.equals(EntityType.GIANT) || t.equals(EntityType.ARMOR_STAND)))
|
.filter(t -> !(t.equals(EntityType.PLAYER) || t.equals(EntityType.GIANT) || t.equals(EntityType.ARMOR_STAND)))
|
||||||
.sorted(Comparator.comparing(EntityType::name))
|
.sorted(Comparator.comparing(EntityType::name))
|
||||||
.collect(Collectors.toList()));
|
.toList());
|
||||||
|
|
||||||
public enum EntityLimitTabType {
|
public enum EntityLimitTabType {
|
||||||
GEO_LIMIT,
|
GEO_LIMIT,
|
||||||
@ -110,7 +109,7 @@ public class GeoMobLimitTab implements Tab, ClickHandler {
|
|||||||
@Override
|
@Override
|
||||||
public List<@Nullable PanelItem> getPanelItems() {
|
public List<@Nullable PanelItem> getPanelItems() {
|
||||||
// Make panel items
|
// Make panel items
|
||||||
return LIVING_ENTITY_TYPES.stream().map(c -> getPanelItem(c, user)).collect(Collectors.toList());
|
return LIVING_ENTITY_TYPES.stream().map(c -> getPanelItem(c, user)).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package world.bentobox.bentobox.listeners.flags.protection;
|
package world.bentobox.bentobox.listeners.flags.protection;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@ -36,18 +35,19 @@ public class BlockInteractionListener extends FlagListener
|
|||||||
* These cover materials in another server version. This avoids run time errors due to unknown enum values, at the
|
* These cover materials in another server version. This avoids run time errors due to unknown enum values, at the
|
||||||
* expense of a string comparison
|
* expense of a string comparison
|
||||||
*/
|
*/
|
||||||
private final static Map<String, String> stringFlags;
|
private static final Map<String, String> stringFlags;
|
||||||
|
private static final String CHEST = "CHEST";
|
||||||
|
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
stringFlags = Map.of(
|
stringFlags = Map.of(
|
||||||
"ACACIA_CHEST_BOAT", "CHEST",
|
"ACACIA_CHEST_BOAT", CHEST,
|
||||||
"BIRCH_CHEST_BOAT", "CHEST",
|
"BIRCH_CHEST_BOAT", CHEST,
|
||||||
"JUNGLE_CHEST_BOAT", "CHEST",
|
"JUNGLE_CHEST_BOAT", CHEST,
|
||||||
"DARK_OAK_CHEST_BOAT", "CHEST",
|
"DARK_OAK_CHEST_BOAT", CHEST,
|
||||||
"MANGROVE_CHEST_BOAT", "CHEST",
|
"MANGROVE_CHEST_BOAT", CHEST,
|
||||||
"OAK_CHEST_BOAT", "CHEST",
|
"OAK_CHEST_BOAT", CHEST,
|
||||||
"SPRUCE_CHEST_BOAT", "CHEST");
|
"SPRUCE_CHEST_BOAT", CHEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,7 +6,6 @@ import org.bukkit.block.data.BlockData;
|
|||||||
import org.bukkit.entity.AbstractArrow;
|
import org.bukkit.entity.AbstractArrow;
|
||||||
import org.bukkit.entity.ArmorStand;
|
import org.bukkit.entity.ArmorStand;
|
||||||
import org.bukkit.entity.EnderCrystal;
|
import org.bukkit.entity.EnderCrystal;
|
||||||
import org.bukkit.entity.EntityType;
|
|
||||||
import org.bukkit.entity.ItemFrame;
|
import org.bukkit.entity.ItemFrame;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.entity.Projectile;
|
import org.bukkit.entity.Projectile;
|
||||||
@ -123,14 +122,12 @@ public class BreakBlocksListener extends FlagListener {
|
|||||||
if (e.getDamager() instanceof Player p) {
|
if (e.getDamager() instanceof Player p) {
|
||||||
// Check the break blocks flag
|
// Check the break blocks flag
|
||||||
notAllowed(e, p, e.getEntity().getLocation());
|
notAllowed(e, p, e.getEntity().getLocation());
|
||||||
} else if (e.getDamager() instanceof Projectile p) {
|
} else if (e.getDamager() instanceof Projectile p && // Find out who fired the arrow
|
||||||
// Find out who fired the arrow
|
p.getShooter() instanceof Player player && notAllowed(e, player, e.getEntity().getLocation())) {
|
||||||
if (p.getShooter() instanceof Player && notAllowed(e, (Player)p.getShooter(), e.getEntity().getLocation())) {
|
|
||||||
e.getEntity().setFireTicks(0);
|
e.getEntity().setFireTicks(0);
|
||||||
p.setFireTicks(0);
|
p.setFireTicks(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private boolean notAllowed(EntityDamageByEntityEvent e, Player player, Location location) {
|
private boolean notAllowed(EntityDamageByEntityEvent e, Player player, Location location) {
|
||||||
if (!checkIsland(e, player, location, Flags.BREAK_BLOCKS)) return true;
|
if (!checkIsland(e, player, location, Flags.BREAK_BLOCKS)) return true;
|
||||||
|
@ -2,7 +2,7 @@ package world.bentobox.bentobox.listeners.flags.protection;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.EnumMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ public class BreedingListener extends FlagListener {
|
|||||||
*/
|
*/
|
||||||
private static final Map<EntityType, List<Material>> BREEDING_ITEMS;
|
private static final Map<EntityType, List<Material>> BREEDING_ITEMS;
|
||||||
static {
|
static {
|
||||||
Map<EntityType, List<Material>> bi = new HashMap<>();
|
Map<EntityType, List<Material>> bi = new EnumMap<>(EntityType.class);
|
||||||
|
|
||||||
bi.put(EntityType.HORSE, Arrays.asList(Material.GOLDEN_APPLE, Material.GOLDEN_CARROT));
|
bi.put(EntityType.HORSE, Arrays.asList(Material.GOLDEN_APPLE, Material.GOLDEN_CARROT));
|
||||||
bi.put(EntityType.DONKEY, Arrays.asList(Material.GOLDEN_APPLE, Material.GOLDEN_CARROT));
|
bi.put(EntityType.DONKEY, Arrays.asList(Material.GOLDEN_APPLE, Material.GOLDEN_CARROT));
|
||||||
|
@ -18,12 +18,11 @@ public class ElytraListener extends FlagListener {
|
|||||||
*/
|
*/
|
||||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||||
public void onGlide(EntityToggleGlideEvent e) {
|
public void onGlide(EntityToggleGlideEvent e) {
|
||||||
if (e.getEntity() instanceof Player player) {
|
if (e.getEntity() instanceof Player player
|
||||||
if (!checkIsland(e, player, player.getLocation(), Flags.ELYTRA)) {
|
&& !checkIsland(e, player, player.getLocation(), Flags.ELYTRA)) {
|
||||||
player.setGliding(false);
|
player.setGliding(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||||
public void onGliding(PlayerTeleportEvent e) {
|
public void onGliding(PlayerTeleportEvent e) {
|
||||||
|
@ -2,8 +2,19 @@ package world.bentobox.bentobox.listeners.flags.protection;
|
|||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.entity.*;
|
import org.bukkit.entity.Allay;
|
||||||
|
import org.bukkit.entity.Animals;
|
||||||
|
import org.bukkit.entity.ArmorStand;
|
||||||
|
import org.bukkit.entity.Boat;
|
||||||
|
import org.bukkit.entity.ChestBoat;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.entity.Vehicle;
|
||||||
|
import org.bukkit.entity.Villager;
|
||||||
|
import org.bukkit.entity.WanderingTrader;
|
||||||
|
import org.bukkit.entity.minecart.HopperMinecart;
|
||||||
|
import org.bukkit.entity.minecart.PoweredMinecart;
|
||||||
import org.bukkit.entity.minecart.RideableMinecart;
|
import org.bukkit.entity.minecart.RideableMinecart;
|
||||||
|
import org.bukkit.entity.minecart.StorageMinecart;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
|
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
|
||||||
@ -11,7 +22,6 @@ import org.bukkit.event.player.PlayerInteractEntityEvent;
|
|||||||
|
|
||||||
import world.bentobox.bentobox.api.flags.FlagListener;
|
import world.bentobox.bentobox.api.flags.FlagListener;
|
||||||
import world.bentobox.bentobox.lists.Flags;
|
import world.bentobox.bentobox.lists.Flags;
|
||||||
import world.bentobox.bentobox.versions.ServerCompatibility;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,11 +57,19 @@ public class EntityInteractListener extends FlagListener {
|
|||||||
// Minecart riding
|
// Minecart riding
|
||||||
this.checkIsland(e, p, l, Flags.MINECART);
|
this.checkIsland(e, p, l, Flags.MINECART);
|
||||||
}
|
}
|
||||||
else if (!ServerCompatibility.getInstance().isVersion(
|
else if (e.getRightClicked() instanceof StorageMinecart)
|
||||||
ServerCompatibility.ServerVersion.V1_18,
|
{
|
||||||
ServerCompatibility.ServerVersion.V1_18_1,
|
this.checkIsland(e, p, l, Flags.CHEST);
|
||||||
ServerCompatibility.ServerVersion.V1_18_2) &&
|
}
|
||||||
e.getPlayer().isSneaking() && e.getRightClicked() instanceof ChestBoat)
|
else if (e.getRightClicked() instanceof HopperMinecart)
|
||||||
|
{
|
||||||
|
this.checkIsland(e, p, l, Flags.HOPPER);
|
||||||
|
}
|
||||||
|
else if (e.getRightClicked() instanceof PoweredMinecart)
|
||||||
|
{
|
||||||
|
this.checkIsland(e, p, l, Flags.FURNACE);
|
||||||
|
}
|
||||||
|
else if (e.getPlayer().isSneaking() && e.getRightClicked() instanceof ChestBoat)
|
||||||
{
|
{
|
||||||
// Access to chest boat since 1.19
|
// Access to chest boat since 1.19
|
||||||
this.checkIsland(e, p, l, Flags.CHEST);
|
this.checkIsland(e, p, l, Flags.CHEST);
|
||||||
@ -73,11 +91,7 @@ public class EntityInteractListener extends FlagListener {
|
|||||||
this.checkIsland(e, p, l, Flags.NAME_TAG);
|
this.checkIsland(e, p, l, Flags.NAME_TAG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!ServerCompatibility.getInstance().isVersion(
|
else if (e.getRightClicked() instanceof Allay)
|
||||||
ServerCompatibility.ServerVersion.V1_18,
|
|
||||||
ServerCompatibility.ServerVersion.V1_18_1,
|
|
||||||
ServerCompatibility.ServerVersion.V1_18_2) &&
|
|
||||||
e.getRightClicked() instanceof Allay)
|
|
||||||
{
|
{
|
||||||
// Allay item giving/taking
|
// Allay item giving/taking
|
||||||
this.checkIsland(e, p, l, Flags.ALLAY);
|
this.checkIsland(e, p, l, Flags.ALLAY);
|
||||||
|
@ -74,15 +74,13 @@ public class HurtingListener extends FlagListener {
|
|||||||
*/
|
*/
|
||||||
private void respond(EntityDamageByEntityEvent e, Entity damager, Flag flag) {
|
private void respond(EntityDamageByEntityEvent e, Entity damager, Flag flag) {
|
||||||
// Get the attacker
|
// Get the attacker
|
||||||
if (damager instanceof Player) {
|
if (damager instanceof Player player) {
|
||||||
checkIsland(e, (Player)damager, damager.getLocation(), flag);
|
checkIsland(e, player, player.getLocation(), flag);
|
||||||
} else if (damager instanceof Projectile p) {
|
} else if (damager instanceof Projectile p && // Find out who fired the projectile
|
||||||
// Find out who fired the projectile
|
p.getShooter() instanceof Player player && !checkIsland(e, player, player.getLocation(), flag)) {
|
||||||
if (p.getShooter() instanceof Player && !checkIsland(e, (Player)p.getShooter(), damager.getLocation(), flag)) {
|
|
||||||
e.getEntity().setFireTicks(0);
|
e.getEntity().setFireTicks(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle attacks with a fishing rod
|
* Handle attacks with a fishing rod
|
||||||
@ -166,9 +164,9 @@ public class HurtingListener extends FlagListener {
|
|||||||
public void onLingeringPotionSplash(final LingeringPotionSplashEvent e) {
|
public void onLingeringPotionSplash(final LingeringPotionSplashEvent e) {
|
||||||
// Try to get the shooter
|
// Try to get the shooter
|
||||||
Projectile projectile = e.getEntity();
|
Projectile projectile = e.getEntity();
|
||||||
if (projectile.getShooter() instanceof Player) {
|
if (projectile.getShooter() instanceof Player player) {
|
||||||
// Store it and remove it when the effect is gone
|
// Store it and remove it when the effect is gone
|
||||||
thrownPotions.put(e.getAreaEffectCloud().getEntityId(), (Player)projectile.getShooter());
|
thrownPotions.put(e.getAreaEffectCloud().getEntityId(), player);
|
||||||
getPlugin().getServer().getScheduler().runTaskLater(getPlugin(), () -> thrownPotions.remove(e.getAreaEffectCloud().getEntityId()), e.getAreaEffectCloud().getDuration());
|
getPlugin().getServer().getScheduler().runTaskLater(getPlugin(), () -> thrownPotions.remove(e.getAreaEffectCloud().getEntityId()), e.getAreaEffectCloud().getDuration());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@ import org.bukkit.inventory.InventoryHolder;
|
|||||||
|
|
||||||
import world.bentobox.bentobox.api.flags.FlagListener;
|
import world.bentobox.bentobox.api.flags.FlagListener;
|
||||||
import world.bentobox.bentobox.lists.Flags;
|
import world.bentobox.bentobox.lists.Flags;
|
||||||
import world.bentobox.bentobox.versions.ServerCompatibility;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,10 +53,7 @@ public class InventoryListener extends FlagListener
|
|||||||
// Prevent opening animal inventories.
|
// Prevent opening animal inventories.
|
||||||
this.checkIsland(event, player, event.getInventory().getLocation(), Flags.MOUNT_INVENTORY);
|
this.checkIsland(event, player, event.getInventory().getLocation(), Flags.MOUNT_INVENTORY);
|
||||||
}
|
}
|
||||||
else if (!ServerCompatibility.getInstance().isVersion(ServerCompatibility.ServerVersion.V1_18,
|
else if (inventoryHolder instanceof ChestBoat)
|
||||||
ServerCompatibility.ServerVersion.V1_18_1,
|
|
||||||
ServerCompatibility.ServerVersion.V1_18_2) &&
|
|
||||||
inventoryHolder instanceof ChestBoat)
|
|
||||||
{
|
{
|
||||||
// Prevent opening chest inventories
|
// Prevent opening chest inventories
|
||||||
this.checkIsland(event, player, event.getInventory().getLocation(), Flags.CHEST);
|
this.checkIsland(event, player, event.getInventory().getLocation(), Flags.CHEST);
|
||||||
@ -132,8 +128,7 @@ public class InventoryListener extends FlagListener
|
|||||||
{
|
{
|
||||||
this.checkIsland(e, player, e.getInventory().getLocation(), Flags.CHEST);
|
this.checkIsland(e, player, e.getInventory().getLocation(), Flags.CHEST);
|
||||||
}
|
}
|
||||||
else if (!ServerCompatibility.getInstance().isVersion(ServerCompatibility.ServerVersion.V1_18, ServerCompatibility.ServerVersion.V1_18_1, ServerCompatibility.ServerVersion.V1_18_2) &&
|
else if (inventoryHolder instanceof ChestBoat)
|
||||||
inventoryHolder instanceof ChestBoat)
|
|
||||||
{
|
{
|
||||||
// TODO: 1.19 added chest boat. Remove compatibility check when 1.18 is dropped.
|
// TODO: 1.19 added chest boat. Remove compatibility check when 1.18 is dropped.
|
||||||
this.checkIsland(e, player, e.getInventory().getLocation(), Flags.CHEST);
|
this.checkIsland(e, player, e.getInventory().getLocation(), Flags.CHEST);
|
||||||
|
@ -27,8 +27,8 @@ public class ItemDropPickUpListener extends FlagListener {
|
|||||||
*/
|
*/
|
||||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||||
public void onPickup(EntityPickupItemEvent e) {
|
public void onPickup(EntityPickupItemEvent e) {
|
||||||
if (e.getEntity() instanceof Player) {
|
if (e.getEntity() instanceof Player player) {
|
||||||
checkIsland(e, (Player)e.getEntity(), e.getItem().getLocation(), Flags.ITEM_PICKUP);
|
checkIsland(e, player, e.getItem().getLocation(), Flags.ITEM_PICKUP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ public class LockAndBanListener extends FlagListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// For each Player in the vehicle
|
// For each Player in the vehicle
|
||||||
e.getVehicle().getPassengers().stream().filter(en -> en instanceof Player).map(en -> (Player)en).forEach(p -> {
|
e.getVehicle().getPassengers().stream().filter(Player.class::isInstance).map(Player.class::cast).forEach(p -> {
|
||||||
if (!checkAndNotify(p, e.getTo()).equals(CheckResult.OPEN)) {
|
if (!checkAndNotify(p, e.getTo()).equals(CheckResult.OPEN)) {
|
||||||
p.leaveVehicle();
|
p.leaveVehicle();
|
||||||
p.teleport(e.getFrom());
|
p.teleport(e.getFrom());
|
||||||
@ -140,13 +140,11 @@ public class LockAndBanListener extends FlagListener {
|
|||||||
private CheckResult checkAndNotify(@NonNull Player player, Location loc)
|
private CheckResult checkAndNotify(@NonNull Player player, Location loc)
|
||||||
{
|
{
|
||||||
CheckResult result = this.check(player, loc);
|
CheckResult result = this.check(player, loc);
|
||||||
|
if (result == CheckResult.BANNED) {
|
||||||
switch (result)
|
User.getInstance(player).notify("commands.island.ban.you-are-banned");
|
||||||
{
|
} else if (result == CheckResult.LOCKED) {
|
||||||
case BANNED -> User.getInstance(player).notify("commands.island.ban.you-are-banned");
|
User.getInstance(player).notify("protection.locked");
|
||||||
case LOCKED -> User.getInstance(player).notify("protection.locked");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user