mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2024-11-28 05:35:44 +01:00
Merge pull request #466 from BentoBoxWorld/IslandDelete
Island delete and async saving for YAML and MySQL
This commit is contained in:
commit
6557d2fad5
@ -25,6 +25,7 @@ import world.bentobox.bentobox.managers.AddonsManager;
|
||||
import world.bentobox.bentobox.managers.CommandsManager;
|
||||
import world.bentobox.bentobox.managers.FlagsManager;
|
||||
import world.bentobox.bentobox.managers.HooksManager;
|
||||
import world.bentobox.bentobox.managers.IslandDeletionManager;
|
||||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
import world.bentobox.bentobox.managers.IslandsManager;
|
||||
import world.bentobox.bentobox.managers.LocalesManager;
|
||||
@ -67,6 +68,8 @@ public class BentoBox extends JavaPlugin {
|
||||
|
||||
private boolean isLoaded;
|
||||
|
||||
private IslandDeletionManager islandDeletionManager;
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
if (!ServerCompatibility.getInstance().checkCompatibility(this).isCanLaunch()) {
|
||||
@ -142,10 +145,10 @@ public class BentoBox extends JavaPlugin {
|
||||
// Load islands from database - need to wait until all the worlds are loaded
|
||||
islandsManager.load();
|
||||
|
||||
// Save islands & players data asynchronously every X minutes
|
||||
// Save islands & players data every X minutes
|
||||
instance.getServer().getScheduler().runTaskTimer(instance, () -> {
|
||||
playersManager.save(true);
|
||||
islandsManager.save(true);
|
||||
playersManager.saveAll();
|
||||
islandsManager.saveAll();
|
||||
}, getSettings().getDatabaseBackupPeriod() * 20 * 60L, getSettings().getDatabaseBackupPeriod() * 20 * 60L);
|
||||
|
||||
// Make sure all flag listeners are registered.
|
||||
@ -169,13 +172,15 @@ public class BentoBox extends JavaPlugin {
|
||||
// Setup the Placeholders manager
|
||||
placeholdersManager = new PlaceholdersManager(this);
|
||||
|
||||
// Fire plugin ready event
|
||||
isLoaded = true;
|
||||
Bukkit.getServer().getPluginManager().callEvent(new BentoBoxReadyEvent());
|
||||
|
||||
// Show banner
|
||||
User.getInstance(Bukkit.getConsoleSender()).sendMessage("successfully-loaded",
|
||||
TextVariables.VERSION, instance.getDescription().getVersion(),
|
||||
"[time]", String.valueOf(System.currentTimeMillis() - startMillis));
|
||||
|
||||
// Fire plugin ready event - this should go last after everything else
|
||||
isLoaded = true;
|
||||
Bukkit.getServer().getPluginManager().callEvent(new BentoBoxReadyEvent());
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@ -196,6 +201,9 @@ public class BentoBox extends JavaPlugin {
|
||||
manager.registerEvents(new BannedVisitorCommands(this), this);
|
||||
// Death counter
|
||||
manager.registerEvents(new DeathListener(this), this);
|
||||
// Island Delete Manager
|
||||
islandDeletionManager = new IslandDeletionManager(this);
|
||||
manager.registerEvents(islandDeletionManager, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -356,4 +364,11 @@ public class BentoBox extends JavaPlugin {
|
||||
public PlaceholdersManager getPlaceholdersManager() {
|
||||
return placeholdersManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the islandDeletionManager
|
||||
*/
|
||||
public IslandDeletionManager getIslandDeletionManager() {
|
||||
return islandDeletionManager;
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +51,12 @@ public class AdminRegisterCommand extends ConfirmableCommand {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if this spot is still being deleted
|
||||
Location closestIsland = getClosestIsland(user.getLocation());
|
||||
if (getPlugin().getIslandDeletionManager().inDeletion(closestIsland)) {
|
||||
user.sendMessage("commands.admin.register.in-deletion");
|
||||
return false;
|
||||
}
|
||||
// Check if island is owned
|
||||
Optional<Island> island = getIslands().getIslandAt(user.getLocation());
|
||||
if (island.map(i -> i.getOwner() != null).orElse(false)) {
|
||||
@ -69,7 +75,7 @@ public class AdminRegisterCommand extends ConfirmableCommand {
|
||||
user.sendMessage("commands.admin.register.no-island-here");
|
||||
this.askConfirmation(user, () -> {
|
||||
// Make island here
|
||||
Island i = getIslands().createIsland(getClosestIsland(user.getLocation()), targetUUID);
|
||||
Island i = getIslands().createIsland(closestIsland, targetUUID);
|
||||
getIslands().setOwner(user, targetUUID, i);
|
||||
getWorld().getBlockAt(i.getCenter()).setType(Material.BEDROCK);
|
||||
user.sendMessage("commands.admin.register.registered-island", "[xyz]", Util.xyz(i.getCenter().toVector()));
|
||||
|
@ -1,12 +1,15 @@
|
||||
package world.bentobox.bentobox.api.commands.admin.range;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
public class AdminRangeResetCommand extends CompositeCommand {
|
||||
|
||||
@ -50,4 +53,15 @@ public class AdminRangeResetCommand extends CompositeCommand {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
|
||||
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
|
||||
if (args.isEmpty()) {
|
||||
// Don't show every player on the server. Require at least the first letter
|
||||
return Optional.empty();
|
||||
}
|
||||
List<String> options = new ArrayList<>(Util.getOnlinePlayerList(user));
|
||||
return Optional.of(Util.tabLimit(options, lastArg));
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package world.bentobox.bentobox.api.commands.admin.range;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
@ -9,6 +11,7 @@ import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
public class AdminRangeSetCommand extends CompositeCommand {
|
||||
|
||||
@ -72,4 +75,15 @@ public class AdminRangeSetCommand extends CompositeCommand {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
|
||||
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
|
||||
if (args.isEmpty()) {
|
||||
// Don't show every player on the server. Require at least the first letter
|
||||
return Optional.empty();
|
||||
}
|
||||
List<String> options = new ArrayList<>(Util.getOnlinePlayerList(user));
|
||||
return Optional.of(Util.tabLimit(options, lastArg));
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ public class IslandTeamInviteAcceptCommand extends CompositeCommand {
|
||||
if (inviter != null) {
|
||||
inviter.sendMessage("commands.island.team.invite.accept.name-joined-your-island", TextVariables.NAME, user.getName());
|
||||
}
|
||||
getIslands().save(false);
|
||||
getIslands().save(island);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ 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;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
public class IslandTeamSetownerCommand extends CompositeCommand {
|
||||
@ -59,9 +60,9 @@ public class IslandTeamSetownerCommand extends CompositeCommand {
|
||||
return false;
|
||||
}
|
||||
// Fire event so add-ons can run commands, etc.
|
||||
Island island = getIslands().getIsland(getWorld(), playerUUID);
|
||||
IslandBaseEvent event = TeamEvent.builder()
|
||||
.island(getIslands()
|
||||
.getIsland(getWorld(), playerUUID))
|
||||
.island(island)
|
||||
.reason(TeamEvent.Reason.SETOWNER)
|
||||
.involvedPlayer(targetUUID)
|
||||
.build();
|
||||
@ -70,7 +71,7 @@ public class IslandTeamSetownerCommand extends CompositeCommand {
|
||||
return false;
|
||||
}
|
||||
getIslands().setOwner(getWorld(), user, targetUUID);
|
||||
getIslands().save(true);
|
||||
getIslands().save(island);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ public class IslandBaseEvent extends PremadeEvent implements Cancellable {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the island involved in this event
|
||||
* @return the island involved in this event. This may be null in the case of deleted islands, so use location instead
|
||||
*/
|
||||
public Island getIsland(){
|
||||
return island;
|
||||
|
@ -6,6 +6,7 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import world.bentobox.bentobox.api.events.IslandBaseEvent;
|
||||
import world.bentobox.bentobox.database.objects.IslandDeletion;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.lists.Flags;
|
||||
|
||||
@ -58,9 +59,14 @@ public class IslandEvent extends IslandBaseEvent {
|
||||
*/
|
||||
CREATED,
|
||||
/**
|
||||
* Fired just before any island chunks are to be deleted.
|
||||
* Fired when an island is to be deleted. Note an island can be deleted without having
|
||||
* chunks removed.
|
||||
*/
|
||||
DELETE,
|
||||
/**
|
||||
* Fired when island chunks are going to be deleted
|
||||
*/
|
||||
DELETE_CHUNKS,
|
||||
/**
|
||||
* Fired after all island chunks have been deleted or set for regeneration by the server
|
||||
*/
|
||||
@ -168,14 +174,39 @@ public class IslandEvent extends IslandBaseEvent {
|
||||
super(island, player, admin, location);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Fired when an island chunks are going to be deleted.
|
||||
* May be cancelled.
|
||||
*
|
||||
*/
|
||||
public static class IslandDeleteChunksEvent extends IslandBaseEvent {
|
||||
private final IslandDeletion deletedIslandInfo;
|
||||
|
||||
private IslandDeleteChunksEvent(Island island, UUID player, boolean admin, Location location, IslandDeletion deletedIsland) {
|
||||
// Final variables have to be declared in the constructor
|
||||
super(island, player, admin, location);
|
||||
this.deletedIslandInfo = deletedIsland;
|
||||
}
|
||||
|
||||
public IslandDeletion getDeletedIslandInfo() {
|
||||
return deletedIslandInfo;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Fired when an island is deleted.
|
||||
*
|
||||
*/
|
||||
public static class IslandDeletedEvent extends IslandBaseEvent {
|
||||
private IslandDeletedEvent(Island island, UUID player, boolean admin, Location location) {
|
||||
private final IslandDeletion deletedIslandInfo;
|
||||
|
||||
private IslandDeletedEvent(Island island, UUID player, boolean admin, Location location, IslandDeletion deletedIsland) {
|
||||
// Final variables have to be declared in the constructor
|
||||
super(island, player, admin, location);
|
||||
this.deletedIslandInfo = deletedIsland;
|
||||
}
|
||||
|
||||
public IslandDeletion getDeletedIslandInfo() {
|
||||
return deletedIslandInfo;
|
||||
}
|
||||
}
|
||||
/**
|
||||
@ -256,6 +287,7 @@ public class IslandEvent extends IslandBaseEvent {
|
||||
private Reason reason = Reason.UNKNOWN;
|
||||
private boolean admin;
|
||||
private Location location;
|
||||
private IslandDeletion deletedIslandInfo;
|
||||
|
||||
public IslandEventBuilder island(Island island) {
|
||||
this.island = island;
|
||||
@ -295,6 +327,11 @@ public class IslandEvent extends IslandBaseEvent {
|
||||
return this;
|
||||
}
|
||||
|
||||
public IslandEventBuilder deletedIslandInfo(IslandDeletion deletedIslandInfo) {
|
||||
this.deletedIslandInfo = deletedIslandInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IslandBaseEvent build() {
|
||||
// Call the generic event for developers who just want one event and use the Reason enum
|
||||
Bukkit.getServer().getPluginManager().callEvent(new IslandEvent(island, player, admin, location, reason));
|
||||
@ -316,8 +353,12 @@ public class IslandEvent extends IslandBaseEvent {
|
||||
IslandDeleteEvent delete = new IslandDeleteEvent(island, player, admin, location);
|
||||
Bukkit.getServer().getPluginManager().callEvent(delete);
|
||||
return delete;
|
||||
case DELETE_CHUNKS:
|
||||
IslandDeleteChunksEvent deleteChunks = new IslandDeleteChunksEvent(island, player, admin, location, deletedIslandInfo);
|
||||
Bukkit.getServer().getPluginManager().callEvent(deleteChunks);
|
||||
return deleteChunks;
|
||||
case DELETED:
|
||||
IslandDeletedEvent deleted = new IslandDeletedEvent(island, player, admin, location);
|
||||
IslandDeletedEvent deleted = new IslandDeletedEvent(island, player, admin, location, deletedIslandInfo);
|
||||
Bukkit.getServer().getPluginManager().callEvent(deleted);
|
||||
return deleted;
|
||||
case ENTER:
|
||||
|
@ -4,6 +4,8 @@ import java.beans.IntrospectionException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.addons.Addon;
|
||||
|
||||
@ -38,12 +40,14 @@ public abstract class AbstractDatabaseHandler<T> {
|
||||
/**
|
||||
* The addon that is accessing the database, if any.
|
||||
*/
|
||||
@Nullable
|
||||
private Addon addon;
|
||||
|
||||
/**
|
||||
* Get the addon that is accessing the database, if any. May be null.
|
||||
* @return the addon
|
||||
*/
|
||||
@Nullable
|
||||
public Addon getAddon() {
|
||||
return addon;
|
||||
}
|
||||
@ -52,7 +56,7 @@ public abstract class AbstractDatabaseHandler<T> {
|
||||
* Set the addon that is accessing the database, if any.
|
||||
* @param addon the addon to set
|
||||
*/
|
||||
public void setAddon(Addon addon) {
|
||||
public void setAddon(@Nullable Addon addon) {
|
||||
this.addon = addon;
|
||||
}
|
||||
|
||||
@ -84,7 +88,8 @@ public abstract class AbstractDatabaseHandler<T> {
|
||||
* @param uniqueId - unique ID
|
||||
* @return <T>
|
||||
*/
|
||||
public abstract T loadObject(String uniqueId) throws InstantiationException, IllegalAccessException, InvocationTargetException, ClassNotFoundException, IntrospectionException, NoSuchMethodException;
|
||||
@Nullable
|
||||
public abstract T loadObject(@NonNull String uniqueId) throws InstantiationException, IllegalAccessException, InvocationTargetException, ClassNotFoundException, IntrospectionException, NoSuchMethodException;
|
||||
|
||||
/**
|
||||
* Save T into the corresponding database
|
||||
@ -110,4 +115,12 @@ public abstract class AbstractDatabaseHandler<T> {
|
||||
* Closes the database
|
||||
*/
|
||||
public abstract void close();
|
||||
|
||||
/**
|
||||
* Attempts to delete the object with the uniqueId
|
||||
* @param uniqueId - uniqueId of object
|
||||
* @return true if successful, false if there is no such uniqueId
|
||||
* @since 1.1
|
||||
*/
|
||||
public abstract boolean deleteID(String uniqueId);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.addons.Addon;
|
||||
|
||||
@ -44,6 +45,7 @@ public class Database<T> {
|
||||
* Load all the config objects and supply them as a list
|
||||
* @return list of config objects or an empty list if they cannot be loaded
|
||||
*/
|
||||
@NonNull
|
||||
public List<T> loadObjects() {
|
||||
List<T> result = new ArrayList<>();
|
||||
try {
|
||||
@ -100,6 +102,16 @@ public class Database<T> {
|
||||
return handler.objectExists(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to delete the object with the uniqueId
|
||||
* @param uniqueId - uniqueId of object
|
||||
* @return true if successful, false if there is no such uniqueId
|
||||
* @since 1.1
|
||||
*/
|
||||
public boolean deleteID(String uniqueId) {
|
||||
return handler.deleteID(uniqueId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete object from database
|
||||
* @param object - object to delete
|
||||
@ -109,7 +121,7 @@ public class Database<T> {
|
||||
handler.deleteObject(object);
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
|
||||
| IntrospectionException e) {
|
||||
logger.severe(() -> "Could not delete config! Error: " + e.getMessage());
|
||||
logger.severe(() -> "Could not delete object! Error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,4 +132,6 @@ public class Database<T> {
|
||||
handler.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -122,6 +122,28 @@ public class JSONDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteID(String uniqueId) {
|
||||
// The filename of the JSON file is the value of uniqueId field plus .json. Sometimes the .json is already appended.
|
||||
if (!uniqueId.endsWith(JSON)) {
|
||||
uniqueId = uniqueId + JSON;
|
||||
}
|
||||
// Get the database and table folders
|
||||
File dataFolder = new File(plugin.getDataFolder(), DATABASE_FOLDER_NAME);
|
||||
File tableFolder = new File(dataFolder, dataObject.getSimpleName());
|
||||
if (tableFolder.exists()) {
|
||||
// Obtain the file and delete it
|
||||
File file = new File(tableFolder, uniqueId);
|
||||
try {
|
||||
Files.delete(file.toPath());
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
plugin.logError("Could not delete json database object! " + file.getName() + " - " + e.getMessage());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteObject(T instance) throws IllegalAccessException, InvocationTargetException, IntrospectionException {
|
||||
// Null check
|
||||
@ -137,25 +159,7 @@ public class JSONDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
|
||||
// Obtain the value of uniqueId within the instance (which must be a DataObject)
|
||||
PropertyDescriptor propertyDescriptor = new PropertyDescriptor("uniqueId", dataObject);
|
||||
Method method = propertyDescriptor.getReadMethod();
|
||||
String fileName = (String) method.invoke(instance);
|
||||
|
||||
// The filename of the JSON file is the value of uniqueId field plus .json. Sometimes the .json is already appended.
|
||||
if (!fileName.endsWith(JSON)) {
|
||||
fileName = fileName + JSON;
|
||||
}
|
||||
|
||||
// Get the database and table folders
|
||||
File dataFolder = new File(plugin.getDataFolder(), DATABASE_FOLDER_NAME);
|
||||
File tableFolder = new File(dataFolder, dataObject.getSimpleName());
|
||||
if (tableFolder.exists()) {
|
||||
// Obtain the file and delete it
|
||||
File file = new File(tableFolder, fileName);
|
||||
try {
|
||||
Files.delete(file.toPath());
|
||||
} catch (IOException e) {
|
||||
plugin.logError("Could not delete json database object! " + file.getName() + " - " + e.getMessage());
|
||||
}
|
||||
}
|
||||
deleteID((String) method.invoke(instance));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -106,6 +106,16 @@ public class MongoDBDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteID(String uniqueId) {
|
||||
try {
|
||||
return collection.findOneAndDelete(new Document(MONGO_ID, uniqueId)) == null ? false : true;
|
||||
} catch (Exception e) {
|
||||
plugin.logError("Could not delete object " + dataObject.getCanonicalName() + " " + uniqueId + " " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteObject(T instance) {
|
||||
// Null check
|
||||
@ -117,11 +127,7 @@ public class MongoDBDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
|
||||
plugin.logError("This class is not a DataObject: " + instance.getClass().getName());
|
||||
return;
|
||||
}
|
||||
try {
|
||||
collection.findOneAndDelete(new Document(MONGO_ID, ((DataObject)instance).getUniqueId()));
|
||||
} catch (Exception e) {
|
||||
plugin.logError("Could not delete object " + instance.getClass().getName() + " " + e.getMessage());
|
||||
}
|
||||
deleteID(((DataObject)instance).getUniqueId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -9,6 +9,8 @@ import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
@ -128,11 +130,18 @@ public class MySQLDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
|
||||
"`" +
|
||||
dataObject.getCanonicalName() +
|
||||
"` (json) VALUES (?) ON DUPLICATE KEY UPDATE json = ?";
|
||||
// Replace into is used so that any data in the table will be replaced with updated data
|
||||
// The table name is the canonical name, so that add-ons can be sure of a unique table in the database
|
||||
|
||||
Gson gson = getGson();
|
||||
String toStore = gson.toJson(instance);
|
||||
if (plugin.isEnabled()) {
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> store(instance, toStore, sb));
|
||||
} else {
|
||||
store(instance, toStore, sb);
|
||||
}
|
||||
}
|
||||
|
||||
private void store(T instance, String toStore, String sb) {
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(sb)) {
|
||||
Gson gson = getGson();
|
||||
String toStore = gson.toJson(instance);
|
||||
preparedStatement.setString(1, toStore);
|
||||
preparedStatement.setString(2, toStore);
|
||||
preparedStatement.execute();
|
||||
@ -141,6 +150,22 @@ public class MySQLDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteID(String uniqueId) {
|
||||
String sb = "DELETE FROM `" +
|
||||
dataObject.getCanonicalName() +
|
||||
"` WHERE uniqueId = ?";
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(sb)) {
|
||||
// UniqueId needs to be placed in quotes
|
||||
preparedStatement.setString(1, "\"" + uniqueId + "\"");
|
||||
preparedStatement.execute();
|
||||
return preparedStatement.getUpdateCount() > 0;
|
||||
} catch (Exception e) {
|
||||
plugin.logError("Could not delete object " + dataObject.getCanonicalName() + " " + uniqueId + " " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteObject(T instance) {
|
||||
// Null check
|
||||
@ -152,15 +177,9 @@ public class MySQLDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
|
||||
plugin.logError("This class is not a DataObject: " + instance.getClass().getName());
|
||||
return;
|
||||
}
|
||||
String sb = "DELETE FROM `" +
|
||||
dataObject.getCanonicalName() +
|
||||
"` WHERE uniqueId = ?";
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(sb)) {
|
||||
try {
|
||||
Method getUniqueId = dataObject.getMethod("getUniqueId");
|
||||
String uniqueId = (String) getUniqueId.invoke(instance);
|
||||
// UniqueId needs to be placed in quotes
|
||||
preparedStatement.setString(1, "\"" + uniqueId + "\"");
|
||||
preparedStatement.execute();
|
||||
deleteID((String) getUniqueId.invoke(instance));
|
||||
} catch (Exception e) {
|
||||
plugin.logError("Could not delete object " + instance.getClass().getName() + " " + e.getMessage());
|
||||
}
|
||||
|
@ -26,11 +26,11 @@ import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.configuration.WorldSettings;
|
||||
import world.bentobox.bentobox.api.flags.Flag;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
import world.bentobox.bentobox.api.logs.LogEntry;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.objects.adapters.Adapter;
|
||||
import world.bentobox.bentobox.database.objects.adapters.FlagSerializer;
|
||||
import world.bentobox.bentobox.database.objects.adapters.LogEntryListAdapter;
|
||||
import world.bentobox.bentobox.api.logs.LogEntry;
|
||||
import world.bentobox.bentobox.lists.Flags;
|
||||
import world.bentobox.bentobox.managers.RanksManager;
|
||||
import world.bentobox.bentobox.util.Pair;
|
||||
@ -62,6 +62,10 @@ public class Island implements DataObject {
|
||||
@Expose
|
||||
private int protectionRange;
|
||||
|
||||
// Maximum ever protection range - used in island deletion
|
||||
@Expose
|
||||
private int maxEverProtectionRange;
|
||||
|
||||
// World the island started in. This may be different from the island location
|
||||
@Expose
|
||||
private World world;
|
||||
@ -115,6 +119,7 @@ public class Island implements DataObject {
|
||||
center = new Location(location.getWorld(), location.getX(), location.getY(), location.getZ());
|
||||
range = BentoBox.getInstance().getIWM().getIslandDistance(world);
|
||||
this.protectionRange = protectionRange;
|
||||
this.maxEverProtectionRange = protectionRange;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -283,6 +288,20 @@ public class Island implements DataObject {
|
||||
return protectionRange;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the maxEverProtectionRange or the protection range, whichever is larger
|
||||
*/
|
||||
public int getMaxEverProtectionRange() {
|
||||
return Math.max(protectionRange, maxEverProtectionRange);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param maxEverProtectionRange the maxEverProtectionRange to set
|
||||
*/
|
||||
public void setMaxEverProtectionRange(int maxEverProtectionRange) {
|
||||
this.maxEverProtectionRange = maxEverProtectionRange;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the island is protected from the Purge, otherwise false
|
||||
*/
|
||||
@ -532,6 +551,10 @@ public class Island implements DataObject {
|
||||
*/
|
||||
public void setProtectionRange(int protectionRange) {
|
||||
this.protectionRange = protectionRange;
|
||||
// Ratchet up the maximum protection range
|
||||
if (protectionRange > this.maxEverProtectionRange) {
|
||||
this.maxEverProtectionRange = protectionRange;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -659,14 +682,14 @@ public class Island implements DataObject {
|
||||
// Fixes #getLastPlayed() returning 0 when it is the owner's first connection.
|
||||
long lastPlayed = (plugin.getServer().getOfflinePlayer(owner).getLastPlayed() != 0) ?
|
||||
plugin.getServer().getOfflinePlayer(owner).getLastPlayed() : plugin.getServer().getOfflinePlayer(owner).getFirstPlayed();
|
||||
user.sendMessage("commands.admin.info.last-login","[date]", new Date(lastPlayed).toString());
|
||||
user.sendMessage("commands.admin.info.last-login","[date]", new Date(lastPlayed).toString());
|
||||
|
||||
user.sendMessage("commands.admin.info.deaths", "[number]", String.valueOf(plugin.getPlayers().getDeaths(world, owner)));
|
||||
String resets = String.valueOf(plugin.getPlayers().getResets(world, owner));
|
||||
String total = plugin.getIWM().getResetLimit(world) < 0 ? "Unlimited" : String.valueOf(plugin.getIWM().getResetLimit(world));
|
||||
user.sendMessage("commands.admin.info.resets-left", "[number]", resets, "[total]", total);
|
||||
// Show team members
|
||||
showMembers(user);
|
||||
user.sendMessage("commands.admin.info.deaths", "[number]", String.valueOf(plugin.getPlayers().getDeaths(world, owner)));
|
||||
String resets = String.valueOf(plugin.getPlayers().getResets(world, owner));
|
||||
String total = plugin.getIWM().getResetLimit(world) < 0 ? "Unlimited" : String.valueOf(plugin.getIWM().getResetLimit(world));
|
||||
user.sendMessage("commands.admin.info.resets-left", "[number]", resets, "[total]", total);
|
||||
// Show team members
|
||||
showMembers(user);
|
||||
}
|
||||
Vector location = center.toVector();
|
||||
user.sendMessage("commands.admin.info.island-location", "[xyz]", Util.xyz(location));
|
||||
@ -674,6 +697,7 @@ public class Island implements DataObject {
|
||||
Vector to = center.toVector().add(new Vector(range-1, 0, range-1)).setY(center.getWorld().getMaxHeight());
|
||||
user.sendMessage("commands.admin.info.island-coords", "[xz1]", Util.xyz(from), "[xz2]", Util.xyz(to));
|
||||
user.sendMessage("commands.admin.info.protection-range", "[range]", String.valueOf(protectionRange));
|
||||
user.sendMessage("commands.admin.info.max-protection-range", "[range]", String.valueOf(maxEverProtectionRange));
|
||||
Vector pfrom = center.toVector().subtract(new Vector(protectionRange, 0, protectionRange)).setY(0);
|
||||
Vector pto = center.toVector().add(new Vector(protectionRange-1, 0, protectionRange-1)).setY(center.getWorld().getMaxHeight());
|
||||
user.sendMessage("commands.admin.info.protection-coords", "[xz1]", Util.xyz(pfrom), "[xz2]", Util.xyz(pto));
|
||||
|
@ -0,0 +1,178 @@
|
||||
package world.bentobox.bentobox.database.objects;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
/**
|
||||
* Data object to store islands in deletion
|
||||
* @author tastybento
|
||||
* @since 1.1
|
||||
*/
|
||||
public class IslandDeletion implements DataObject {
|
||||
|
||||
@Expose
|
||||
private String uniqueId = "";
|
||||
|
||||
@Expose
|
||||
private Location location;
|
||||
|
||||
@Expose
|
||||
private int minXChunk;
|
||||
|
||||
@Expose
|
||||
private int maxXChunk;
|
||||
|
||||
@Expose
|
||||
private int minZChunk;
|
||||
|
||||
@Expose
|
||||
private int maxZChunk;
|
||||
|
||||
public IslandDeletion() {}
|
||||
|
||||
public IslandDeletion(Island island) {
|
||||
uniqueId = UUID.randomUUID().toString();
|
||||
location = island.getCenter();
|
||||
minXChunk = (location.getBlockX() - island.getMaxEverProtectionRange()) >> 4;
|
||||
maxXChunk = (island.getMaxEverProtectionRange() + location.getBlockX() - 1) >> 4;
|
||||
minZChunk = (location.getBlockZ() - island.getMaxEverProtectionRange()) >> 4;
|
||||
maxZChunk = (island.getMaxEverProtectionRange() + location.getBlockZ() - 1) >> 4;
|
||||
}
|
||||
|
||||
public IslandDeletion(Location location, int minXChunk, int maxXChunk, int minZChunk, int maxZChunk) {
|
||||
this.uniqueId = UUID.randomUUID().toString();
|
||||
this.location = location;
|
||||
this.minXChunk = minXChunk;
|
||||
this.maxXChunk = maxXChunk;
|
||||
this.minZChunk = minZChunk;
|
||||
this.maxZChunk = maxZChunk;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof IslandDeletion)) {
|
||||
return false;
|
||||
}
|
||||
IslandDeletion other = (IslandDeletion) obj;
|
||||
if (uniqueId == null) {
|
||||
if (other.uniqueId != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!uniqueId.equals(other.uniqueId)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the location
|
||||
*/
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the maxXChunk
|
||||
*/
|
||||
public int getMaxXChunk() {
|
||||
return maxXChunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the maxZChunk
|
||||
*/
|
||||
public int getMaxZChunk() {
|
||||
return maxZChunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the minXChunk
|
||||
*/
|
||||
public int getMinXChunk() {
|
||||
return minXChunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the minZChunk
|
||||
*/
|
||||
public int getMinZChunk() {
|
||||
return minZChunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueId() {
|
||||
return uniqueId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the world
|
||||
*/
|
||||
public World getWorld() {
|
||||
return location.getWorld();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((uniqueId == null) ? 0 : uniqueId.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param location the location to set
|
||||
*/
|
||||
public void setLocation(Location location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param maxXChunk the maxXChunk to set
|
||||
*/
|
||||
public void setMaxXChunk(int maxXChunk) {
|
||||
this.maxXChunk = maxXChunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param maxZChunk the maxZChunk to set
|
||||
*/
|
||||
public void setMaxZChunk(int maxZChunk) {
|
||||
this.maxZChunk = maxZChunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param minXChunk the minXChunk to set
|
||||
*/
|
||||
public void setMinXChunk(int minXChunk) {
|
||||
this.minXChunk = minXChunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param minZChunk the minZChunk to set
|
||||
*/
|
||||
public void setMinZChunk(int minZChunk) {
|
||||
this.minZChunk = minZChunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUniqueId(String uniqueId) {
|
||||
this.uniqueId = uniqueId;
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,9 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.sql.Connection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -18,6 +19,8 @@ import java.util.UUID;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.database.DatabaseConnector;
|
||||
|
||||
@ -78,29 +81,21 @@ public class YamlDatabaseConnector implements DatabaseConnector {
|
||||
return config;
|
||||
}
|
||||
|
||||
public void saveYamlFile(YamlConfiguration yamlConfig, String tableName, String fileName, Map<String, String> commentMap) {
|
||||
if (!fileName.endsWith(YML)) {
|
||||
fileName = fileName + YML;
|
||||
}
|
||||
public void saveYamlFile(String data, String tableName, String fileName, Map<String, String> commentMap) {
|
||||
String name = fileName.endsWith(YML) ? fileName : fileName + YML;
|
||||
File tableFolder = new File(plugin.getDataFolder(), tableName);
|
||||
File file = new File(tableFolder, fileName);
|
||||
File file = new File(tableFolder, name);
|
||||
if (!tableFolder.exists()) {
|
||||
tableFolder.mkdirs();
|
||||
}
|
||||
try {
|
||||
File tmpFile = new File(tableFolder, fileName + ".bak");
|
||||
if (file.exists()) {
|
||||
// Make a backup of file
|
||||
Files.copy(file.toPath(), tmpFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
yamlConfig.save(file.toPath().toString());
|
||||
Files.deleteIfExists(tmpFile.toPath());
|
||||
} catch (Exception e) {
|
||||
try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8)) {
|
||||
writer.write(data);
|
||||
} catch (IOException e) {
|
||||
plugin.logError("Could not save yml file: " + tableName + " " + fileName + " " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
if (commentMap != null && !commentMap.isEmpty()) {
|
||||
commentFile(new File(tableFolder, fileName), commentMap);
|
||||
commentFile(new File(tableFolder, name), commentMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.MemorySection;
|
||||
@ -307,18 +308,14 @@ public class YamlDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
// This is the Yaml Configuration that will be used and saved at the end
|
||||
YamlConfiguration config = new YamlConfiguration();
|
||||
|
||||
// The file name of the Yaml file.
|
||||
String filename = "";
|
||||
String path = DATABASE_FOLDER_NAME + File.separator + dataObject.getSimpleName();
|
||||
// Comments for the file
|
||||
Map<String, String> yamlComments = new HashMap<>();
|
||||
|
||||
// Only allow storing in an arbitrary place if it is a config object. Otherwise it is in the database
|
||||
StoreAt storeAt = instance.getClass().getAnnotation(StoreAt.class);
|
||||
if (storeAt != null) {
|
||||
path = storeAt.path();
|
||||
filename = storeAt.filename();
|
||||
}
|
||||
String path = storeAt == null ? DATABASE_FOLDER_NAME + File.separator + dataObject.getSimpleName() : storeAt.path();
|
||||
String filename = storeAt == null ? "" : storeAt.filename();
|
||||
|
||||
// See if there are any top-level comments
|
||||
// See if there are multiple comments
|
||||
ConfigComment.Line comments = instance.getClass().getAnnotation(ConfigComment.Line.class);
|
||||
@ -443,7 +440,16 @@ public class YamlDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
throw new IllegalArgumentException("No uniqueId in class");
|
||||
}
|
||||
|
||||
((YamlDatabaseConnector)databaseConnector).saveYamlFile(config, path, filename, yamlComments);
|
||||
// Save
|
||||
String name = filename;
|
||||
String data = config.saveToString();
|
||||
if (plugin.isEnabled()) {
|
||||
// Async
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> ((YamlDatabaseConnector)databaseConnector).saveYamlFile(data, path, name, yamlComments));
|
||||
} else {
|
||||
// Sync for shutdown
|
||||
((YamlDatabaseConnector)databaseConnector).saveYamlFile(data, path, name, yamlComments);
|
||||
}
|
||||
}
|
||||
|
||||
private void setComment(ConfigComment comment, YamlConfiguration config, Map<String, String> yamlComments, String parent) {
|
||||
@ -553,6 +559,28 @@ public class YamlDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteID(String uniqueId) {
|
||||
// The filename of the YAML file is the value of uniqueId field plus .yml. Sometimes the .yml is already appended.
|
||||
if (!uniqueId.endsWith(YML)) {
|
||||
uniqueId = uniqueId + YML;
|
||||
}
|
||||
// Get the database and table folders
|
||||
File dataFolder = new File(plugin.getDataFolder(), DATABASE_FOLDER_NAME);
|
||||
File tableFolder = new File(dataFolder, dataObject.getSimpleName());
|
||||
if (tableFolder.exists()) {
|
||||
// Obtain the file and delete it
|
||||
File file = new File(tableFolder, uniqueId);
|
||||
try {
|
||||
Files.delete(file.toPath());
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
plugin.logError("Could not delete yml database object! " + file.getName() + " - " + e.getMessage());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see world.bentobox.bentobox.database.AbstractDatabaseHandler#deleteObject(java.lang.Object)
|
||||
*/
|
||||
@ -571,23 +599,8 @@ public class YamlDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
// Obtain the value of uniqueId within the instance (which must be a DataObject)
|
||||
PropertyDescriptor propertyDescriptor = new PropertyDescriptor("uniqueId", dataObject);
|
||||
Method method = propertyDescriptor.getReadMethod();
|
||||
String fileName = (String) method.invoke(instance);
|
||||
// The filename of the YAML file is the value of uniqueId field plus .yml. Sometimes the .yml is already appended.
|
||||
if (!fileName.endsWith(YML)) {
|
||||
fileName = fileName + YML;
|
||||
}
|
||||
// Get the database and table folders
|
||||
File dataFolder = new File(plugin.getDataFolder(), DATABASE_FOLDER_NAME);
|
||||
File tableFolder = new File(dataFolder, dataObject.getSimpleName());
|
||||
if (tableFolder.exists()) {
|
||||
// Obtain the file and delete it
|
||||
File file = new File(tableFolder, fileName);
|
||||
try {
|
||||
Files.delete(file.toPath());
|
||||
} catch (IOException e) {
|
||||
plugin.logError("Could not delete yml database object! " + file.getName() + " - " + e.getMessage());
|
||||
}
|
||||
}
|
||||
deleteID((String) method.invoke(instance));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,83 @@
|
||||
package world.bentobox.bentobox.managers;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.events.BentoBoxReadyEvent;
|
||||
import world.bentobox.bentobox.api.events.island.IslandEvent.IslandDeleteChunksEvent;
|
||||
import world.bentobox.bentobox.api.events.island.IslandEvent.IslandDeletedEvent;
|
||||
import world.bentobox.bentobox.database.Database;
|
||||
import world.bentobox.bentobox.database.objects.IslandDeletion;
|
||||
import world.bentobox.bentobox.util.DeleteIslandChunks;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
/**
|
||||
* Listens for island deletions and adds them to the database. Removes them when the island is deleted.
|
||||
* @author tastybento
|
||||
* @since 1.1
|
||||
*/
|
||||
public class IslandDeletionManager implements Listener {
|
||||
|
||||
private BentoBox plugin;
|
||||
/**
|
||||
* Queue of islands to delete
|
||||
*/
|
||||
private Database<IslandDeletion> handler;
|
||||
private Set<Location> inDeletion;
|
||||
|
||||
public IslandDeletionManager(BentoBox plugin) {
|
||||
this.plugin = plugin;
|
||||
handler = new Database<>(plugin, IslandDeletion.class);
|
||||
inDeletion = new HashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* When BentoBox is fully loaded, load the islands that still need to be deleted and kick them off
|
||||
* @param e
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onBentoBoxReady(BentoBoxReadyEvent e) {
|
||||
// Load list of islands that were mid deletion and delete them
|
||||
List<IslandDeletion> toBeDeleted = handler.loadObjects();
|
||||
if (toBeDeleted != null && toBeDeleted.size() > 0) {
|
||||
plugin.log("There are " + toBeDeleted.size() + " islands pending deletion.");
|
||||
toBeDeleted.forEach(di -> {
|
||||
plugin.log("Resuming deletion of island at " + di.getLocation().getWorld().getName() + " " + Util.xyz(di.getLocation().toVector()));
|
||||
inDeletion.add(di.getLocation());
|
||||
new DeleteIslandChunks(plugin, di);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onIslandDelete(IslandDeleteChunksEvent e) {
|
||||
// Store location
|
||||
inDeletion.add(e.getDeletedIslandInfo().getLocation());
|
||||
// Save to database
|
||||
handler.saveObject(e.getDeletedIslandInfo());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onIslandDeleted(IslandDeletedEvent e) {
|
||||
// Delete
|
||||
inDeletion.remove(e.getDeletedIslandInfo().getLocation());
|
||||
// Delete from database
|
||||
handler.deleteID(e.getDeletedIslandInfo().getUniqueId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an island location is in deletion
|
||||
* @param location - center of location
|
||||
* @return true if island is in the process of being deleted
|
||||
*/
|
||||
public boolean inDeletion(Location location) {
|
||||
return inDeletion.contains(location);
|
||||
}
|
||||
}
|
@ -24,9 +24,13 @@ import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.events.IslandBaseEvent;
|
||||
import world.bentobox.bentobox.api.events.island.IslandEvent;
|
||||
import world.bentobox.bentobox.api.events.island.IslandEvent.Reason;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.Database;
|
||||
import world.bentobox.bentobox.database.objects.IslandDeletion;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.lists.Flags;
|
||||
import world.bentobox.bentobox.managers.island.IslandCache;
|
||||
@ -60,9 +64,6 @@ public class IslandsManager {
|
||||
// Island Cache
|
||||
private IslandCache islandCache;
|
||||
|
||||
// Async database saving semaphore
|
||||
private boolean midSave;
|
||||
|
||||
/**
|
||||
* Islands Manager
|
||||
* @param plugin - plugin
|
||||
@ -244,6 +245,11 @@ public class IslandsManager {
|
||||
if (island == null) {
|
||||
return;
|
||||
}
|
||||
// Fire event
|
||||
IslandBaseEvent event = IslandEvent.builder().island(island).reason(Reason.DELETE).build();
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
// Set the owner of the island to no one.
|
||||
island.setOwner(null);
|
||||
island.setFlag(Flags.LOCK, RanksManager.VISITOR_RANK);
|
||||
@ -255,7 +261,7 @@ public class IslandsManager {
|
||||
// Remove players from island
|
||||
removePlayersFromIsland(island);
|
||||
// Remove blocks from world
|
||||
new DeleteIslandChunks(plugin, island);
|
||||
new DeleteIslandChunks(plugin, new IslandDeletion(island));
|
||||
}
|
||||
}
|
||||
|
||||
@ -685,8 +691,7 @@ public class IslandsManager {
|
||||
* @param user - user
|
||||
*/
|
||||
public void removePlayer(World world, User user) {
|
||||
islandCache.removePlayer(world, user.getUniqueId());
|
||||
save(true);
|
||||
removePlayer(world, user.getUniqueId());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -695,8 +700,10 @@ public class IslandsManager {
|
||||
* @param uuid - user's uuid
|
||||
*/
|
||||
public void removePlayer(World world, UUID uuid) {
|
||||
islandCache.removePlayer(world, uuid);
|
||||
save(true);
|
||||
Island island = islandCache.removePlayer(world, uuid);
|
||||
if (island != null) {
|
||||
handler.saveObject(island);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -727,36 +734,18 @@ public class IslandsManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the islands to the database
|
||||
* @param async - if true, saving will be done async
|
||||
* Save the all the islands to the database
|
||||
*/
|
||||
public void save(boolean async){
|
||||
if (midSave) {
|
||||
// If it's already saving, then do nothing
|
||||
return;
|
||||
}
|
||||
public void saveAll(){
|
||||
Collection<Island> collection = islandCache.getIslands();
|
||||
if(async) {
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||
midSave = true;
|
||||
for(Island island : collection){
|
||||
try {
|
||||
handler.saveObject(island);
|
||||
} catch (Exception e) {
|
||||
plugin.logError("Could not save island to database when running async! " + e.getMessage());
|
||||
}
|
||||
}
|
||||
midSave = false;
|
||||
});
|
||||
} else {
|
||||
for(Island island : collection){
|
||||
try {
|
||||
handler.saveObject(island);
|
||||
} catch (Exception e) {
|
||||
plugin.logError("Could not save island to database when running sync! " + e.getMessage());
|
||||
}
|
||||
for(Island island : collection){
|
||||
try {
|
||||
handler.saveObject(island);
|
||||
} catch (Exception e) {
|
||||
plugin.logError("Could not save island to database when running sync! " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -768,8 +757,8 @@ public class IslandsManager {
|
||||
// Add player to new island
|
||||
teamIsland.addMember(playerUUID);
|
||||
islandCache.addPlayer(playerUUID, teamIsland);
|
||||
// Save the database
|
||||
save(false);
|
||||
// Save the island
|
||||
handler.saveObject(teamIsland);
|
||||
}
|
||||
|
||||
public void setLast(Location last) {
|
||||
@ -789,7 +778,7 @@ public class IslandsManager {
|
||||
public void shutdown(){
|
||||
// Remove all coop associations
|
||||
islandCache.getIslands().stream().forEach(i -> i.getMembers().values().removeIf(p -> p == RanksManager.COOP_RANK));
|
||||
save(false);
|
||||
saveAll();
|
||||
islandCache.clear();
|
||||
handler.close();
|
||||
}
|
||||
@ -867,4 +856,13 @@ public class IslandsManager {
|
||||
islandCache.getIslands().stream().forEach(i -> i.getMembers().entrySet().removeIf(e -> e.getKey().equals(uniqueId) && e.getValue() == rank));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the island to the database
|
||||
* @param island - island
|
||||
*/
|
||||
public void save(Island island) {
|
||||
handler.saveObject(island);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package world.bentobox.bentobox.managers;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@ -8,7 +7,6 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
|
||||
@ -63,20 +61,13 @@ public class PlayersManager {
|
||||
|
||||
/**
|
||||
* Save all players
|
||||
* @param async - if true, save async
|
||||
*/
|
||||
public void save(boolean async){
|
||||
Collection<Players> set = Collections.unmodifiableCollection(playerCache.values());
|
||||
if(async) {
|
||||
Runnable save = () -> set.forEach(handler::saveObject);
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, save);
|
||||
} else {
|
||||
set.forEach(handler::saveObject);
|
||||
}
|
||||
public void saveAll(){
|
||||
Collections.unmodifiableCollection(playerCache.values()).forEach(handler::saveObject);
|
||||
}
|
||||
|
||||
public void shutdown(){
|
||||
save(false);
|
||||
saveAll();
|
||||
playerCache.clear();
|
||||
handler.close();
|
||||
}
|
||||
|
@ -169,8 +169,9 @@ public class IslandCache {
|
||||
* The island is removed from the islandsByUUID map, but kept in the location map.
|
||||
* @param world - world
|
||||
* @param uuid - player's UUID
|
||||
* @return island player had or null if none
|
||||
*/
|
||||
public void removePlayer(World world, UUID uuid) {
|
||||
public Island removePlayer(World world, UUID uuid) {
|
||||
world = Util.getWorld(world);
|
||||
islandsByUUID.putIfAbsent(world, new HashMap<>());
|
||||
Island island = islandsByUUID.get(world).get(uuid);
|
||||
@ -185,6 +186,7 @@ public class IslandCache {
|
||||
}
|
||||
}
|
||||
islandsByUUID.get(world).remove(uuid);
|
||||
return island;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -244,7 +244,7 @@ public class NewIsland {
|
||||
*/
|
||||
private Result isIsland(Location location){
|
||||
location = Util.getClosestIsland(location);
|
||||
if (plugin.getIslands().getIslandAt(location).isPresent()) {
|
||||
if (plugin.getIslands().getIslandAt(location).isPresent() || plugin.getIslandDeletionManager().inDeletion(location)) {
|
||||
return Result.ISLAND_FOUND;
|
||||
}
|
||||
|
||||
|
@ -353,8 +353,8 @@ public class Clipboard {
|
||||
|
||||
/**
|
||||
* Sets any entity that is in this location
|
||||
* @param location - locaton
|
||||
* @param config - config section
|
||||
* @param location - location
|
||||
* @param en - config section
|
||||
*/
|
||||
private void setEntity(Location location, ConfigurationSection en) {
|
||||
en.getKeys(false).forEach(k -> {
|
||||
|
@ -1,12 +1,12 @@
|
||||
package world.bentobox.bentobox.util;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.events.IslandBaseEvent;
|
||||
import world.bentobox.bentobox.api.events.island.IslandEvent;
|
||||
import world.bentobox.bentobox.api.events.island.IslandEvent.Reason;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.database.objects.IslandDeletion;
|
||||
|
||||
/**
|
||||
* Deletes islands fast using chunk regeneration
|
||||
@ -17,40 +17,41 @@ import world.bentobox.bentobox.database.objects.Island;
|
||||
public class DeleteIslandChunks {
|
||||
|
||||
/**
|
||||
* Deletes the island
|
||||
* @param plugin - plugin object
|
||||
* @param island - island to delete
|
||||
* This is how many chunks per world will be done in one tick.
|
||||
*/
|
||||
private final static int SPEED = 5;
|
||||
private int x;
|
||||
private int z;
|
||||
private BukkitTask task;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public DeleteIslandChunks(final BentoBox plugin, final Island island) {
|
||||
public DeleteIslandChunks(BentoBox plugin, IslandDeletion di) {
|
||||
// Fire event
|
||||
IslandBaseEvent event = IslandEvent.builder().island(island).reason(Reason.DELETE).build();
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
final World world = island.getCenter().getWorld();
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
int minXChunk = island.getMinX() >> 4;
|
||||
int maxXChunk = (island.getRange() * 2 + island.getMinX() - 1) >> 4;
|
||||
int minZChunk = island.getMinZ() >> 4;
|
||||
int maxZChunk = (island.getRange() * 2 + island.getMinZ() - 1) >> 4;
|
||||
for (int x = minXChunk; x <= maxXChunk; x++) {
|
||||
for (int z = minZChunk; z<=maxZChunk; z++) {
|
||||
world.regenerateChunk(x, z);
|
||||
//System.out.println("regenerating = " + x + "," + z);
|
||||
if (plugin.getIWM().isNetherGenerate(world) && plugin.getIWM().isNetherIslands(world)) {
|
||||
plugin.getIWM().getNetherWorld(world).regenerateChunk(x, z);
|
||||
IslandEvent.builder().deletedIslandInfo(di).reason(Reason.DELETE_CHUNKS).build();
|
||||
x = di.getMinXChunk();
|
||||
z = di.getMinZChunk();
|
||||
task = Bukkit.getScheduler().runTaskTimer(plugin, () -> {
|
||||
for (int i = 0; i < SPEED; i++) {
|
||||
di.getWorld().regenerateChunk(x, z);
|
||||
if (plugin.getIWM().isNetherGenerate(di.getWorld()) && plugin.getIWM().isNetherIslands(di.getWorld())) {
|
||||
plugin.getIWM().getNetherWorld(di.getWorld()).regenerateChunk(x, z);
|
||||
|
||||
}
|
||||
if (plugin.getIWM().isEndGenerate(world) && plugin.getIWM().isEndIslands(world)) {
|
||||
plugin.getIWM().getEndWorld(world).regenerateChunk(x, z);
|
||||
if (plugin.getIWM().isEndGenerate(di.getWorld()) && plugin.getIWM().isEndIslands(di.getWorld())) {
|
||||
plugin.getIWM().getEndWorld(di.getWorld()).regenerateChunk(x, z);
|
||||
}
|
||||
z++;
|
||||
if (z > di.getMaxZChunk()) {
|
||||
z = di.getMinZChunk();
|
||||
x++;
|
||||
if (x > di.getMaxXChunk()) {
|
||||
task.cancel();
|
||||
// Fire event
|
||||
IslandEvent.builder().deletedIslandInfo(di).reason(Reason.DELETED).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fire event
|
||||
IslandEvent.builder().island(island).reason(Reason.DELETED).build();
|
||||
}, 0L, 1L);
|
||||
|
||||
}
|
||||
|
||||
|
@ -109,6 +109,7 @@ commands:
|
||||
registered-island: "&aRegistered player to island at [xyz]."
|
||||
already-owned: "&cIsland is already owned by another player!"
|
||||
no-island-here: "&cThere is no island here. Confirm to make one."
|
||||
in-deletion: "&cThis island space is currently being deleted. Try later."
|
||||
unregister:
|
||||
parameters: "<owner>"
|
||||
description: "unregister owner from island, but keep island blocks"
|
||||
@ -128,6 +129,7 @@ commands:
|
||||
island-location: "Island location: [xyz]"
|
||||
island-coords: "Island coordinates: [xz1] to [xz2]"
|
||||
protection-range: "Protection range: [range]"
|
||||
max-protection-range: "Largest historical protection range: [range]"
|
||||
protection-coords: "Protection coordinates: [xz1] to [xz2]"
|
||||
is-spawn: "Island is a spawn island"
|
||||
banned-players: "Banned players:"
|
||||
|
@ -30,6 +30,7 @@ import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.managers.CommandsManager;
|
||||
import world.bentobox.bentobox.managers.IslandDeletionManager;
|
||||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
import world.bentobox.bentobox.managers.IslandsManager;
|
||||
import world.bentobox.bentobox.managers.LocalesManager;
|
||||
@ -50,6 +51,7 @@ public class AdminRegisterCommandTest {
|
||||
private IslandsManager im;
|
||||
private PlayersManager pm;
|
||||
private UUID notUUID;
|
||||
private IslandDeletionManager idm;
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
@ -111,11 +113,16 @@ public class AdminRegisterCommandTest {
|
||||
LocalesManager lm = mock(LocalesManager.class);
|
||||
when(lm.get(Mockito.any(), Mockito.any())).thenReturn("mock translation");
|
||||
when(plugin.getLocalesManager()).thenReturn(lm);
|
||||
|
||||
// Deletion Manager
|
||||
idm = mock(IslandDeletionManager.class);
|
||||
when(idm.inDeletion(Mockito.any())).thenReturn(false);
|
||||
when(plugin.getIslandDeletionManager()).thenReturn(idm);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test method for .
|
||||
* Test method for {@link AdminRegisterCommand#execute(org.bukkit.command.CommandSender, String, String[])}.
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteNoTarget() {
|
||||
@ -125,7 +132,7 @@ public class AdminRegisterCommandTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for .
|
||||
* Test method for {@link AdminRegisterCommand#execute(org.bukkit.command.CommandSender, String, String[])}.
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteUnknownPlayer() {
|
||||
@ -137,7 +144,7 @@ public class AdminRegisterCommandTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for .
|
||||
* Test method for {@link AdminRegisterCommand#execute(org.bukkit.command.CommandSender, String, String[])}.
|
||||
*/
|
||||
@Test
|
||||
public void testExecutePlayerHasIsland() {
|
||||
@ -151,7 +158,7 @@ public class AdminRegisterCommandTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for .
|
||||
* Test method for {@link AdminRegisterCommand#execute(org.bukkit.command.CommandSender, String, String[])}.
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteInTeam() {
|
||||
@ -165,7 +172,7 @@ public class AdminRegisterCommandTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for .
|
||||
* Test method for {@link AdminRegisterCommand#execute(org.bukkit.command.CommandSender, String, String[])}.
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteAlreadyOwnedIsland() {
|
||||
@ -186,6 +193,32 @@ public class AdminRegisterCommandTest {
|
||||
Mockito.verify(user).sendMessage("commands.admin.register.already-owned");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link AdminRegisterCommand#execute(org.bukkit.command.CommandSender, String, String[])}.
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteInDeletionIsland() {
|
||||
when(idm.inDeletion(Mockito.any())).thenReturn(true);
|
||||
when(im.inTeam(Mockito.any(), Mockito.any())).thenReturn(false);
|
||||
when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(false);
|
||||
String[] name = {"tastybento"};
|
||||
when(pm.getUUID(Mockito.any())).thenReturn(notUUID);
|
||||
Location loc = mock(Location.class);
|
||||
|
||||
// Island has owner
|
||||
Island is = mock(Island.class);
|
||||
when(is.getOwner()).thenReturn(uuid);
|
||||
Optional<Island> opi = Optional.of(is);
|
||||
when(im.getIslandAt(Mockito.any())).thenReturn(opi);
|
||||
when(user.getLocation()).thenReturn(loc);
|
||||
AdminRegisterCommand itl = new AdminRegisterCommand(ac);
|
||||
assertFalse(itl.execute(user, itl.getLabel(), Arrays.asList(name)));
|
||||
Mockito.verify(user).sendMessage("commands.admin.register.in-deletion");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link AdminRegisterCommand#execute(org.bukkit.command.CommandSender, String, String[])}.
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteSuccess() {
|
||||
when(im.inTeam(Mockito.any(), Mockito.any())).thenReturn(false);
|
||||
|
@ -23,6 +23,7 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
@ -37,6 +38,7 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Slime;
|
||||
import org.bukkit.entity.Wither;
|
||||
import org.bukkit.entity.Zombie;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -54,6 +56,7 @@ import com.google.common.collect.ImmutableSet.Builder;
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.Settings;
|
||||
import world.bentobox.bentobox.api.configuration.WorldSettings;
|
||||
import world.bentobox.bentobox.api.events.island.IslandEvent.IslandDeleteEvent;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.lists.Flags;
|
||||
@ -79,6 +82,7 @@ public class IslandsManagerTest {
|
||||
private IslandCache islandCache;
|
||||
private Optional<Island> optionalIsland;
|
||||
private Island is;
|
||||
private PluginManager pim;
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
@ -122,8 +126,7 @@ public class IslandsManagerTest {
|
||||
pm = mock(PlayersManager.class);
|
||||
when(plugin.getPlayers()).thenReturn(pm);
|
||||
|
||||
// Server & Scheduler
|
||||
|
||||
// Scheduler
|
||||
BukkitScheduler sch = mock(BukkitScheduler.class);
|
||||
PowerMockito.mockStatic(Bukkit.class);
|
||||
when(Bukkit.getScheduler()).thenReturn(sch);
|
||||
@ -174,6 +177,11 @@ public class IslandsManagerTest {
|
||||
// User location
|
||||
when(user.getLocation()).thenReturn(location);
|
||||
|
||||
// Server for events
|
||||
Server server = mock(Server.class);
|
||||
when(Bukkit.getServer()).thenReturn(server);
|
||||
pim = mock(PluginManager.class);
|
||||
when(server.getPluginManager()).thenReturn(pim);
|
||||
}
|
||||
|
||||
|
||||
@ -432,16 +440,37 @@ public class IslandsManagerTest {
|
||||
* Test method for {@link world.bentobox.bentobox.managers.IslandsManager#deleteIsland(world.bentobox.bentobox.database.objects.Island, boolean)}.
|
||||
*/
|
||||
@Test
|
||||
public void testDeleteIslandIslandBoolean() {
|
||||
public void testDeleteIslandIslandBooleanNull() {
|
||||
IslandsManager im = new IslandsManager(plugin);
|
||||
|
||||
im.deleteIsland((Island)null, true);
|
||||
Mockito.verify(pim, Mockito.never()).callEvent(Mockito.any());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.managers.IslandsManager#deleteIsland(world.bentobox.bentobox.database.objects.Island, boolean)}.
|
||||
*/
|
||||
@Test
|
||||
public void testDeleteIslandIslandBooleanNoBlockRemoval() {
|
||||
IslandsManager im = new IslandsManager(plugin);
|
||||
UUID owner = UUID.randomUUID();
|
||||
Island island = im.createIsland(location, owner);
|
||||
im.deleteIsland(island, false);
|
||||
island = im.createIsland(location, owner);
|
||||
assertNull(island.getOwner());
|
||||
Mockito.verify(pim, Mockito.times(2)).callEvent(Mockito.any(IslandDeleteEvent.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.managers.IslandsManager#deleteIsland(world.bentobox.bentobox.database.objects.Island, boolean)}.
|
||||
*/
|
||||
@Test
|
||||
public void testDeleteIslandIslandBooleanRemoveBlocks() {
|
||||
Mockito.verify(pim, Mockito.never()).callEvent(Mockito.any());
|
||||
IslandsManager im = new IslandsManager(plugin);
|
||||
UUID owner = UUID.randomUUID();
|
||||
Island island = im.createIsland(location, owner);
|
||||
im.deleteIsland(island, true);
|
||||
assertNull(island);
|
||||
assertNull(island.getOwner());
|
||||
Mockito.verify(pim, Mockito.times(4)).callEvent(Mockito.any(IslandDeleteEvent.class));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -175,13 +175,12 @@ public class PlayersManagerTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.managers.PlayersManager#save(boolean)}.
|
||||
* Test method for {@link world.bentobox.bentobox.managers.PlayersManager#saveAll()}.
|
||||
*/
|
||||
@Test
|
||||
public void testSaveBoolean() {
|
||||
PlayersManager pm = new PlayersManager(plugin);
|
||||
pm.save(false);
|
||||
pm.save(true);
|
||||
pm.saveAll();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,152 +0,0 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package world.bentobox.bentobox.util;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mockito;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
|
||||
/**
|
||||
* Tests the island delete class
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({Bukkit.class})
|
||||
public class DeleteIslandChunksTest {
|
||||
|
||||
private BentoBox plugin;
|
||||
private Island island;
|
||||
private Location location;
|
||||
private World world;
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
PowerMockito.mockStatic(Bukkit.class);
|
||||
Server server = mock(Server.class);
|
||||
PluginManager pim = mock(PluginManager.class);
|
||||
when(server.getPluginManager()).thenReturn(pim);
|
||||
when(Bukkit.getServer()).thenReturn(server);
|
||||
plugin = mock(BentoBox.class);
|
||||
IslandWorldManager iwm = mock(IslandWorldManager.class);
|
||||
// No Nether or End by default
|
||||
when(iwm.isNetherGenerate(Mockito.any())).thenReturn(false);
|
||||
when(iwm.isNetherIslands(Mockito.any())).thenReturn(false);
|
||||
when(iwm.isEndGenerate(Mockito.any())).thenReturn(false);
|
||||
when(iwm.isEndIslands(Mockito.any())).thenReturn(false);
|
||||
|
||||
when(plugin.getIWM()).thenReturn(iwm);
|
||||
// World
|
||||
//world = mock(World.class, Mockito.withSettings().verboseLogging());
|
||||
world = mock(World.class);
|
||||
|
||||
island = new Island();
|
||||
island.setRange(64);
|
||||
|
||||
location = mock(Location.class);
|
||||
|
||||
when(location.getWorld()).thenReturn(world);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.util.DeleteIslandChunks#DeleteIslandChunks(world.bentobox.bentobox.BentoBox, world.bentobox.bentobox.database.objects.Island)}.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testDeleteIslandChunksNegativeX() {
|
||||
|
||||
// Island adjacent to an island at 0,0
|
||||
Location location2 = mock(Location.class);
|
||||
|
||||
when(location2.getWorld()).thenReturn(world);
|
||||
when(location2.getBlockX()).thenReturn(-128);
|
||||
when(location2.getBlockY()).thenReturn(120);
|
||||
when(location2.getBlockZ()).thenReturn(0);
|
||||
island.setCenter(location2);
|
||||
|
||||
new DeleteIslandChunks(plugin, island);
|
||||
Mockito.verify(world, Mockito.times(64)).regenerateChunk(Mockito.anyInt(), Mockito.anyInt());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.util.DeleteIslandChunks#DeleteIslandChunks(world.bentobox.bentobox.BentoBox, world.bentobox.bentobox.database.objects.Island)}.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testDeleteIslandChunksNegativeXX() {
|
||||
|
||||
// Island adjacent to an island at 0,0
|
||||
Location location2 = mock(Location.class);
|
||||
|
||||
when(location2.getWorld()).thenReturn(world);
|
||||
when(location2.getBlockX()).thenReturn(-256);
|
||||
when(location2.getBlockY()).thenReturn(120);
|
||||
when(location2.getBlockZ()).thenReturn(0);
|
||||
island.setCenter(location2);
|
||||
|
||||
new DeleteIslandChunks(plugin, island);
|
||||
Mockito.verify(world, Mockito.times(64)).regenerateChunk(Mockito.anyInt(), Mockito.anyInt());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.util.DeleteIslandChunks#DeleteIslandChunks(world.bentobox.bentobox.BentoBox, world.bentobox.bentobox.database.objects.Island)}.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testDeleteIslandChunksIslandPositiveX() {
|
||||
|
||||
// Island adjacent to an island at 0,0
|
||||
Location location2 = mock(Location.class);
|
||||
|
||||
when(location2.getWorld()).thenReturn(world);
|
||||
when(location2.getBlockX()).thenReturn(0);
|
||||
when(location2.getBlockY()).thenReturn(120);
|
||||
when(location2.getBlockZ()).thenReturn(0);
|
||||
island.setCenter(location2);
|
||||
|
||||
new DeleteIslandChunks(plugin, island);
|
||||
Mockito.verify(world, Mockito.times(64)).regenerateChunk(Mockito.anyInt(), Mockito.anyInt());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.util.DeleteIslandChunks#DeleteIslandChunks(world.bentobox.bentobox.BentoBox, world.bentobox.bentobox.database.objects.Island)}.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testDeleteIslandChunksPositiveXX() {
|
||||
|
||||
// Island adjacent to an island at 0,0
|
||||
Location location2 = mock(Location.class);
|
||||
|
||||
when(location2.getWorld()).thenReturn(world);
|
||||
when(location2.getBlockX()).thenReturn(256);
|
||||
when(location2.getBlockY()).thenReturn(120);
|
||||
when(location2.getBlockZ()).thenReturn(0);
|
||||
island.setCenter(location2);
|
||||
|
||||
new DeleteIslandChunks(plugin, island);
|
||||
Mockito.verify(world, Mockito.times(64)).regenerateChunk(Mockito.anyInt(), Mockito.anyInt());
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user