Merge branch 'develop'

This commit is contained in:
Florian CUNY 2020-01-26 13:46:22 +01:00
commit fb19c1f2ac
91 changed files with 4078 additions and 711 deletions

View File

@ -6,12 +6,7 @@ addons:
jdk:
- openjdk8
- openjdk11
matrix:
allow_failures:
- jdk: openjdk11
script:
#- sonar-scanner
- mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent install sonar:sonar -Dsonar.projectKey=BentoBoxWorld_BentoBox

View File

@ -42,7 +42,7 @@ There are also plenty of other official or community-made Addons you can try and
## Downloads
### Webtool
A [webtool](https://bentobox-tool.herokuapp.com/) is currently being developed to allow you to easily setup BentoBox and Addons on your server.
A [webtool](https://download.bentobox.world/) is currently being developed to allow you to easily setup BentoBox and Addons on your server.
### Direct links
* [Download](https://github.com/BentoBoxWorld/BentoBox/releases)

37
pom.xml
View File

@ -81,7 +81,7 @@
<!-- Do not change unless you want different name for local builds. -->
<build.number>-LOCAL</build.number>
<!-- This allows to change between versions. -->
<build.version>1.10.0</build.version>
<build.version>1.11.0</build.version>
</properties>
<!-- Profiles will allow to automatically change build version. -->
@ -221,6 +221,11 @@
<artifactId>mongodb-driver</artifactId>
<version>${mongodb.version}</version>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.1-901-1.jdbc4</version>
</dependency>
<!-- Vault: as their maven repo is down, we need to get it from jitpack -->
<!-- See https://github.com/MilkBowl/VaultAPI/issues/69 -->
<dependency>
@ -338,21 +343,39 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.1.0</version>
<version>3.1.1</version>
<configuration>
<source>8</source>
<show>private</show>
<failOnError>false</failOnError>
<additionalJOption>-Xdoclint:none</additionalJOption>
<!-- To compile with Java 11, this tag may be required -->
<!-- <javadocExecutable>${java.home}/bin/javadoc</javadocExecutable> -->
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<phase>install</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>install</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
@ -375,6 +398,7 @@
</relocations>
<artifactSet>
<excludes>
<exclude>com.google:*</exclude>
<exclude>org.mongodb:*</exclude>
<exclude>org.eclipse.jdt:*</exclude>
</excludes>
@ -398,6 +422,15 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<executions>
<execution>
<id>default-deploy</id>
<phase>deploy</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>

View File

@ -45,18 +45,24 @@ public class Settings implements ConfigObject {
@ConfigEntry(path = "general.default-language")
private String defaultLanguage = "en-US";
@ConfigComment("Use economy or not. If true, an economy plugin is required. If false, no money is used or give.")
@ConfigComment("Use economy or not. If true, an economy plugin is required. If false, no money is used or given.")
@ConfigComment("If there is no economy plugin present anyway, money will be automatically disabled.")
@ConfigEntry(path = "general.use-economy")
private boolean useEconomy = true;
// Database
@ConfigComment("JSON, MYSQL, MARIADB (10.2.3+), MONGODB, SQLITE, POSTGRESQL and YAML(deprecated).")
@ConfigComment("JSON, MYSQL, MARIADB, MONGODB, SQLITE, POSTGRESQL and YAML(deprecated).")
@ConfigComment("Transition database options are:")
@ConfigComment(" YAML2JSON, YAML2MARIADB, YAML2MYSQL, YAML2MONGODB, YAML2SQLITE")
@ConfigComment(" JSON2MARIADB, JSON2MYSQL, JSON2MONGODB, JSON2SQLITE, JSON2POSTGRESQL")
@ConfigComment(" MYSQL2JSON, MARIADB2JSON, MONGODB2JSON, SQLITE2JSON, POSTGRESQL2JSON")
@ConfigComment("If you need others, please make a feature request.")
@ConfigComment("Minimum required versions:")
@ConfigComment(" MySQL versions 5.7 or later")
@ConfigComment(" MariaDB versions 10.2.3 or later")
@ConfigComment(" MongoDB versions 3.6 or later")
@ConfigComment(" SQLite versions 3.28 or later")
@ConfigComment(" PostgreSQL versions 9.4 or later")
@ConfigComment("Transition options enable migration from one database type to another. Use /bbox migrate.")
@ConfigComment("YAML and JSON are file-based databases.")
@ConfigComment("MYSQL might not work with all implementations: if available, use a dedicated database type (e.g. MARIADB).")

View File

@ -20,6 +20,7 @@ import org.bukkit.util.permissions.DefaultPermissions;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.addons.exceptions.InvalidAddonDescriptionException;
import world.bentobox.bentobox.api.addons.exceptions.InvalidAddonFormatException;
import world.bentobox.bentobox.api.addons.exceptions.InvalidAddonInheritException;
import world.bentobox.bentobox.managers.AddonsManager;
@ -39,6 +40,7 @@ public class AddonClassLoader extends URLClassLoader {
throws InvalidAddonInheritException,
MalformedURLException,
InvalidDescriptionException,
InvalidAddonDescriptionException,
InstantiationException,
IllegalAccessException, InvocationTargetException, NoSuchMethodException {
super(new URL[]{path.toURI().toURL()}, parent);
@ -94,7 +96,7 @@ public class AddonClassLoader extends URLClassLoader {
}
@NonNull
private AddonDescription asDescription(YamlConfiguration data) {
private AddonDescription asDescription(YamlConfiguration data) throws InvalidAddonDescriptionException {
AddonDescription.Builder builder = new AddonDescription.Builder(data.getString("main"), data.getString("name"), data.getString("version"))
.authors(data.getString("authors"))
.metrics(data.getBoolean("metrics", true))
@ -110,6 +112,14 @@ public class AddonClassLoader extends URLClassLoader {
}
builder.icon(Material.getMaterial(data.getString("icon", "PAPER")));
String apiVersion = data.getString("api-version");
if (apiVersion != null) {
if (!apiVersion.matches("^(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$")) {
throw new InvalidAddonDescriptionException("Provided API version '" + apiVersion + "' is not valid. It must only contain digits and dots and not end with a dot.");
}
builder.apiVersion(apiVersion);
}
return builder.build();
}

View File

@ -35,6 +35,12 @@ public final class AddonDescription {
* @since 1.5.0
*/
private final @NonNull Material icon;
/**
* Minimum BentoBox version this addon requires in order to work properly.
* Defaults to {@code "1"}.
* @since 1.11.0
*/
private final @NonNull String apiVersion;
private AddonDescription(@NonNull Builder builder) {
this.main = builder.main;
@ -47,6 +53,7 @@ public final class AddonDescription {
this.metrics = builder.metrics;
this.repository = builder.repository;
this.icon = builder.icon;
this.apiVersion = builder.apiVersion;
}
@NonNull
@ -120,6 +127,29 @@ public final class AddonDescription {
return icon;
}
/**
* Returns the minimum BentoBox version this addon requires in order to work properly.
* <br/>
* Examples:
* <ul>
* <li>{@code "1"} means that the addon relies on BentoBox {@code 1.0.0} or higher.</li>
* <li>Similarly, {@code "2"} sets the requirement to BentoBox {@code 2.0.0} or higher.</li>
* <li>
* More specific versions can be provided:
* <ul>
* <li>{@code "1.10"} -> BentoBox {@code 1.10.0} or higher.</li>
* <li>{@code "1.9.2"} -> BentoBox {@code 1.9.2} or higher.</li>
* </ul>
* </li>
* </ul>
* Defaults to {@code "1"}.
* @return the minimum BentoBox version this addon requires in order to work properly.
*/
@NonNull
public String getApiVersion() {
return apiVersion;
}
public static class Builder {
private @NonNull String main;
private @NonNull String name;
@ -131,6 +161,7 @@ public final class AddonDescription {
private boolean metrics = true;
private @NonNull String repository = "";
private @NonNull Material icon = Material.PAPER;
private @NonNull String apiVersion = "1";
/**
* @since 1.1
@ -196,6 +227,18 @@ public final class AddonDescription {
return this;
}
/**
* Sets the minimum BentoBox version this addon requires in order to work properly.
* @param apiVersion the minimum BentoBox version this addon requires in order to work properly.
* @since 1.11.0
* @see AddonDescription#getApiVersion()
*/
@NonNull
public Builder apiVersion(@NonNull String apiVersion) {
this.apiVersion = apiVersion;
return this;
}
@NonNull
public AddonDescription build() {
return new AddonDescription(this);

View File

@ -0,0 +1,16 @@
package world.bentobox.bentobox.api.addons.exceptions;
/**
* @since 1.11.0
*/
public class InvalidAddonDescriptionException extends AddonException {
/**
*
*/
private static final long serialVersionUID = 7741502900847049986L;
public InvalidAddonDescriptionException(String errorMessage) {
super(errorMessage);
}
}

View File

@ -24,6 +24,7 @@ public class AdminGetrankCommand extends CompositeCommand {
private Island island;
private @Nullable UUID targetUUID;
private @Nullable UUID ownerUUID;
public AdminGetrankCommand(CompositeCommand adminCommand) {
super(adminCommand, "getrank");
@ -39,7 +40,7 @@ public class AdminGetrankCommand extends CompositeCommand {
@Override
public boolean canExecute(User user, String label, List<String> args) {
if (args.size() != 1) {
if (args.size() != 1 && args.size() != 2) {
// Show help
showHelp(this, user);
return false;
@ -50,11 +51,33 @@ public class AdminGetrankCommand extends CompositeCommand {
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
return false;
}
island = getIslands().getIsland(getWorld(), targetUUID);
if (island == null) {
user.sendMessage("general.errors.player-has-no-island");
return false;
if (args.size() == 1) {
// We want to get the rank of the player on the island he is part of.
// So we have to make sure that this player has an island
if (!getIslands().hasIsland(getWorld(), targetUUID) && !getIslands().inTeam(getWorld(), targetUUID)) {
user.sendMessage("general.errors.player-has-no-island");
return false;
}
island = getIslands().getIsland(getWorld(), targetUUID);
} else {
// We want to get the rank of the player on the island of the owner we specify.
// So we have to make sure that the island owner actually owns an island
ownerUUID = getPlayers().getUUID(args.get(1));
if (ownerUUID == null) {
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(1));
return false;
}
if (!getPlugin().getIslands().hasIsland(getWorld(), ownerUUID)) {
user.sendMessage("general.errors.player-is-not-owner", TextVariables.NAME, args.get(1));
return false;
}
island = getIslands().getIsland(getWorld(), ownerUUID);
}
return true;
}
@ -64,9 +87,9 @@ public class AdminGetrankCommand extends CompositeCommand {
RanksManager rm = getPlugin().getRanksManager();
User target = User.getInstance(targetUUID);
int currentRank = island.getRank(target);
user.sendMessage("commands.admin.getrank.rank-is", TextVariables.RANK, user.getTranslation(rm.getRank(currentRank)));
user.sendMessage("commands.admin.getrank.rank-is", TextVariables.RANK, user.getTranslation(rm.getRank(currentRank)),
TextVariables.NAME, getPlayers().getName(island.getOwner()));
return true;
}
@Override
@ -75,7 +98,7 @@ public class AdminGetrankCommand extends CompositeCommand {
// Don't show every player on the server. Require at least the first letter
return Optional.empty();
}
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
String lastArg = args.get(args.size() - 1);
List<String> options = Bukkit.getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
return Optional.of(Util.tabLimit(options, lastArg));
}

View File

@ -5,13 +5,11 @@ import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.island.IslandEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@ -85,14 +83,14 @@ public class AdminRegisterCommand extends ConfirmableCommand {
}
user.sendMessage("commands.admin.register.registered-island", "[xyz]", Util.xyz(i.getCenter().toVector()));
user.sendMessage("general.success");
IslandBaseEvent event = IslandEvent.builder()
.island(i)
.location(i.getCenter())
.reason(IslandEvent.Reason.REGISTERED)
.involvedPlayer(targetUUID)
.admin(true)
.build();
Bukkit.getPluginManager().callEvent(event);
// Build and call event
IslandEvent.builder()
.island(i)
.location(i.getCenter())
.reason(IslandEvent.Reason.REGISTERED)
.involvedPlayer(targetUUID)
.admin(true)
.build();
return true;
}).orElse(false)) {
// Island does not exist - this is a reservation
@ -108,19 +106,19 @@ public class AdminRegisterCommand extends ConfirmableCommand {
i.setReserved(true);
i.getCenter().getBlock().setType(Material.BEDROCK);
user.sendMessage("commands.admin.register.reserved-island", "[xyz]", Util.xyz(i.getCenter().toVector()));
IslandBaseEvent event = IslandEvent.builder()
.island(i)
.location(i.getCenter())
.reason(IslandEvent.Reason.RESERVED)
.involvedPlayer(targetUUID)
.admin(true)
.build();
Bukkit.getPluginManager().callEvent(event);
// Build and fire event
IslandEvent.builder()
.island(i)
.location(i.getCenter())
.reason(IslandEvent.Reason.RESERVED)
.involvedPlayer(targetUUID)
.admin(true)
.build();
});
return false;
}
return true;
}
@Override

View File

@ -13,6 +13,7 @@ import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.bentobox.util.Util;
/**
* @author tastybento
@ -22,6 +23,7 @@ public class AdminSetrankCommand extends CompositeCommand {
private int rankValue;
private @Nullable UUID targetUUID;
private @Nullable UUID ownerUUID;
private RanksManager rm;
public AdminSetrankCommand(CompositeCommand adminCommand) {
@ -39,7 +41,7 @@ public class AdminSetrankCommand extends CompositeCommand {
@Override
public boolean canExecute(User user, String label, List<String> args) {
if (args.size() != 2) {
if (args.size() != 2 && args.size() != 3) {
// Show help
showHelp(this, user);
return false;
@ -50,10 +52,6 @@ public class AdminSetrankCommand extends CompositeCommand {
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
return false;
}
if (!getPlugin().getIslands().hasIsland(getWorld(), targetUUID)) {
user.sendMessage("general.errors.player-has-no-island");
return false;
}
// Get rank
rankValue = rm.getRanks().entrySet().stream()
.filter(r -> user.getTranslation(r.getKey()).equalsIgnoreCase(args.get(1))).findFirst()
@ -66,21 +64,78 @@ public class AdminSetrankCommand extends CompositeCommand {
user.sendMessage("commands.admin.setrank.not-possible");
return false;
}
if (args.size() == 2) {
// We want to change the player's rank on the island he is part of.
// Check if the target is part of an island
if (!getIslands().hasIsland(getWorld(), targetUUID) && !getPlugin().getIslands().inTeam(getWorld(), targetUUID)) {
user.sendMessage("general.errors.player-has-no-island");
return false;
}
} else {
// We want to change the player's rank on the island of the specified owner.
ownerUUID = getPlayers().getUUID(args.get(2));
if (ownerUUID == null) {
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(2));
return false;
}
if (!getPlugin().getIslands().hasIsland(getWorld(), ownerUUID)) {
user.sendMessage("general.errors.player-is-not-owner", TextVariables.NAME, args.get(2));
return false;
}
}
return true;
}
@Override
public boolean execute(User user, String label, List<String> args) {
User target = User.getInstance(targetUUID);
Island island = getPlugin().getIslands().getIsland(getWorld(), targetUUID);
Island island;
if (ownerUUID != null) {
island = getIslands().getIsland(getWorld(), ownerUUID);
} else {
island = getIslands().getIsland(getWorld(), targetUUID);
}
int currentRank = island.getRank(target);
island.setRank(target, rankValue);
user.sendMessage("commands.admin.setrank.rank-set", "[from]", user.getTranslation(rm.getRank(currentRank)), "[to]", user.getTranslation(rm.getRank(rankValue)));
String ownerName;
if (ownerUUID != null) {
ownerName = getPlayers().getName(ownerUUID);
} else {
ownerName = target.getName();
}
user.sendMessage("commands.admin.setrank.rank-set",
"[from]", user.getTranslation(rm.getRank(currentRank)),
"[to]", user.getTranslation(rm.getRank(rankValue)),
TextVariables.NAME, ownerName);
return true;
}
@Override
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
return Optional.of(getPlugin().getRanksManager().getRanks().keySet().stream().map(user::getTranslation).collect(Collectors.toList()));
// Return the player names
if (args.size() == 2) {
return Optional.of(Util.getOnlinePlayerList(user));
}
// Return the ranks
if (args.size() == 3) {
return Optional.of(getPlugin().getRanksManager().getRanks()
.entrySet().stream()
.filter(entry -> entry.getValue() > RanksManager.VISITOR_RANK)
.map(entry -> user.getTranslation(entry.getKey())).collect(Collectors.toList()));
}
// Return the player names again for the optional island owner argument
if (args.size() == 4) {
return Optional.of(Util.getOnlinePlayerList(user));
}
return Optional.empty();
}
}

View File

@ -4,14 +4,12 @@ import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.World;
import com.google.common.collect.ImmutableSet;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.island.IslandEvent;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
@ -57,15 +55,14 @@ public class AdminSetspawnCommand extends ConfirmableCommand {
private void setSpawn(User user, Island i) {
if (!i.getMembers().isEmpty()) {
if (i.isOwned()) {
// Fire event
IslandBaseEvent event = IslandEvent.builder()
.island(i)
.location(i.getCenter())
.reason(IslandEvent.Reason.UNREGISTERED)
.involvedPlayer(i.getOwner())
.admin(true)
.build();
Bukkit.getPluginManager().callEvent(event);
// Build and fire event
IslandEvent.builder()
.island(i)
.location(i.getCenter())
.reason(IslandEvent.Reason.UNREGISTERED)
.involvedPlayer(i.getOwner())
.admin(true)
.build();
}
// If island is owned, then unregister the owner and any members
new ImmutableSet.Builder<UUID>().addAll(i.getMembers().keySet()).build().forEach(m -> {

View File

@ -7,6 +7,7 @@ import java.util.UUID;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@ -34,7 +35,7 @@ public class AdminTeleportCommand extends CompositeCommand {
@Override
public boolean execute(User user, String label, List<String> args) {
if (args.isEmpty()) {
if (args.size() != 1 && args.size() != 2) {
this.showHelp(this, user);
return false;
}
@ -52,12 +53,31 @@ public class AdminTeleportCommand extends CompositeCommand {
} else if (getLabel().equals("tpend")) {
warpSpot = getIslands().getIslandLocation(getWorld(), targetUUID).toVector().toLocation(getPlugin().getIWM().getEndWorld(getWorld()));
}
// Otherwise, go to a safe spot
// Otherwise, ask the admin to go to a safe spot
String failureMessage = user.getTranslation("commands.admin.tp.manual", "[location]", warpSpot.getBlockX() + " " + warpSpot.getBlockY() + " "
+ warpSpot.getBlockZ());
Player player = user.getPlayer();
if (args.size() == 2) {
// We are trying to teleport another player
UUID playerToTeleportUUID = getPlayers().getUUID(args.get(1));
if (playerToTeleportUUID == null) {
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(1));
return false;
} else {
User userToTeleport = User.getInstance(playerToTeleportUUID);
if (!userToTeleport.isOnline()) {
user.sendMessage("general.errors.offline-player");
return false;
}
player = userToTeleport.getPlayer();
failureMessage = userToTeleport.getTranslation("general.errors.no-safe-location-found");
}
}
// Teleport
new SafeSpotTeleport.Builder(getPlugin())
.entity(user.getPlayer())
.entity(player)
.location(warpSpot)
.failureMessage(failureMessage)
.build();

View File

@ -5,13 +5,8 @@ import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.bukkit.Bukkit;
import com.google.common.collect.ImmutableSet;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.island.IslandEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@ -60,22 +55,25 @@ public class AdminUnregisterCommand extends ConfirmableCommand {
return true;
}
private void unregisterPlayer(User user, UUID targetUUID) {
void unregisterPlayer(User user, UUID targetUUID) {
// Unregister island
Island oldIsland = getIslands().getIsland(getWorld(), targetUUID);
IslandBaseEvent event = IslandEvent.builder()
.island(oldIsland)
.location(oldIsland.getCenter())
.reason(IslandEvent.Reason.UNREGISTERED)
.involvedPlayer(targetUUID)
.admin(true)
.build();
Bukkit.getPluginManager().callEvent(event);
if (oldIsland == null) return;
IslandEvent.builder()
.island(oldIsland)
.location(oldIsland.getCenter())
.reason(IslandEvent.Reason.UNREGISTERED)
.involvedPlayer(targetUUID)
.admin(true)
.build();
// Remove all island members
new ImmutableSet.Builder<UUID>().addAll(oldIsland.getMembers().keySet()).build().forEach(m -> {
oldIsland.getMemberSet().forEach(m -> {
getIslands().removePlayer(getWorld(), m);
getPlayers().clearHomeLocations(getWorld(), m);
});
// Remove all island players that reference this island
oldIsland.getMembers().clear();
getIslands().save(oldIsland);
user.sendMessage("commands.admin.unregister.unregistered-island", "[xyz]", Util.xyz(oldIsland.getCenter().toVector()));
}

View File

@ -14,6 +14,7 @@ public class AdminBlueprintCopyCommand extends CompositeCommand {
@Override
public void setup() {
inheritPermission();
setParametersHelp("commands.admin.blueprint.copy.parameters");
setDescription("commands.admin.blueprint.copy.description");
}

View File

@ -22,6 +22,7 @@ public class AdminBlueprintDeleteCommand extends ConfirmableCommand {
@Override
public void setup() {
inheritPermission();
setParametersHelp("commands.admin.blueprint.delete.parameters");
setDescription("commands.admin.blueprint.delete.description");
}

View File

@ -20,6 +20,7 @@ public class AdminBlueprintListCommand extends CompositeCommand {
@Override
public void setup() {
inheritPermission();
setDescription("commands.admin.blueprint.list.description");
}

View File

@ -17,13 +17,14 @@ public class AdminBlueprintLoadCommand extends CompositeCommand {
@Override
public void setup() {
inheritPermission();
setParametersHelp("commands.admin.blueprint.load.parameters");
setDescription("commands.admin.blueprint.load.description");
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (args.isEmpty() || args.size() != 1) {
if (args.size() != 1) {
showHelp(this, user);
return false;
}

View File

@ -18,6 +18,7 @@ public class AdminBlueprintOriginCommand extends CompositeCommand {
@Override
public void setup() {
inheritPermission();
setParametersHelp("commands.admin.blueprint.origin.parameters");
setDescription("commands.admin.blueprint.origin.description");
}

View File

@ -15,6 +15,7 @@ public class AdminBlueprintPasteCommand extends CompositeCommand {
@Override
public void setup() {
inheritPermission();
setParametersHelp("commands.admin.blueprint.paste.parameters");
setDescription("commands.admin.blueprint.paste.description");
}

View File

@ -15,6 +15,7 @@ public class AdminBlueprintPos1Command extends CompositeCommand {
@Override
public void setup() {
inheritPermission();
setParametersHelp("commands.admin.blueprint.pos1.parameters");
setDescription("commands.admin.blueprint.pos1.description");
}

View File

@ -15,6 +15,7 @@ public class AdminBlueprintPos2Command extends CompositeCommand {
@Override
public void setup() {
inheritPermission();
setParametersHelp("commands.admin.blueprint.pos2.parameters");
setDescription("commands.admin.blueprint.pos2.description");
}

View File

@ -23,6 +23,7 @@ public class AdminBlueprintRenameCommand extends ConfirmableCommand {
@Override
public void setup() {
inheritPermission();
setParametersHelp("commands.admin.blueprint.rename.parameters");
setDescription("commands.admin.blueprint.rename.description");
}

View File

@ -18,6 +18,7 @@ public class AdminBlueprintSaveCommand extends ConfirmableCommand {
@Override
public void setup() {
inheritPermission();
setParametersHelp("commands.admin.blueprint.save.parameters");
setDescription("commands.admin.blueprint.save.description");
}

View File

@ -22,6 +22,7 @@ public class AdminDeathsAddCommand extends CompositeCommand {
@Override
public void setup() {
inheritPermission();
setDescription("commands.admin.deaths.add.description");
setParametersHelp("commands.admin.deaths.add.parameters");
}

View File

@ -22,6 +22,7 @@ public class AdminDeathsRemoveCommand extends CompositeCommand {
@Override
public void setup() {
inheritPermission();
setDescription("commands.admin.deaths.remove.description");
setParametersHelp("commands.admin.deaths.remove.parameters");
}

View File

@ -20,6 +20,7 @@ public class AdminDeathsResetCommand extends CompositeCommand {
@Override
public void setup() {
inheritPermission();
setDescription("commands.admin.deaths.reset.description");
setParametersHelp("commands.admin.deaths.reset.parameters");
}

View File

@ -21,6 +21,7 @@ public class AdminDeathsSetCommand extends CompositeCommand {
@Override
public void setup() {
inheritPermission();
setDescription("commands.admin.deaths.set.description");
setParametersHelp("commands.admin.deaths.set.parameters");
}

View File

@ -16,7 +16,7 @@ public class AdminPurgeProtectCommand extends CompositeCommand {
@Override
public void setup() {
setPermission("admin.purge");
inheritPermission();
setOnlyPlayer(true);
setDescription("commands.admin.purge.protect.description");
}

View File

@ -13,7 +13,7 @@ public class AdminPurgeStopCommand extends CompositeCommand {
@Override
public void setup() {
setPermission("admin.purge");
inheritPermission();
setOnlyPlayer(false);
setDescription("commands.admin.purge.stop.description");
}

View File

@ -17,7 +17,7 @@ public class AdminPurgeUnownedCommand extends ConfirmableCommand {
@Override
public void setup() {
setPermission("admin.purge");
inheritPermission();
setOnlyPlayer(false);
setParametersHelp("commands.admin.purge.unowned.parameters");
setDescription("commands.admin.purge.unowned.description");

View File

@ -6,6 +6,7 @@ import java.util.UUID;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.island.IslandEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
@ -23,6 +24,7 @@ public class AdminRangeAddCommand extends CompositeCommand {
@Override
public void setup() {
inheritPermission();
setDescription("commands.admin.range.add.description");
setParametersHelp("commands.admin.range.add.parameters");
}
@ -61,8 +63,22 @@ public class AdminRangeAddCommand extends CompositeCommand {
return false;
}
// Well, now it can be applied without taking any risks !
// Get old range for event
int oldRange = island.getProtectionRange();
// Well, now it can be applied without taking any risks!
island.setProtectionRange(newRange);
// Call Protection Range Change event. Does not support cancelling.
IslandEvent.builder()
.island(island)
.location(island.getCenter())
.reason(IslandEvent.Reason.RANGE_CHANGE)
.involvedPlayer(target)
.admin(true)
.protectionRange(newRange, oldRange)
.build();
user.sendMessage("commands.admin.range.add.success",
TextVariables.NAME, args.get(0), TextVariables.NUMBER, args.get(1),
"[total]", String.valueOf(newRange));

View File

@ -6,6 +6,7 @@ import java.util.UUID;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.island.IslandEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
@ -23,6 +24,7 @@ public class AdminRangeRemoveCommand extends CompositeCommand {
@Override
public void setup() {
inheritPermission();
setDescription("commands.admin.range.remove.description");
setParametersHelp("commands.admin.range.remove.parameters");
}
@ -61,8 +63,22 @@ public class AdminRangeRemoveCommand extends CompositeCommand {
return false;
}
// Well, now it can be applied without taking any risks !
// Get old range for event
int oldRange = island.getProtectionRange();
// Well, now it can be applied without taking any risks!
island.setProtectionRange(newRange);
// Call Protection Range Change event. Does not support cancelling.
IslandEvent.builder()
.island(island)
.location(island.getCenter())
.reason(IslandEvent.Reason.RANGE_CHANGE)
.involvedPlayer(target)
.admin(true)
.protectionRange(newRange, oldRange)
.build();
user.sendMessage("commands.admin.range.remove.success",
TextVariables.NAME, args.get(0), TextVariables.NUMBER, args.get(1),
"[total]", String.valueOf(newRange));

View File

@ -6,6 +6,7 @@ import java.util.Optional;
import java.util.UUID;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.island.IslandEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
@ -46,9 +47,25 @@ public class AdminRangeResetCommand extends CompositeCommand {
// Get island
Island island = getIslands().getIsland(getWorld(), targetUUID);
// Get old range for event
int oldRange = island.getProtectionRange();
// Reset the protection range
int range = getIWM().getIslandProtectionRange(getWorld());
island.setProtectionRange(range);
if (oldRange != range) {
// Call Protection Range Change event. Does not support cancelling.
IslandEvent.builder()
.island(island)
.location(island.getCenter())
.reason(IslandEvent.Reason.RANGE_CHANGE)
.involvedPlayer(targetUUID)
.admin(true)
.protectionRange(range, oldRange)
.build();
}
user.sendMessage("commands.admin.range.reset.success", TextVariables.NUMBER, String.valueOf(range));
return true;

View File

@ -6,6 +6,7 @@ import java.util.Optional;
import java.util.UUID;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.island.IslandEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
@ -67,8 +68,22 @@ public class AdminRangeSetCommand extends CompositeCommand {
return false;
}
// Well, now it can be applied without taking any risks !
// Get old range for event
int oldRange = island.getProtectionRange();
// Well, now it can be applied without taking any risks!
island.setProtectionRange(range);
// Call Protection Range Change event. Does not support cancelling.
IslandEvent.builder()
.island(island)
.location(island.getCenter())
.reason(IslandEvent.Reason.RANGE_CHANGE)
.involvedPlayer(targetUUID)
.admin(true)
.protectionRange(range, oldRange)
.build();
user.sendMessage("commands.admin.range.set.success", TextVariables.NUMBER, String.valueOf(range));
return true;

View File

@ -22,6 +22,7 @@ public class AdminResetsAddCommand extends CompositeCommand {
@Override
public void setup() {
inheritPermission();
setDescription("commands.admin.resets.add.description");
setParametersHelp("commands.admin.resets.add.parameters");
}

View File

@ -22,6 +22,7 @@ public class AdminResetsRemoveCommand extends CompositeCommand {
@Override
public void setup() {
inheritPermission();
setDescription("commands.admin.resets.remove.description");
setParametersHelp("commands.admin.resets.remove.parameters");
}

View File

@ -21,6 +21,7 @@ public class AdminResetsResetCommand extends ConfirmableCommand {
@Override
public void setup() {
inheritPermission();
setDescription("commands.admin.resets.reset.description");
setParametersHelp("commands.admin.resets.reset.parameters");
}

View File

@ -16,6 +16,7 @@ public class AdminResetsSetCommand extends CompositeCommand {
@Override
public void setup() {
inheritPermission();
setDescription("commands.admin.resets.set.description");
setParametersHelp("commands.admin.resets.set.parameters");
}

View File

@ -3,10 +3,7 @@ package world.bentobox.bentobox.api.commands.admin.team;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@ -69,13 +66,12 @@ public class AdminTeamAddCommand extends CompositeCommand {
if (teamIsland != null) {
getIslands().setJoinTeam(teamIsland, targetUUID);
user.sendMessage("commands.admin.team.add.success", TextVariables.NAME, target.getName(), "[owner]", owner.getName());
IslandBaseEvent event = TeamEvent.builder()
.island(teamIsland)
.reason(TeamEvent.Reason.JOINED)
.involvedPlayer(targetUUID)
.admin(true)
.build();
Bukkit.getPluginManager().callEvent(event);
TeamEvent.builder()
.island(teamIsland)
.reason(TeamEvent.Reason.JOINED)
.involvedPlayer(targetUUID)
.admin(true)
.build();
return true;
} else {
user.sendMessage("general.errors.player-has-no-island");

View File

@ -3,10 +3,7 @@ package world.bentobox.bentobox.api.commands.admin.team;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@ -57,13 +54,12 @@ public class AdminTeamDisbandCommand extends CompositeCommand {
// The owner gets to keep the island
if (!m.equals(targetUUID)) {
getIslands().setLeaveTeam(getWorld(), m);
IslandBaseEvent event = TeamEvent.builder()
.island(island)
.reason(TeamEvent.Reason.KICK)
.involvedPlayer(targetUUID)
.admin(true)
.build();
Bukkit.getPluginManager().callEvent(event);
TeamEvent.builder()
.island(island)
.reason(TeamEvent.Reason.KICK)
.involvedPlayer(targetUUID)
.admin(true)
.build();
}
});
user.sendMessage("commands.admin.team.disband.success", TextVariables.NAME, args.get(0));

View File

@ -3,11 +3,9 @@ package world.bentobox.bentobox.api.commands.admin.team;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@ -71,13 +69,12 @@ public class AdminTeamKickCommand extends CompositeCommand {
user.sendMessage("commands.admin.team.kick.success", TextVariables.NAME, target.getName(), "[owner]", getPlayers().getName(island.getOwner()));
// Fire event so add-ons know
IslandBaseEvent event = TeamEvent.builder()
.island(island)
.reason(TeamEvent.Reason.KICK)
.involvedPlayer(targetUUID)
.admin(true)
.build();
Bukkit.getPluginManager().callEvent(event);
TeamEvent.builder()
.island(island)
.reason(TeamEvent.Reason.KICK)
.involvedPlayer(targetUUID)
.admin(true)
.build();
return true;
}
}

View File

@ -3,10 +3,7 @@ package world.bentobox.bentobox.api.commands.admin.team;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@ -55,13 +52,12 @@ public class AdminTeamSetownerCommand extends CompositeCommand {
user.sendMessage("commands.admin.team.setowner.success", TextVariables.NAME, args.get(0));
// Fire event so add-ons know
Island island = getIslands().getIsland(getWorld(), targetUUID);
IslandBaseEvent event = TeamEvent.builder()
.island(island)
.reason(TeamEvent.Reason.SETOWNER)
.involvedPlayer(targetUUID)
.admin(true)
.build();
Bukkit.getPluginManager().callEvent(event);
TeamEvent.builder()
.island(island)
.reason(TeamEvent.Reason.SETOWNER)
.involvedPlayer(targetUUID)
.admin(true)
.build();
return true;
}
}

View File

@ -9,7 +9,6 @@ import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.island.IslandEvent.Reason;
import world.bentobox.bentobox.api.events.team.TeamEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
@ -223,12 +222,11 @@ public class IslandResetCommand extends ConfirmableCommand {
}
// Fire event
IslandBaseEvent e = TeamEvent.builder()
.island(island)
.reason(TeamEvent.Reason.DELETE)
.involvedPlayer(memberUUID)
.build();
Bukkit.getPluginManager().callEvent(e);
TeamEvent.builder()
.island(island)
.reason(TeamEvent.Reason.DELETE)
.involvedPlayer(memberUUID)
.build();
});
}
}

View File

@ -15,7 +15,6 @@ import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@ -158,14 +157,13 @@ public class IslandTeamCommand extends CompositeCommand {
}
private boolean fireEvent(User user) {
IslandBaseEvent event = TeamEvent.builder()
return TeamEvent.builder()
.island(getIslands()
.getIsland(getWorld(), user.getUniqueId()))
.reason(TeamEvent.Reason.INFO)
.involvedPlayer(user.getUniqueId())
.build();
Bukkit.getPluginManager().callEvent(event);
return event.isCancelled();
.build()
.isCancelled();
}
/**

View File

@ -3,12 +3,8 @@ package world.bentobox.bentobox.api.commands.island.team;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.commands.island.team.Invite.Type;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@ -31,7 +27,7 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
@Override
public void setup() {
setPermission("island.team");
setPermission("island.team.accept");
setOnlyPlayer(true);
setDescription("commands.island.team.invite.accept.description");
}
@ -59,13 +55,12 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
return false;
}
// Fire event so add-ons can run commands, etc.
IslandBaseEvent event = TeamEvent.builder()
return !TeamEvent.builder()
.island(getIslands().getIsland(getWorld(), prospectiveOwnerUUID))
.reason(TeamEvent.Reason.JOIN)
.involvedPlayer(playerUUID)
.build();
Bukkit.getPluginManager().callEvent(event);
return !event.isCancelled();
.build()
.isCancelled();
}
return true;
}
@ -149,12 +144,11 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
}
getIslands().save(teamIsland);
// Fire event
IslandBaseEvent e = TeamEvent.builder()
.island(getIslands().getIsland(getWorld(), prospectiveOwnerUUID))
.reason(TeamEvent.Reason.JOINED)
.involvedPlayer(playerUUID)
.build();
Bukkit.getPluginManager().callEvent(e);
TeamEvent.builder()
.island(getIslands().getIsland(getWorld(), prospectiveOwnerUUID))
.reason(TeamEvent.Reason.JOINED)
.involvedPlayer(playerUUID)
.build();
}
private void cleanPlayer(User user) {

View File

@ -6,12 +6,10 @@ import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.island.team.Invite.Type;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@ -30,7 +28,7 @@ public class IslandTeamInviteCommand extends CompositeCommand {
@Override
public void setup() {
setPermission("island.team");
setPermission("island.team.invite");
setOnlyPlayer(true);
setDescription("commands.island.team.invite.description");
setConfigurableRankCommand();
@ -120,13 +118,12 @@ public class IslandTeamInviteCommand extends CompositeCommand {
user.sendMessage("commands.island.team.invite.removing-invite");
}
// Fire event so add-ons can run commands, etc.
IslandBaseEvent event = TeamEvent.builder()
if (TeamEvent.builder()
.island(getIslands().getIsland(getWorld(), user.getUniqueId()))
.reason(TeamEvent.Reason.INVITE)
.involvedPlayer(invitedPlayer.getUniqueId())
.build();
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
.build()
.isCancelled()) {
return false;
}
// Put the invited player (key) onto the list with inviter (value)

View File

@ -3,10 +3,7 @@ package world.bentobox.bentobox.api.commands.island.team;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@ -22,7 +19,7 @@ public class IslandTeamInviteRejectCommand extends CompositeCommand {
@Override
public void setup() {
setPermission("island.team");
setPermission("island.team.reject");
setOnlyPlayer(true);
setDescription("commands.island.team.invite.reject.description");
}
@ -33,14 +30,13 @@ public class IslandTeamInviteRejectCommand extends CompositeCommand {
// Reject /island reject
if (itc.isInvited(playerUUID)) {
// Fire event so add-ons can run commands, etc.
IslandBaseEvent event = TeamEvent.builder()
if (TeamEvent.builder()
.island(getIslands()
.getIsland(getWorld(), itc.getInviter(playerUUID)))
.reason(TeamEvent.Reason.REJECT)
.involvedPlayer(playerUUID)
.build();
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
.build()
.isCancelled()) {
return false;
}

View File

@ -7,7 +7,6 @@ import org.bukkit.Bukkit;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@ -22,7 +21,7 @@ public class IslandTeamKickCommand extends ConfirmableCommand {
@Override
public void setup() {
setPermission("island.team");
setPermission("island.team.kick");
setOnlyPlayer(true);
setParametersHelp("commands.island.team.kick.parameters");
setDescription("commands.island.team.kick.description");
@ -126,12 +125,11 @@ public class IslandTeamKickCommand extends ConfirmableCommand {
}
user.sendMessage("commands.island.team.kick.success", TextVariables.NAME, target.getName());
// Fire event
IslandBaseEvent e = TeamEvent.builder()
.island(oldIsland)
.reason(TeamEvent.Reason.KICK)
.involvedPlayer(targetUUID)
.build();
Bukkit.getPluginManager().callEvent(e);
TeamEvent.builder()
.island(oldIsland)
.reason(TeamEvent.Reason.KICK)
.involvedPlayer(targetUUID)
.build();
// Add cooldown for this player and target
if (getSettings().getInviteCooldown() > 0 && getParent() != null) {

View File

@ -7,7 +7,6 @@ import org.bukkit.Bukkit;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@ -21,7 +20,7 @@ public class IslandTeamLeaveCommand extends ConfirmableCommand {
@Override
public void setup() {
setPermission("island.team");
setPermission("island.team.leave");
setOnlyPlayer(true);
setDescription("commands.island.team.leave.description");
}
@ -121,11 +120,10 @@ public class IslandTeamLeaveCommand extends ConfirmableCommand {
}
user.sendMessage("commands.island.team.leave.success");
// Fire event
IslandBaseEvent e = TeamEvent.builder()
.island(island)
.reason(TeamEvent.Reason.LEAVE)
.involvedPlayer(user.getUniqueId())
.build();
Bukkit.getPluginManager().callEvent(e);
TeamEvent.builder()
.island(island)
.reason(TeamEvent.Reason.LEAVE)
.involvedPlayer(user.getUniqueId())
.build();
}
}

View File

@ -8,7 +8,6 @@ import java.util.UUID;
import org.bukkit.Bukkit;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@ -23,7 +22,7 @@ public class IslandTeamSetownerCommand extends CompositeCommand {
@Override
public void setup() {
setPermission("island.team");
setPermission("island.team.setowner");
setOnlyPlayer(true);
setParametersHelp("commands.island.team.setowner.parameters");
setDescription("commands.island.team.setowner.description");
@ -63,13 +62,12 @@ public class IslandTeamSetownerCommand extends CompositeCommand {
}
// Fire event so add-ons can run commands, etc.
Island island = getIslands().getIsland(getWorld(), playerUUID);
IslandBaseEvent event = TeamEvent.builder()
if (TeamEvent.builder()
.island(island)
.reason(TeamEvent.Reason.SETOWNER)
.involvedPlayer(targetUUID)
.build();
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
.build()
.isCancelled()) {
return false;
}
getIslands().setOwner(getWorld(), user, targetUUID);

View File

@ -28,7 +28,7 @@ public class IslandTeamUntrustCommand extends CompositeCommand {
@Override
public void setup() {
setPermission("island.team.coop");
setPermission("island.team.trust");
setOnlyPlayer(true);
setParametersHelp("commands.island.team.untrust.parameters");
setDescription("commands.island.team.untrust.description");

View File

@ -276,7 +276,7 @@ public interface WorldSettings extends ConfigObject {
boolean isOnLeaveResetXP();
/**
* Returns a list of commands that should be executed when the player leaves an island or resets one.<br/>
* Returns a list of commands that should be executed when the player leaves an island, resets his island or gets kicked from it.<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:

View File

@ -3,6 +3,8 @@ package world.bentobox.bentobox.api.events.addon;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.Bukkit;
import world.bentobox.bentobox.api.addons.Addon;
public class AddonEvent {
@ -16,6 +18,9 @@ public class AddonEvent {
}
/**
* @return Addon event builder
*/
public AddonEventBuilder builder() {
return new AddonEventBuilder();
}
@ -71,7 +76,7 @@ public class AddonEvent {
return this;
}
public AddonBaseEvent build() {
private AddonBaseEvent getEvent() {
switch (reason) {
case ENABLE:
return new AddonEnableEvent(addon, keyValues);
@ -83,5 +88,15 @@ public class AddonEvent {
return new AddonGeneralEvent(addon, keyValues);
}
}
/**
* Build and fire event
* @return event
*/
public AddonBaseEvent build() {
AddonBaseEvent e = getEvent();
Bukkit.getPluginManager().callEvent(e);
return e;
}
}
}

View File

@ -129,7 +129,12 @@ public class IslandEvent extends IslandBaseEvent {
* The island was reserved and now is being pasted.
* @since 1.6.0
*/
RESERVED
RESERVED,
/**
* The island protection range was changed.
* @since 1.11.0
*/
RANGE_CHANGE
}
public static IslandEventBuilder builder() {
@ -376,6 +381,77 @@ public class IslandEvent extends IslandBaseEvent {
}
}
/**
* Fired when island protection range is changed.
* @since 1.11.0
*/
public static class IslandProtectionRangeChangeEvent extends IslandBaseEvent {
/**
* New protection range value.
*/
private int newRange;
/**
* Old protection range value.
*/
private int oldRange;
/**
* Constructor IslandProtectionRangeChange creates a new IslandProtectionRangeChange instance.
*
* @param island of type Island
* @param player of type UUID
* @param admin of type boolean
* @param location of type Location
* @param newRange of type int
* @param oldRange of type int
*/
private IslandProtectionRangeChangeEvent(Island island, UUID player, boolean admin, Location location, int newRange, int oldRange) {
super(island, player, admin, location);
this.newRange = newRange;
this.oldRange = oldRange;
}
/**
* This method returns the newRange value.
* @return the value of newRange.
*/
public int getNewRange() {
return newRange;
}
/**
* This method returns the oldRange value.
* @return the value of oldRange.
*/
public int getOldRange() {
return oldRange;
}
/**
* This method sets the newRange value.
* @param newRange the newRange new value.
*/
public void setNewRange(int newRange) {
this.newRange = newRange;
}
/**
* This method sets the oldRange value.
* @param oldRange the oldRange new value.
*/
public void setOldRange(int oldRange) {
this.oldRange = oldRange;
}
}
public static class IslandEventBuilder {
// Here field are NOT final. They are just used for the building.
private Island island;
@ -386,6 +462,16 @@ public class IslandEvent extends IslandBaseEvent {
private IslandDeletion deletedIslandInfo;
private BlueprintBundle blueprintBundle;
/**
* Stores new protection range for island.
*/
private int newRange;
/**
* Stores old protection range for island.
*/
private int oldRange;
public IslandEventBuilder island(Island island) {
this.island = island;
return this;
@ -438,6 +524,21 @@ public class IslandEvent extends IslandBaseEvent {
return this;
}
/**
* Allows to set new and old protection range.
* @param newRange New value of protection range.
* @param oldRange Old value of protection range.
* @since 1.11.0
*/
@NonNull
public IslandEventBuilder protectionRange(int newRange, int oldRange) {
this.newRange = newRange;
this.oldRange = oldRange;
return this;
}
public IslandBaseEvent build() {
// Call the generic event for developers who just want one event and use the Reason enum
Bukkit.getPluginManager().callEvent(new IslandEvent(island, player, admin, location, reason));
@ -507,6 +608,11 @@ public class IslandEvent extends IslandBaseEvent {
IslandUnregisteredEvent unreg = new IslandUnregisteredEvent(island, player, admin, location);
Bukkit.getPluginManager().callEvent(unreg);
return unreg;
case RANGE_CHANGE:
IslandProtectionRangeChangeEvent
change = new IslandProtectionRangeChangeEvent(island, player, admin, location, newRange, oldRange);
Bukkit.getPluginManager().callEvent(change);
return change;
default:
IslandGeneralEvent general = new IslandGeneralEvent(island, player, admin, location);
Bukkit.getPluginManager().callEvent(general);

View File

@ -2,6 +2,7 @@ package world.bentobox.bentobox.api.events.team;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
@ -179,7 +180,7 @@ public class TeamEvent {
return this;
}
public IslandBaseEvent build() {
private IslandBaseEvent getEvent() {
switch (reason) {
case JOIN:
return new TeamJoinEvent(island, player, admin, location);
@ -205,5 +206,15 @@ public class TeamEvent {
return new TeamGeneralEvent(island, player, admin, location);
}
}
/**
* Build the event and call it
* @return event
*/
public IslandBaseEvent build() {
IslandBaseEvent e = getEvent();
Bukkit.getPluginManager().callEvent(e);
return e;
}
}
}

View File

@ -20,10 +20,6 @@ import world.bentobox.bentobox.versions.ServerCompatibility;
*/
public class BentoBoxVersionCommand extends CompositeCommand {
private static final String GAMEWORLD_COLOR_ISLANDS = "&a";
private static final String GAMEWORLD_COLOR_EXISTS_NO_ISLANDS = "&6";
private static final String GAMEWORLD_COLOR_NOT_EXIST = "&c";
/**
* Info command
* @param parent - command parent
@ -51,35 +47,35 @@ public class BentoBoxVersionCommand extends CompositeCommand {
getIWM().getOverWorldNames().entrySet().stream().sorted(Comparator.comparing(Map.Entry::getKey))
.forEach(e -> {
String netherColor = GAMEWORLD_COLOR_ISLANDS;
String endColor = GAMEWORLD_COLOR_ISLANDS;
String worlds = user.getTranslation("general.worlds.overworld");
// It should be present, but let's stay safe.
Optional<GameModeAddon> addonOptional = getIWM().getAddon(Bukkit.getWorld(e.getKey()));
if (addonOptional.isPresent()) {
GameModeAddon addon = addonOptional.get();
/* Get the colors
&a = dimension exists and contains islands
&6 = dimension exists but is vanilla
&c = dimension does not exist
*/
// Get the nether color
if (addon.getNetherWorld() == null || !getIWM().isNetherGenerate(addon.getOverWorld())) {
netherColor = GAMEWORLD_COLOR_NOT_EXIST;
} else if (!getIWM().isNetherIslands(addon.getOverWorld())) {
netherColor = GAMEWORLD_COLOR_EXISTS_NO_ISLANDS;
/*
* If the dimension is generated, it is displayed.
* If the dimension is not made up of islands, a '*' is appended to its name.
*/
// Append the nether
if (addon.getNetherWorld() != null && getIWM().isNetherGenerate(addon.getOverWorld())) {
worlds += ", " + user.getTranslation("general.worlds.nether");
if (!getIWM().isNetherIslands(addon.getOverWorld())) {
worlds += "*";
}
}
// Get the nether color
if (addon.getEndWorld() == null || !getIWM().isEndGenerate(addon.getOverWorld())) {
endColor = GAMEWORLD_COLOR_NOT_EXIST;
} else if (!getIWM().isEndIslands(addon.getOverWorld())) {
endColor = GAMEWORLD_COLOR_EXISTS_NO_ISLANDS;
// Append the End
if (addon.getEndWorld() != null && getIWM().isEndGenerate(addon.getOverWorld())) {
worlds += ", " + user.getTranslation("general.worlds.the-end");
if (!getIWM().isEndIslands(addon.getOverWorld())) {
worlds += "*";
}
}
}
user.sendMessage(user.getTranslation("commands.bentobox.version.game-world", TextVariables.NAME, e.getKey(), "[addon]", e.getValue(),
"[nether_color]", netherColor, "[end_color]", endColor));
"[worlds]", worlds));
});
user.sendMessage("commands.bentobox.version.loaded-addons");

View File

@ -154,8 +154,10 @@ public class SQLDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
plugin.logError("This class is not a DataObject: " + instance.getClass().getName());
return;
}
// This has to be on the main thread to avoid concurrent modification errors
String toStore = getGson().toJson(instance);
// Async
processQueue.add(() -> store(instance.getClass().getName(), getGson().toJson(instance), sqlConfig.getSaveObjectSQL()));
processQueue.add(() -> store(instance.getClass().getName(), toStore, sqlConfig.getSaveObjectSQL()));
}
private void store(String name, String toStore, String sb) {

View File

@ -1,6 +1,7 @@
package world.bentobox.bentobox.database.sql.postgresql;
import org.eclipse.jdt.annotation.NonNull;
import org.postgresql.Driver;
import world.bentobox.bentobox.database.DatabaseConnectionSettingsImpl;
import world.bentobox.bentobox.database.sql.SQLDatabaseConnector;
@ -11,6 +12,17 @@ import world.bentobox.bentobox.database.sql.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
* @param dbSettings - database settings

View File

@ -1,7 +1,13 @@
package world.bentobox.bentobox.database.sql.postgresql;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.google.gson.Gson;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.database.DatabaseConnector;
import world.bentobox.bentobox.database.objects.DataObject;
import world.bentobox.bentobox.database.sql.SQLConfiguration;
import world.bentobox.bentobox.database.sql.SQLDatabaseHandler;
@ -9,8 +15,8 @@ import world.bentobox.bentobox.database.sql.SQLDatabaseHandler;
*
* @param <T>
*
* @since 1.6.0
* @author tastybento, Poslovitch
* @since 1.11.0
* @author tastybento
*/
public class PostgreSQLDatabaseHandler<T> extends SQLDatabaseHandler<T> {
@ -23,7 +29,50 @@ public class PostgreSQLDatabaseHandler<T> extends SQLDatabaseHandler<T> {
* @param databaseConnector Contains the settings to create a connection to the database
*/
PostgreSQLDatabaseHandler(BentoBox plugin, Class<T> type, DatabaseConnector databaseConnector) {
super(plugin, type, databaseConnector, new SQLConfiguration(type.getCanonicalName()));
super(plugin, type, databaseConnector, new SQLConfiguration(type.getCanonicalName())
// Set uniqueid as the primary key (index). Postgresql convention is to use lower case field names
// Postgresql also uses double quotes (") instead of (`) around tables names with dots.
.schema("CREATE TABLE IF NOT EXISTS \"" + type.getCanonicalName() + "\" (uniqueid VARCHAR PRIMARY KEY, json jsonb NOT NULL)")
.loadObject("SELECT * FROM \"" + type.getCanonicalName() + "\" WHERE uniqueid = ? LIMIT 1")
.deleteObject("DELETE FROM \"" + type.getCanonicalName() + "\" WHERE uniqueid = ?")
// uniqueId has to be added into the row explicitly so we need to override the saveObject method
// The json value is a string but has to be cast to json when done in Java
.saveObject("INSERT INTO \"" + type.getCanonicalName() + "\" (uniqueid, json) VALUES (?, cast(? as json)) "
// This is the Postgresql version of UPSERT.
+ "ON CONFLICT (uniqueid) "
+ "DO UPDATE SET json = cast(? as json)")
.loadObjects("SELECT json FROM \"" + type.getCanonicalName() + "\"")
// Postgres exists function returns true or false natively
.objectExists("SELECT EXISTS(SELECT * FROM \"" + type.getCanonicalName() + "\" WHERE uniqueid = ?)")
);
}
/* (non-Javadoc)
* @see world.bentobox.bentobox.database.sql.SQLDatabaseHandler#saveObject(java.lang.Object)
*/
@Override
public void saveObject(T instance) {
// Null check
if (instance == null) {
plugin.logError("Postgres database request to store a null. ");
return;
}
if (!(instance instanceof DataObject)) {
plugin.logError("This class is not a DataObject: " + instance.getClass().getName());
return;
}
Gson gson = getGson();
String toStore = gson.toJson(instance);
String uniqueId = ((DataObject)instance).getUniqueId();
processQueue.add(() -> {
try (PreparedStatement preparedStatement = getConnection().prepareStatement(getSqlConfig().getSaveObjectSQL())) {
preparedStatement.setString(1, uniqueId); // INSERT
preparedStatement.setString(2, toStore); // INSERT
preparedStatement.setString(3, toStore); // ON CONFLICT
preparedStatement.execute();
} catch (SQLException e) {
plugin.logError("Could not save object " + instance.getClass().getName() + " " + e.getMessage());
}
});
}
}

View File

@ -32,7 +32,7 @@ public class BannedCommands implements Listener {
* Prevents visitors from using commands on islands, like /spawner
* @param e - event
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onVisitorCommand(PlayerCommandPreprocessEvent e) {
if (!plugin.getIWM().inWorld(e.getPlayer().getLocation()) || e.getPlayer().isOp()
|| e.getPlayer().hasPermission(plugin.getIWM().getPermissionPrefix(e.getPlayer().getWorld()) + "mod.bypassprotect")
@ -53,7 +53,7 @@ public class BannedCommands implements Listener {
* Prevents falling players from using commands, like /warp
* @param e - event
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onFallingCommand(PlayerCommandPreprocessEvent e) {
if (!plugin.getIWM().inWorld(e.getPlayer().getLocation()) || e.getPlayer().isOp()
|| e.getPlayer().hasPermission(plugin.getIWM().getPermissionPrefix(e.getPlayer().getWorld()) + "mod.bypassprotect")

View File

@ -18,6 +18,7 @@ import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.events.island.IslandEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
@ -197,8 +198,22 @@ public class JoinLeaveListener implements Listener {
user.sendMessage("commands.admin.setrange.range-updated", TextVariables.NUMBER, String.valueOf(range));
plugin.log("Island protection range changed from " + island.getProtectionRange() + " to "
+ range + " for " + user.getName() + " due to permission.");
// Get old range for event
int oldRange = island.getProtectionRange();
island.setProtectionRange(range);
// Call Protection Range Change event. Does not support cancelling.
IslandEvent.builder()
.island(island)
.location(island.getCenter())
.reason(IslandEvent.Reason.RANGE_CHANGE)
.involvedPlayer(user.getUniqueId())
.admin(true)
.protectionRange(range, oldRange)
.build();
}
island.setProtectionRange(range);
}
});
}

View File

@ -12,6 +12,7 @@ import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityPortalEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.BentoBox;
@ -115,13 +116,21 @@ public class PortalTeleportationListener implements Listener {
&& plugin.getIWM().isEndGenerate(overWorld)
&& plugin.getIWM().isEndIslands(overWorld)
&& plugin.getIWM().getEndWorld(overWorld) != null
&& !optionalIsland.map(Island::hasEndIsland).orElse(true)) {
// No end island present so paste the default one
pasteNewIsland(e.getPlayer(), to, optionalIsland.get(), Environment.THE_END);
&& optionalIsland.filter(i -> !i.hasEndIsland())
.map(i -> {
// No end island present so paste the default one
pasteNewIsland(e.getPlayer(), to, i, Environment.THE_END);
return true;
}).orElse(false)) {
// We are done here
return true;
}
// Else other worlds teleport to the nether
// Else other worlds teleport to the end
// Set player's velocity to zero
e.getPlayer().setVelocity(new Vector(0,0,0));
e.getPlayer().setFallDistance(0);
// Teleport
new SafeSpotTeleport.Builder(plugin)
.entity(e.getPlayer())
.location(to)
@ -188,15 +197,18 @@ public class PortalTeleportationListener implements Listener {
e.setCancelled(true);
// Check if there is an island there or not
if (plugin.getIWM().isPasteMissingIslands(overWorld) &&
!plugin.getIWM().isUseOwnGenerator(overWorld) && plugin.getIWM().isNetherGenerate(overWorld)
!plugin.getIWM().isUseOwnGenerator(overWorld)
&& plugin.getIWM().isNetherGenerate(overWorld)
&& plugin.getIWM().isNetherIslands(overWorld)
&& plugin.getIWM().getNetherWorld(overWorld) != null
&& !optionalIsland.map(Island::hasNetherIsland).orElse(true)) {
// No nether island present so paste the default one
pasteNewIsland(e.getPlayer(), to, optionalIsland.get(), Environment.NETHER);
&& optionalIsland.filter(i -> !i.hasNetherIsland()).map(i -> {
// No nether island present so paste the default one
pasteNewIsland(e.getPlayer(), to, i, Environment.NETHER);
return true;
}).orElse(false)) {
// All done here
return true;
}
// Else other worlds teleport to the nether
new SafeSpotTeleport.Builder(plugin)
.entity(e.getPlayer())

View File

@ -37,7 +37,8 @@ public class EnterExitListener extends FlagListener {
private void handleEnterExit(@NonNull User user, @NonNull Location from, @NonNull Location to) {
// Only process if there is a change in X or Z coords
if (from.getWorld().equals(to.getWorld()) && from.toVector().multiply(XZ).equals(to.toVector().multiply(XZ))) {
if (from.getWorld() != null && from.getWorld().equals(to.getWorld())
&& from.toVector().multiply(XZ).equals(to.toVector().multiply(XZ))) {
return;
}
@ -99,8 +100,15 @@ public class EnterExitListener extends FlagListener {
// Send message if island is owned by someone
if (island.isOwned()) {
// Leave messages are always specific to this world
user.notify(island.getWorld(), "protection.flags.ENTER_EXIT_MESSAGES.now-leaving", TextVariables.NAME, (island.getName() != null) ? island.getName() :
user.getTranslation(island.getWorld(), "protection.flags.ENTER_EXIT_MESSAGES.island", TextVariables.NAME, getPlugin().getPlayers().getName(island.getOwner())));
// Send specific message if the player is member of this island
if (island.getMemberSet().contains(user.getUniqueId())) {
user.notify(island.getWorld(), "protection.flags.ENTER_EXIT_MESSAGES.now-leaving-your-island", TextVariables.NAME, (island.getName() != null) ? island.getName() :
user.getTranslation(island.getWorld(), "protection.flags.ENTER_EXIT_MESSAGES.island", TextVariables.NAME, getPlugin().getPlayers().getName(island.getOwner())));
} else {
user.notify(island.getWorld(), "protection.flags.ENTER_EXIT_MESSAGES.now-leaving", TextVariables.NAME, (island.getName() != null) ? island.getName() :
user.getTranslation(island.getWorld(), "protection.flags.ENTER_EXIT_MESSAGES.island", TextVariables.NAME, getPlugin().getPlayers().getName(island.getOwner())));
}
}
// Send message if island is unowned, but has a name
else if (island.getName() != null) {
@ -122,9 +130,15 @@ public class EnterExitListener extends FlagListener {
// Send message if island is owned by someone
if (island.isOwned()) {
// Leave messages are always specific to this world
user.notify(island.getWorld(), "protection.flags.ENTER_EXIT_MESSAGES.now-entering", TextVariables.NAME, (island.getName() != null) ? island.getName() :
user.getTranslation(island.getWorld(), "protection.flags.ENTER_EXIT_MESSAGES.island", TextVariables.NAME, getPlugin().getPlayers().getName(island.getOwner())));
// Enter messages are always specific to this world
// Send specific message if the player is member of this island
if (island.getMemberSet().contains(user.getUniqueId())) {
user.notify(island.getWorld(), "protection.flags.ENTER_EXIT_MESSAGES.now-entering-your-island", TextVariables.NAME, (island.getName() != null) ? island.getName() :
user.getTranslation(island.getWorld(), "protection.flags.ENTER_EXIT_MESSAGES.island", TextVariables.NAME, getPlugin().getPlayers().getName(island.getOwner())));
} else {
user.notify(island.getWorld(), "protection.flags.ENTER_EXIT_MESSAGES.now-entering", TextVariables.NAME, (island.getName() != null) ? island.getName() :
user.getTranslation(island.getWorld(), "protection.flags.ENTER_EXIT_MESSAGES.island", TextVariables.NAME, getPlugin().getPlayers().getName(island.getOwner())));
}
}
// Send message if island is unowned, but has a name
else if (island.getName() != null) {

View File

@ -24,15 +24,23 @@ public class OfflineRedstoneListener extends FlagListener {
return;
}
// Check if island exists and members are online - excludes spawn
// Check if island exists and members are online, or mods or ops are on the island - ignores spawn
getIslands().getProtectedIslandAt(e.getBlock().getLocation())
.filter(i -> !i.isSpawn())
.ifPresent(i -> {
// Check team members
for (UUID uuid : i.getMemberSet(RanksManager.COOP_RANK)) {
if (Bukkit.getPlayer(uuid) != null) {
return;
}
}
// Check mods or Ops on island
if (Bukkit.getOnlinePlayers().parallelStream()
.filter(p -> p.isOp() || p.hasPermission(getIWM().getPermissionPrefix(i.getWorld()) + "mod.bypassprotect"))
.anyMatch(p -> i.onIsland(p.getLocation()))) {
return;
}
// No one there...
e.setNewCurrent(0);
});
}

View File

@ -5,6 +5,7 @@ import java.time.Instant;
import java.util.Date;
import java.util.Optional;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.placeholders.GameModePlaceholderReplacer;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.RanksManager;
@ -43,9 +44,12 @@ public enum GameModePlaceholder {
ISLAND_OWNER("island_owner", (addon, user, island) -> island == null ? "" : addon.getPlayers().getName(island.getOwner())),
ISLAND_CREATION_DATE("island_creation_date", (addon, user, island) -> island == null ? "" : DateFormat.getInstance().format(Date.from(Instant.ofEpochMilli(island.getCreatedDate())))),
ISLAND_NAME("island_name", (addon, user, island) -> {
if (island == null || island.getName() == null) {
if (island == null || user == null) {
return "";
}
if (island.getName() == null) {
return user.getTranslation(island.getWorld(), "protection.flags.ENTER_EXIT_MESSAGES.island", TextVariables.NAME, addon.getPlayers().getName(island.getOwner()));
}
return island.getName();
}),
/**
@ -153,7 +157,14 @@ public enum GameModePlaceholder {
return "";
}
Optional<Island> visitedIsland = addon.getIslands().getIslandAt(user.getLocation());
return visitedIsland.map(Island::getName).orElse("");
return visitedIsland.map(is -> {
if (is.getName() != null) {
return is.getName();
} else {
return user.getTranslation(is.getWorld(), "protection.flags.ENTER_EXIT_MESSAGES.island", TextVariables.NAME, addon.getPlayers().getName(is.getOwner()));
}
}).orElse("");
}),
/**
* Returns the coordinates of the center of the island the player is standing on.

View File

@ -108,7 +108,7 @@ public class AddonsManager {
plugin.getLocalesManager().loadLocalesFromFile(addon.getDescription().getName());
// Fire the load event
Bukkit.getPluginManager().callEvent(new AddonEvent().builder().addon(addon).reason(AddonEvent.Reason.LOAD).build());
new AddonEvent().builder().addon(addon).reason(AddonEvent.Reason.LOAD).build();
// Add it to the list of addons
addons.remove(addon);
@ -117,6 +117,15 @@ public class AddonsManager {
// Add to the list of loaders
loaders.put(addon, addonClassLoader);
// Checks if this addon is compatible with the current BentoBox version.
if (!isAddonCompatibleWithBentoBox(addon)) {
// It is not, abort.
plugin.logError("Cannot load " + addon.getDescription().getName() + " because it requires BentoBox version " + addon.getDescription().getApiVersion() + " or greater.");
plugin.logError("NOTE: Please update BentoBox.");
addon.setState(State.INCOMPATIBLE);
return;
}
try {
// Run the onLoad.
addon.onLoad();
@ -176,7 +185,7 @@ public class AddonsManager {
gameMode.getPlayerCommand().ifPresent(c -> c.setWorld(gameMode.getOverWorld()));
gameMode.getAdminCommand().ifPresent(c -> c.setWorld(gameMode.getOverWorld()));
}
Bukkit.getPluginManager().callEvent(new AddonEvent().builder().addon(addon).reason(AddonEvent.Reason.ENABLE).build());
new AddonEvent().builder().addon(addon).reason(AddonEvent.Reason.ENABLE).build();
addon.setState(Addon.State.ENABLED);
plugin.log("Enabling " + addon.getDescription().getName() + "...");
} catch (NoClassDefFoundError | NoSuchMethodError | NoSuchFieldError e) {
@ -199,9 +208,35 @@ public class AddonsManager {
private void handleAddonIncompatibility(@NonNull Addon addon) {
// Set the AddonState as "INCOMPATIBLE".
addon.setState(Addon.State.INCOMPATIBLE);
plugin.log("Skipping " + addon.getDescription().getName() + " as it is incompatible with the current version of BentoBox or of server software...");
plugin.log("NOTE: The addon is referring to no longer existing classes.");
plugin.log("NOTE: DO NOT report this as a bug from BentoBox.");
plugin.logWarning("Skipping " + addon.getDescription().getName() + " as it is incompatible with the current version of BentoBox or of server software...");
plugin.logWarning("NOTE: The addon is referring to no longer existing classes.");
plugin.logWarning("NOTE: DO NOT report this as a bug from BentoBox.");
}
/**
* Checks if the addon does not explicitly rely on API from a more recent BentoBox version.
* @param addon instance of the Addon.
* @return {@code true} if the addon relies on available BentoBox API, {@code false} otherwise.
* @since 1.11.0
*/
private boolean isAddonCompatibleWithBentoBox(@NonNull Addon addon) {
// We have to use lists instead of arrays for dynamic changes and optimization (appending something to an array is O(n) whereas O(1) with lists).
List<String> apiVersion = Arrays.asList(addon.getDescription().getApiVersion().split("\\."));
List<String> bentoboxVersion = Arrays.asList(plugin.getDescription().getVersion().split("\\."));
while (bentoboxVersion.size() < apiVersion.size()) {
bentoboxVersion.add("0");
}
for (int i = 0; i < apiVersion.size(); i++) {
int apiNumber = Integer.parseInt(apiVersion.get(i));
int bentoboxNumber = Integer.parseInt(bentoboxVersion.get(i));
if (bentoboxNumber < apiNumber) {
return false;
}
}
return true;
}
/**
@ -429,7 +464,7 @@ public class AddonsManager {
addon.getDescription().getAuthors().forEach(plugin::logError);
plugin.logStacktrace(e);
}
Bukkit.getPluginManager().callEvent(new AddonEvent().builder().addon(addon).reason(AddonEvent.Reason.DISABLE).build());
new AddonEvent().builder().addon(addon).reason(AddonEvent.Reason.DISABLE).build();
}
// Clear loaders
if (loaders.containsKey(addon)) {

View File

@ -141,6 +141,7 @@ public class BlueprintsManager {
*
* @param addon the {@link GameModeAddon} to get the blueprint bundles.
*/
@NonNull
public Map<String, BlueprintBundle> getBlueprintBundles(@NonNull GameModeAddon addon) {
if (!blueprintBundles.containsKey(addon)) {
return new HashMap<>();
@ -154,6 +155,7 @@ public class BlueprintsManager {
* @return the default blueprint bundle or null if none
* @since 1.8.0
*/
@Nullable
public BlueprintBundle getDefaultBlueprintBundle(@NonNull GameModeAddon addon) {
if (blueprintBundles.containsKey(addon)) {
return blueprintBundles.get(addon).stream().filter(bb -> bb.getUniqueId().equals(DEFAULT_BUNDLE_NAME)).findFirst().orElse(null);
@ -180,24 +182,21 @@ public class BlueprintsManager {
public void loadBlueprintBundles(@NonNull GameModeAddon addon) {
// Set loading flag
blueprintsLoaded.add(addon);
Bukkit
.getScheduler()
.runTaskAsynchronously(
plugin, () -> {
// Load bundles
blueprintBundles.put(addon, new ArrayList<>());
// See if there are any schems that need converting
new SchemToBlueprint(plugin).convertSchems(addon);
if (!loadBundles(addon)) {
makeDefaults(addon);
loadBundles(addon);
}
// Load blueprints
loadBlueprints(addon);
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
// Load bundles
blueprintBundles.put(addon, new ArrayList<>());
// See if there are any schems that need converting
new SchemToBlueprint(plugin).convertSchems(addon);
if (!loadBundles(addon)) {
makeDefaults(addon);
loadBundles(addon);
}
// Load blueprints
loadBlueprints(addon);
// Clear loading flag
blueprintsLoaded.remove(addon);
});
// Clear loading flag
blueprintsLoaded.remove(addon);
});
}
/**
@ -223,14 +222,22 @@ public class BlueprintsManager {
try {
BlueprintBundle bb = gson.fromJson(new FileReader(file), BlueprintBundle.class);
if (bb != null) {
blueprintBundles
.get(addon)
.add(bb);
plugin.log("Loaded Blueprint Bundle '" + bb.getUniqueId() + FOR + addon.getDescription().getName());
loaded = true;
// Make sure there is no existing bundle with the same uniqueId
if (blueprintBundles.get(addon).stream().noneMatch(bundle -> bundle.getUniqueId().equals(bb.getUniqueId()))) {
blueprintBundles.get(addon).add(bb);
plugin.log("Loaded Blueprint Bundle '" + bb.getUniqueId() + FOR + addon.getDescription().getName() + ".");
loaded = true;
} else {
// There is a bundle that already uses this uniqueId.
// In that case, we log that and do not load the new bundle.
plugin.logWarning("Could not load blueprint bundle '" + file.getName() + FOR + addon.getDescription().getName() + ".");
plugin.logWarning("The uniqueId '" + bb.getUniqueId() + "' is already used by another Blueprint Bundle.");
plugin.logWarning("This can occur if the Blueprint Bundles' files were manually edited.");
plugin.logWarning("Please review your Blueprint Bundles' files and make sure their uniqueIds are not in duplicate.");
}
}
} catch (Exception e) {
plugin.logError("Could not load blueprint bundle " + file.getName() + " " + e.getMessage());
plugin.logError("Could not load blueprint bundle '" + file.getName() + "'. Cause: " + e.getMessage() + ".");
plugin.logStacktrace(e);
}
}

View File

@ -910,8 +910,8 @@ public class IslandsManager {
// Island is off grid
x = Math.round((double) x / distance) * distance + plugin.getIWM().getIslandXOffset(world);
z = Math.round((double) z / distance) * distance + plugin.getIWM().getIslandZOffset(world);
island.setCenter(new Location(world, x, island.getCenter().getBlockY(), z));
}
island.setCenter(new Location(world, x, island.getCenter().getBlockY(), z));
}
/**
@ -931,7 +931,7 @@ public class IslandsManager {
}
/**
* Checks if an online player is in the protected area of an island he owns or he is part of. i.e. rank is > VISITOR_RANK
* Checks if an online player is in the protected area of an island he owns or he is part of. i.e. rank is greater than VISITOR_RANK
*
* @param world the World to check. Typically this is the user's world. Does not check nether or end worlds. If null the method will always return {@code false}.
* @param user the User to check, if null or if this is not a Player the method will always return {@code false}.
@ -1094,7 +1094,10 @@ public class IslandsManager {
// Tell target. If they are offline, then they may receive a message when they login
target.sendMessage("commands.island.team.setowner.you-are-the-owner");
// Permission checks for range changes only work when the target is online
if (target.isOnline()) {
if (target.isOnline() &&
target.getEffectivePermissions().parallelStream()
.map(p -> p.getPermission())
.anyMatch(p -> p.startsWith(addon.getPermissionPrefix() + "island.range"))) {
// Check if new owner has a different range permission than the island size
int range = target.getPermissionValue(
addon.getPermissionPrefix() + "island.range",
@ -1105,8 +1108,21 @@ public class IslandsManager {
target.sendMessage("commands.admin.setrange.range-updated", TextVariables.NUMBER, String.valueOf(range));
plugin.log("Setowner: Island protection range changed from " + island.getProtectionRange() + " to "
+ range + " for " + user.getName() + " due to permission.");
// Get old range for event
int oldRange = island.getProtectionRange();
island.setProtectionRange(range);
// Call Protection Range Change event. Does not support cancelling.
IslandEvent.builder()
.island(island)
.location(island.getCenter())
.reason(IslandEvent.Reason.RANGE_CHANGE)
.involvedPlayer(targetUUID)
.admin(true)
.protectionRange(range, oldRange)
.build();
}
island.setProtectionRange(range);
}
});
}

View File

@ -273,7 +273,7 @@ public class PlayersManager {
}
/**
* Sets the player's name and updates the name>UUID database
* Sets the player's name and updates the name to UUID database
* @param user - the User
*/
public void setPlayerName(@NonNull User user) {

View File

@ -101,8 +101,8 @@ public class DefaultNewIslandLocationStrategy implements NewIslandLocationStrate
return Result.FREE;
}
// Block check
if (!plugin.getIWM().isUseOwnGenerator(world) && Arrays.asList(BlockFace.values()).stream().anyMatch(bf -> location.getBlock().getRelative(bf).isEmpty()
&& !location.getBlock().getRelative(bf).getType().equals(Material.WATER))) {
if (!plugin.getIWM().isUseOwnGenerator(world) && Arrays.asList(BlockFace.values()).stream().anyMatch(bf ->
!location.getBlock().getRelative(bf).isEmpty() && !location.getBlock().getRelative(bf).getType().equals(Material.WATER))) {
// Block found
plugin.getIslands().createIsland(location);
return Result.BLOCKS_IN_AREA;

View File

@ -273,7 +273,9 @@ public class IslandCache {
*/
public void setOwner(@NonNull Island island, @Nullable UUID newOwnerUUID) {
island.setOwner(newOwnerUUID);
islandsByUUID.computeIfAbsent(Util.getWorld(island.getWorld()), k -> new HashMap<>()).put(newOwnerUUID, island);
if (newOwnerUUID != null) {
islandsByUUID.computeIfAbsent(Util.getWorld(island.getWorld()), k -> new HashMap<>()).put(newOwnerUUID, island);
}
islandsByLocation.put(island.getCenter(), island);
islandsById.put(island.getUniqueId(), island);
}

View File

@ -61,9 +61,15 @@ public class BlueprintManagementPanel {
this.plugin = plugin;
this.user = user;
this.addon = addon;
normalBlueprint = new Blueprint().setIcon(Material.GREEN_STAINED_GLASS_PANE).setName(t("normal")).setDescription(t(INSTRUCTION));
netherBlueprint = new Blueprint().setIcon(Material.RED_STAINED_GLASS_PANE).setName(t("nether")).setDescription(t(INSTRUCTION));
endBlueprint = new Blueprint().setIcon(Material.YELLOW_STAINED_GLASS_PANE).setName(t("end")).setDescription(t(INSTRUCTION));
normalBlueprint = new Blueprint().setIcon(Material.GREEN_STAINED_GLASS_PANE)
.setName(user.getTranslation("general.worlds.overworld"))
.setDescription(t(INSTRUCTION));
netherBlueprint = new Blueprint().setIcon(Material.RED_STAINED_GLASS_PANE)
.setName(user.getTranslation("general.worlds.nether"))
.setDescription(t(INSTRUCTION));
endBlueprint = new Blueprint().setIcon(Material.YELLOW_STAINED_GLASS_PANE)
.setName(user.getTranslation("general.worlds.the-end"))
.setDescription(t(INSTRUCTION));
slotToEnvironment = ImmutableMap.of(3, World.Environment.NORMAL, 5, World.Environment.NETHER, 7, World.Environment.THE_END);
environmentToBlueprint = ImmutableMap.of(World.Environment.NORMAL, normalBlueprint, World.Environment.NETHER, netherBlueprint, World.Environment.THE_END, endBlueprint);
}
@ -163,7 +169,7 @@ public class BlueprintManagementPanel {
});
for (int i = 9; i < 18; i++) {
pb.item(i, new PanelItemBuilder().icon(Material.BLACK_STAINED_GLASS_PANE).name("-").build());
pb.item(i, new PanelItemBuilder().icon(Material.BLACK_STAINED_GLASS_PANE).name(" ").build());
}
blueprints.entrySet().stream().limit(18).forEach(b -> pb.item(getBlueprintItem(addon, b.getKey(), bb, b.getValue())));
// Buttons for non-default bundle
@ -238,10 +244,16 @@ public class BlueprintManagementPanel {
}
private PanelItem getWorldInstrTile(Environment env) {
Material icon;
if (env.equals(Environment.NORMAL)) icon = Material.GRASS_BLOCK;
else if (env.equals(Environment.NETHER)) icon = Material.NETHERRACK;
else icon = Material.END_STONE;
return new PanelItemBuilder()
.name(t("world-name-syntax", TextVariables.NAME, Util.prettifyText(env.name())))
.description(t("world-instructions"))
.icon(Material.GRAY_STAINED_GLASS_PANE)
.glow(true)
.icon(icon)
.build();
}

View File

@ -123,7 +123,11 @@ public class ServerCompatibility {
/**
* @since 1.10.0
*/
V1_15_1(Compatibility.COMPATIBLE)
V1_15_1(Compatibility.COMPATIBLE),
/**
* @since 1.11.0
*/
V1_15_2(Compatibility.COMPATIBLE)
;

View File

@ -29,12 +29,18 @@ general:
# If there is no economy plugin present anyway, money will be automatically disabled.
use-economy: true
database:
# JSON, MYSQL, MARIADB (10.2.3+), MONGODB, SQLITE, POSTGRESQL and YAML(deprecated).
# JSON, MYSQL, MARIADB, MONGODB, SQLITE, POSTGRESQL and YAML(deprecated).
# Transition database options are:
# YAML2JSON, YAML2MARIADB, YAML2MYSQL, YAML2MONGODB, YAML2SQLITE
# JSON2MARIADB, JSON2MYSQL, JSON2MONGODB, JSON2SQLITE, JSON2POSTGRESQL
# MYSQL2JSON, MARIADB2JSON, MONGODB2JSON, SQLITE2JSON, POSTGRESQL2JSON
# If you need others, please make a feature request.
# Minimum required versions:
# MySQL versions 5.7 or later
# MariaDB versions 10.2.3 or later
# MongoDB versions 3.6 or later
# SQLite versions 3.28 or later
# PostgreSQL versions 9.4 or later
# Transition options enable migration from one database type to another. Use /bbox migrate.
# YAML and JSON are file-based databases.
# MYSQL might not work with all implementations: if available, use a dedicated database type (e.g. MARIADB).

File diff suppressed because it is too large Load Diff

View File

@ -25,6 +25,7 @@ general:
already-have-island: "&c You already have an island!"
no-safe-location-found: "&c Could not find a safe spot to teleport you to on the island."
not-owner: "&c You are not the owner of the island!"
player-is-not-owner: "&b [name] &c is not the owner of an island!"
not-in-team: "&c That player is not in your team!"
offline-player: "&c That player is offline or doesn't exist."
unknown-player: "&c [name] is an unknown player!"
@ -35,6 +36,10 @@ general:
must-be-positive-number: "&c [number] is not a valid positive number."
tips:
changing-obsidian-to-lava: "Changing obsidian back into lava. Be careful!"
worlds:
overworld: "Overworld"
nether: "Nether"
the-end: "The End"
commands:
# Parameters in <> are required, parameters in [] are optional
@ -52,20 +57,20 @@ commands:
resets:
description: "edit resets of the players"
set:
description: "sets the resets of this player"
description: "sets how many time this player reset his island"
parameters: "<player> <resets>"
success: "&a Successfully set &b [name]&a 's resets to &b [number]&a ."
reset:
description: "resets the resets of this player to 0"
description: "resets how many time this player reset his island to 0"
parameters: "<player>"
success-everyone: "&a Successfully reset &b everyone&a 's resets to &b 0&a ."
success: "&a Successfully reset &b [name]&a 's resets to &b 0&a ."
add:
description: "adds resets to the player"
description: "adds to how many times this player reset his island"
parameters: "<player> <resets>"
success: "&a Successfully added &b [number] &a resets to &b [name], increasing the total to &b [total]&a resets."
remove:
description: "removes resets to the player"
description: "removes from how many times this player reset his island"
parameters: "<player> <resets>"
success: "&a Successfully removed &b [number] &a resets to &b [name], decreasing the total to &b [total]&a resets."
purge:
@ -219,19 +224,19 @@ commands:
reload:
description: "reload"
tp:
parameters: "<player>"
parameters: "<player> [player to teleport]"
description: "teleport to a player's island"
manual: "&c No safe warp found! Manually tp near to &b [location] &c and check it out"
getrank:
parameters: "<player>"
description: "get a player's rank on their island"
rank-is: "&a Rank is [rank] on their island."
parameters: "<player> [island owner]"
description: "get a player's rank on their island or the island of the owner"
rank-is: "&a Rank is &b [rank] &a on &b [name]&a 's island."
setrank:
parameters: "<player> <rank>"
description: "set a player's rank on their island"
parameters: "<player> <rank> [island owner]"
description: "set a player's rank on their island or the island of the owner"
unknown-rank: "&c Unknown rank!"
not-possible: "&c Rank must be higher than visitor"
rank-set: "&a Rank set from [from] to [to]."
not-possible: "&c Rank must be higher than visitor."
rank-set: "&a Rank set from &b [from] &a to &b [to] &a on &b [name]&a 's island."
setspawn:
description: "set an island as spawn for this world"
already-spawn: "&c This island is already a spawn!"
@ -297,9 +302,6 @@ commands:
management:
back: "Back"
instruction: "Click on blueprint then click here"
normal: "Normal"
nether: "Nether"
end: "The End"
title: "Blueprint Bundle Manager"
edit: "Click to edit"
rename: "Right-click to rename"
@ -396,7 +398,7 @@ commands:
loaded-addons: "Loaded Addons:"
loaded-game-worlds: "Loaded Game Worlds:"
addon-syntax: "&2 [name] &3 [version] &7 (&3 [state]&7 )"
game-world: "&2 [name] &7 (&3 [addon]&7 ): &a Overworld&7 , &r [nether_color]Nether&7 , &r [end_color]End"
game-world: "&2 [name] &7 (&3 [addon]&7 ): &3 [worlds]"
server: "&2 Running &3 [name] [version]&2 ."
database: "&2 Database: &3 [database]"
manage:
@ -801,7 +803,7 @@ protection:
DYE:
description: "Prevent dye use"
name: "Dye use"
hint: "Dying disabled"
hint: "Dyeing disabled"
EGGS:
description: "Toggle egg throwing"
name: "Egg throwing"
@ -833,8 +835,10 @@ protection:
description: "Display entry and exit messages"
island: "[name]'s island"
name: "Enter/Exit messages"
now-entering: "&b Now entering [name]"
now-leaving: "&b Now leaving [name]"
now-entering: "&a Now entering &b [name]&a ."
now-entering-your-island: "&a Now entering your island."
now-leaving: "&a Now leaving &b [name]&a ."
now-leaving-your-island: "&a Now leaving your island."
EXPERIENCE_BOTTLE_THROWING:
name: "Experience bottle throwing"
description: "Toggle throwing experience bottles."

File diff suppressed because it is too large Load Diff

View File

@ -126,6 +126,19 @@ commands:
set-different-pos: "&cUzstādi citu pozīciju - šī jau ir uzstādīta!"
set-pos1: "&aPozīcija 1 uzstādīta uz [vector]"
set-pos2: "&aPozīcija 2 uzstādīta uz [vector]"
delete:
parameters: "<nosaukums>"
description: dzēš salas shēmas plānu
no-blueprint: "&b [name] &c neeksistē."
confirmation: |-
&c Vai tiesām vēlies dzēst šo salas shēmas plānu?
&c Tiklīdz dzēsts, to nevarēs vairs atjaunot.
success: "&a Veiksmīgi dzēts salas shēmas plāns &b [name]&a ."
rename:
parameters: "<shēmas plāna nosaukums> <jaunais nosaukums>"
description: pārsaukt shēmas plānu
success: "&a Shēmas plāns &b [old] &a veiksmīgi pārsaukts par &b [name]&a."
pick-different-name: "&c Lūdzu izvēlies citu shēmas plāna nosaukumu."
deaths:
description: maina nāvju skaitu spēlētājam
reset:
@ -136,6 +149,16 @@ commands:
description: maina nāvju skaitu spēlētājam
parameters: "<spēlētājs> <nāves>"
success: "&aSpēlētājam &b[name]&a nāvju skaits uzstādīts uz &b[number]&a."
add:
description: palielina nāvju skaitu spēlētājam
parameters: "<spēlētājs> <nāvju skaits>"
success: "&a Veiksmīgi palielināts nāvju skaits par &b [number] &a priekš
&b [name], kopā sasniedzot &b [total]&a nāves."
remove:
description: samazina nāvju skaitu spēlētājam
parameters: "<spēlētājs> <nāvju skaits>"
success: "&a Veiksmīgi samazināts nāvju skaits par &b [number] &a priekš &b
[name], kopā sasniedzot &b [total]&a nāves."
delete:
cannot-delete-owner: "&cVisi spēlētāja komandas biedriem ir jābūt izmestiem
no komandas pirms salas dzēšanas."
@ -224,6 +247,21 @@ commands:
too-low: "&cAizsardzības distancei jābūt lielākai par &b1&c!"
parameters: "<spēlētājs> <distance>"
success: "&aSalas aizsardzības distance nomainīta uz &b[number]&a."
invalid-value:
too-low: "&c Aizsardzības rādiusam ir jābūt lielākam par &b 1&c !"
too-high: "&c Aizsardzības rādiusam ir jābūt mazākam vai vienādam ar &b [number]&c
!"
same-as-before: "&c Aizsardzības rādiuss ir uzstādīts uz &b [number]&c !"
add:
description: palielina salas aizsardzības rādiusa distanci
parameters: "<spēlētājs> <attālums>"
success: "&a Veiksmīgi palielināts &b [name]&a salas aizsardzības rādiuss
līdz &b [total] &7 (&b +[number]&7 )&a ."
remove:
description: samazina salas aizsardzības rādiusa distanci
parameters: "<spēlētājs> <attālums>"
success: "&a Veiksmīgi samazināts &b [name]&a salas aizsardzības rādiuss līdz
&b [total] &7 (&b +[number]&7 )&a ."
register:
already-owned: "&cSala jau pieder citam spēlētājam!"
cannot-make-island: "&cAtvaino, bet neizdevās izveidot šeit salu. Iespējams
@ -235,19 +273,41 @@ commands:
parameters: "<spēlētājs>"
registered-island: "&aPiereģistrē spēlētāju pie salas ar koordinātēm [xyz]."
reserved-island: "&aSala ir rezērvēta [xyz] priekš spēlētāja."
island-is-spawn: "&6 Šī ir sākuma sala. Vai tiešām vēlies turpināt? Ievadi komandu
vēlreiz, lai apstiprinātu."
reload:
description: pārlādēt
resetflags:
description: Atiestatī visu salu noklusējuma karodziņu iestatījumus no config.yml
success: "&aVeiksmīgi atiestatīti visi salu iestatījumi uz sākotnējām vērtībām."
parameters: "[karogs]"
confirm: "&4 Šis atjaunos visus karogus uz sākotnējām vērtībām priekš visām
salām!"
success-one: "&a [name] karogs ir atjaunots uz sākotnējo vērtību visās salās."
resets:
description: mainīt spēlētāja 'resetus'
reset:
description: uzstāta spēlētājam 'resetus' uz 0
parameters: "<spēlētājs>"
success-everyone: "&a Veiksmīgi uzstādītas &b 0&a atsākšanas &b visiem&a
spēlētājiem ."
success: "&a Veiksmīgi uzstādītas &b 0&a atsākšanas &b [name]&a spēlētājam
."
set:
description: uzstāda 'resetus' spēlētājam
parameters: "<spēlētājs> <reseti>"
success: "&a Veiksmīgi uzstādītas &b [number]&a atssākšanas reizes spēlētājam
&b [name]&a ."
add:
description: palielina atsākšanu skaitu spēlētājam
parameters: "<spēlētājs> <cipars>"
success: "&a Veiksmīgi palielināts par &b [number] &a atsākšanu skaits priekš
&b [name], šobrīd kopā &b [total]&a atsākšanas reizes."
remove:
description: samazina atsākšanu skaitu spēlētājam
parameters: "<spēlētājs> <cipars>"
success: "&a Veiksmīgi samazināts par &b [number] &a atsākšanu skaits priekš
&b [name], šobrīd kopā &b [total]&a atsākšanas reizes."
setrange:
description: uzstāda aizsardzības distanci spēlētāja salai
parameters: "<spēlētājs> <distance>"
@ -258,6 +318,7 @@ commands:
parameters: "<spēlētājs> <rangs>"
rank-set: "&aSpēlētājam nomainīts rangs no [from] uz [to]."
unknown-rank: "&cNezināms rangs!"
name-not-owner: "&b [name] &c nav salas īpašnieks."
setspawn:
already-spawn: "&cŠī sala jau ir uzstādīta kā sākuma sala!"
confirmation: "&cVai tiešām vēlies uzstādīt šo salu kā sākuma salu?"
@ -423,6 +484,16 @@ commands:
vietas."
unable-create-island: "&cNeizdevās izveidot tavu salu, ziņo par kļūdu administratoram."
unknown-blueprint: "&cŠī shēma nav ielādēta vai tā neeksistē."
pasting:
estimated-time: "&a Aptuvenais laiks: &b [number] &a sekundes."
blocks: "&a Būvē ik pa blokam: bloku skaits &b [number] &a..."
entities: "&a Aizpilda ar radībām: kopā &b [number] &a radības..."
done: "&a Darīts! Tava sala ir gatava un gaida tevi!"
on-first-login: "&a Sveicināts! Mums ir nepieciešamas pāris sekundes tavas salas
sagatavošanai."
cannot-create-island: "&c Neizdevās atrast brīvu salas vietu laikā, mēģini vēlreiz..."
you-can-teleport-to-your-island: "&a Tu vari pārvietoties uz savu salu, kad
vien vēlies."
expel:
cannot-ban-member: "&cTu nevari izraidīt komandas biedrus!"
cannot-expel: "&cŠis spēlētājs nevar tikt izraidīts."
@ -432,6 +503,7 @@ commands:
parameters: "<spēlētājs>"
player-expelled-you: "&b[name]&c izraidīja tevi no salas!"
success: "&aTu izmeti spēlētāju &b[name] &ano savas salas."
cannot-expel-member: "&c Tu nevari izraidīt komandas biedru!"
go:
description: pārvieto tevi uz tavu salu
parameters: "[mājas numurs]"
@ -456,16 +528,16 @@ commands:
the-following-islands: "&aSekojošās salas ir tev apkārt:"
west: Rietumos
reset:
description: pārstartē salu vai izdzēš iepriekšējo
none-left: "&cTu esi sasniedzis restartu limitu!"
parameters: "<shēma>"
resets-left: "&cTev ir palikušas &b[number] &catstatīšanas reizes"
confirmation: |-
&cVai esi pārliecināts, ka vēlies to darīt?
&cVisi salas biedri tiks izmesti no komandas, nāksies viņus aicināt vēlreiz.
&cŠai darbībai nav atpakaļceļa. Salu nevarēs atjaunot!
description: pārstartē salu vai izdzēš iepriekšējo
kicked-from-island: "&cTu esi izmests no salas iekš [gamemode], jo tās īpašnieks
savu salu atstatīja."
none-left: "&cTu esi sasniedzis restartu limitu!"
parameters: "<shēma>"
resets-left: "&cTev ir palikušas &b[number] &catstatīšanas reizes"
resetname:
description: noņemt salas nosaukumu
sethome:
@ -482,10 +554,10 @@ commands:
not-allowed: "&cTev nav atļaujas uzstādīt mājas punktu Beigās."
setname:
description: uzstāda nosaukumu tavai salai
name-already-exists: "&cSala ar šādu nosaukumu jau eksistē šajā spēles režīmā."
name-too-long: "&cPārāk garšs. Maksimālais izmērs ir [number] simboli."
name-too-short: "&cPārāk īss. Minimālais izmērs ir [number] simboli."
parameters: "<nosaukums>"
name-already-exists: "&cSala ar šādu nosaukumu jau eksistē šajā spēles režīmā."
settings:
description: attaino salas iestatījumus
spawn:
@ -500,6 +572,8 @@ commands:
parameters: "<spēlētājs>"
success: "&aSabiedrotā rangs uzstādīts spēlētājam &b[name]."
you-are-a-coop-member: "&2Tu esi uzstādīts kā sabiedrotajs spēlētājam [name]"
name-has-invited-you: "&a [name] ielūdza tevi pievienoties savai salai kā
sabiedrotais."
demote:
description: samazina spēlētāja komandas rangu
errors:
@ -510,6 +584,21 @@ commands:
description: pārvaldīt savu komandu
info:
description: parādīt detalizētu informāciju par tavu komandu
last-seen:
days: dienas
hours: stundas
minutes: minūtes
layout: pirms &b [number] &7 [unit]
member-layout:
online: "&a &l o &r &f [name]"
offline: "&c &l o &r &f [name] &7 ([last_seen])"
header: |-
&f --- &a Komandas detaļas &f ---
&a Biedri: &b [total]&7 /&b [max]
&a Biedri tiešsaitē: &b [online]
rank-layout:
owner: "&6 [rank]:"
generic: "&6 [rank] &7 (&b [number]&7 )&6 :"
invite:
accept:
confirmation: |-
@ -531,6 +620,7 @@ commands:
spēlētājus."
none-invited-you: "&cNeviens tevi nav ielūdzis :c."
you-already-are-in-team: "&cTu jau esi komandā!"
you-have-already-invited: "&c Tu jau esi uzaicinājis šo spēlētāju!"
invitation-sent: "&aIelūgums nosūtīts [name]"
name-has-invited-you: "&a[name] ielūdza tevi pievienoties viņa komandai."
parameters: "<spēlētājs>"
@ -547,9 +637,9 @@ commands:
kick:
cannot-kick: "&cTu nevari izmest pats sevi!"
description: izmest spēlētāju no tavas salas
owner-kicked: "&cĪpašnieks jūs izmeta no savas salas iekš [gamemode]!"
parameters: "<spēlētājs>"
success: "&b[name] &atika izmests no šīs salas."
owner-kicked: "&cĪpašnieks jūs izmeta no savas salas iekš [gamemode]!"
leave:
cannot-leave: "&cĪpašnieks nevar pamest komandu! Nodod salu citam vai izmet
visus no komandas."
@ -578,6 +668,8 @@ commands:
success: "&aUzticamā rangs uzstādīts spēlētājam &b[name]&a."
trust-in-yourself: "&cTu jau sev esi uzticams!"
you-are-trusted: "&2Spēlētājs [name] tev uzticas!"
name-has-invited-you: "&a [name] ielūdza tevi pievienoties savai salai kā
uzticams."
uncoop:
all-members-logged-off: "&cVisi salas spēlētāji ir izgājuši, tā ka tu vairs
neesi sabiedrotais [name] salā."
@ -650,6 +742,9 @@ management:
empty-here:
description: "&aKā būtu, ja tu apskatītu katalogu?"
name: "&bŠis izskatās tukšs..."
credits:
name: "&6 Pateicība"
description: "&a Atvērt patecības sarakstu priekš BentoBox"
information:
state:
description:
@ -1181,6 +1276,14 @@ protection:
&aradīšanas olas.
hint: Radīšanas olu mešana nav atļauta
name: Radīšanas olas
SPAWNER_SPAWN_EGGS:
description: |-
&aAtļauj mainīt radību iekš radīšanas
&ablokiem lietojot radīšanas olas.
hint: 'mainīt radību radīšanas bloka radību izmantojot radīšanas olu nav atļauta
'
name: Radīšanas olas uz radīšanas blokiem
TNT_DAMAGE:
description: |-
&aĻauj Dinamītam un Vagonam
@ -1228,14 +1331,19 @@ protection:
&aĻauj katlem saplēst blokus
&aun bojāt radības.
name: Pārslēgt
SPAWNER_SPAWN_EGGS:
CAKE:
name: Kūkas
description: Pārslēdz iespēju ēst kūkas
hint: Kūku ēšana nav atļauta
LECTERN:
name: Lektors
description: |-
&aAtļauj mainīt radību iekš radīšanas
&ablokiem lietojot radīšanas olas.
name: Radīšanas olas uz radīšanas blokiem
hint: 'mainīt radību radīšanas bloka radību izmantojot radīšanas olu nav atļauta
&a Ļauj novietot grāmatas uz lektora
&a vai arī tās noņemt
'
&c Neaizsargā grāmatas no lasīšanas,
&c kamēr tās ir uz lektora
hint: nav ļauts novietot vai paņemt grāmatas no lektora.
locked: "&cŠī sala ir slēgta!"
panel:
flag-item:
@ -1287,6 +1395,11 @@ protection:
WORLD_SETTING:
description: "&aSpēles režīma iestatījumi"
title: "&b[world_name] &6Iestatījumi"
reset-to-default:
name: "&c Atjaunot uz sākotnējām vērtībām"
description: |-
&a Atjaunot &c &l VISUS &r &a iestatījumus
&a uz sākotnējām vērtībām
protected: "&cSala ir aizsargāta: [description]"
spawn-protected: "&cSākuma sala ir aizsargāta: [description]"
world-protected: "&cPasaule aizsargāta: [description]"
@ -1309,3 +1422,17 @@ successfully-loaded: |2
&6 | |_) | __/ | | | || (_) | |_) | (_) > < &bv&e[version]
&6 |____/ \___|_| |_|\__\___/|____/ \___/_/\_\ &8Ielādēts &e[time]&8ms.
&6 &7Tulkoja &aBONNe1704
panel:
credits:
title: "&8 [name] &2 Pateicība"
contributor:
name: "&a [name]"
description: "&a Labojumi: &b [commits]"
empty-here:
name: "&c Šis izskatās tukšs..."
description: |-
&c BentoBox nevarēja iegūt Izstrādātājus
&c šim papildinājumam.
&a Ļauj BentoBox savienoties ar GitHub
&a konfigurācijā vai mēgīni vēlāk.

View File

@ -179,6 +179,7 @@ public class AdminGetrankCommandTest {
when(pm.getUUID(any())).thenReturn(targetUUID);
when(im.getIsland(any(), any(UUID.class))).thenReturn(island);
when(user.getTranslation(anyString())).thenReturn("member");
when(im.hasIsland(any(), any(UUID.class))).thenReturn(true);
assertTrue(c.canExecute(user, "", Collections.singletonList("tastybento")));
}
@ -192,10 +193,14 @@ public class AdminGetrankCommandTest {
testCanExecuteKnownPlayerHasIslandSuccess();
when(island.getRank(any())).thenReturn(RanksManager.SUB_OWNER_RANK);
when(user.getTranslation(any())).thenReturn("sub-owner", "sub-owner");
when(island.getOwner()).thenReturn(targetUUID);
when(pm.getName(targetUUID)).thenReturn("tastybento");
assertTrue(c.execute(user, "", Collections.singletonList("tastybento")));
verify(user).sendMessage(eq("commands.admin.getrank.rank-is"),
eq("[rank]"),
eq("sub-owner"));
eq("sub-owner"),
eq("[name]"),
eq("tastybento"));
}
/**

View File

@ -24,6 +24,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
@ -35,13 +37,14 @@ import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.PlayersManager;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.bentobox.util.Util;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class, BentoBox.class, User.class })
@PrepareForTest({Bukkit.class, BentoBox.class, Util.class})
public class AdminSetrankCommandTest {
@Mock
@ -53,7 +56,6 @@ public class AdminSetrankCommandTest {
@Mock
private PlayersManager pm;
@Mock
private RanksManager rm;
private AdminSetrankCommand c;
@ -69,6 +71,7 @@ public class AdminSetrankCommandTest {
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// Ranks Manager
rm = new RanksManager();
when(plugin.getRanksManager()).thenReturn(rm);
// Players Manager
@ -82,7 +85,14 @@ public class AdminSetrankCommandTest {
Player p = mock(Player.class);
when(p.getUniqueId()).thenReturn(targetUUID);
User.getInstance(p);
// Online players
PowerMockito.mockStatic(Util.class);
when(Util.getOnlinePlayerList(any())).thenReturn(Collections.singletonList("tastybento"));
// Translations
when(user.getTranslation(anyString())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
// Command
c = new AdminSetrankCommand(ac);
}
@ -151,7 +161,7 @@ public class AdminSetrankCommandTest {
@Test
public void testCanExecuteKnownPlayerNoIsland() {
when(pm.getUUID(any())).thenReturn(targetUUID);
assertFalse(c.canExecute(user, "", Arrays.asList("tastybento", "member")));
assertFalse(c.canExecute(user, "", Arrays.asList("tastybento", "ranks.member")));
verify(user).sendMessage("general.errors.player-has-no-island");
}
@ -173,9 +183,7 @@ public class AdminSetrankCommandTest {
public void testCanExecuteKnownPlayerHasIslandTooLowRank() {
when(pm.getUUID(any())).thenReturn(targetUUID);
when(im.hasIsland(any(), any(UUID.class))).thenReturn(true);
when(rm.getRanks()).thenReturn(Collections.singletonMap("visitor", 0));
when(user.getTranslation(anyString())).thenReturn("visitor");
assertFalse(c.canExecute(user, "", Arrays.asList("tastybento", "visitor")));
assertFalse(c.canExecute(user, "", Arrays.asList("tastybento", "ranks.visitor")));
verify(user).sendMessage("commands.admin.setrank.not-possible");
}
@ -186,9 +194,7 @@ public class AdminSetrankCommandTest {
public void testCanExecuteKnownPlayerHasIslandSuccess() {
when(pm.getUUID(any())).thenReturn(targetUUID);
when(im.hasIsland(any(), any(UUID.class))).thenReturn(true);
when(rm.getRanks()).thenReturn(Collections.singletonMap("member", 500));
when(user.getTranslation(anyString())).thenReturn("member");
assertTrue(c.canExecute(user, "", Arrays.asList("tastybento", "member")));
assertTrue(c.canExecute(user, "", Arrays.asList("tastybento", "ranks.member")));
}
@ -202,13 +208,14 @@ public class AdminSetrankCommandTest {
Island island = mock(Island.class);
when(island.getRank(any())).thenReturn(RanksManager.SUB_OWNER_RANK);
when(im.getIsland(any(), any(UUID.class))).thenReturn(island);
when(user.getTranslation(any())).thenReturn("sub-owner", "member");
assertTrue(c.execute(user, "", Arrays.asList("tastybento", "member")));
verify(user).sendMessage(eq("commands.admin.setrank.rank-set"),
eq("[from]"),
eq("sub-owner"),
eq("ranks.sub-owner"),
eq("[to]"),
eq("member"));
eq("ranks.member"),
eq("[name]"),
eq(null));
}
/**
@ -216,13 +223,11 @@ public class AdminSetrankCommandTest {
*/
@Test
public void testTabCompleteUserStringListOfString() {
when(rm.getRanks()).thenReturn(Collections.singletonMap("visitor", 0));
when(user.getTranslation(any())).thenReturn("visitor");
Optional<List<String>> result = c.tabComplete(user, "", Collections.emptyList());
Optional<List<String>> result = c.tabComplete(user, "", Arrays.asList("setrank", ""));
assertTrue(result.isPresent());
result.ifPresent(list -> {
assertTrue(list.size() == 1);
assertEquals("visitor", list.get(0));
assertEquals("tastybento", list.get(0));
});
}

View File

@ -2,12 +2,18 @@ package world.bentobox.bentobox.api.commands.admin;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.framework;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.bukkit.Bukkit;
@ -16,6 +22,7 @@ import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@ -26,6 +33,8 @@ import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import com.google.common.collect.ImmutableSet;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.Settings;
import world.bentobox.bentobox.api.commands.CompositeCommand;
@ -36,6 +45,7 @@ import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.LocalesManager;
import world.bentobox.bentobox.managers.PlayersManager;
import world.bentobox.bentobox.managers.RanksManager;
/**
@ -96,15 +106,15 @@ public class AdminUnregisterCommandTest {
// Player has island to begin with
im = mock(IslandsManager.class);
when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(true);
when(im.hasIsland(Mockito.any(), Mockito.any(User.class))).thenReturn(true);
when(im.isOwner(Mockito.any(),Mockito.any())).thenReturn(true);
when(im.getOwner(Mockito.any(),Mockito.any())).thenReturn(uuid);
when(im.hasIsland(any(), any(UUID.class))).thenReturn(true);
when(im.hasIsland(any(), any(User.class))).thenReturn(true);
when(im.isOwner(any(),any())).thenReturn(true);
when(im.getOwner(any(),any())).thenReturn(uuid);
when(plugin.getIslands()).thenReturn(im);
// Has team
pm = mock(PlayersManager.class);
when(im.inTeam(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
when(im.inTeam(any(), eq(uuid))).thenReturn(true);
when(plugin.getPlayers()).thenReturn(pm);
@ -115,7 +125,7 @@ public class AdminUnregisterCommandTest {
// Locales
LocalesManager lm = mock(LocalesManager.class);
when(lm.get(Mockito.any(), Mockito.any())).thenReturn("mock translation");
when(lm.get(any(), any())).thenReturn("mock translation");
when(plugin.getLocalesManager()).thenReturn(lm);
// Plugin Manager
@ -127,11 +137,11 @@ public class AdminUnregisterCommandTest {
@After
public void tearDown() {
User.clearUsers();
Mockito.framework().clearInlineMocks();
framework().clearInlineMocks();
}
/**
* Test method for .
* Test method for {@link AdminUnregisterCommand#canExecute(User, String, java.util.List)}.
*/
@Test
public void testExecuteNoTarget() {
@ -141,48 +151,86 @@ public class AdminUnregisterCommandTest {
}
/**
* Test method for .
* Test method for {@link AdminUnregisterCommand#canExecute(User, String, java.util.List)}.
*/
@Test
public void testExecuteUnknownPlayer() {
AdminUnregisterCommand itl = new AdminUnregisterCommand(ac);
String[] name = {"tastybento"};
when(pm.getUUID(Mockito.any())).thenReturn(null);
when(pm.getUUID(any())).thenReturn(null);
assertFalse(itl.canExecute(user, itl.getLabel(), Arrays.asList(name)));
Mockito.verify(user).sendMessage("general.errors.unknown-player", "[name]", name[0]);
verify(user).sendMessage("general.errors.unknown-player", "[name]", name[0]);
}
/**
* Test method for .
* Test method for {@link AdminUnregisterCommand#canExecute(User, String, java.util.List)}.
*/
@Test
public void testExecutePlayerNoIsland() {
AdminUnregisterCommand itl = new AdminUnregisterCommand(ac);
String[] name = {"tastybento"};
when(pm.getUUID(Mockito.any())).thenReturn(notUUID);
when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(false);
when(pm.getUUID(any())).thenReturn(notUUID);
when(im.hasIsland(any(), any(UUID.class))).thenReturn(false);
assertFalse(itl.canExecute(user, itl.getLabel(), Arrays.asList(name)));
Mockito.verify(user).sendMessage(Mockito.eq("general.errors.player-has-no-island"));
verify(user).sendMessage(Mockito.eq("general.errors.player-has-no-island"));
}
/**
* Test method for .
* Test method for {@link AdminUnregisterCommand#execute(User, String, java.util.List)}.
*/
@Test
public void testExecuteSuccess() {
when(im.inTeam(Mockito.any(), Mockito.any())).thenReturn(false);
when(im.inTeam(any(), any())).thenReturn(false);
Island is = mock(Island.class);
Location loc = mock(Location.class);
when(loc.toVector()).thenReturn(new Vector(123,123,432));
when(is.getCenter()).thenReturn(loc);
when(im.getIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(is);
when(im.getIsland(any(), any(UUID.class))).thenReturn(is);
String[] name = {"tastybento"};
when(pm.getUUID(Mockito.any())).thenReturn(notUUID);
when(pm.getUUID(any())).thenReturn(notUUID);
AdminUnregisterCommand itl = new AdminUnregisterCommand(ac);
assertTrue(itl.execute(user, itl.getLabel(), Arrays.asList(name)));
// Add other verifications
Mockito.verify(user).sendMessage("commands.confirmation.confirm", "[seconds]", "0");
verify(user).sendMessage("commands.confirmation.confirm", "[seconds]", "0");
}
/**
* Test method for {@link AdminUnregisterCommand#unregisterPlayer(User, UUID)}.
*/
@Test
public void testUnregisterPlayer() {
@Nullable
Island oldIsland = mock(Island.class);
@Nullable
Location center = mock(Location.class);
when(oldIsland.getCenter()).thenReturn(center);
when(center.toVector()).thenReturn(new Vector(1,2,3));
// Members
UUID uuid1 = UUID.randomUUID();
UUID uuid2 = UUID.randomUUID();
UUID uuid3 = UUID.randomUUID();
ImmutableSet<UUID> imSet = ImmutableSet.of(uuid1, uuid2, uuid3);
when(oldIsland.getMemberSet()).thenReturn(imSet);
// Trusted member
UUID uuid4 = UUID.randomUUID();
// Map must be mutable because it is cleared
Map<UUID, Integer> map = new HashMap<>();
map.put(uuid4, RanksManager.TRUSTED_RANK);
when(oldIsland.getMembers()).thenReturn(map);
// Island
when(im.getIsland(any(), any(UUID.class))).thenReturn(oldIsland);
AdminUnregisterCommand itl = new AdminUnregisterCommand(ac);
UUID targetUUID = UUID.randomUUID();
itl.unregisterPlayer(user, targetUUID);
verify(user).sendMessage("commands.admin.unregister.unregistered-island", "[xyz]", "1,2,3");
assertTrue(map.isEmpty());
verify(im).removePlayer(any(), eq(uuid1));
verify(im).removePlayer(any(), eq(uuid2));
verify(im).removePlayer(any(), eq(uuid3));
verify(pm).clearHomeLocations(any(), eq(uuid1));
verify(pm).clearHomeLocations(any(), eq(uuid2));
verify(pm).clearHomeLocations(any(), eq(uuid3));
verify(im, never()).removePlayer(any(), eq(uuid4));
}
}

View File

@ -15,11 +15,13 @@ import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.scheduler.BukkitScheduler;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
@ -51,6 +53,8 @@ public class AdminRangeResetCommandTest {
private User user;
private IslandsManager im;
private PlayersManager pm;
@Mock
private PluginManager pim;
/**
@ -113,6 +117,7 @@ public class AdminRangeResetCommandTest {
BukkitScheduler sch = mock(BukkitScheduler.class);
PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.getScheduler()).thenReturn(sch);
when(Bukkit.getPluginManager()).thenReturn(pim);
// Locales
LocalesManager lm = mock(LocalesManager.class);

View File

@ -15,11 +15,13 @@ import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.scheduler.BukkitScheduler;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
@ -51,6 +53,8 @@ public class AdminRangeSetCommandTest {
private User user;
private IslandsManager im;
private PlayersManager pm;
@Mock
private PluginManager pim;
/**
@ -115,6 +119,7 @@ public class AdminRangeSetCommandTest {
BukkitScheduler sch = mock(BukkitScheduler.class);
PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.getScheduler()).thenReturn(sch);
when(Bukkit.getPluginManager()).thenReturn(pim);
// Locales
LocalesManager lm = mock(LocalesManager.class);

View File

@ -170,7 +170,7 @@ public class IslandTeamInviteAcceptCommandTest {
*/
@Test
public void testSetup() {
assertEquals("bskyblock.island.team", c.getPermission());
//TODO: test permission inheritance?
assertTrue(c.isOnlyPlayer());
assertEquals("commands.island.team.invite.accept.description", c.getDescription());
}
@ -286,7 +286,6 @@ public class IslandTeamInviteAcceptCommandTest {
when(teb.build()).thenReturn(ibe);
when(TeamEvent.builder()).thenReturn(teb);
assertFalse(c.canExecute(user, "accept", Collections.emptyList()));
verify(pim).callEvent(any());
}
/**

View File

@ -6,7 +6,6 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import java.sql.Connection;
import java.sql.DriverManager;
@ -32,7 +31,7 @@ import world.bentobox.bentobox.database.DatabaseConnectionSettingsImpl;
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest( { Bukkit.class, DriverManager.class })
@PrepareForTest({ Bukkit.class, DriverManager.class })
public class MySQLDatabaseConnectorTest {
@Mock
@ -52,14 +51,6 @@ public class MySQLDatabaseConnectorTest {
when(dbSettings.getPort()).thenReturn(1234);
when(dbSettings.getUsername()).thenReturn("username");
when(dbSettings.getPassword()).thenReturn("password");
mockStatic(DriverManager.class);
when(DriverManager.getConnection(
"jdbc:mysql://localhost:1234/bentobox?autoReconnect=true&useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8",
"username",
"password"
)).thenReturn(connection);
// Logger
PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.getLogger()).thenReturn(logger);
@ -98,6 +89,7 @@ public class MySQLDatabaseConnectorTest {
* Test method for {@link world.bentobox.bentobox.database.sql.mysql.MySQLDatabaseConnector#createConnection()}.
* @throws SQLException
*/
@Ignore("Does not work in Java 11")
@Test
public void testCreateConnectionError() throws SQLException {
PowerMockito.doThrow(new SQLException("error")).when(DriverManager.class);

View File

@ -27,6 +27,7 @@ import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.PluginManager;
import org.bukkit.scheduler.BukkitScheduler;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.After;
@ -96,6 +97,8 @@ public class JoinLeaveListenerTest {
private @Nullable Island island;
@Mock
private GameModeAddon gameMode;
@Mock
private PluginManager pim;
/**
* @throws java.lang.Exception
@ -167,6 +170,8 @@ public class JoinLeaveListenerTest {
PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.getScheduler()).thenReturn(scheduler);
when(Bukkit.getPluginManager()).thenReturn(pim);
// Bukkit - online players
Map<UUID, String> online = new HashMap<>();
@ -292,8 +297,8 @@ public class JoinLeaveListenerTest {
jll.onPlayerJoin(event);
// Verify
verify(player, never()).sendMessage(eq("commands.admin.setrange.range-updated"));
// Verify island setting
verify(island).setProtectionRange(eq(50));
// Verify that the island protection range is not changed if it is already at that value
verify(island, never()).setProtectionRange(eq(50));
// Verify log
verify(plugin, never()).log("Island protection range changed from 50 to 10 for tastybento due to permission.");
}

View File

@ -3,9 +3,13 @@ package world.bentobox.bentobox.listeners;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.Optional;
import java.util.UUID;
@ -20,10 +24,12 @@ import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
@ -32,8 +38,13 @@ import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.Settings;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.Blueprint;
import world.bentobox.bentobox.blueprints.BlueprintPaster;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBundle;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.BlueprintsManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.LocalesManager;
@ -45,46 +56,53 @@ import world.bentobox.bentobox.util.Util;
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class, BentoBox.class, User.class, Util.class })
@PrepareForTest({Bukkit.class, BentoBox.class, User.class, Util.class, BlueprintPaster.class })
public class PortalTeleportationListenerTest {
@Mock
private BentoBox plugin;
@Mock
private IslandsManager im;
private PlayersManager pm;
@Mock
private IslandWorldManager iwm;
@Mock
private World world;
@Mock
private World nether;
@Mock
private World end;
@Mock
private Player p;
@Mock
private BlueprintsManager bpm;
@Mock
private GameModeAddon gameModeAddon;
@Before
public void setUp() throws Exception {
// Set up plugin
plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// island world mgr
iwm = mock(IslandWorldManager.class);
world = mock(World.class);
when(world.getEnvironment()).thenReturn(Environment.NORMAL);
nether = mock(World.class);
when(nether.getEnvironment()).thenReturn(Environment.NETHER);
end = mock(World.class);
when(end.getEnvironment()).thenReturn(Environment.THE_END);
Location endSpawn = mock(Location.class);
when(endSpawn.getWorld()).thenReturn(end);
when(end.getSpawnLocation()).thenReturn(endSpawn);
when(iwm.getEndWorld(Mockito.any())).thenReturn(end);
when(iwm.isEndGenerate(Mockito.any())).thenReturn(true);
when(iwm.getIslandWorld(Mockito.any())).thenReturn(world);
when(iwm.getNetherWorld(Mockito.any())).thenReturn(nether);
when(iwm.isNetherGenerate(Mockito.any())).thenReturn(true);
when(iwm.getEndWorld(any())).thenReturn(end);
when(iwm.isEndGenerate(any())).thenReturn(true);
when(iwm.getIslandWorld(any())).thenReturn(world);
when(iwm.getNetherWorld(any())).thenReturn(nether);
when(iwm.isNetherGenerate(any())).thenReturn(true);
when(iwm.inWorld(any(World.class))).thenReturn(true);
when(iwm.inWorld(any(Location.class))).thenReturn(true);
when(iwm.getNetherSpawnRadius(Mockito.any())).thenReturn(100);
when(iwm.getNetherSpawnRadius(any())).thenReturn(100);
when(plugin.getIWM()).thenReturn(iwm);
PowerMockito.mockStatic(Util.class);
when(Util.getWorld(Mockito.any())).thenReturn(world);
when(Util.getWorld(any())).thenReturn(world);
// Settings
Settings s = mock(Settings.class);
@ -97,7 +115,6 @@ public class PortalTeleportationListenerTest {
when(nether.getSpawnLocation()).thenReturn(netherSpawn);
// Player
Player p = mock(Player.class);
// Sometimes use Mockito.withSettings().verboseLogging()
User user = mock(User.class);
when(user.isOp()).thenReturn(false);
@ -112,12 +129,11 @@ public class PortalTeleportationListenerTest {
User.setPlugin(plugin);
// Player has island to begin with
im = mock(IslandsManager.class);
when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(true);
when(im.isOwner(Mockito.any(), Mockito.any())).thenReturn(true);
when(im.getOwner(Mockito.any(), Mockito.any())).thenReturn(uuid);
when(im.hasIsland(any(), any(UUID.class))).thenReturn(true);
when(im.isOwner(any(), any())).thenReturn(true);
when(im.getOwner(any(), any())).thenReturn(uuid);
Optional<Island> optionalIsland = Optional.empty();
when(im.getIslandAt(Mockito.any())).thenReturn(optionalIsland);
when(im.getIslandAt(any())).thenReturn(optionalIsland);
when(plugin.getIslands()).thenReturn(im);
when(plugin.getPlayers()).thenReturn(pm);
@ -129,14 +145,27 @@ public class PortalTeleportationListenerTest {
// Locales
LocalesManager lm = mock(LocalesManager.class);
when(lm.get(Mockito.any(), Mockito.any())).thenReturn("mock translation");
when(lm.get(any(), any())).thenReturn("mock translation");
when(plugin.getLocalesManager()).thenReturn(lm);
// Normally in world
Util.setPlugin(plugin);
// Addon
when(iwm.getAddon(Mockito.any())).thenReturn(Optional.empty());
Optional<GameModeAddon> opAddon = Optional.of(gameModeAddon);
when(iwm.getAddon(any())).thenReturn(opAddon);
// Blueprints
when(plugin.getBlueprintsManager()).thenReturn(bpm);
@Nullable
BlueprintBundle defaultBB = new BlueprintBundle();
Blueprint bp = new Blueprint();
bp.setName("blueprintname");
defaultBB.setBlueprint(World.Environment.NETHER, bp);
defaultBB.setBlueprint(World.Environment.THE_END, bp);
when(bpm.getDefaultBlueprintBundle(any())).thenReturn(defaultBB);
when(bpm.getBlueprints(any())).thenReturn(Collections.singletonMap("blueprintname", bp));
// Paster
}
@ -177,7 +206,7 @@ public class PortalTeleportationListenerTest {
when(from.getWorld()).thenReturn(world);
when(from.toVector()).thenReturn(new Vector(1,2,3));
// No end world
when(iwm.isEndGenerate(Mockito.any())).thenReturn(false);
when(iwm.isEndGenerate(any())).thenReturn(false);
PortalTeleportationListener np = new PortalTeleportationListener(plugin);
PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.END_PORTAL);
np.onEndIslandPortal(e);
@ -227,17 +256,17 @@ public class PortalTeleportationListenerTest {
// Player has no island
Player player = mock(Player.class);
when(player.getUniqueId()).thenReturn(UUID.randomUUID());
when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(false);
when(im.hasIsland(any(), any(UUID.class))).thenReturn(false);
// Right cause, end exists, right world
PlayerPortalEvent e = new PlayerPortalEvent(player, from, null, TeleportCause.END_PORTAL);
when(iwm.isEndGenerate(world)).thenReturn(true);
np.onEndIslandPortal(e);
assertFalse(e.isCancelled());
// Give player an island
when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(true);
when(im.hasIsland(any(), any(UUID.class))).thenReturn(true);
np.onEndIslandPortal(e);
assertTrue(e.isCancelled());
Mockito.verify(im).homeTeleport(Mockito.any(), Mockito.eq(player));
verify(im).homeTeleport(any(), eq(player));
}
/**
@ -245,7 +274,7 @@ public class PortalTeleportationListenerTest {
*/
@Test
public void testOnEndIslandPortalNonBentoBoxWorld() {
when(iwm.inWorld(Mockito.any(World.class))).thenReturn(false);
when(iwm.inWorld(any(World.class))).thenReturn(false);
PortalTeleportationListener np = new PortalTeleportationListener(plugin);
Location from = mock(Location.class);
// Teleport from nether to world
@ -254,7 +283,7 @@ public class PortalTeleportationListenerTest {
assertFalse(np.onEndIslandPortal(e));
// Verify
assertFalse(e.isCancelled());
Mockito.verify(iwm, Mockito.never()).isEndGenerate(Mockito.any());
verify(iwm, never()).isEndGenerate(any());
}
/**
@ -314,15 +343,72 @@ public class PortalTeleportationListenerTest {
when(from.toVector()).thenReturn(new Vector(1,2,3));
PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.NETHER_PORTAL);
// Nether islands active
when(iwm.isNetherIslands(Mockito.any())).thenReturn(true);
when(iwm.isNetherGenerate(Mockito.any())).thenReturn(true);
when(iwm.isNetherIslands(any())).thenReturn(true);
when(iwm.isNetherGenerate(any())).thenReturn(true);
assertTrue(np.onNetherPortal(e));
// Verify
assertTrue(e.isCancelled());
// If nether islands, then to = from but in nether
Mockito.verify(from).toVector();
verify(from).toVector();
// Do not go to spawn
Mockito.verify(nether, Mockito.never()).getSpawnLocation();
verify(nether, never()).getSpawnLocation();
}
/**
* Test method for {@link PortalTeleportationListener#onNetherPortal(org.bukkit.event.player.PlayerPortalEvent)}.
*/
@Test
public void testOnNetherPortalFromWorldToNetherIslandPasteBlueprintError() {
PortalTeleportationListener np = new PortalTeleportationListener(plugin);
Location from = mock(Location.class);
// Teleport from world to nether
when(from.getWorld()).thenReturn(world);
when(from.toVector()).thenReturn(new Vector(1,2,3));
PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.NETHER_PORTAL);
// Nether islands active
when(iwm.isNetherIslands(any())).thenReturn(true);
when(iwm.isNetherGenerate(any())).thenReturn(true);
// Paste
when(iwm.isPasteMissingIslands(any())).thenReturn(true);
Island isle = mock(Island.class);
when(isle.getWorld()).thenReturn(world);
when(isle.hasEndIsland()).thenReturn(false);
Optional<Island> island = Optional.of(isle );
when(im.getIslandAt(any())).thenReturn(island);
// No bp
when(bpm.getBlueprints(any())).thenReturn(Collections.emptyMap());
// Test
assertTrue(np.onNetherPortal(e));
// Error
verify(plugin).logError(eq("Could not paste default island in nether or end. Is there a nether-island or end-island blueprint?"));
}
/**
* Test method for {@link PortalTeleportationListener#onNetherPortal(org.bukkit.event.player.PlayerPortalEvent)}.
*/
@Test
public void testOnNetherPortalFromWorldToNetherIslandPasteBlueprint() {
PortalTeleportationListener np = new PortalTeleportationListener(plugin);
Location from = mock(Location.class);
// Teleport from world to nether
when(from.getWorld()).thenReturn(world);
when(from.toVector()).thenReturn(new Vector(1,2,3));
PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.NETHER_PORTAL);
// Nether islands active
when(iwm.isNetherIslands(any())).thenReturn(true);
when(iwm.isNetherGenerate(any())).thenReturn(true);
// Paste
when(iwm.isPasteMissingIslands(any())).thenReturn(true);
Island isle = mock(Island.class);
when(isle.getWorld()).thenReturn(world);
when(isle.getCenter()).thenReturn(from);
when(isle.hasEndIsland()).thenReturn(false);
Optional<Island> island = Optional.of(isle );
when(im.getIslandAt(any())).thenReturn(island);
// Test
assertTrue(np.onNetherPortal(e));
// Error
verify(plugin, never()).logError(eq("Could not paste default island in nether or end. Is there a nether-island or end-island blueprint?"));
}
/**
@ -337,24 +423,24 @@ public class PortalTeleportationListenerTest {
when(from.toVector()).thenReturn(new Vector(1,2,3));
PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.NETHER_PORTAL);
// Nether islands active
when(iwm.isNetherIslands(Mockito.any())).thenReturn(true);
when(iwm.isNetherGenerate(Mockito.any())).thenReturn(true);
when(iwm.isNetherIslands(any())).thenReturn(true);
when(iwm.isNetherGenerate(any())).thenReturn(true);
Island island = mock(Island.class);
Location spawnLoc = mock(Location.class);
when(island.getSpawnPoint(Mockito.any())).thenReturn(spawnLoc);
when(island.getSpawnPoint(any())).thenReturn(spawnLoc);
Optional<Island> optionalIsland = Optional.of(island);
// Island exists at location
when(im.getIslandAt(Mockito.any())).thenReturn(optionalIsland);
when(im.getIslandAt(any())).thenReturn(optionalIsland);
assertTrue(np.onNetherPortal(e));
// Verify
assertTrue(e.isCancelled());
// If nether islands, then to = from but in nether
Mockito.verify(from).toVector();
verify(from).toVector();
// Do not go to spawn
Mockito.verify(nether, Mockito.never()).getSpawnLocation();
verify(nether, never()).getSpawnLocation();
}
/**
@ -369,23 +455,23 @@ public class PortalTeleportationListenerTest {
when(from.toVector()).thenReturn(new Vector(1,2,3));
PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.NETHER_PORTAL);
// Nether islands active
when(iwm.isNetherIslands(Mockito.any())).thenReturn(true);
when(iwm.isNetherGenerate(Mockito.any())).thenReturn(true);
when(iwm.isNetherIslands(any())).thenReturn(true);
when(iwm.isNetherGenerate(any())).thenReturn(true);
Island island = mock(Island.class);
when(island.getSpawnPoint(Mockito.any())).thenReturn(null);
when(island.getSpawnPoint(any())).thenReturn(null);
Optional<Island> optionalIsland = Optional.of(island);
// Island exists at location
when(im.getIslandAt(Mockito.any())).thenReturn(optionalIsland);
when(im.getIslandAt(any())).thenReturn(optionalIsland);
assertTrue(np.onNetherPortal(e));
// Verify
assertTrue(e.isCancelled());
// If nether islands, then to = from but in nether
Mockito.verify(from).toVector();
verify(from).toVector();
// Do not go to spawn
Mockito.verify(nether, Mockito.never()).getSpawnLocation();
verify(nether, never()).getSpawnLocation();
}
/**
@ -400,8 +486,8 @@ public class PortalTeleportationListenerTest {
when(from.toVector()).thenReturn(new Vector(1,2,3));
PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.NETHER_PORTAL);
// Nether islands inactive
when(iwm.isNetherIslands(Mockito.any())).thenReturn(false);
when(iwm.isNetherGenerate(Mockito.any())).thenReturn(true);
when(iwm.isNetherIslands(any())).thenReturn(false);
when(iwm.isNetherGenerate(any())).thenReturn(true);
assertFalse(np.onNetherPortal(e));
// Verify
assertFalse(e.isCancelled());
@ -423,8 +509,8 @@ public class PortalTeleportationListenerTest {
PlayerPortalEvent e = new PlayerPortalEvent(p, from, null, TeleportCause.NETHER_PORTAL);
// Nether islands inactive
when(iwm.isNetherIslands(Mockito.any())).thenReturn(false);
when(iwm.isNetherGenerate(Mockito.any())).thenReturn(true);
when(iwm.isNetherIslands(any())).thenReturn(false);
when(iwm.isNetherGenerate(any())).thenReturn(true);
// Player should be teleported to their island
assertFalse(np.onNetherPortal(e));
@ -444,14 +530,14 @@ public class PortalTeleportationListenerTest {
when(from.toVector()).thenReturn(new Vector(1,2,3));
PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.NETHER_PORTAL);
// Nether islands active
when(iwm.isNetherIslands(Mockito.any())).thenReturn(true);
when(iwm.isNetherGenerate(Mockito.any())).thenReturn(true);
when(iwm.isNetherIslands(any())).thenReturn(true);
when(iwm.isNetherGenerate(any())).thenReturn(true);
assertTrue(np.onNetherPortal(e));
// Verify
assertTrue(e.isCancelled());
// If regular nether, then to = island location
Mockito.verify(from).toVector();
Mockito.verify(im, Mockito.never()).getIslandLocation(Mockito.any(), Mockito.any());
verify(from).toVector();
verify(im, never()).getIslandLocation(any(), any());
}
/**
@ -486,7 +572,7 @@ public class PortalTeleportationListenerTest {
*/
@Test
public void testOnNetherPortalNonBentoBoxWorld() {
when(iwm.inWorld(Mockito.any(World.class))).thenReturn(false);
when(iwm.inWorld(any(World.class))).thenReturn(false);
PortalTeleportationListener np = new PortalTeleportationListener(plugin);
Location from = mock(Location.class);
// Teleport from nether to world
@ -495,7 +581,7 @@ public class PortalTeleportationListenerTest {
assertFalse(np.onNetherPortal(e));
// Verify
assertFalse(e.isCancelled());
Mockito.verify(iwm, Mockito.never()).isNetherGenerate(Mockito.any());
verify(iwm, never()).isNetherGenerate(any());
}

View File

@ -41,7 +41,6 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.PluginManager;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;

View File

@ -35,6 +35,8 @@ import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import com.google.common.collect.ImmutableSet;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.Settings;
import world.bentobox.bentobox.api.configuration.WorldSettings;
@ -136,6 +138,7 @@ public class EnterExitListenerTest {
when(island.getCenter()).thenReturn(loc);
when(island.getProtectionRange()).thenReturn(PROTECTION_RANGE);
when(island.getOwner()).thenReturn(uuid);
when(island.getMemberSet()).thenReturn(ImmutableSet.of(uuid));
when(island.isOwned()).thenReturn(true);
when(im.getIsland(any(), any(UUID.class))).thenReturn(island);
@ -376,4 +379,5 @@ public class EnterExitListenerTest {
verify(pim).callEvent(any(IslandExitEvent.class));
}
// TODO add tests to make sure the enter/exit messages work properly when on an island the player is part of.
}

View File

@ -7,8 +7,10 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
@ -23,6 +25,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@ -43,6 +46,8 @@ import world.bentobox.bentobox.util.Util;
@PrepareForTest({BentoBox.class, Util.class, Bukkit.class })
public class OfflineRedstoneListenerTest {
private static final String[] NAMES = {"adam", "ben", "cara", "dave", "ed", "frank", "freddy", "george", "harry", "ian", "joe"};
@Mock
private World world;
@Mock
@ -100,6 +105,19 @@ public class OfflineRedstoneListenerTest {
when(iwm.getAddon(any())).thenReturn(Optional.empty());
PowerMockito.mockStatic(Bukkit.class);
// Online players
Set<Player> onlinePlayers = new HashSet<>();
for (int j = 0; j < NAMES.length; j++) {
Player p1 = mock(Player.class);
UUID u = UUID.randomUUID();
when(p1.getUniqueId()).thenReturn(u);
when(p1.getName()).thenReturn(NAMES[j]);
// All ops
when(p1.isOp()).thenReturn(true);
onlinePlayers.add(p1);
}
when(Bukkit.getOnlinePlayers()).then((Answer<Set<Player>>) invocation -> onlinePlayers);
}
@After
@ -150,7 +168,7 @@ public class OfflineRedstoneListenerTest {
OfflineRedstoneListener orl = new OfflineRedstoneListener();
// Offline redstone not allowed
Flags.OFFLINE_REDSTONE.setSetting(world, false);
// Members are online
// Members are offline
when(Bukkit.getPlayer(any(UUID.class))).thenReturn(null);
orl.onBlockRedstone(e);
@ -158,6 +176,44 @@ public class OfflineRedstoneListenerTest {
assertEquals(0, e.getNewCurrent());
}
/**
* Test method for {@link OfflineRedstoneListener#onBlockRedstone(BlockRedstoneEvent)}.
*/
@Test
public void testOnBlockRedstoneMembersOfflineOpsOnlineNotOnIsland() {
// Make an event to give some current to block
BlockRedstoneEvent e = new BlockRedstoneEvent(block, 0, 10);
OfflineRedstoneListener orl = new OfflineRedstoneListener();
// Offline redstone not allowed
Flags.OFFLINE_REDSTONE.setSetting(world, false);
// Members are offline
when(Bukkit.getPlayer(any(UUID.class))).thenReturn(null);
orl.onBlockRedstone(e);
// Current will be 0
assertEquals(0, e.getNewCurrent());
}
/**
* Test method for {@link OfflineRedstoneListener#onBlockRedstone(BlockRedstoneEvent)}.
*/
@Test
public void testOnBlockRedstoneMembersOfflineOpsOnlineOnIsland() {
// Make an event to give some current to block
BlockRedstoneEvent e = new BlockRedstoneEvent(block, 0, 10);
OfflineRedstoneListener orl = new OfflineRedstoneListener();
// Offline redstone not allowed
Flags.OFFLINE_REDSTONE.setSetting(world, false);
// Members are offline
when(Bukkit.getPlayer(any(UUID.class))).thenReturn(null);
// On island
when(island.onIsland(any())).thenReturn(true);
orl.onBlockRedstone(e);
// Current remains 10
assertEquals(10, e.getNewCurrent());
}
/**
* Test method for {@link OfflineRedstoneListener#onBlockRedstone(BlockRedstoneEvent)}.
*/

View File

@ -0,0 +1,216 @@
package world.bentobox.bentobox.managers.island;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Optional;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.IslandDeletionManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.island.DefaultNewIslandLocationStrategy.Result;
import world.bentobox.bentobox.util.Util;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest(Util.class)
public class DefaultNewIslandLocationStrategyTest {
private DefaultNewIslandLocationStrategy dnils;
@Mock
private BentoBox plugin;
@Mock
private Location location;
@Mock
private World world;
@Mock
private IslandWorldManager iwm;
@Mock
private IslandsManager im;
@Mock
private IslandDeletionManager idm;
@Mock
private Block block;
@Mock
private Block adjBlock;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// Location
when(location.getWorld()).thenReturn(world);
when(location.getX()).thenReturn(100D);
when(location.getZ()).thenReturn(-100D);
when(location.getBlock()).thenReturn(block);
// Block
when(block.getRelative(any())).thenReturn(adjBlock);
when(block.getType()).thenReturn(Material.AIR);
when(block.isEmpty()).thenReturn(true);
when(adjBlock.getType()).thenReturn(Material.AIR);
when(adjBlock.isEmpty()).thenReturn(true);
// Islands manager
when(plugin.getIslands()).thenReturn(im);
when(im.getIslandAt(any())).thenReturn(Optional.empty());
// IWM
when(plugin.getIWM()).thenReturn(iwm);
when(iwm.getIslandDistance(eq(world))).thenReturn(50);
when(iwm.getIslandHeight(eq(world))).thenReturn(120);
when(iwm.getIslandXOffset(eq(world))).thenReturn(0);
when(iwm.getIslandZOffset(eq(world))).thenReturn(0);
when(iwm.getIslandStartX(eq(world))).thenReturn(1000);
when(iwm.getIslandStartZ(eq(world))).thenReturn(11000);
// Island deletion manager
when(plugin.getIslandDeletionManager()).thenReturn(idm);
when(idm.inDeletion(any())).thenReturn(false);
// Util
PowerMockito.mockStatic(Util.class);
// Return back what the argument was, i.e., no change
when(Util.getClosestIsland(any())).thenAnswer((Answer<Location>) invocation -> invocation.getArgument(0, Location.class));
// Default is that chunks have been generated
when(Util.isChunkGenerated(any())).thenReturn(true);
// Last island location
when(im.getLast(eq(world))).thenReturn(location);
// Class under test
dnils = new DefaultNewIslandLocationStrategy();
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() {
Mockito.framework().clearInlineMocks();
}
/**
* Test method for {@link world.bentobox.bentobox.managers.island.DefaultNewIslandLocationStrategy#getNextLocation(org.bukkit.World)}.
*/
@Test
public void testGetNextLocationSuccess() {
assertEquals(location,dnils.getNextLocation(world));
verify(im).setLast(location);
}
/**
* Test method for {@link world.bentobox.bentobox.managers.island.DefaultNewIslandLocationStrategy#getNextLocation(org.bukkit.World)}.
*/
@Test
public void testGetNextLocationFailBlocks() {
when(adjBlock.getType()).thenReturn(Material.STONE);
when(adjBlock.isEmpty()).thenReturn(false);
assertNull(dnils.getNextLocation(world));
verify(plugin).logError("Could not find a free spot for islands! Is this world empty?");
verify(plugin).logError("Blocks around center locations: 20 max 20");
verify(plugin).logError("Known islands: 0 max unlimited.");
verify(im, never()).setLast(any());
}
/**
* Test method for {@link world.bentobox.bentobox.managers.island.DefaultNewIslandLocationStrategy#getNextLocation(org.bukkit.World)}.
*/
@SuppressWarnings("unchecked")
@Test
public void testGetNextLocationSuccessSomeIslands() {
Optional<Island> opIsland = Optional.of(new Island());
Optional<Island> emptyIsland = Optional.empty();
when(im.getIslandAt(any())).thenReturn(opIsland, opIsland, opIsland, opIsland, emptyIsland);
assertEquals(location,dnils.getNextLocation(world));
verify(im).setLast(location);
}
/**
* Test method for {@link world.bentobox.bentobox.managers.island.DefaultNewIslandLocationStrategy#isIsland(org.bukkit.Location)}.
*/
@Test
public void testIsIslandIslandFound() {
Optional<Island> opIsland = Optional.of(new Island());
when(im.getIslandAt(any())).thenReturn(opIsland);
assertEquals(Result.ISLAND_FOUND, dnils.isIsland(location));
}
/**
* Test method for {@link world.bentobox.bentobox.managers.island.DefaultNewIslandLocationStrategy#isIsland(org.bukkit.Location)}.
*/
@Test
public void testIsIslandIslandInDeletion() {
when(idm.inDeletion(any())).thenReturn(true);
assertEquals(Result.ISLAND_FOUND, dnils.isIsland(location));
}
/**
* Test method for {@link world.bentobox.bentobox.managers.island.DefaultNewIslandLocationStrategy#isIsland(org.bukkit.Location)}.
*/
@Test
public void testIsIslandChunkNotGenerated() {
when(Util.isChunkGenerated(any())).thenReturn(false);
assertEquals(Result.FREE, dnils.isIsland(location));
}
/**
* Test method for {@link world.bentobox.bentobox.managers.island.DefaultNewIslandLocationStrategy#isIsland(org.bukkit.Location)}.
*/
@Test
public void testIsIslandUseOwnGenerator() {
when(iwm.isUseOwnGenerator(eq(world))).thenReturn(true);
assertEquals(Result.FREE, dnils.isIsland(location));
}
/**
* Test method for {@link world.bentobox.bentobox.managers.island.DefaultNewIslandLocationStrategy#isIsland(org.bukkit.Location)}.
*/
@Test
public void testIsIslandFreeAirBlocks() {
assertEquals(Result.FREE, dnils.isIsland(location));
}
/**
* Test method for {@link world.bentobox.bentobox.managers.island.DefaultNewIslandLocationStrategy#isIsland(org.bukkit.Location)}.
*/
@Test
public void testIsIslandFreeWaterBlocks() {
when(adjBlock.getType()).thenReturn(Material.WATER);
when(adjBlock.isEmpty()).thenReturn(false);
assertEquals(Result.FREE, dnils.isIsland(location));
}
/**
* Test method for {@link world.bentobox.bentobox.managers.island.DefaultNewIslandLocationStrategy#isIsland(org.bukkit.Location)}.
*/
@Test
public void testIsIslandBlocksInArea() {
when(adjBlock.getType()).thenReturn(Material.STONE);
when(adjBlock.isEmpty()).thenReturn(false);
assertEquals(Result.BLOCKS_IN_AREA, dnils.isIsland(location));
}
}