Implemeted Blueprint bundles and blueprints (#672)

* A prototype for Blueprint bundles and blueprints

This stores blueprints inside bundles. Each bundle can have up to 3
blueprints defines by the World.Environment.

This is not a finished manager. It just handles all the saving and
loading side of things. I thought this would help you so you can then
concentrate on the UI.

* WIP: Copy blocks to Blueprint done.

* WIP Pasting done.

* WIP: Added BlueprintsManager to ultimately replace SchemsManager.

* Moved blueprint suffix and changed to .blu

* Fixed unit test.

* Now tested and working.

Integrated with new island and resetting island.

If there are no blueprint bundles or blueprints then a default bedrock
set will be made and put in the game mode addon's blueprints folder.

Still to do: enable schems to be loaded and pasted for legacy support.
Add blueprints and a bundle to GameModeAddons like BSkyBlock.

* Renamed most of the classes

* Cleaned up clipboard and paster.

* Further cleanup on blueprint clipboard and paster.

* Merged blueprint classes into one package.

* Put Blueprint data objects in their own package.

Isolated schems classes for later removal.

* Renamed admin command classes and changed locale files.

* More clean up to remove schems

* Schem to blueprints converter done.

Converts schems to blueprint bundles and sets up a default set. Tested
the happy-path. Need to do more testing on edge cases.

* Added basic UI for development. Fixed bug with schem conversion.

* Adds permissions into the blueprints.

Fixes tests, cleans up some naming

* Added IslandCreationPanel and created BlueprintManagementPanel

* Fixed JSONDatabaseHandler's constructor being public

* Made the Blueprints button in ManagementPanel open the Blueprint management panel

* Fixed tests and ignored one (NPE)
This commit is contained in:
tastybento 2019-05-15 11:16:41 -07:00 committed by Florian CUNY
parent d19caa82ca
commit 700043fe40
55 changed files with 2643 additions and 1774 deletions

View File

@ -1,5 +1,7 @@
package world.bentobox.bentobox;
import java.util.Optional;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.bukkit.Bukkit;
import org.bukkit.generator.ChunkGenerator;
@ -7,6 +9,7 @@ import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.configuration.Config;
import world.bentobox.bentobox.api.events.BentoBoxReadyEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
@ -37,13 +40,10 @@ import world.bentobox.bentobox.managers.LocalesManager;
import world.bentobox.bentobox.managers.PlaceholdersManager;
import world.bentobox.bentobox.managers.PlayersManager;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.bentobox.managers.SchemsManager;
import world.bentobox.bentobox.managers.WebManager;
import world.bentobox.bentobox.util.heads.HeadGetter;
import world.bentobox.bentobox.versions.ServerCompatibility;
import java.util.Optional;
/**
* Main BentoBox class
* @author tastybento, Poslovitch
@ -62,7 +62,6 @@ public class BentoBox extends JavaPlugin {
private FlagsManager flagsManager;
private IslandWorldManager islandWorldManager;
private RanksManager ranksManager;
private SchemsManager schemsManager;
private BlueprintsManager blueprintsManager;
private HooksManager hooksManager;
private PlaceholdersManager placeholdersManager;
@ -135,8 +134,8 @@ public class BentoBox extends JavaPlugin {
// Start Island Worlds Manager
islandWorldManager = new IslandWorldManager(this);
// Load schems manager
schemsManager = new SchemsManager(this);
// Load blueprints manager
blueprintsManager = new BlueprintsManager(this);
// Locales manager must be loaded before addons
@ -385,13 +384,6 @@ public class BentoBox extends JavaPlugin {
getLogger().warning(() -> warning);
}
/**
* @return the schemsManager
*/
public SchemsManager getSchemsManager() {
return schemsManager;
}
/**
* Returns the instance of the {@link BlueprintsManager}.
* @return the {@link BlueprintsManager}.

View File

@ -143,7 +143,7 @@ public class Settings implements ConfigObject {
@ConfigEntry(path = "island.name.max-length")
private int nameMaxLength = 20;
@ConfigComment("Number of blocks to paste per tick when pasting a schem")
@ConfigComment("Number of blocks to paste per tick when pasting blueprints")
@ConfigComment("Smaller values will help reduce noticeable lag but will make pasting take longer")
@ConfigEntry(path = "island.paste-speed")
private int pasteSpeed = 1000;

View File

@ -14,7 +14,7 @@ import world.bentobox.bentobox.util.Util;
/**
* Defines the addon as a game mode.
* A game mode creates worlds, registers world settings and has schems in a jar folder.
* A game mode creates worlds, registers world settings and has blueprints in a jar folder.
* @author tastybento, Poslovitch
*/
public abstract class GameModeAddon extends Addon {

View File

@ -1,80 +0,0 @@
package world.bentobox.bentobox.api.blueprints;
import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;
import org.bukkit.Material;
import org.bukkit.World;
import org.eclipse.jdt.annotation.NonNull;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.zip.ZipFile;
/**
* @since 1.5.0
* @author Poslovitch
*/
public class Blueprint {
public static final @NonNull String FILE_EXTENSION = "blueprint";
private @NonNull String name;
private String displayName;
private @NonNull Material icon = Material.PAPER;
private List<String> description; //TODO
private World.Environment environment;
public Blueprint(@NonNull String name, @NonNull ZipFile zip) throws IOException {
this.name = name;
try (JsonReader reader = new Gson().newJsonReader(new InputStreamReader(zip.getInputStream(zip.getEntry("properties.json"))))) {
readProperties(reader);
}
//System.out.println(new Gson().toJson(this));
}
private void readProperties(@NonNull JsonReader reader) throws IOException {
reader.beginObject();
while (reader.hasNext()) {
String field = reader.nextName();
switch (field) {
case "displayName":
displayName = reader.nextString();
break;
case "icon":
icon = Material.valueOf(reader.nextString());
break;
case "environment":
environment = World.Environment.valueOf(reader.nextString());
break;
default:
reader.skipValue();
break;
}
}
reader.endObject();
}
@NonNull
public String getName() {
return name;
}
public String getDisplayName() {
return displayName;
}
@NonNull
public Material getIcon() {
return icon;
}
public List<String> getDescription() {
return description;
}
public World.Environment getEnvironment() {
return environment;
}
}

View File

@ -1,21 +0,0 @@
package world.bentobox.bentobox.api.blueprints;
import org.bukkit.Material;
import java.util.List;
/**
* Represents a bundle of three {@link Blueprint}s.
* This is what the player will choose when creating his island.
* @since 1.5.0
* @author Poslovitch
*/
public class BlueprintBundle {
private Material icon;
private String displayName;
private List<String> description;
private Blueprint overworldBlueprint;
private Blueprint netherBlueprint;
private Blueprint endBlueprint;
}

View File

@ -1,4 +1,13 @@
package world.bentobox.bentobox.api.commands.admin.schem;
package world.bentobox.bentobox.api.commands.admin.blueprints;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.Particle;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.BlueprintClipboard;
import world.bentobox.bentobox.managers.BlueprintsManager;
import java.io.File;
import java.util.HashMap;
@ -6,47 +15,37 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.Particle;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.Clipboard;
import world.bentobox.bentobox.managers.SchemsManager;
public class AdminSchemCommand extends ConfirmableCommand {
public class AdminBlueprintCommand extends ConfirmableCommand {
// Clipboards
private Map<UUID, Clipboard> clipboards;
private Map<UUID, BlueprintClipboard> clipboards;
// Map containing selection cuboid display tasks
private Map<User, Integer> displayClipboards;
private static final Particle PARTICLE = Particle.REDSTONE;
private static final Particle.DustOptions PARTICLE_DUST_OPTIONS = new Particle.DustOptions(Color.RED, 1.0F);
public AdminSchemCommand(CompositeCommand parent) {
super(parent, "schem");
public AdminBlueprintCommand(CompositeCommand parent) {
super(parent, "bp", "blueprint");
}
@Override
public void setup() {
setPermission("admin.schem");
setParametersHelp("commands.admin.schem.parameters");
setDescription("commands.admin.schem.description");
setPermission("admin.blueprint");
setParametersHelp("commands.admin.blueprint.parameters");
setDescription("commands.admin.blueprint.description");
setOnlyPlayer(true);
clipboards = new HashMap<>();
displayClipboards = new HashMap<>();
new AdminSchemLoadCommand(this);
new AdminSchemPasteCommand(this);
new AdminSchemOriginCommand(this);
new AdminSchemCopyCommand(this);
new AdminSchemSaveCommand(this);
new AdminSchemPos1Command(this);
new AdminSchemPos2Command(this);
new AdminSchemListCommand(this);
new AdminBlueprintLoadCommand(this);
new AdminBlueprintPasteCommand(this);
new AdminBlueprintOriginCommand(this);
new AdminBlueprintCopyCommand(this);
new AdminBlueprintSaveCommand(this);
new AdminBlueprintPos1Command(this);
new AdminBlueprintPos2Command(this);
new AdminBlueprintListCommand(this);
}
@Override
@ -55,7 +54,7 @@ public class AdminSchemCommand extends ConfirmableCommand {
return true;
}
protected Map<UUID, Clipboard> getClipboards() {
protected Map<UUID, BlueprintClipboard> getClipboards() {
return clipboards;
}
@ -66,7 +65,7 @@ public class AdminSchemCommand extends ConfirmableCommand {
}
if (clipboards.containsKey(user.getUniqueId())) {
Clipboard clipboard = clipboards.get(user.getUniqueId());
BlueprintClipboard clipboard = clipboards.get(user.getUniqueId());
if (clipboard.getPos1() != null && clipboard.getPos2() != null) {
paintAxis(user, clipboard);
}
@ -75,7 +74,7 @@ public class AdminSchemCommand extends ConfirmableCommand {
}, 20, 20));
}
private void paintAxis(User user, Clipboard clipboard) {
private void paintAxis(User user, BlueprintClipboard clipboard) {
int minX = Math.min(clipboard.getPos1().getBlockX(), clipboard.getPos2().getBlockX());
int minY = Math.min(clipboard.getPos1().getBlockY(), clipboard.getPos2().getBlockY());
int minZ = Math.min(clipboard.getPos1().getBlockZ(), clipboard.getPos2().getBlockZ());
@ -121,7 +120,7 @@ public class AdminSchemCommand extends ConfirmableCommand {
}
}
protected File getSchemsFolder() {
return new File(getIWM().getDataFolder(getWorld()), SchemsManager.FOLDER_NAME);
protected File getBlueprintsFolder() {
return new File(getIWM().getDataFolder(getWorld()), BlueprintsManager.FOLDER_NAME);
}
}

View File

@ -0,0 +1,34 @@
package world.bentobox.bentobox.api.commands.admin.blueprints;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.BlueprintClipboard;
import java.util.List;
public class AdminBlueprintCopyCommand extends CompositeCommand {
public AdminBlueprintCopyCommand(AdminBlueprintCommand parent) {
super(parent, "copy");
}
@Override
public void setup() {
setParametersHelp("commands.admin.blueprint.copy.parameters");
setDescription("commands.admin.blueprint.copy.description");
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (args.size() > 1) {
showHelp(this, user);
return false;
}
AdminBlueprintCommand parent = (AdminBlueprintCommand) getParent();
BlueprintClipboard clipboard = parent.getClipboards().computeIfAbsent(user.getUniqueId(), v -> new BlueprintClipboard());
boolean copyAir = (args.size() == 1 && args.get(0).equalsIgnoreCase("air"));
return clipboard.copy(user, copyAir);
}
}

View File

@ -0,0 +1,54 @@
package world.bentobox.bentobox.api.commands.admin.blueprints;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.managers.BlueprintsManager;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public class AdminBlueprintListCommand extends CompositeCommand {
public AdminBlueprintListCommand(AdminBlueprintCommand parent) {
super(parent, "list");
}
@Override
public void setup() {
setDescription("commands.admin.blueprint.list.description");
}
@Override
public boolean canExecute(User user, String label, List<String> args) {
if (!args.isEmpty()) {
showHelp(this, user);
return false;
}
return true;
}
@Override
public boolean execute(User user, String label, List<String> args) {
File blueprints = new File(getAddon().getDataFolder(), BlueprintsManager.FOLDER_NAME);
if (!blueprints.exists()) {
user.sendMessage("commands.admin.blueprint.list.no-blueprints");
return false;
}
FilenameFilter blueprintFilter = (File dir, String name) -> name.toLowerCase(java.util.Locale.ENGLISH).endsWith(BlueprintsManager.BLUEPRINT_SUFFIX);
List<String> blueprintList = Arrays.stream(Objects.requireNonNull(blueprints.list(blueprintFilter))).map(name -> name.substring(0, name.length() - BlueprintsManager.BLUEPRINT_SUFFIX.length())).collect(Collectors.toList());
if (blueprintList.isEmpty()) {
user.sendMessage("commands.admin.blueprint.list.no-blueprints");
return false;
}
user.sendMessage("commands.admin.blueprint.list.available-blueprints");
blueprintList.forEach(user::sendRawMessage);
return true;
}
}

View File

@ -1,24 +1,24 @@
package world.bentobox.bentobox.api.commands.admin.schem;
package world.bentobox.bentobox.api.commands.admin.blueprints;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.managers.BlueprintClipboardManager;
import world.bentobox.bentobox.util.Util;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.managers.ClipboardManager;
import world.bentobox.bentobox.util.Util;
public class AdminBlueprintLoadCommand extends CompositeCommand {
public class AdminSchemLoadCommand extends CompositeCommand {
public AdminSchemLoadCommand(AdminSchemCommand parent) {
public AdminBlueprintLoadCommand(AdminBlueprintCommand parent) {
super(parent, "load");
}
@Override
public void setup() {
setParametersHelp("commands.admin.schem.load.parameters");
setDescription("commands.admin.schem.load.description");
setParametersHelp("commands.admin.blueprint.load.parameters");
setDescription("commands.admin.blueprint.load.description");
}
@Override
@ -28,9 +28,9 @@ public class AdminSchemLoadCommand extends CompositeCommand {
return false;
}
AdminSchemCommand parent = (AdminSchemCommand) getParent();
AdminBlueprintCommand parent = (AdminBlueprintCommand) getParent();
ClipboardManager bp = new ClipboardManager(getPlugin(), parent.getSchemsFolder());
BlueprintClipboardManager bp = new BlueprintClipboardManager(getPlugin(), parent.getBlueprintsFolder());
if (bp.load(user, args.get(0))) {
parent.getClipboards().put(user.getUniqueId(), bp.getClipboard());
return true;

View File

@ -1,34 +1,33 @@
package world.bentobox.bentobox.api.commands.admin.schem;
import java.util.List;
package world.bentobox.bentobox.api.commands.admin.blueprints;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.Block;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.Clipboard;
import world.bentobox.bentobox.blueprints.BlueprintClipboard;
public class AdminSchemOriginCommand extends CompositeCommand {
import java.util.List;
public AdminSchemOriginCommand(AdminSchemCommand parent) {
public class AdminBlueprintOriginCommand extends CompositeCommand {
public AdminBlueprintOriginCommand(AdminBlueprintCommand parent) {
super(parent, "origin");
}
@Override
public void setup() {
setParametersHelp("commands.admin.schem.origin.parameters");
setDescription("commands.admin.schem.origin.description");
setParametersHelp("commands.admin.blueprint.origin.parameters");
setDescription("commands.admin.blueprint.origin.description");
}
@Override
public boolean execute(User user, String label, List<String> args) {
AdminSchemCommand parent = (AdminSchemCommand) getParent();
AdminBlueprintCommand parent = (AdminBlueprintCommand) getParent();
Clipboard clipboard = parent.getClipboards().computeIfAbsent(user.getUniqueId(), v -> new Clipboard());
BlueprintClipboard clipboard = parent.getClipboards().computeIfAbsent(user.getUniqueId(), v -> new BlueprintClipboard());
if (clipboard.getPos1() == null || clipboard.getPos2() == null) {
user.sendMessage("commands.admin.schem.need-pos1-pos2");
user.sendMessage("commands.admin.blueprint.need-pos1-pos2");
return false;
}
@ -44,7 +43,7 @@ public class AdminSchemOriginCommand extends CompositeCommand {
return true;
}
user.sendMessage("commands.admin.schem.look-at-a-block");
user.sendMessage("commands.admin.blueprint.look-at-a-block");
return false;
}
}

View File

@ -0,0 +1,35 @@
package world.bentobox.bentobox.api.commands.admin.blueprints;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.BlueprintClipboard;
import world.bentobox.bentobox.blueprints.BlueprintPaster;
import java.util.List;
public class AdminBlueprintPasteCommand extends CompositeCommand {
public AdminBlueprintPasteCommand(AdminBlueprintCommand parent) {
super(parent, "paste");
}
@Override
public void setup() {
setParametersHelp("commands.admin.blueprint.paste.parameters");
setDescription("commands.admin.blueprint.paste.description");
}
@Override
public boolean execute(User user, String label, List<String> args) {
AdminBlueprintCommand parent = (AdminBlueprintCommand) getParent();
BlueprintClipboard clipboard = parent.getClipboards().computeIfAbsent(user.getUniqueId(), v -> new BlueprintClipboard());
if (clipboard.isFull()) {
new BlueprintPaster(getPlugin(), clipboard, user.getLocation(), () -> user.sendMessage("general.success"));
user.sendMessage("commands.admin.blueprint.paste.pasting");
return true;
}
user.sendMessage("commands.admin.blueprint.copy-first");
return false;
}
}

View File

@ -0,0 +1,37 @@
package world.bentobox.bentobox.api.commands.admin.blueprints;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.BlueprintClipboard;
import world.bentobox.bentobox.util.Util;
import java.util.List;
public class AdminBlueprintPos1Command extends CompositeCommand {
public AdminBlueprintPos1Command(AdminBlueprintCommand parent) {
super(parent, "pos1");
}
@Override
public void setup() {
setParametersHelp("commands.admin.blueprint.pos1.parameters");
setDescription("commands.admin.blueprint.pos1.description");
}
@Override
public boolean execute(User user, String label, List<String> args) {
AdminBlueprintCommand parent = (AdminBlueprintCommand) getParent();
BlueprintClipboard clipboard = parent.getClipboards().computeIfAbsent(user.getUniqueId(), v -> new BlueprintClipboard());
if (user.getLocation().equals(clipboard.getPos2())) {
user.sendMessage("commands.admin.blueprint.set-different-pos");
return false;
}
clipboard.setPos1(user.getLocation());
user.sendMessage("commands.admin.blueprint.set-pos1", "[vector]", Util.xyz(clipboard.getPos1().toVector()));
parent.getClipboards().put(user.getUniqueId(), clipboard);
parent.showClipboard(user);
return true;
}
}

View File

@ -0,0 +1,37 @@
package world.bentobox.bentobox.api.commands.admin.blueprints;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.BlueprintClipboard;
import world.bentobox.bentobox.util.Util;
import java.util.List;
public class AdminBlueprintPos2Command extends CompositeCommand {
public AdminBlueprintPos2Command(AdminBlueprintCommand parent) {
super(parent, "pos2");
}
@Override
public void setup() {
setParametersHelp("commands.admin.blueprint.pos2.parameters");
setDescription("commands.admin.blueprint.pos2.description");
}
@Override
public boolean execute(User user, String label, List<String> args) {
AdminBlueprintCommand parent = (AdminBlueprintCommand) getParent();
BlueprintClipboard clipboard = parent.getClipboards().computeIfAbsent(user.getUniqueId(), v -> new BlueprintClipboard());
if (user.getLocation().equals(clipboard.getPos1())) {
user.sendMessage("commands.admin.blueprint.set-different-pos");
return false;
}
clipboard.setPos2(user.getLocation());
user.sendMessage("commands.admin.blueprint.set-pos2", "[vector]", Util.xyz((clipboard.getPos2()).toVector()));
parent.getClipboards().put(user.getUniqueId(), clipboard);
parent.showClipboard(user);
return true;
}
}

View File

@ -0,0 +1,52 @@
package world.bentobox.bentobox.api.commands.admin.blueprints;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.BlueprintClipboard;
import world.bentobox.bentobox.managers.BlueprintClipboardManager;
import world.bentobox.bentobox.managers.BlueprintsManager;
import java.io.File;
import java.util.List;
public class AdminBlueprintSaveCommand extends ConfirmableCommand {
public AdminBlueprintSaveCommand(AdminBlueprintCommand parent) {
super(parent, "save");
}
@Override
public void setup() {
setParametersHelp("commands.admin.blueprint.save.parameters");
setDescription("commands.admin.blueprint.save.description");
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (args.size() != 1) {
showHelp(this, user);
return false;
}
AdminBlueprintCommand parent = (AdminBlueprintCommand) getParent();
BlueprintClipboard clipboard = parent.getClipboards().computeIfAbsent(user.getUniqueId(), v -> new BlueprintClipboard());
if (clipboard.isFull()) {
// Check if file exists
File newFile = new File(parent.getBlueprintsFolder(), args.get(0) + BlueprintsManager.BLUEPRINT_SUFFIX);
if (newFile.exists()) {
this.askConfirmation(user, user.getTranslation("commands.admin.blueprint.file-exists"), () -> {
parent.hideClipboard(user);
new BlueprintClipboardManager(getPlugin(), parent.getBlueprintsFolder(), clipboard).save(user, args.get(0));
});
return false;
} else {
parent.hideClipboard(user);
return new BlueprintClipboardManager(getPlugin(), parent.getBlueprintsFolder(), clipboard).save(user, args.get(0));
}
} else {
user.sendMessage("commands.admin.blueprint.copy-first");
return false;
}
}
}

View File

@ -1,34 +0,0 @@
package world.bentobox.bentobox.api.commands.admin.schem;
import java.util.List;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.Clipboard;
public class AdminSchemCopyCommand extends CompositeCommand {
public AdminSchemCopyCommand(AdminSchemCommand parent) {
super(parent, "copy");
}
@Override
public void setup() {
setParametersHelp("commands.admin.schem.copy.parameters");
setDescription("commands.admin.schem.copy.description");
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (args.size() > 1) {
showHelp(this, user);
return false;
}
AdminSchemCommand parent = (AdminSchemCommand) getParent();
Clipboard clipboard = parent.getClipboards().computeIfAbsent(user.getUniqueId(), v -> new Clipboard());
boolean copyAir = (args.size() == 1 && args.get(0).equalsIgnoreCase("air"));
return clipboard.copy(user, copyAir);
}
}

View File

@ -1,53 +0,0 @@
package world.bentobox.bentobox.api.commands.admin.schem;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
public class AdminSchemListCommand extends CompositeCommand {
public AdminSchemListCommand(AdminSchemCommand parent) {
super(parent, "list");
}
@Override
public void setup() {
setDescription("commands.admin.schem.list.description");
}
@Override
public boolean canExecute(User user, String label, List<String> args) {
if (!args.isEmpty()) {
showHelp(this, user);
return false;
}
return true;
}
@Override
public boolean execute(User user, String label, List<String> args) {
File schems = new File(getAddon().getDataFolder(), "schems");
if (!schems.exists()) {
user.sendMessage("commands.admin.schem.list.no-schems");
return false;
}
FilenameFilter schemFilter = (File dir, String name) -> name.toLowerCase(java.util.Locale.ENGLISH).endsWith(".schem");
List<String> schemList = Arrays.stream(Objects.requireNonNull(schems.list(schemFilter))).map(name -> name.substring(0, name.length() - 6)).collect(Collectors.toList());
if (schemList.isEmpty()) {
user.sendMessage("commands.admin.schem.list.no-schems");
return false;
}
user.sendMessage("commands.admin.schem.list.available-schems");
schemList.forEach(user::sendRawMessage);
return true;
}
}

View File

@ -1,35 +0,0 @@
package world.bentobox.bentobox.api.commands.admin.schem;
import java.util.List;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.Clipboard;
import world.bentobox.bentobox.blueprints.Paster;
public class AdminSchemPasteCommand extends CompositeCommand {
public AdminSchemPasteCommand(AdminSchemCommand parent) {
super(parent, "paste");
}
@Override
public void setup() {
setParametersHelp("commands.admin.schem.paste.parameters");
setDescription("commands.admin.schem.paste.description");
}
@Override
public boolean execute(User user, String label, List<String> args) {
AdminSchemCommand parent = (AdminSchemCommand) getParent();
Clipboard clipboard = parent.getClipboards().computeIfAbsent(user.getUniqueId(), v -> new Clipboard());
if (clipboard.isFull()) {
new Paster(getPlugin(), clipboard, user.getLocation(), () -> user.sendMessage("general.success"));
user.sendMessage("commands.admin.schem.paste.pasting");
return true;
}
user.sendMessage("commands.admin.schem.copy-first");
return false;
}
}

View File

@ -1,37 +0,0 @@
package world.bentobox.bentobox.api.commands.admin.schem;
import java.util.List;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.Clipboard;
import world.bentobox.bentobox.util.Util;
public class AdminSchemPos1Command extends CompositeCommand {
public AdminSchemPos1Command(AdminSchemCommand parent) {
super(parent, "pos1");
}
@Override
public void setup() {
setParametersHelp("commands.admin.schem.pos1.parameters");
setDescription("commands.admin.schem.pos1.description");
}
@Override
public boolean execute(User user, String label, List<String> args) {
AdminSchemCommand parent = (AdminSchemCommand) getParent();
Clipboard clipboard = parent.getClipboards().computeIfAbsent(user.getUniqueId(), v -> new Clipboard());
if (user.getLocation().equals(clipboard.getPos2())) {
user.sendMessage("commands.admin.schem.set-different-pos");
return false;
}
clipboard.setPos1(user.getLocation());
user.sendMessage("commands.admin.schem.set-pos1", "[vector]", Util.xyz(clipboard.getPos1().toVector()));
parent.getClipboards().put(user.getUniqueId(), clipboard);
parent.showClipboard(user);
return true;
}
}

View File

@ -1,37 +0,0 @@
package world.bentobox.bentobox.api.commands.admin.schem;
import java.util.List;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.Clipboard;
import world.bentobox.bentobox.util.Util;
public class AdminSchemPos2Command extends CompositeCommand {
public AdminSchemPos2Command(AdminSchemCommand parent) {
super(parent, "pos2");
}
@Override
public void setup() {
setParametersHelp("commands.admin.schem.pos2.parameters");
setDescription("commands.admin.schem.pos2.description");
}
@Override
public boolean execute(User user, String label, List<String> args) {
AdminSchemCommand parent = (AdminSchemCommand) getParent();
Clipboard clipboard = parent.getClipboards().computeIfAbsent(user.getUniqueId(), v -> new Clipboard());
if (user.getLocation().equals(clipboard.getPos1())) {
user.sendMessage("commands.admin.schem.set-different-pos");
return false;
}
clipboard.setPos2(user.getLocation());
user.sendMessage("commands.admin.schem.set-pos2", "[vector]", Util.xyz((clipboard.getPos2()).toVector()));
parent.getClipboards().put(user.getUniqueId(), clipboard);
parent.showClipboard(user);
return true;
}
}

View File

@ -1,51 +0,0 @@
package world.bentobox.bentobox.api.commands.admin.schem;
import java.io.File;
import java.util.List;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.Clipboard;
import world.bentobox.bentobox.managers.ClipboardManager;
public class AdminSchemSaveCommand extends ConfirmableCommand {
public AdminSchemSaveCommand(AdminSchemCommand parent) {
super(parent, "save");
}
@Override
public void setup() {
setParametersHelp("commands.admin.schem.save.parameters");
setDescription("commands.admin.schem.save.description");
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (args.size() != 1) {
showHelp(this, user);
return false;
}
AdminSchemCommand parent = (AdminSchemCommand) getParent();
Clipboard clipboard = parent.getClipboards().computeIfAbsent(user.getUniqueId(), v -> new Clipboard());
if (clipboard.isFull()) {
// Check if file exists
File newFile = new File(parent.getSchemsFolder(), args.get(0) + ".schem");
if (newFile.exists()) {
this.askConfirmation(user, user.getTranslation("commands.admin.schem.file-exists"), () -> {
parent.hideClipboard(user);
new ClipboardManager(getPlugin(), parent.getSchemsFolder(), clipboard).save(user, args.get(0));
});
return false;
} else {
parent.hideClipboard(user);
return new ClipboardManager(getPlugin(), parent.getSchemsFolder(), clipboard).save(user, args.get(0));
}
} else {
user.sendMessage("commands.admin.schem.copy-first");
return false;
}
}
}

View File

@ -3,11 +3,12 @@ package world.bentobox.bentobox.api.commands.island;
import java.io.IOException;
import java.util.List;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
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.managers.island.NewIsland;
import world.bentobox.bentobox.panels.IslandCreationPanel;
/**
* /island create - Create an island.
@ -50,28 +51,33 @@ public class IslandCreateCommand extends CompositeCommand {
@Override
public boolean execute(User user, String label, List<String> args) {
// Default schem is 'island'
String name = "island";
// Permission check if the name is not the default one
if (!args.isEmpty()) {
name = args.get(0).toLowerCase(java.util.Locale.ENGLISH);
// Permission check
String permission = this.getPermissionPrefix() + "island.create." + name;
if (!user.hasPermission(permission)) {
user.sendMessage("general.errors.no-permission", TextVariables.PERMISSION, permission);
return false;
}
// Check the schem name exists
name = getPlugin().getSchemsManager().validate(getWorld(), name);
String name = getPlugin().getBlueprintsManager().validate((GameModeAddon)getAddon(), args.get(0).toLowerCase(java.util.Locale.ENGLISH));
if (name == null) {
user.sendMessage("commands.island.create.unknown-schem");
// The blueprint name is not valid.
user.sendMessage("commands.island.create.unknown-blueprint");
return false;
}
if (!getPlugin().getBlueprintsManager().checkPerm(getAddon(), user, args.get(0))) {
return false;
}
// Make island
return makeIsland(user, name);
} else {
// Show panel
//getPlugin().getBlueprintsManager().showPanel(this, user, label);
IslandCreationPanel.openPanel(user, (GameModeAddon) getAddon());
return true;
}
}
private boolean makeIsland(User user, String name) {
user.sendMessage("commands.island.create.creating-island");
try {
NewIsland.builder()
.player(user)
.world(getWorld())
.addon((GameModeAddon)getAddon())
.reason(Reason.CREATE)
.name(name)
.build();

View File

@ -1,19 +1,20 @@
package world.bentobox.bentobox.api.commands.island;
import java.io.IOException;
import java.util.List;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
import org.eclipse.jdt.annotation.Nullable;
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.island.IslandEvent.Reason;
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.SchemsManager;
import world.bentobox.bentobox.managers.island.NewIsland;
import java.io.IOException;
import java.util.List;
import world.bentobox.bentobox.panels.IslandCreationPanel;
/**
* @author tastybento
@ -33,7 +34,7 @@ public class IslandResetCommand extends ConfirmableCommand {
}
@Override
public boolean execute(User user, String label, List<String> args) {
public boolean canExecute(User user, String label, List<String> args) {
// Check cooldown
if (getSettings().getResetCooldown() > 0 && checkCooldown(user, null)) {
return false;
@ -65,45 +66,35 @@ public class IslandResetCommand extends ConfirmableCommand {
}
}
// Default schem is 'island'
String name = getSchemName(args);
if (name == null) {
// The schem name is not valid.
user.sendMessage("commands.island.create.unknown-schem");
return false;
}
return true;
}
@Override
public boolean execute(User user, String label, List<String> args) {
// Permission check if the name is not the default one
String permission = getPermissionPrefix() + "island.create." + name;
if (!name.equals(SchemsManager.DEFAULT_SCHEM_NAME) && !user.hasPermission(permission)) {
user.sendMessage("general.errors.no-permission", TextVariables.PERMISSION, permission);
return false;
}
// Request confirmation
if (getSettings().isResetConfirmation()) {
this.askConfirmation(user, () -> resetIsland(user, name));
return true;
} else {
if (!args.isEmpty()) {
String name = getPlugin().getBlueprintsManager().validate((GameModeAddon)getAddon(), args.get(0).toLowerCase(java.util.Locale.ENGLISH));
if (name == null || name.isEmpty()) {
// The blueprint name is not valid.
user.sendMessage("commands.island.create.unknown-blueprint");
return false;
}
if (!getPlugin().getBlueprintsManager().checkPerm(getAddon(), user, args.get(0))) {
return false;
}
return resetIsland(user, name);
} else {
// Show panel after confirmation
if (getPlugin().getSettings().isResetConfirmation()) {
this.askConfirmation(user, () -> getPlugin().getBlueprintsManager().showPanel(this, user, label));
} else {
//getPlugin().getBlueprintsManager().showPanel(this, user, label);
IslandCreationPanel.openPanel(user, (GameModeAddon) getAddon());
}
return true;
}
}
/**
* Returns the schem name from the args.
* {@link SchemsManager#DEFAULT_SCHEM_NAME} is the default.
* May be null if the schem does not exist.
* @param args args of the command
* @return schem name or null
* @since 1.1
*/
@Nullable
private String getSchemName(List<String> args) {
if (args.isEmpty()) {
return SchemsManager.DEFAULT_SCHEM_NAME;
}
return getPlugin().getSchemsManager().validate(getWorld(), args.get(0).toLowerCase(java.util.Locale.ENGLISH));
}
private boolean resetIsland(User user, String name) {
// Reset the island
@ -131,6 +122,7 @@ public class IslandResetCommand extends ConfirmableCommand {
NewIsland.builder()
.player(user)
.reason(Reason.RESET)
.addon((GameModeAddon)getAddon())
.oldIsland(oldIsland)
.name(name)
.build();

View File

@ -0,0 +1,183 @@
/**
*
*/
package world.bentobox.bentobox.blueprints;
import java.util.List;
import java.util.Map;
import org.bukkit.Material;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import com.google.gson.annotations.Expose;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBlock;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity;
/**
* Stores all details of a blueprint
* @author tastybento
*
*/
public class Blueprint {
/**
* Unique name for this blueprint. The filename will be this plus the blueprint suffix
*/
@Expose
private @NonNull String name;
@Expose
private String displayName;
@Expose
private @NonNull Material icon;
@Expose
private List<String> description;
@Expose
private Map<Vector, BlueprintBlock> attached;
@Expose
private Map<Vector, List<BlueprintEntity>> entities;
@Expose
private Map<Vector, BlueprintBlock> blocks;
@Expose
private int xSize;
@Expose
private int ySize;
@Expose
private int zSize;
@Expose
private Vector bedrock;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the displayName
*/
public String getDisplayName() {
return displayName;
}
/**
* @param displayName the displayName to set
*/
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
/**
* @return the icon
*/
public Material getIcon() {
return icon;
}
/**
* @param icon the icon to set
*/
public void setIcon(Material icon) {
this.icon = icon;
}
/**
* @return the description
*/
public List<String> getDescription() {
return description;
}
/**
* @param description the description to set
*/
public void setDescription(List<String> description) {
this.description = description;
}
/**
* @return the attached
*/
public Map<Vector, BlueprintBlock> getAttached() {
return attached;
}
/**
* @param attached the attached to set
*/
public void setAttached(Map<Vector, BlueprintBlock> attached) {
this.attached = attached;
}
/**
* @return the entities
*/
public Map<Vector, List<BlueprintEntity>> getEntities() {
return entities;
}
/**
* @param entities the entities to set
*/
public void setEntities(Map<Vector, List<BlueprintEntity>> entities) {
this.entities = entities;
}
/**
* @return the blocks
*/
public Map<Vector, BlueprintBlock> getBlocks() {
return blocks;
}
/**
* @param blocks the blocks to set
*/
public void setBlocks(Map<Vector, BlueprintBlock> blocks) {
this.blocks = blocks;
}
/**
* @return the xSize
*/
public int getxSize() {
return xSize;
}
/**
* @param xSize the xSize to set
*/
public void setxSize(int xSize) {
this.xSize = xSize;
}
/**
* @return the ySize
*/
public int getySize() {
return ySize;
}
/**
* @param ySize the ySize to set
*/
public void setySize(int ySize) {
this.ySize = ySize;
}
/**
* @return the zSize
*/
public int getzSize() {
return zSize;
}
/**
* @param zSize the zSize to set
*/
public void setzSize(int zSize) {
this.zSize = zSize;
}
/**
* @return the bedrock
*/
public Vector getBedrock() {
return bedrock;
}
/**
* @param bedrock the bedrock to set
*/
public void setBedrock(Vector bedrock) {
this.bedrock = bedrock;
}
}

View File

@ -1,12 +1,5 @@
package world.bentobox.bentobox.blueprints;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
@ -15,9 +8,6 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.block.Sign;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.AbstractHorse;
import org.bukkit.entity.Ageable;
import org.bukkit.entity.ChestedHorse;
@ -34,26 +24,33 @@ import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBlock;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintCreatureSpawner;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* The clipboard provides the holding spot for an active blueprint that is being
* manipulated by a user. It supports copying from the world and setting of coordinates
* such as the bounding box around the cuboid copy area.
* Pasting is done by the {@link BlueprintPaster} class.
* @author tastybento
* @since 1.5.0
*/
public class Clipboard {
public class BlueprintClipboard {
// Commonly used texts along this class.
private static final String ATTACHED_YAML_PREFIX = "attached.";
private static final String ENTITIES_YAML_PREFIX = "entities.";
private static final String BLOCKS_YAML_PREFIX = "blocks.";
private static final String BEDROCK = "bedrock";
private static final String COLOR = "color";
private static final String LINES = "lines";
private @Nullable YamlConfiguration blockConfig;
private @Nullable Blueprint blueprint;
private @Nullable Location pos1;
private @Nullable Location pos2;
private @Nullable Location origin;
@ -62,18 +59,19 @@ public class Clipboard {
private boolean copying;
private int index;
private int lastPercentage;
private Map<Vector, List<BlueprintEntity>> bpEntities = new HashMap<>();
private Map<Vector, BlueprintBlock> bpAttachable = new HashMap<>();
private Map<Vector, BlueprintBlock> bpBlocks = new HashMap<>();
public Clipboard(String contents) throws InvalidConfigurationException {
set(contents);
/**
* Create a clipboard for blueprint
* @param blueprint - the blueprint to load into the clipboard
*/
public BlueprintClipboard(@NonNull Blueprint blueprint) {
this.blueprint = blueprint;
}
public Clipboard(@NonNull YamlConfiguration config) {
this.blockConfig = config;
}
public Clipboard() {
super();
}
public BlueprintClipboard() { }
/**
* Copy the blocks between pos1 and pos2 into the clipboard for a user.
@ -84,29 +82,29 @@ public class Clipboard {
*/
public boolean copy(User user, boolean copyAir) {
if (copying) {
user.sendMessage("commands.admin.schem.mid-copy");
user.sendMessage("commands.admin.blueprint.mid-copy");
return false;
}
origin = origin == null ? user.getLocation() : origin;
if (pos1 == null || pos2 == null) {
user.sendMessage("commands.admin.schem.need-pos1-pos2");
user.sendMessage("commands.admin.blueprint.need-pos1-pos2");
return false;
}
user.sendMessage("commands.admin.schem.copying");
user.sendMessage("commands.admin.blueprint.copying");
// World
World world = pos1.getWorld();
// Clear the clipboard
blockConfig = new YamlConfiguration();
blueprint = new Blueprint();
count = 0;
index = 0;
lastPercentage = 0;
BoundingBox toCopy = BoundingBox.of(pos1, pos2);
blockConfig.set("size.xsize", toCopy.getWidthX());
blockConfig.set("size.ysize", toCopy.getHeight());
blockConfig.set("size.zsize", toCopy.getWidthZ());
blueprint.setxSize((int)toCopy.getWidthX());
blueprint.setySize((int)toCopy.getHeight());
blueprint.setzSize((int)toCopy.getWidthZ());
BentoBox plugin = BentoBox.getInstance();
@ -120,26 +118,30 @@ public class Clipboard {
}
copying = true;
vectorsToCopy.stream().skip(index).limit(speed).forEach(v -> {
if (copyBlock(v.toLocation(world),
origin,
copyAir,
world.getLivingEntities().stream()
List<LivingEntity> ents = world.getLivingEntities().stream()
.filter(Objects::nonNull)
.filter(e -> !(e instanceof Player) && e.getLocation().equals(v.toLocation(world)))
.collect(Collectors.toList()))) {
.filter(e -> !(e instanceof Player))
.filter(e -> new Vector(e.getLocation().getBlockX(),
e.getLocation().getBlockY(),
e.getLocation().getBlockZ()).equals(v))
.collect(Collectors.toList());
if (copyBlock(v.toLocation(world), origin, copyAir, ents)) {
count++;
}
});
index += speed;
int percent = (int)(index * 100 / (double)vectorsToCopy.size());
if (percent != lastPercentage && percent % 10 == 0) {
user.sendMessage("commands.admin.schem.copied-percent", TextVariables.NUMBER, String.valueOf(percent));
user.sendMessage("commands.admin.blueprint.copied-percent", TextVariables.NUMBER, String.valueOf(percent));
lastPercentage = percent;
}
if (index > vectorsToCopy.size()) {
copyTask.cancel();
blueprint.setAttached(bpAttachable);
blueprint.setBlocks(bpBlocks);
blueprint.setEntities(bpEntities);
user.sendMessage("general.success");
user.sendMessage("commands.admin.schem.copied-blocks", TextVariables.NUMBER, String.valueOf(count));
user.sendMessage("commands.admin.blueprint.copied-blocks", TextVariables.NUMBER, String.valueOf(count));
}
copying = false;
}, 0L, 1L);
@ -173,46 +175,51 @@ public class Clipboard {
int x = l.getBlockX() - copyOrigin.getBlockX();
int y = l.getBlockY() - copyOrigin.getBlockY();
int z = l.getBlockZ() - copyOrigin.getBlockZ();
String pos = x + "," + y + "," + z;
// Position defines the section
ConfigurationSection blocksSection = blockConfig.createSection(BLOCKS_YAML_PREFIX + "." + pos);
Vector pos = new Vector(x, y, z);
// Set entities
List<BlueprintEntity> bpEnts = new ArrayList<>();
for (LivingEntity entity: entities) {
ConfigurationSection entitySection = blockConfig.createSection(ENTITIES_YAML_PREFIX + pos + "." + entity.getUniqueId());
entitySection.set("type", entity.getType().name());
entitySection.set("name", entity.getCustomName());
BlueprintEntity bpe = new BlueprintEntity();
bpe.setType(entity.getType());
bpe.setCustomName(entity.getCustomName());
if (entity instanceof Colorable) {
Colorable c = (Colorable)entity;
if (c.getColor() != null) {
entitySection.set(COLOR, c.getColor().name());
bpe.setColor(c.getColor());
}
}
if (entity instanceof Tameable && ((Tameable)entity).isTamed()) {
entitySection.set("tamed", true);
if (entity instanceof Tameable) {
bpe.setTamed(((Tameable)entity).isTamed());
}
if (entity instanceof ChestedHorse && ((ChestedHorse)entity).isCarryingChest()) {
entitySection.set("chest", true);
if (entity instanceof ChestedHorse) {
bpe.setChest(((ChestedHorse)entity).isCarryingChest());
}
if (entity instanceof Ageable) {
entitySection.set("adult", ((Ageable)entity).isAdult());
// Only set if child. Most animals are adults
if (!((Ageable)entity).isAdult()) bpe.setAdult(false);
}
if (entity instanceof AbstractHorse) {
AbstractHorse horse = (AbstractHorse)entity;
entitySection.set("domestication", horse.getDomestication());
bpe.setDomestication(horse.getDomestication());
bpe.setInventory(new HashMap<>());
for (int index = 0; index < horse.getInventory().getSize(); index++) {
ItemStack i = horse.getInventory().getItem(index);
if (i != null) {
entitySection.set("inventory." + index, i);
bpe.getInventory().put(index, i);
}
}
}
if (entity instanceof Horse) {
Horse horse = (Horse)entity;
entitySection.set("style", horse.getStyle().name());
bpe.setStyle(horse.getStyle());
}
bpEnts.add(bpe);
}
// Store
if (!bpEnts.isEmpty()) {
bpEntities.put(pos, bpEnts);
}
// Return if this is just air block
@ -222,64 +229,52 @@ public class Clipboard {
// Block state
BlockState blockState = block.getState();
BlueprintBlock b = new BlueprintBlock(block.getBlockData().getAsString());
// Signs
if (blockState instanceof Sign) {
Sign sign = (Sign)blockState;
b.setSignLines(Arrays.asList(sign.getLines()));
}
// Set block data
if (blockState.getData() instanceof Attachable) {
ConfigurationSection attachedSection = blockConfig.createSection(ATTACHED_YAML_PREFIX + pos);
attachedSection.set("bd", block.getBlockData().getAsString());
// Placeholder for attachment
blocksSection.set("bd", "minecraft:air");
// Signs
if (blockState instanceof Sign) {
Sign sign = (Sign)blockState;
attachedSection.set(LINES, Arrays.asList(sign.getLines()));
}
bpBlocks.put(pos, new BlueprintBlock("minecraft:air"));
bpAttachable.put(pos, b);
return true;
} else {
blocksSection.set("bd", block.getBlockData().getAsString());
// Signs
if (blockState instanceof Sign) {
Sign sign = (Sign)blockState;
blocksSection.set(LINES, Arrays.asList(sign.getLines()));
}
}
if (block.getType().equals(Material.BEDROCK)) {
blockConfig.set(BEDROCK, x + "," + y + "," + z);
blueprint.setBedrock(pos);
}
// Chests
if (blockState instanceof InventoryHolder) {
b.setInventory(new HashMap<>());
InventoryHolder ih = (InventoryHolder)blockState;
for (int index = 0; index < ih.getInventory().getSize(); index++) {
ItemStack i = ih.getInventory().getItem(index);
if (i != null) {
blocksSection.set("inventory." + index, i);
b.getInventory().put(index, i);
}
}
}
if (blockState instanceof CreatureSpawner) {
CreatureSpawner spawner = (CreatureSpawner)blockState;
blocksSection.set("spawnedType",spawner.getSpawnedType().name());
blocksSection.set("delay", spawner.getDelay());
blocksSection.set("maxNearbyEntities", spawner.getMaxNearbyEntities());
blocksSection.set("maxSpawnDelay", spawner.getMaxSpawnDelay());
blocksSection.set("minSpawnDelay", spawner.getMinSpawnDelay());
blocksSection.set("requiredPlayerRange", spawner.getRequiredPlayerRange());
blocksSection.set("spawnRange", spawner.getSpawnRange());
BlueprintCreatureSpawner cs = new BlueprintCreatureSpawner();
cs.setSpawnedType(spawner.getSpawnedType());
cs.setDelay(spawner.getDelay());
cs.setMaxNearbyEntities(spawner.getMaxNearbyEntities());
cs.setMaxSpawnDelay(spawner.getMaxSpawnDelay());
cs.setMinSpawnDelay(spawner.getMinSpawnDelay());
cs.setRequiredPlayerRange(spawner.getRequiredPlayerRange());
cs.setSpawnRange(spawner.getSpawnRange());
b.setCreatureSpawner(cs);
}
this.bpBlocks.put(pos, b);
return true;
}
/**
* @return the blockConfig
*/
@Nullable
public YamlConfiguration getBlockConfig() {
return blockConfig;
}
/**
* @return the origin
*/
@ -303,31 +298,7 @@ public class Clipboard {
}
public boolean isFull() {
return blockConfig != null;
}
/**
* Set the clipboard from a YAML string
* @param contents - YAML config as a string
* @return clipboard
* @throws InvalidConfigurationException - if YAML config is bad
*/
public Clipboard set(String contents) throws InvalidConfigurationException {
this.blockConfig.loadFromString(contents);
setPos1(null);
setPos2(null);
return this;
}
/**
* Set the clipboard contents from a YAML configuration
* @param blockConfig the blockConfig
*/
public Clipboard set(@NonNull YamlConfiguration blockConfig) {
this.blockConfig = blockConfig;
setPos1(null);
setPos2(null);
return this;
return blueprint != null;
}
/**
@ -366,11 +337,17 @@ public class Clipboard {
}
/**
* Returns the clipboard as a String using {@link YamlConfiguration#saveToString()}.
* @return the clipboard as a String.
* @return the blueprint
*/
@Override
public String toString() {
return blockConfig.saveToString();
public Blueprint getBlueprint() {
return blueprint;
}
/**
* @param blueprint the blueprint to set
*/
public BlueprintClipboard setBlueprint(Blueprint blueprint) {
this.blueprint = blueprint;
return this;
}
}

View File

@ -1,11 +1,7 @@
package world.bentobox.bentobox.blueprints;
import java.util.Iterator;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.DyeColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
@ -13,35 +9,40 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.block.Sign;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.AbstractHorse;
import org.bukkit.entity.Ageable;
import org.bukkit.entity.ChestedHorse;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Horse;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Tameable;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.Colorable;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBlock;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintCreatureSpawner;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.util.Util;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* This class pastes the clipboard it is given
* @author tastybento
*
*/
public class Paster {
public class BlueprintPaster {
enum PasteState {
BLOCKS,
@ -51,18 +52,6 @@ public class Paster {
CANCEL
}
private static final String BEDROCK = "bedrock";
// Commonly used texts along this class.
private static final String ATTACHED_YAML_PREFIX = "attached.";
private static final String ENTITIES_YAML_PREFIX = "entities.";
private static final String BLOCKS_YAML_PREFIX = "blocks.";
private static final String INVENTORY = "inventory";
private static final String ENTITY = "entity";
private static final String COLOR = "color";
private static final String LINES = "lines";
private BentoBox plugin;
// The minimum block position (x,y,z)
private Location pos1;
@ -72,57 +61,57 @@ public class Paster {
private int pasteSpeed;
private PasteState pasteState;
private BukkitTask pastingTask;
private BlueprintClipboard clipboard;
/**
* Paste a clipboard
* Paste a clipboard to a location and run task
* @param plugin - BentoBox
* @param clipboard - clipboard to paste
* @param location - location to paste to
* @param task - task to run after pasting, null if none
*/
public Paster(@NonNull BentoBox plugin, @NonNull Clipboard clipboard, @NonNull Location location) {
public BlueprintPaster(@NonNull BentoBox plugin, @NonNull BlueprintClipboard clipboard, @NonNull Location location, @Nullable Runnable task) {
this.plugin = plugin;
paste(location.getWorld(), null, location, clipboard, null);
this.clipboard = clipboard;
// Calculate location for pasting
Location loc = location.toVector().subtract(clipboard.getOrigin().toVector()).toLocation(location.getWorld());
paste(location.getWorld(), null, loc, clipboard.getBlueprint(), task);
}
/**
* Paste a clipboard
* Pastes a blueprint to an island
* @param plugin - BentoBox
* @param clipboard - clipboard to paste
* @param location - location to paste to
* @param task - task to run after pasting
*/
public Paster(@NonNull BentoBox plugin, @NonNull Clipboard clipboard, @NonNull Location location, @Nullable Runnable task) {
this.plugin = plugin;
paste(location.getWorld(), null, location, clipboard, task);
}
/**
* Pastes a clipboard
* @param plugin - BentoBox
* @param clipboard - clipboard to paste
* @param bp - blueprint to paste
* @param world - world to paste to
* @param island - island related to this paste
* @param task - task to run after pasting
*/
public Paster(@NonNull BentoBox plugin, @NonNull Clipboard clipboard, @NonNull World world, @NonNull Island island, @Nullable Runnable task) {
public BlueprintPaster(@NonNull BentoBox plugin, Blueprint bp, World world, Island island, Runnable task) {
this.plugin = plugin;
// Offset due to bedrock
Vector off = new Vector(0,0,0);
if (clipboard.getBlockConfig().contains(BEDROCK)) {
String[] offset = clipboard.getBlockConfig().getString(BEDROCK).split(",");
off = new Vector(Integer.valueOf(offset[0]), Integer.valueOf(offset[1]), Integer.valueOf(offset[2]));
}
Vector off = bp.getBedrock() != null ? bp.getBedrock() : new Vector(0,0,0);
// Calculate location for pasting
Location loc = island.getCenter().toVector().subtract(off).toLocation(world);
// Paste
paste(world, island, loc, clipboard, task);
paste(world, island, loc, bp, task);
}
private void paste(@NonNull World world, @Nullable Island island, @NonNull Location loc, @NonNull Clipboard clipboard, @Nullable Runnable task) {
// Iterators for the various schem sections
Iterator<String> it = clipboard.getBlockConfig().getConfigurationSection(BLOCKS_YAML_PREFIX).getKeys(false).iterator();
Iterator<String> it2 = clipboard.getBlockConfig().contains(ATTACHED_YAML_PREFIX) ? clipboard.getBlockConfig().getConfigurationSection(ATTACHED_YAML_PREFIX).getKeys(false).iterator() : null;
Iterator<String> it3 = clipboard.getBlockConfig().contains(ENTITIES_YAML_PREFIX) ? clipboard.getBlockConfig().getConfigurationSection(ENTITIES_YAML_PREFIX).getKeys(false).iterator() : null;
/**
* The main pasting method
* @param world - world to paste to
* @param island - the island related to this pasting - may be null
* @param loc - the location to paste to
* @param blueprint - the blueprint to paste
* @param task - task to run after pasting
*/
private void paste(@NonNull World world, @Nullable Island island, @NonNull Location loc, @NonNull Blueprint blueprint, @Nullable Runnable task) {
// Iterators for the various maps to paste
Map<Vector, BlueprintBlock> blocks = blueprint.getBlocks() == null ? new HashMap<>() : blueprint.getBlocks();
Map<Vector, BlueprintBlock> attached = blueprint.getAttached() == null ? new HashMap<>() : blueprint.getAttached();
Map<Vector, List<BlueprintEntity>> entities = blueprint.getEntities() == null ? new HashMap<>() : blueprint.getEntities();
Iterator<Entry<Vector, BlueprintBlock>> it = blocks.entrySet().iterator();
Iterator<Entry<Vector, BlueprintBlock>> it2 = attached.entrySet().iterator();
Iterator<Entry<Vector, List<BlueprintEntity>>> it3 = entities.entrySet().iterator();
// Initial state & speed
pasteState = PasteState.BLOCKS;
@ -131,15 +120,15 @@ public class Paster {
pastingTask = Bukkit.getScheduler().runTaskTimer(plugin, () -> {
int count = 0;
while (pasteState.equals(PasteState.BLOCKS) && count < pasteSpeed && it.hasNext()) {
pasteBlock(world, island, loc, clipboard.getBlockConfig().getConfigurationSection(BLOCKS_YAML_PREFIX + it.next()));
pasteBlock(world, island, loc, it.next());
count++;
}
while (it2 != null && pasteState.equals(PasteState.ATTACHMENTS) && count < pasteSpeed && it2.hasNext()) {
pasteBlock(world, island, loc, clipboard.getBlockConfig().getConfigurationSection(ATTACHED_YAML_PREFIX + it2.next()));
pasteBlock(world, island, loc, it2.next());
count++;
}
while (it3 != null && pasteState.equals(PasteState.ENTITIES) && count < pasteSpeed && it3.hasNext()) {
pasteEntity(world, loc, clipboard.getBlockConfig().getConfigurationSection(ENTITIES_YAML_PREFIX + it3.next()));
pasteEntity(world, loc, it3.next());
count++;
}
// STATE SHIFT
@ -163,7 +152,7 @@ public class Paster {
if (pasteState.equals(PasteState.DONE)) {
// All done. Cancel task
// Set pos1 and 2 if this was a clipboard paste
if (island == null && (clipboard.getPos1() == null || clipboard.getPos2() == null)) {
if (island == null && clipboard != null &&(clipboard.getPos1() == null || clipboard.getPos2() == null)) {
clipboard.setPos1(pos1);
clipboard.setPos2(pos2);
}
@ -180,77 +169,55 @@ public class Paster {
}
private void pasteBlock(World world, Island island, Location location, ConfigurationSection config) {
String[] pos = config.getName().split(",");
int x = location.getBlockX() + Integer.valueOf(pos[0]);
int y = location.getBlockY() + Integer.valueOf(pos[1]);
int z = location.getBlockZ() + Integer.valueOf(pos[2]);
Block block = world.getBlockAt(x, y, z);
String blockData = config.getString("bd");
if (blockData != null) {
setBlock(island, block, config, blockData);
}
// Entities (legacy)
if (config.isConfigurationSection(ENTITY)) {
setEntity(block.getLocation(), config.getConfigurationSection(ENTITY));
}
// pos1 and pos2 update
updatePos(world, x,y,z);
}
private void pasteEntity(World world, Location location, ConfigurationSection config) {
String[] pos = config.getName().split(",");
int x = location.getBlockX() + Integer.valueOf(pos[0]);
int y = location.getBlockY() + Integer.valueOf(pos[1]);
int z = location.getBlockZ() + Integer.valueOf(pos[2]);
setEntity(new Location(world, x, y, z), config);
}
private void setBlock(Island island, Block block, ConfigurationSection config, String blockData) {
private void pasteBlock(World world, Island island, Location location, Entry<Vector, BlueprintBlock> entry) {
Location pasteTo = location.clone().add(entry.getKey());
BlueprintBlock bpBlock = entry.getValue();
Block block = pasteTo.getBlock();
// Set the block data
block.setBlockData(Bukkit.createBlockData(blockData));
// Set the block state for chests, signs and mob spawners
setBlockState(island, block, config);
block.setBlockData(Bukkit.createBlockData(bpBlock.getBlockData()));
setBlockState(island, block, bpBlock);
// pos1 and pos2 update
updatePos(world, entry.getKey());
}
private void pasteEntity(World world, Location location, Entry<Vector, List<BlueprintEntity>> entry) {
int x = location.getBlockX() + entry.getKey().getBlockX();
int y = location.getBlockY() + entry.getKey().getBlockY();
int z = location.getBlockZ() + entry.getKey().getBlockZ();
setEntity(new Location(world, x, y, z), entry.getValue());
}
/**
* Handles signs, chests and mob spawner blocks
* @param island - island
* @param block - block
* @param config - config
* @param bpBlock - config
*/
private void setBlockState(Island island, Block block, ConfigurationSection config) {
private void setBlockState(Island island, Block block, BlueprintBlock bpBlock) {
// Get the block state
BlockState bs = block.getState();
// Signs
if (bs instanceof Sign) {
List<String> lines = config.getStringList(LINES);
writeSign(island, block, lines);
writeSign(island, block, bpBlock.getSignLines());
}
// Chests, in general
if (bs instanceof InventoryHolder) {
bs.update(true, false);
Inventory ih = ((InventoryHolder)bs).getInventory();
if (config.isConfigurationSection(INVENTORY)) {
ConfigurationSection inv = config.getConfigurationSection(INVENTORY);
// Double chests are pasted as two blocks so inventory is filled twice. This code stops over filling for the first block.
inv.getKeys(false).stream()
.filter(i -> Integer.valueOf(i) < ih.getSize())
.forEach(i -> ih.setItem(Integer.valueOf(i), (ItemStack)inv.get(i)));
}
// Double chests are pasted as two blocks so inventory is filled twice. This code stops over filling for the first block.
bpBlock.getInventory().forEach(ih::setItem);
}
// Mob spawners
if (bs instanceof CreatureSpawner) {
CreatureSpawner spawner = ((CreatureSpawner) bs);
spawner.setSpawnedType(EntityType.valueOf(config.getString("spawnedType", "PIG")));
spawner.setMaxNearbyEntities(config.getInt("maxNearbyEntities", 16));
spawner.setMaxSpawnDelay(config.getInt("maxSpawnDelay", 2*60*20));
spawner.setMinSpawnDelay(config.getInt("minSpawnDelay", 5*20));
spawner.setDelay(config.getInt("delay", -1));
spawner.setRequiredPlayerRange(config.getInt("requiredPlayerRange", 16));
spawner.setSpawnRange(config.getInt("spawnRange", 4));
BlueprintCreatureSpawner s = bpBlock.getCreatureSpawner();
spawner.setSpawnedType(s.getSpawnedType());
spawner.setMaxNearbyEntities(s.getMaxNearbyEntities());
spawner.setMaxSpawnDelay(s.getMaxSpawnDelay());
spawner.setMinSpawnDelay(s.getMinSpawnDelay());
spawner.setDelay(s.getDelay());
spawner.setRequiredPlayerRange(s.getRequiredPlayerRange());
spawner.setSpawnRange(s.getSpawnRange());
bs.update(true, false);
}
}
@ -258,28 +225,27 @@ public class Paster {
/**
* Sets any entity that is in this location
* @param location - location
* @param en - config section
* @param list - list of entities to paste
*/
private void setEntity(Location location, ConfigurationSection en) {
en.getKeys(false).forEach(k -> {
ConfigurationSection ent = en.getConfigurationSection(k);
private void setEntity(Location location, List<BlueprintEntity> list) {
list.forEach(k -> {
// Center, and just a bit high
Location center = location.add(new Vector(0.5, 0.5, 0.5));
LivingEntity e = (LivingEntity)location.getWorld().spawnEntity(center, EntityType.valueOf(ent.getString("type", "PIG")));
if (e != null) {
e.setCustomName(ent.getString("name"));
LivingEntity e = (LivingEntity)location.getWorld().spawnEntity(center, k.getType());
if (k.getCustomName() != null) {
e.setCustomName(k.getCustomName());
}
if (e instanceof Colorable && ent.contains(COLOR)) {
((Colorable) e).setColor(DyeColor.valueOf(ent.getString(COLOR)));
if (e instanceof Colorable && k.getColor() != null) {
((Colorable) e).setColor(k.getColor());
}
if (e instanceof Tameable) {
((Tameable)e).setTamed(ent.getBoolean("tamed"));
if (e instanceof Tameable && k.getTamed() != null) {
((Tameable)e).setTamed(k.getTamed());
}
if (e instanceof ChestedHorse) {
((ChestedHorse)e).setCarryingChest(ent.getBoolean("chest"));
if (e instanceof ChestedHorse && k.getChest() != null) {
((ChestedHorse)e).setCarryingChest(k.getChest());
}
if (e instanceof Ageable) {
if (ent.getBoolean("adult")) {
if (e instanceof Ageable && k.getAdult() != null) {
if (k.getAdult()) {
((Ageable)e).setAdult();
} else {
((Ageable)e).setBaby();
@ -287,14 +253,13 @@ public class Paster {
}
if (e instanceof AbstractHorse) {
AbstractHorse horse = (AbstractHorse)e;
horse.setDomestication(ent.getInt("domestication"));
if (ent.isConfigurationSection(INVENTORY)) {
ConfigurationSection inv = ent.getConfigurationSection(INVENTORY);
inv.getKeys(false).forEach(i -> horse.getInventory().setItem(Integer.valueOf(i), (ItemStack)inv.get(i)));
if (k.getDomestication() != null) horse.setDomestication(k.getDomestication());
if (k.getInventory() != null) {
k.getInventory().forEach(horse.getInventory()::setItem);
}
}
if (e instanceof Horse) {
((Horse)e).setStyle(Horse.Style.valueOf(ent.getString("style", "NONE")));
if (e instanceof Horse && k.getStyle() != null) {
((Horse)e).setStyle(k.getStyle());
}
});
@ -303,34 +268,32 @@ public class Paster {
/**
* Tracks the minimum and maximum block positions
* @param world - world
* @param x - x
* @param y - y
* @param z - z
* @param v - vector
*/
private void updatePos(World world, int x, int y, int z) {
private void updatePos(World world, Vector v) {
if (pos1 == null) {
pos1 = new Location(world, x, y, z);
pos1 = v.toLocation(world);
}
if (pos2 == null) {
pos2 = new Location(world, x, y, z);
pos2 = v.toLocation(world);
}
if (x < pos1.getBlockX()) {
pos1.setX(x);
if (v.getBlockX() < pos1.getBlockX()) {
pos1.setX(v.getBlockX());
}
if (x > pos2.getBlockX()) {
pos2.setX(x);
if (v.getBlockX() > pos2.getBlockX()) {
pos2.setX(v.getBlockX());
}
if (y < pos1.getBlockY()) {
pos1.setY(y);
if (v.getBlockY() < pos1.getBlockY()) {
pos1.setY(v.getBlockY());
}
if (y > pos2.getBlockY()) {
pos2.setY(y);
if (v.getBlockY() > pos2.getBlockY()) {
pos2.setY(v.getBlockY());
}
if (z < pos1.getBlockZ()) {
pos1.setZ(z);
if (v.getBlockZ() < pos1.getBlockZ()) {
pos1.setZ(v.getBlockZ());
}
if (z > pos2.getBlockZ()) {
pos2.setZ(z);
if (v.getBlockZ() > pos2.getBlockZ()) {
pos2.setZ(v.getBlockZ());
}
}

View File

@ -0,0 +1,84 @@
package world.bentobox.bentobox.blueprints.dataobjects;
import java.util.List;
import java.util.Map;
import org.bukkit.inventory.ItemStack;
import com.google.gson.annotations.Expose;
/**
* @author tastybento
* @since 1.5.0
*/
public class BlueprintBlock {
@Expose
private String blockData;
@Expose
private List<String> signLines;
@Expose
private Map<Integer, ItemStack> inventory;
@Expose
private BlueprintCreatureSpawner creatureSpawner;
public BlueprintBlock(String blockData) {
this.blockData = blockData;
}
/**
* @return the blockData
*/
public String getBlockData() {
return blockData;
}
/**
* @param blockData the blockData to set
*/
public void setBlockData(String blockData) {
this.blockData = blockData;
}
/**
* @return the signLines
*/
public List<String> getSignLines() {
return signLines;
}
/**
* @param signLines the signLines to set
*/
public void setSignLines(List<String> signLines) {
this.signLines = signLines;
}
/**
* @return the inventory
*/
public Map<Integer, ItemStack> getInventory() {
return inventory;
}
/**
* @param inventory the inventory to set
*/
public void setInventory(Map<Integer, ItemStack> inventory) {
this.inventory = inventory;
}
/**
* @return the creatureSpawner
*/
public BlueprintCreatureSpawner getCreatureSpawner() {
return creatureSpawner;
}
/**
* @param creatureSpawner the creatureSpawner to set
*/
public void setCreatureSpawner(BlueprintCreatureSpawner creatureSpawner) {
this.creatureSpawner = creatureSpawner;
}
}

View File

@ -0,0 +1,161 @@
package world.bentobox.bentobox.blueprints.dataobjects;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import org.bukkit.Material;
import org.bukkit.World;
import com.google.gson.annotations.Expose;
import world.bentobox.bentobox.blueprints.Blueprint;
import world.bentobox.bentobox.database.objects.DataObject;
/**
* Represents a bundle of three {@link Blueprint}s.
* This is what the player will choose when creating his island.
* @since 1.5.0
* @author Poslovitch, tastybento
*/
public class BlueprintBundle implements DataObject {
/**
* The unique id of this bundle
*/
@Expose
private String uniqueId;
/**
* Icon of the bundle
*/
@Expose
private Material icon = Material.PAPER;
/**
* Name on the icon
*/
@Expose
private String displayName = "";
/**
* Description to show players
*/
@Expose
private List<String> description = new ArrayList<>();
/**
* If true, then the player needs to have a permission to view or use this bundle
* The permission is GameModeAddon.island.create.uniqueId of blueprint bundle.
* e.g. bskyblock.island.create.vip
*/
@Expose
private boolean requirePermission;
/**
* Reference to the blueprint
*/
@Expose
private EnumMap<World.Environment, String> blueprints = new EnumMap<>(World.Environment.class);
/**
* @return the uniqueId
*/
@Override
public String getUniqueId() {
return uniqueId;
}
/**
* @param uniqueId the uniqueId to set
*/
@Override
public void setUniqueId(String uniqueId) {
this.uniqueId = uniqueId;
}
/**
* @return the icon
*/
public Material getIcon() {
return icon;
}
/**
* @param icon the icon to set
*/
public void setIcon(Material icon) {
this.icon = icon;
}
/**
* @return the displayName
*/
public String getDisplayName() {
return displayName;
}
/**
* @param displayName the displayName to set
*/
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
/**
* @return the description
*/
public List<String> getDescription() {
return description;
}
/**
* @param description the description to set
*/
public void setDescription(List<String> description) {
this.description = description;
}
/**
* @return the blueprints
*/
public EnumMap<World.Environment, String> getBlueprints() {
return blueprints;
}
/**
* @param blueprints the blueprints to set
*/
public void setBlueprints(EnumMap<World.Environment, String> blueprints) {
this.blueprints = blueprints;
}
/**
* Adds a blueprint to the blueprint bundle. It will replace any blueprint that already exists of the same {@link World.Environment} type.
* @param env - the {@link World#Environment}
* @param bp - blueprint
*/
public void setBlueprint(World.Environment env, Blueprint bp) {
this.blueprints.put(env, bp.getName());
}
/**
* Get the blueprint for the environment type
* @param env - {@link World#Environment} type
* @return Blueprint or null if one does not exist
*/
public String getBlueprint(World.Environment env) {
return this.blueprints.get(env);
}
/**
* Adds a line to the description
*
* @param string
*/
public void setDescription(String string) {
if (description == null)
description = new ArrayList<>();
this.description.add(string);
}
/**
* @return the requirePermission
*/
public boolean isRequirePermission() {
return requirePermission;
}
/**
* @param requirePermission the requirePermission to set
*/
public void setRequirePermission(boolean requirePermission) {
this.requirePermission = requirePermission;
}
}

View File

@ -0,0 +1,111 @@
package world.bentobox.bentobox.blueprints.dataobjects;
import org.bukkit.entity.EntityType;
import com.google.gson.annotations.Expose;
/**
* @author tastybento
* @since 1.5.0
*/
public class BlueprintCreatureSpawner {
@Expose
private EntityType spawnedType;
@Expose
private int delay;
@Expose
private int maxNearbyEntities;
@Expose
private int maxSpawnDelay;
@Expose
private int minSpawnDelay;
@Expose
private int requiredPlayerRange;
@Expose
private int spawnRange;
/**
* @return the spawnedType
*/
public EntityType getSpawnedType() {
return spawnedType;
}
/**
* @param spawnedType the spawnedType to set
*/
public void setSpawnedType(EntityType spawnedType) {
this.spawnedType = spawnedType;
}
/**
* @return the delay
*/
public int getDelay() {
return delay;
}
/**
* @param delay the delay to set
*/
public void setDelay(int delay) {
this.delay = delay;
}
/**
* @return the maxNearbyEntities
*/
public int getMaxNearbyEntities() {
return maxNearbyEntities;
}
/**
* @param maxNearbyEntities the maxNearbyEntities to set
*/
public void setMaxNearbyEntities(int maxNearbyEntities) {
this.maxNearbyEntities = maxNearbyEntities;
}
/**
* @return the maxSpawnDelay
*/
public int getMaxSpawnDelay() {
return maxSpawnDelay;
}
/**
* @param maxSpawnDelay the maxSpawnDelay to set
*/
public void setMaxSpawnDelay(int maxSpawnDelay) {
this.maxSpawnDelay = maxSpawnDelay;
}
/**
* @return the minSpawnDelay
*/
public int getMinSpawnDelay() {
return minSpawnDelay;
}
/**
* @param minSpawnDelay the minSpawnDelay to set
*/
public void setMinSpawnDelay(int minSpawnDelay) {
this.minSpawnDelay = minSpawnDelay;
}
/**
* @return the requiredPlayerRange
*/
public int getRequiredPlayerRange() {
return requiredPlayerRange;
}
/**
* @param requiredPlayerRange the requiredPlayerRange to set
*/
public void setRequiredPlayerRange(int requiredPlayerRange) {
this.requiredPlayerRange = requiredPlayerRange;
}
/**
* @return the spawnRange
*/
public int getSpawnRange() {
return spawnRange;
}
/**
* @param spawnRange the spawnRange to set
*/
public void setSpawnRange(int spawnRange) {
this.spawnRange = spawnRange;
}
}

View File

@ -0,0 +1,145 @@
package world.bentobox.bentobox.blueprints.dataobjects;
import java.util.Map;
import org.bukkit.DyeColor;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Horse.Style;
import org.bukkit.inventory.ItemStack;
import com.google.gson.annotations.Expose;
/**
* @author tastybento
* @since 1.5.0
*/
public class BlueprintEntity {
@Expose
private DyeColor color;
@Expose
private EntityType type;
@Expose
private String customName;
@Expose
private Boolean tamed;
@Expose
private Boolean chest;
@Expose
private Boolean adult;
@Expose
private Integer domestication;
@Expose
private Map<Integer, ItemStack> inventory;
@Expose
private Style style;
/**
* @return the color
*/
public DyeColor getColor() {
return color;
}
/**
* @param color the color to set
*/
public void setColor(DyeColor color) {
this.color = color;
}
/**
* @return the type
*/
public EntityType getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(EntityType type) {
this.type = type;
}
/**
* @return the customName
*/
public String getCustomName() {
return customName;
}
/**
* @param customName the customName to set
*/
public void setCustomName(String customName) {
this.customName = customName;
}
/**
* @return the tamed
*/
public Boolean getTamed() {
return tamed;
}
/**
* @param tamed the tamed to set
*/
public void setTamed(Boolean tamed) {
this.tamed = tamed;
}
/**
* @return the chest
*/
public Boolean getChest() {
return chest;
}
/**
* @param chest the chest to set
*/
public void setChest(Boolean chest) {
this.chest = chest;
}
/**
* @return the adult
*/
public Boolean getAdult() {
return adult;
}
/**
* @param adult the adult to set
*/
public void setAdult(Boolean adult) {
this.adult = adult;
}
/**
* @return the domestication
*/
public Integer getDomestication() {
return domestication;
}
/**
* @param domestication the domestication to set
*/
public void setDomestication(int domestication) {
this.domestication = domestication;
}
/**
* @return the inventory
*/
public Map<Integer, ItemStack> getInventory() {
return inventory;
}
/**
* @param inventory the inventory to set
*/
public void setInventory(Map<Integer, ItemStack> inventory) {
this.inventory = inventory;
}
/**
* @return the style
*/
public Style getStyle() {
return style;
}
/**
* @param style the style to set
*/
public void setStyle(Style style) {
this.style = style;
}
}

View File

@ -10,6 +10,7 @@ import org.bukkit.World;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.Vector;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
@ -23,6 +24,7 @@ import world.bentobox.bentobox.database.json.adapters.FlagTypeAdapter;
import world.bentobox.bentobox.database.json.adapters.ItemStackTypeAdapter;
import world.bentobox.bentobox.database.json.adapters.LocationTypeAdapter;
import world.bentobox.bentobox.database.json.adapters.PotionEffectTypeAdapter;
import world.bentobox.bentobox.database.json.adapters.VectorTypeAdapter;
import world.bentobox.bentobox.database.json.adapters.WorldTypeAdapter;
/**
@ -61,6 +63,8 @@ public class BentoboxTypeAdapterFactory implements TypeAdapterFactory {
return (TypeAdapter<T>) new PotionEffectTypeAdapter();
} else if (World.class.isAssignableFrom(rawType)) {
return (TypeAdapter<T>) new WorldTypeAdapter();
} else if (Vector.class.isAssignableFrom(rawType)) {
return (TypeAdapter<T>) new VectorTypeAdapter();
} else if (ConfigurationSerializable.class.isAssignableFrom(rawType)) {
// This covers a lot of Bukkit objects
return (TypeAdapter<T>) new BukkitObjectTypeAdapter(gson.getAdapter(Map.class));

View File

@ -0,0 +1,40 @@
package world.bentobox.bentobox.database.json.adapters;
import java.io.IOException;
import org.bukkit.util.Vector;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
public class VectorTypeAdapter extends TypeAdapter<Vector> {
@Override
public void write(JsonWriter out, Vector value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
out.beginArray();
out.value(value.getX());
out.value(value.getY());
out.value(value.getZ());
out.endArray();
}
@Override
public Vector read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
in.beginArray();
double x = in.nextDouble();
double y = in.nextDouble();
double z = in.nextDouble();
in.endArray();
return new Vector(x, y, z);
}
}

View File

@ -154,17 +154,15 @@ public class AddonsManager {
*/
private void enableAddon(Addon addon) {
try {
// If this is a GameModeAddon create the worlds, register it and load the schems
// If this is a GameModeAddon create the worlds, register it and load the blueprints
if (addon instanceof GameModeAddon) {
GameModeAddon gameMode = (GameModeAddon) addon;
// Create the gameWorlds
gameMode.createWorlds();
plugin.getIWM().addGameMode(gameMode);
// Register the schems
plugin.getSchemsManager().loadIslands(gameMode);
// Save and load blueprints
plugin.getBlueprintsManager().extractDefaultBlueprints(gameMode);
plugin.getBlueprintsManager().loadBlueprints(gameMode);
plugin.getBlueprintsManager().loadBlueprintBundles(gameMode);
}
addon.onEnable();
if (addon instanceof GameModeAddon) {

View File

@ -4,6 +4,8 @@ import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@ -12,92 +14,97 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.Clipboard;
import world.bentobox.bentobox.blueprints.Paster;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.blueprints.Blueprint;
import world.bentobox.bentobox.blueprints.BlueprintClipboard;
import world.bentobox.bentobox.database.json.BentoboxTypeAdapterFactory;
/**
* @author tastybento
* @since 1.5.0
*/
public class ClipboardManager {
public class BlueprintClipboardManager {
private static final String LOAD_ERROR = "Could not load schems file - does not exist : ";
private static final String LOAD_ERROR = "Could not load blueprint file - does not exist : ";
private static void unzipFiles(final ZipInputStream zipInputStream, final Path unzipFilePath) throws IOException {
private File blueprintFolder;
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(unzipFilePath.toAbsolutePath().toString()))) {
byte[] bytesIn = new byte[1024];
int read;
while ((read = zipInputStream.read(bytesIn)) != -1) {
bos.write(bytesIn, 0, read);
}
}
private BlueprintClipboard clipboard;
}
private Gson gson;
private BentoBox plugin;
private File schemFolder;
private Clipboard clipboard;
public ClipboardManager(BentoBox plugin, File schemFolder) {
this(plugin, schemFolder, null);
public BlueprintClipboardManager(BentoBox plugin, File blueprintFolder) {
this(plugin, blueprintFolder, null);
}
public ClipboardManager(BentoBox plugin, File schemFolder, Clipboard clipboard) {
public BlueprintClipboardManager(BentoBox plugin, File blueprintFolder, BlueprintClipboard clipboard) {
super();
this.plugin = plugin;
if (!schemFolder.exists()) {
schemFolder.mkdirs();
if (!blueprintFolder.exists()) {
blueprintFolder.mkdirs();
}
this.schemFolder = schemFolder;
this.blueprintFolder = blueprintFolder;
this.clipboard = clipboard;
getGson();
}
/**
* @return the clipboard
*/
public Clipboard getClipboard() {
public BlueprintClipboard getClipboard() {
return clipboard;
}
private void getGson() {
GsonBuilder builder = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().enableComplexMapKeySerialization();
// Disable <>'s escaping etc.
builder.disableHtmlEscaping();
// Register adapter factory
builder.registerTypeAdapterFactory(new BentoboxTypeAdapterFactory(plugin));
gson = builder.create();
}
/**
* Load a file to clipboard
* @param fileName - filename in schems folder
* @param fileName - filename in blueprints folder
* @throws IOException - if there's a load error with unziping or name
* @throws InvalidConfigurationException - the YAML of the schem is at fault
*/
public void load(String fileName) throws IOException, InvalidConfigurationException {
File zipFile = new File(schemFolder, fileName + ".schem");
public void load(String fileName) throws IOException {
clipboard = new BlueprintClipboard(loadBlueprint(fileName));
}
/**
* Loads a blueprint
* @param fileName - the filename without the suffix
* @return the blueprint
* @throws IOException
*/
public Blueprint loadBlueprint(String fileName) throws IOException {
File zipFile = new File(blueprintFolder, fileName + BlueprintsManager.BLUEPRINT_SUFFIX);
if (!zipFile.exists()) {
plugin.logError(LOAD_ERROR + zipFile.getName());
throw new IOException(LOAD_ERROR + zipFile.getName());
}
unzip(zipFile.getAbsolutePath());
File file = new File(schemFolder, fileName);
File file = new File(blueprintFolder, fileName);
if (!file.exists()) {
plugin.logError(LOAD_ERROR + file.getName());
throw new IOException(LOAD_ERROR + file.getName());
throw new IOException(LOAD_ERROR + file.getName() + " temp file");
}
YamlConfiguration blockConfig = new YamlConfiguration();
blockConfig.load(file);
clipboard = new Clipboard(blockConfig);
Blueprint bp = gson.fromJson(new FileReader(file), Blueprint.class);
Files.delete(file.toPath());
return bp;
}
/*
Load a file to clipboard
*/
/**
* Load a blueprint to the clipboard for a user
* @param user - user trying to load
* @param fileName - filename
* @return - <tt>true</tt> if load is successful, <tt>false</tt> if not
@ -106,66 +113,57 @@ public class ClipboardManager {
try {
load(fileName);
} catch (IOException e1) {
user.sendMessage("commands.admin.schem.could-not-load");
plugin.logError("Could not load schems file: " + fileName + " " + e1.getMessage());
return false;
} catch (InvalidConfigurationException e1) {
user.sendMessage("commands.admin.schem.could-not-load");
plugin.logError("Could not load schems file - YAML error : " + fileName + " " + e1.getMessage());
user.sendMessage("commands.admin.blueprint.could-not-load");
plugin.logError("Could not load blueprint file: " + fileName + " " + e1.getMessage());
return false;
}
user.sendMessage("general.success");
return true;
}
/**
* Paste clipboard to this location
* @param location - location
*/
public void pasteClipboard(Location location) {
if (clipboard != null) {
new Paster(plugin, clipboard, location);
} else {
plugin.logError("Clipboard has no block data in it to paste!");
}
}
/**
* Pastes the clipboard to island location.
* If pos1 and pos2 are not set already, they are automatically set to the pasted coordinates
* @param world - world in which to paste
* @param island - location to paste
* @param task - task to run after pasting
*/
public void pasteIsland(World world, Island island, Runnable task) {
new Paster(plugin, clipboard, world, island, task);
}
/**
* Save the clipboard to a file
* @param user - user who is copying
* @param newFile - filename
* @param newName - new name of this blueprint
* @return - true if successful, false if error
*/
public boolean save(User user, String newFile) {
File file = new File(schemFolder, newFile);
try {
clipboard.getBlockConfig().save(file);
public boolean save(User user, String newName) {
clipboard.getBlueprint().setName(newName);
if (saveBlueprint(clipboard.getBlueprint())) {
user.sendMessage("general.success");
return true;
}
user.sendMessage("commands.admin.blueprint.could-not-save", "[message]", "Could not save temp blueprint file.");
return false;
}
/**
* Save a blueprint
* @param blueprint - blueprint
* @return true if successful, false if not
*/
public boolean saveBlueprint(Blueprint blueprint) {
if (blueprint.getName().isEmpty()) {
plugin.logError("Blueprint name was empty - could not save it");
return false;
}
File file = new File(blueprintFolder, blueprint.getName());
String toStore = gson.toJson(blueprint, Blueprint.class);
try (FileWriter fileWriter = new FileWriter(file)) {
fileWriter.write(toStore);
} catch (IOException e) {
user.sendMessage("commands.admin.schem.could-not-save", "[message]", "Could not save temp schems file.");
plugin.logError("Could not save temporary schems file: " + file.getName());
plugin.logError("Could not save temporary blueprint file: " + file.getName());
return false;
}
try {
zip(file);
} catch (IOException e) {
user.sendMessage("commands.admin.schem.could-not-save", "[message]", "Could not zip temp schems file.");
plugin.logError("Could not zip temporary schems file: " + file.getName());
plugin.logError("Could not zip temporary blueprint file: " + file.getName());
return false;
}
user.sendMessage("general.success");
return true;
}
private void unzip(final String zipFilePath) throws IOException {
Path path = Paths.get(zipFilePath);
if (!(path.toFile().exists())) {
@ -187,8 +185,18 @@ public class ClipboardManager {
}
}
private void unzipFiles(final ZipInputStream zipInputStream, final Path unzipFilePath) throws IOException {
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(unzipFilePath.toAbsolutePath().toString()))) {
byte[] bytesIn = new byte[1024];
int read;
while ((read = zipInputStream.read(bytesIn)) != -1) {
bos.write(bytesIn, 0, read);
}
}
}
private void zip(File targetFile) throws IOException {
try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(targetFile.getAbsolutePath() + ".schem"))) {
try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(targetFile.getAbsolutePath() + BlueprintsManager.BLUEPRINT_SUFFIX))) {
zipOutputStream.putNextEntry(new ZipEntry(targetFile.getName()));
try (FileInputStream inputStream = new FileInputStream(targetFile)) {
final byte[] buffer = new byte[1024];

View File

@ -1,43 +1,110 @@
package world.bentobox.bentobox.managers;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.blueprints.Blueprint;
import world.bentobox.bentobox.api.blueprints.BlueprintBundle;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.zip.ZipFile;
import java.util.jar.JarFile;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.InstanceCreator;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
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.BlueprintBlock;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBundle;
import world.bentobox.bentobox.database.json.BentoboxTypeAdapterFactory;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.schems.SchemToBlueprint;
import world.bentobox.bentobox.util.Util;
/**
* Handles {@link world.bentobox.bentobox.api.blueprints.Blueprint Blueprints}.
* Handles Blueprints
* @since 1.5.0
* @author Poslovitch
* @author Poslovitch, tastybento
*/
public class BlueprintsManager {
private static final String BLUEPRINT_BUNDLE_SUFFIX = ".json";
public static final String BLUEPRINT_SUFFIX = ".blu";
public static final String DEFAULT_BUNDLE_NAME = "default";
public static final @NonNull String FOLDER_NAME = "blueprints";
/**
* Map of blueprint bundles to game mode addon.
* Inner map's key is the uniqueId of the blueprint bundle so it's
* easy to get from a UI
*/
private @NonNull Map<GameModeAddon, Map<String, BlueprintBundle>> blueprintBundles;
/**
* Map of blueprints. There can be many blueprints per game mode addon
* Inner map's key is the blueprint's name so it's easy to get from a UI
*/
private @NonNull Map<GameModeAddon, Map<String, Blueprint>> blueprints;
/**
* Gson used for serializing/deserializing the bundle class
*/
private final Gson gson;
private @NonNull BentoBox plugin;
private @NonNull Map<GameModeAddon, List<Blueprint>> blueprints;
private @NonNull Map<GameModeAddon, List<BlueprintBundle>> blueprintBundles;
public BlueprintsManager(@NonNull BentoBox plugin) {
this.plugin = plugin;
this.blueprints = new HashMap<>();
this.blueprintBundles = new HashMap<>();
this.blueprints = new HashMap<>();
@SuppressWarnings("rawtypes")
GsonBuilder builder = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.enableComplexMapKeySerialization()
.setPrettyPrinting()
// This enables gson to deserialize enum maps
.registerTypeAdapter(EnumMap.class, new InstanceCreator<EnumMap>() {
@SuppressWarnings("unchecked")
@Override
public EnumMap createInstance(Type type) {
Type[] types = (((ParameterizedType) type).getActualTypeArguments());
return new EnumMap((Class<?>) types[0]);
}
});
// Disable <>'s escaping etc.
builder.disableHtmlEscaping();
// Register adapter factory
builder.registerTypeAdapterFactory(new BentoboxTypeAdapterFactory(plugin));
gson = builder.create();
}
/**
* Extracts the blueprints provided by this {@link GameModeAddon} in its .jar file.
* Extracts the blueprints and bundles provided by this {@link GameModeAddon} in its .jar file.
* This will do nothing if the blueprints folder already exists for this GameModeAddon.
* @param addon the {@link GameModeAddon} to extract the blueprints from.
*/
@ -54,61 +121,21 @@ public class BlueprintsManager {
return;
}
// Get any blueprints from the jar and save them.
// TODO
}
/**
* Loads the blueprints of this addon from its blueprints folder.
* @param addon the {@link GameModeAddon} to load the blueprints of.
*/
public void loadBlueprints(@NonNull GameModeAddon addon) {
File folder = getBlueprintsFolder(addon);
// Create the empty list if not already there
blueprints.putIfAbsent(addon, new LinkedList<>());
// Look through the folder
FilenameFilter filter = (dir, name) -> name.toLowerCase().endsWith("." + Blueprint.FILE_EXTENSION);
Arrays.stream(Objects.requireNonNull(folder.list(filter))).map(name -> name.split("\\.")[0]).forEach(name -> loadBlueprint(addon, name));
}
/**
* Loads the blueprint of this addon corresponding to this name.
* @param addon the {@link GameModeAddon} to load the blueprint from.
* @param name the name of the blueprint to load, without the file extension.
* E.g: {@code "island"}.
*/
public void loadBlueprint(@NonNull GameModeAddon addon, @NonNull String name) {
File folder = getBlueprintsFolder(addon);
// Create the empty list if not already there
blueprints.putIfAbsent(addon, new LinkedList<>());
// Load the blueprint
plugin.log("Loading " + name + ".blueprint for " + addon.getDescription().getName());
try {
Blueprint blueprint = new Blueprint(name, new ZipFile(new File(folder, name + "." + Blueprint.FILE_EXTENSION)));
blueprints.get(addon).add(blueprint);
} catch (Exception e) {
// TODO: add error debug
// Get any blueprints or bundles from the jar and save them.
try (JarFile jar = new JarFile(addon.getFile())) {
Util.listJarFiles(jar, FOLDER_NAME, BLUEPRINT_BUNDLE_SUFFIX).forEach(name -> addon.saveResource(name, false));
Util.listJarFiles(jar, FOLDER_NAME, BLUEPRINT_SUFFIX).forEach(name -> addon.saveResource(name, false));
} catch (IOException e) {
plugin.logError("Could not load blueprint files from addon jar " + e.getMessage());
}
}
@NonNull
public Map<GameModeAddon, List<Blueprint>> getBlueprints() {
return blueprints;
}
@NonNull
public List<Blueprint> getBlueprints(@NonNull GameModeAddon addon) {
return blueprints.getOrDefault(addon, new LinkedList<>());
}
@NonNull
public Map<GameModeAddon, List<BlueprintBundle>> getBlueprintBundles() {
return blueprintBundles;
}
@NonNull
public List<BlueprintBundle> getBlueprintBundles(@NonNull GameModeAddon addon) {
return blueprintBundles.getOrDefault(addon, new LinkedList<>());
/**
* Get the blueprint bundles of this addon.
* @param addon the {@link GameModeAddon} to get the blueprint bundles.
*/
public Map<String, BlueprintBundle> getBlueprintBundles(@NonNull GameModeAddon addon) {
return blueprintBundles.getOrDefault(addon, new HashMap<>());
}
/**
@ -117,7 +144,278 @@ public class BlueprintsManager {
* @return a {@link File} instance of the blueprints folder of this GameModeAddon.
*/
@NonNull
public File getBlueprintsFolder(@NonNull GameModeAddon addon) {
private File getBlueprintsFolder(@NonNull GameModeAddon addon) {
return new File(addon.getDataFolder(), FOLDER_NAME);
}
/**
* Loads the blueprint bundles of this addon from its blueprints folder.
* @param addon the {@link GameModeAddon} to load the blueprints of.
*/
public void loadBlueprintBundles(@NonNull GameModeAddon addon) {
blueprintBundles.put(addon, new HashMap<>());
// 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);
}
private boolean loadBundles(@NonNull GameModeAddon addon) {
File bpf = getBlueprintsFolder(addon);
boolean loaded = false;
for (File file: Objects.requireNonNull(bpf.listFiles((dir, name) -> name.toLowerCase(Locale.ENGLISH).endsWith(BLUEPRINT_BUNDLE_SUFFIX)))) {
try {
BlueprintBundle bb = gson.fromJson(new FileReader(file), BlueprintBundle.class);
blueprintBundles.get(addon).put(bb.getUniqueId(), bb);
plugin.log("Loaded Blueprint Bundle '" + bb.getUniqueId() + "' for " + addon.getDescription().getName());
loaded = true;
} catch (Exception e) {
plugin.logError("Could not load blueprint bundle " + file.getName() + " " + e.getMessage());
e.printStackTrace();
}
}
return loaded;
}
/**
* This should never be needed and is just a boot strap
* @param addon
*/
private void makeDefaults(@NonNull GameModeAddon addon) {
plugin.logError("No blueprint bundles found! Creating a default one.");
BlueprintBundle bb = new BlueprintBundle();
bb.setIcon(Material.PAPER);
bb.setUniqueId(DEFAULT_BUNDLE_NAME);
bb.setDisplayName("Default bundle");
bb.setDescription(Collections.singletonList(ChatColor.AQUA + "Default bundle of blueprints"));
// Default blueprints
Blueprint defaultBp = new Blueprint();
defaultBp.setName("bedrock");
defaultBp.setDescription(Collections.singletonList(ChatColor.AQUA + "A bedrock block"));
defaultBp.setBedrock(new Vector(0,0,0));
Map<Vector, BlueprintBlock> map = new HashMap<>();
map.put(new Vector(0,0,0), new BlueprintBlock("minecraft:bedrock"));
defaultBp.setBlocks(map);
// Save a default "bedrock" blueprint
new BlueprintClipboardManager(plugin, getBlueprintsFolder(addon)).saveBlueprint(defaultBp);
// This blueprint is used for all environments
bb.setBlueprint(World.Environment.NORMAL, defaultBp);
bb.setBlueprint(World.Environment.NETHER, defaultBp);
bb.setBlueprint(World.Environment.THE_END, defaultBp);
blueprintBundles.get(addon).put(DEFAULT_BUNDLE_NAME, bb);
this.saveBlueprintBundles();
}
/**
* Loads all the blueprints of this addon from its blueprints folder.
* @param addon the {@link GameModeAddon} to load the blueprints of.
*/
public void loadBlueprints(@NonNull GameModeAddon addon) {
blueprints.put(addon, new HashMap<>());
File bpf = getBlueprintsFolder(addon);
for (File file: Objects.requireNonNull(bpf.listFiles((dir, name) -> name.toLowerCase(Locale.ENGLISH).endsWith(BLUEPRINT_SUFFIX)))) {
String fileName = file.getName().substring(0, file.getName().length() - BLUEPRINT_SUFFIX.length());
try {
Blueprint bp = new BlueprintClipboardManager(plugin, bpf).loadBlueprint(fileName);
blueprints.get(addon).put(bp.getName(), bp);
plugin.log("Loaded blueprint '" + bp.getName() + "' for " + addon.getDescription().getName());
} catch (Exception e) {
plugin.logError("Could not load blueprint " + fileName + " " + e.getMessage());
e.printStackTrace();
}
}
}
/**
* Adds a blueprint to addon's list of blueprints
* @param addon - the {@link GameModeAddon}
* @param bp - blueprint
*/
public void addBlueprint(@NonNull GameModeAddon addon, @NonNull Blueprint bp) {
blueprints.putIfAbsent(addon, new HashMap<>());
blueprints.get(addon).put(bp.getName(), bp);
plugin.log("Added blueprint '" + bp.getName() + "' for " + addon.getDescription().getName());
}
/**
* Saves a blueprint into addon's blueprint folder
* @param addon - the {@link GameModeAddon}
* @param bp - blueprint to save
*/
public boolean saveBlueprint(@NonNull GameModeAddon addon, @NonNull Blueprint bp) {
return new BlueprintClipboardManager(plugin, getBlueprintsFolder(addon)).saveBlueprint(bp);
}
/**
* Save blueprint bundles for game mode
* @param addon - gamemode addon
* @param bundleList - list of bundles
*/
public void saveBlueprintBundle(GameModeAddon addon, BlueprintBundle bb) {
File bpf = getBlueprintsFolder(addon);
File fileName = new File(bpf, bb.getUniqueId() + BLUEPRINT_BUNDLE_SUFFIX);
String toStore = gson.toJson(bb, BlueprintBundle.class);
try (FileWriter fileWriter = new FileWriter(fileName)) {
fileWriter.write(toStore);
} catch (IOException e) {
plugin.logError("Could not save blueprint bundle file: " + e.getMessage());
}
}
/**
* Saves all the blueprint bundles
*/
public void saveBlueprintBundles() {
blueprintBundles.forEach((k,v) -> v.values().forEach(m -> saveBlueprintBundle(k, m)));
}
/**
* Set the bundles for this addon
* @param addon - {@link GameModeAddon}
* @param map - map of bundles, key is the bundle unique id, value is the bundle
*/
public void setBlueprintBundles(@NonNull GameModeAddon addon, Map<String, BlueprintBundle> map) {
blueprintBundles.put(addon, map);
}
/**
* @return the blueprints
*/
public Map<GameModeAddon, Map<String, Blueprint>> getBlueprints() {
return blueprints;
}
/**
* Paste the islands to world
* @param addon - GameModeAddon
* @param island - island
* @param name - bundle name
*/
public void paste(GameModeAddon addon, Island island, String name) {
paste(addon, island, name, null);
}
/**
* Paste islands to the world and run task afterwards
* @param addon - the game mode addon
* @param island - the island
* @param name - name of bundle to paste
* @param task - task to run after pasting is completed
* @return true if okay, false is there is a problem
*/
public boolean paste(GameModeAddon addon, Island island, String name, Runnable task) {
if (validate(addon, name) == null) {
plugin.logError("Tried to paste '" + name + "' but the bundle is not loaded!");
return false;
}
BlueprintBundle bb = blueprintBundles.get(addon).get(name.toLowerCase(Locale.ENGLISH));
if (!blueprints.containsKey(addon) || blueprints.get(addon).isEmpty()) {
plugin.logError("No blueprints loaded for bundle '" + name + "'!");
return false;
}
Blueprint bp = blueprints.get(addon).get(bb.getBlueprint(World.Environment.NORMAL));
// Paste overworld
new BlueprintPaster(plugin, bp, addon.getOverWorld(), island, task);
// Make nether island
if (bb.getBlueprint(World.Environment.NETHER) != null
&& addon.getWorldSettings().isNetherGenerate()
&& addon.getWorldSettings().isNetherIslands()
&& addon.getNetherWorld() != null) {
bp = blueprints.get(addon).get(bb.getBlueprint(World.Environment.NETHER));
new BlueprintPaster(plugin, bp, addon.getNetherWorld(), island, null);
}
// Make end island
if (bb.getBlueprint(World.Environment.THE_END) != null
&& addon.getWorldSettings().isEndGenerate()
&& addon.getWorldSettings().isEndIslands()
&& addon.getEndWorld() != null) {
bp = blueprints.get(addon).get(bb.getBlueprint(World.Environment.THE_END));
new BlueprintPaster(plugin, bp, addon.getEndWorld(), island, null);
}
return true;
}
/**
* Validate if the bundle name is valid or not
* @param addon - game mode addon
* @param name - bundle name
* @return bundle name or null if it's invalid
*/
public @Nullable String validate(GameModeAddon addon, String name) {
if (name == null) {
return null;
}
if (blueprintBundles.containsKey(addon) && blueprintBundles.get(addon).containsKey(name.toLowerCase(Locale.ENGLISH))) {
return name;
}
return null;
}
/**
* Adds a blueprint bundle
* @param addon - the game mode addon
* @param bb - the blueprint bundle
*/
public void addBlueprintBundle(GameModeAddon addon, BlueprintBundle bb) {
blueprintBundles.computeIfAbsent(addon, k -> new HashMap<>()).put(bb.getUniqueId(), bb);
}
/**
* Shows a player a panel of selectable blueprint bundles. Checks user's permission
* @param command - the command requesting the panel, e.g., create or reset
* @param user - the user
* @param label - label
*/
public void showPanel(CompositeCommand command, User user, String label) {
// Create the panel
PanelBuilder pb = new PanelBuilder().name(user.getTranslation("commands.island.create.pick")).user(user);
// Get the bundles
Collection<BlueprintBundle> bbs = getBlueprintBundles((@NonNull GameModeAddon) command.getAddon()).values();
// Loop through them and create items in the panel
for (BlueprintBundle bb : bbs) {
String perm = command.getPermissionPrefix() + "island.create." + bb.getUniqueId();
if (!bb.getUniqueId().equals(BlueprintsManager.DEFAULT_BUNDLE_NAME)
&& bb.isRequirePermission()
&& !user.hasPermission(perm)) {
// Skip bundles that the user has no permission for
continue;
}
PanelItem pi = new PanelItemBuilder().name(bb.getDisplayName()).description(bb.getDescription())
.icon(bb.getIcon()).name(bb.getUniqueId()).clickHandler((panel, user1, clickType, slot1) -> {
user1.closeInventory();
command.execute(user1, label, Collections.singletonList(bb.getUniqueId()));
return true;
}).build();
pb.item(pi);
}
pb.build();
}
/**
* Checks if a player has permission to see or use this blueprint bundle.
* @param addon - addon making the request
* @param user - user making the request
* @param name - name of the blueprint bundle
* @return <tt>true</tt> if allowed
*/
public boolean checkPerm(Addon addon, User user, String name) {
// Permission
String permission = addon.getPermissionPrefix() + "island.create." + name;
// Get Blueprint bundle
BlueprintBundle bb = getBlueprintBundles((GameModeAddon)addon).get(name.toLowerCase(Locale.ENGLISH));
if (bb == null || (bb.isRequirePermission() && !name.equals(DEFAULT_BUNDLE_NAME) && !user.hasPermission(permission))) {
user.sendMessage("general.errors.no-permission", TextVariables.PERMISSION, permission);
return false;
}
return true;
}
}

View File

@ -246,7 +246,7 @@ public class IslandsManager {
}
/**
* Create an island with owner. Note this does not create the schematic. It just creates the island data object.
* Create an island with owner. Note this does not paste blocks. It just creates the island data object.
* @param location the location, not null
* @param owner the island owner UUID, may be null
* @return Island or null if the island could not be created for some reason

View File

@ -1,179 +0,0 @@
package world.bentobox.bentobox.managers;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.jar.JarFile;
import org.bukkit.World;
import org.bukkit.configuration.InvalidConfigurationException;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.blueprints.Clipboard;
import world.bentobox.bentobox.blueprints.Paster;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.util.Util;
public class SchemsManager {
/**
* Name of the schem that is expected to be the default one.
* @since 1.2.0
*/
public static final @NonNull String DEFAULT_SCHEM_NAME = "island";
/**
* File extension of the schems file.
* @since 1.2.0
*/
public static final @NonNull String FILE_EXTENSION = ".schem";
/**
* Name of the folder containing schems.
* @since 1.2.0
*/
public static final @NonNull String FOLDER_NAME = "schems";
private BentoBox plugin;
private Map<World, Map<String, Clipboard>> islandSchems;
/**
* @param plugin - plugin
*/
public SchemsManager(BentoBox plugin) {
this.plugin = plugin;
islandSchems = new HashMap<>();
}
private void copySchems(Addon addon, File folder) {
if (folder.exists()) {
// If the folder exists, do not copy anything from the jar
return;
}
if (!folder.exists() && !folder.mkdirs()) {
plugin.logError("Could not make '" + FOLDER_NAME + "' folder!");
return;
}
// Save any schems that are in the jar
try (JarFile jar = new JarFile(addon.getFile())) {
Util.listJarFiles(jar, FOLDER_NAME, FILE_EXTENSION).forEach(name -> addon.saveResource(name, false));
} catch (IOException e) {
plugin.logError("Could not load schem files from addon jar " + e.getMessage());
}
}
/**
* Get all the blueprints for this world
* @param world world
* @return map of blueprints for this world or an empty map if there are none registered
*/
public Map<String, Clipboard> get(World world) {
return islandSchems.getOrDefault(world, new TreeMap<>(String.CASE_INSENSITIVE_ORDER));
}
/**
* Load schems for addon. Will try and load nether and end schems too if settings are set.
* @param addon - GameModeAddon
*/
public void loadIslands(GameModeAddon addon) {
File schems = new File(addon.getDataFolder(), FOLDER_NAME);
// Copy any schems fould in the jar
copySchems(addon, schems);
// Load all schems in folder
// Look through the folder
FilenameFilter schemFilter = (File dir, String name) -> name.toLowerCase(java.util.Locale.ENGLISH).endsWith(FILE_EXTENSION)
&& !name.toLowerCase(java.util.Locale.ENGLISH).startsWith("nether-")
&& !name.toLowerCase(java.util.Locale.ENGLISH).startsWith("end-");
Arrays.stream(Objects.requireNonNull(schems.list(schemFilter))).map(name -> name.substring(0, name.length() - 6)).forEach(name -> importSchem(addon, schems, name));
}
/**
* Imports one schem to the game mode
* @param addon
* @param schems
* @param name
*/
private void importSchem(GameModeAddon addon, File schems, String name) {
if (!plugin.getSchemsManager().loadSchem(addon.getOverWorld(), schems, name)) {
plugin.logError("Could not load " + name + ".schem for " + addon.getWorldSettings().getFriendlyName());
}
if (addon.getWorldSettings().isNetherGenerate() && addon.getWorldSettings().isNetherIslands()
&& !plugin.getSchemsManager().loadSchem(addon.getNetherWorld(), schems, "nether-" + name)) {
plugin.logError("Could not load nether-" + name + ".schem for " + addon.getWorldSettings().getFriendlyName());
}
if (addon.getWorldSettings().isEndGenerate() && addon.getWorldSettings().isEndIslands()
&& !plugin.getSchemsManager().loadSchem(addon.getEndWorld(), schems, "end-" + name)) {
plugin.logError("Could not load end-" + name + ".schem for " + addon.getWorldSettings().getFriendlyName());
}
}
private boolean loadSchem(World world, File schems, String name) {
plugin.log("Loading " + name + ".schem for " + world.getName());
Map<String, Clipboard> schemList = islandSchems.getOrDefault(world, new TreeMap<>(String.CASE_INSENSITIVE_ORDER));
try {
ClipboardManager cb = new ClipboardManager(plugin, schems);
cb.load(name);
schemList.put(name, cb.getClipboard());
islandSchems.put(world, schemList);
} catch (IOException | InvalidConfigurationException e) {
plugin.logError("Could not load " + name + " schem, skipping!");
return false;
}
return true;
}
/**
* Paste the schem to world for island
* @param world - world
* @param island - island
* @param name - file name of schematic (without the .schem suffix)
*/
public void paste(World world, Island island, String name) {
paste(world, island, name, null);
}
/**
* Paste the schem for world to the island center location and run task afterwards
* @param world - world to paste to
* @param island - the island who owns this schem
* @param name - file name of schematic (without the .schem suffix)
* @param task - task to run after pasting is completed
*/
public void paste(World world, Island island, String name, Runnable task) {
if (islandSchems.containsKey(world) && islandSchems.get(world).containsKey(name)) {
new Paster(plugin, islandSchems.get(world).get(name), world, island, task);
} else {
plugin.logError("Tried to paste schem '" + name + "' for " + world.getName() + " but the schem is not loaded!");
plugin.log("This might be due to an invalid schem format. Keep in mind that schems are not schematics.");
}
}
/**
* Check if a schem is valid for this game mode or not
* @param world - the world to check
* @param name - name of schem (not including .schem)
* @return name if valid, <tt>null</tt> if not
*/
public @Nullable String validate(World world, String name) {
Set<String> validNames = get(world).keySet();
if (!name.equals(SchemsManager.DEFAULT_SCHEM_NAME) && !validNames.contains(name)) {
// See if it has not been loaded yet
return null;
}
return name;
}
}

View File

@ -14,11 +14,13 @@ import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.BStats;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
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.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.BlueprintsManager;
import world.bentobox.bentobox.util.Util;
/**
@ -35,6 +37,7 @@ public class NewIsland {
private final World world;
private final String name;
private final boolean noPaste;
private GameModeAddon addon;
private enum Result {
ISLAND_FOUND,
@ -43,15 +46,15 @@ public class NewIsland {
FREE
}
private NewIsland(Island oldIsland, User user, Reason reason, World world, String name, boolean noPaste) {
super();
public NewIsland(Builder builder) {
plugin = BentoBox.getInstance();
this.user = user;
this.reason = reason;
this.world = world;
this.name = name;
this.noPaste = noPaste;
newIsland(oldIsland);
this.user = builder.user2;
this.reason = builder.reason2;
this.world = builder.world2;
this.name = builder.name2;
this.noPaste = builder.noPaste2;
this.addon = builder.addon2;
newIsland(builder.oldIsland2);
}
/**
@ -78,8 +81,9 @@ public class NewIsland {
private User user2;
private Reason reason2;
private World world2;
private String name2 = "island";
private String name2 = BlueprintsManager.DEFAULT_BUNDLE_NAME;
private boolean noPaste2;
private GameModeAddon addon2;
public Builder oldIsland(Island oldIsland) {
this.oldIsland2 = oldIsland;
@ -98,13 +102,28 @@ public class NewIsland {
return this;
}
/**
* @param world
* @deprecated use {@link #addon} instead
*/
@Deprecated
public Builder world(World world) {
this.world2 = world;
return this;
}
/**
* No schematics will be pasted
* Set the addon
* @param addon a game mode addon
*/
public Builder addon(GameModeAddon addon) {
this.addon2 = addon;
this.world2 = addon.getOverWorld();
return this;
}
/**
* No blocks will be pasted
*/
public Builder noPaste() {
this.noPaste2 = true;
@ -112,7 +131,7 @@ public class NewIsland {
}
/**
* @param name - filename of schematic
* @param name - name of Blueprint bundle
*/
public Builder name(String name) {
this.name2 = name;
@ -125,10 +144,10 @@ public class NewIsland {
*/
public Island build() throws IOException {
if (user2 != null) {
NewIsland newIsland = new NewIsland(oldIsland2, user2, reason2, world2, name2, noPaste2);
NewIsland newIsland = new NewIsland(this);
return newIsland.getIsland();
}
throw new IOException("Insufficient parameters. Must have a schematic and a player");
throw new IOException("Insufficient parameters. Must have a user!");
}
}
@ -213,17 +232,8 @@ public class NewIsland {
if (noPaste) {
Bukkit.getScheduler().runTask(plugin, task);
} else {
// Create island
plugin.getSchemsManager().paste(world, island, name, task);
// Make nether island
if (plugin.getIWM().isNetherGenerate(world) && plugin.getIWM().isNetherIslands(world) && plugin.getIWM().getNetherWorld(world) != null) {
plugin.getSchemsManager().paste(plugin.getIWM().getNetherWorld(world), island, "nether-" + name);
}
// Make end island
if (plugin.getIWM().isEndGenerate(world) && plugin.getIWM().isEndIslands(world) && plugin.getIWM().getEndWorld(world) != null) {
plugin.getSchemsManager().paste(plugin.getIWM().getEndWorld(world), island, "end-" + name);
}
// Create islands
plugin.getBlueprintsManager().paste(addon, island, name, task);
}
// Set default settings
island.setFlagsDefaults();

View File

@ -0,0 +1,27 @@
package world.bentobox.bentobox.panels;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
import world.bentobox.bentobox.api.user.User;
/**
* @author tastybento, Poslovitch
* @since 1.5.0
*/
public class BlueprintManagementPanel {
private static final String LOCALE_REF = "blueprint-management";
private BlueprintManagementPanel() {}
public static void openPanel(@NonNull User user, @NonNull GameModeAddon addon) {
PanelBuilder builder = new PanelBuilder()
.name(user.getTranslation(LOCALE_REF + "title"))
.size(54);
builder.build().open(user);
}
}

View File

@ -0,0 +1,48 @@
package world.bentobox.bentobox.panels;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBundle;
/**
* Displays the available BlueprintBundles to pick up as the island.
* @author Poslovitch, tastybento
* @since 1.5.0
*/
public class IslandCreationPanel {
private static final String LOCALE_REF = "island-creation.";
private IslandCreationPanel() {}
/**
* Shows the island creation panel for this Gamemode to this User.
* @param user the User to show the panel to.
* @param addon the addon to display the blueprint bundles from.
*/
public static void openPanel(@NonNull User user, @NonNull GameModeAddon addon) {
BentoBox plugin = BentoBox.getInstance();
PanelBuilder builder = new PanelBuilder()
.name(user.getTranslation(LOCALE_REF + "title"));
plugin.getBlueprintsManager().getBlueprintBundles(addon).forEach((id, bundle) -> {
PanelItemBuilder itemBuilder = new PanelItemBuilder()
.icon(bundle.getIcon())
.name(bundle.getDisplayName())
.description(bundle.getDescription())
.clickHandler((panel, user1, clickType, slot) -> {
user1.closeInventory();
// TODO create the island;
return true;
});
builder.item(itemBuilder.build());
});
builder.build().open(user);
}
}

View File

@ -50,74 +50,74 @@ public class ManagementPanel {
int i = 0;
List<? extends Addon> addons;
switch (view) {
case GAMEMODES:
addons = plugin.getAddonsManager().getGameModeAddons();
if (addons.isEmpty()) {
looksEmpty(builder, user);
break;
}
for (Addon addon : addons) {
GameModeAddon gameModeAddon = (GameModeAddon) addon;
PanelItem addonItem = new PanelItemBuilder()
.icon(addon.getDescription().getIcon())
.name(user.getTranslation(LOCALE_REF + "views.gamemodes.gamemode.name", TextVariables.NAME, addon.getDescription().getName()))
.description(user.getTranslation(LOCALE_REF + "views.gamemodes.gamemode.description",
"[islands]", String.valueOf(addon.getIslands().getIslandCount(gameModeAddon.getOverWorld()))))
.build();
builder.item(startSlot + i, addonItem);
PanelItem schems = new PanelItemBuilder()
.icon(Material.STRUCTURE_BLOCK)
.name(user.getTranslation(LOCALE_REF + "views.gamemodes.schems.name"))
.description(user.getTranslation(LOCALE_REF + "views.gamemodes.schems.description"))
.clickHandler((panel, user1, clickType, slot) -> {
user1.sendRawMessage("opening the admin schems menu (not implemented yet)");
return true;
})
.build();
builder.item(startSlot + i + 9, schems);
i++;
}
case GAMEMODES:
addons = plugin.getAddonsManager().getGameModeAddons();
if (addons.isEmpty()) {
looksEmpty(builder, user);
break;
case ADDONS:
addons = plugin.getAddonsManager().getEnabledAddons().stream().filter(addon -> !(addon instanceof GameModeAddon)).collect(Collectors.toList());
if (addons.isEmpty()) {
looksEmpty(builder, user);
break;
}
for (Addon addon : addons) {
PanelItem addonItem = new PanelItemBuilder()
.icon(addon.getDescription().getIcon())
.name(ChatColor.WHITE + addon.getDescription().getName())
.build();
}
for (Addon addon : addons) {
GameModeAddon gameModeAddon = (GameModeAddon) addon;
PanelItem addonItem = new PanelItemBuilder()
.icon(addon.getDescription().getIcon())
.name(user.getTranslation(LOCALE_REF + "views.gamemodes.gamemode.name", TextVariables.NAME, addon.getDescription().getName()))
.description(user.getTranslation(LOCALE_REF + "views.gamemodes.gamemode.description",
"[islands]", String.valueOf(addon.getIslands().getIslandCount(gameModeAddon.getOverWorld()))))
.build();
builder.item(startSlot + i, addonItem);
i++;
if (builder.slotOccupied(startSlot + i)) {
i = i+2;
}
}
break;
case HOOKS:
if (plugin.getHooks().getHooks().isEmpty()) {
looksEmpty(builder, user);
break;
}
for (Hook hook : plugin.getHooks().getHooks()) {
PanelItem hookItem = new PanelItemBuilder()
.icon(hook.getIcon())
.name(ChatColor.WHITE + hook.getPluginName())
.build();
builder.item(startSlot + i, addonItem);
builder.item(startSlot + i, hookItem);
i++;
if (builder.slotOccupied(startSlot + i)) {
i = i+2;
}
}
PanelItem blueprints = new PanelItemBuilder()
.icon(Material.STRUCTURE_BLOCK)
.name(user.getTranslation(LOCALE_REF + "views.gamemodes.blueprints.name"))
.description(user.getTranslation(LOCALE_REF + "views.gamemodes.blueprints.description"))
.clickHandler((panel, user1, clickType, slot) -> {
BlueprintManagementPanel.openPanel(user, gameModeAddon);
return true;
})
.build();
builder.item(startSlot + i + 9, blueprints);
i++;
}
break;
case ADDONS:
addons = plugin.getAddonsManager().getEnabledAddons().stream().filter(addon -> !(addon instanceof GameModeAddon)).collect(Collectors.toList());
if (addons.isEmpty()) {
looksEmpty(builder, user);
break;
}
for (Addon addon : addons) {
PanelItem addonItem = new PanelItemBuilder()
.icon(addon.getDescription().getIcon())
.name(ChatColor.WHITE + addon.getDescription().getName())
.build();
builder.item(startSlot + i, addonItem);
i++;
if (builder.slotOccupied(startSlot + i)) {
i = i+2;
}
}
break;
case HOOKS:
if (plugin.getHooks().getHooks().isEmpty()) {
looksEmpty(builder, user);
break;
}
for (Hook hook : plugin.getHooks().getHooks()) {
PanelItem hookItem = new PanelItemBuilder()
.icon(hook.getIcon())
.name(ChatColor.WHITE + hook.getPluginName())
.build();
builder.item(startSlot + i, hookItem);
i++;
if (builder.slotOccupied(startSlot + i)) {
i = i+2;
}
}
break;
}
// Setup a few more buttons
@ -168,15 +168,15 @@ public class ManagementPanel {
});
switch (view) {
case GAMEMODES:
gamemodesIconBuilder.glow(true);
break;
case ADDONS:
addonsIconBuilder.glow(true);
break;
case HOOKS:
hooksIconBuilder.glow(true);
break;
case GAMEMODES:
gamemodesIconBuilder.glow(true);
break;
case ADDONS:
addonsIconBuilder.glow(true);
break;
case HOOKS:
hooksIconBuilder.glow(true);
break;
}
builder.item(1, gamemodesIconBuilder.build());
@ -216,19 +216,19 @@ public class ManagementPanel {
.name(user.getTranslation(LOCALE_REF + "information.state.name"))
.description(user.getTranslation(LOCALE_REF + "information.state.description." + compatibility,
TextVariables.NAME, serverSoftware != null ? serverSoftware.toString() : user.getTranslation("general.invalid"),
TextVariables.VERSION, serverVersion != null ? serverVersion.toString() : user.getTranslation("general.invalid")));
TextVariables.VERSION, serverVersion != null ? serverVersion.toString() : user.getTranslation("general.invalid")));
switch (compatibility) {
case COMPATIBLE:
case SUPPORTED:
compatibilityItemBuilder.icon(Material.GREEN_CONCRETE);
break;
case NOT_SUPPORTED:
compatibilityItemBuilder.icon(Material.ORANGE_CONCRETE);
break;
case INCOMPATIBLE:
compatibilityItemBuilder.icon(Material.RED_CONCRETE);
break;
case COMPATIBLE:
case SUPPORTED:
compatibilityItemBuilder.icon(Material.GREEN_CONCRETE);
break;
case NOT_SUPPORTED:
compatibilityItemBuilder.icon(Material.ORANGE_CONCRETE);
break;
case INCOMPATIBLE:
compatibilityItemBuilder.icon(Material.RED_CONCRETE);
break;
}
builder.item(7, compatibilityItemBuilder.build());

View File

@ -0,0 +1,185 @@
package world.bentobox.bentobox.schems;
import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.DyeColor;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Horse;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.blueprints.Blueprint;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBlock;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintCreatureSpawner;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity;
/**
* This class converts a schem to a blueprint
* @author tastybento
* @since 1.5.0
*/
public class Converter {
private static final String ATTACHED_YAML_PREFIX = "attached.";
private static final String BEDROCK = "bedrock";
private static final String BLOCKS_YAML_PREFIX = "blocks.";
private static final String COLOR = "color";
private static final String ENTITIES_YAML_PREFIX = "entities.";
private static final String INVENTORY = "inventory";
private static final String LINES = "lines";
public Blueprint convert(@NonNull YamlConfiguration bc) {
Blueprint bp = new Blueprint();
// Bedrock
if (bc.contains(BEDROCK)) {
bp.setBedrock(getVector(bc.getString(BEDROCK)));
}
// Normal blocks
if (bc.isConfigurationSection(BLOCKS_YAML_PREFIX)) {
bp.setBlocks(bc.getConfigurationSection(BLOCKS_YAML_PREFIX).getKeys(false).stream()
// make configuration section from key
.map(k -> bc.getConfigurationSection(BLOCKS_YAML_PREFIX + k))
// Check the config section contains block data key "bd"
.filter(cs -> cs.contains("bd"))
// Convert it
.map(this::convertBlock)
// Collect into a map
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
}
// Attached blocks
if (bc.isConfigurationSection(ATTACHED_YAML_PREFIX)) {
bp.setAttached(bc.getConfigurationSection(ATTACHED_YAML_PREFIX).getKeys(false).stream()
// make configuration section from key
.map(k -> bc.getConfigurationSection(ATTACHED_YAML_PREFIX + k))
// Check the config section contains block data key "bd"
.filter(cs -> cs.contains("bd"))
// Convert it
.map(this::convertBlock)
// Collect into a map
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
}
// Entities
if (bc.isConfigurationSection(ENTITIES_YAML_PREFIX)) {
bp.setEntities(bc.getConfigurationSection(ENTITIES_YAML_PREFIX).getKeys(false).stream()
// make configuration section from key
.map(k -> bc.getConfigurationSection(ENTITIES_YAML_PREFIX + k))
// Convert it
.map(this::convertEntity)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
}
return bp;
}
private Entry<Vector, BlueprintBlock> convertBlock(ConfigurationSection config) {
String blockData = config.getString("bd");
// Make block
BlueprintBlock block = new BlueprintBlock(blockData);
// Signs
if (config.contains(LINES)) {
block.setSignLines(config.getStringList(LINES));
}
// Chests, in general
if (config.isConfigurationSection(INVENTORY)) {
ConfigurationSection inv = config.getConfigurationSection(INVENTORY);
block.setInventory(
inv.getKeys(false).stream()
.collect(Collectors.toMap(i -> Integer.valueOf(i), i -> (ItemStack)inv.get(i)))
);
}
// Mob spawners
if (blockData.equals("minecraft:spawner")) {
BlueprintCreatureSpawner spawner = new BlueprintCreatureSpawner();
spawner.setSpawnedType(EntityType.valueOf(config.getString("spawnedType", "PIG")));
spawner.setMaxNearbyEntities(config.getInt("maxNearbyEntities", 16));
spawner.setMaxSpawnDelay(config.getInt("maxSpawnDelay", 2*60*20));
spawner.setMinSpawnDelay(config.getInt("minSpawnDelay", 5*20));
spawner.setDelay(config.getInt("delay", -1));
spawner.setRequiredPlayerRange(config.getInt("requiredPlayerRange", 16));
spawner.setSpawnRange(config.getInt("spawnRange", 4));
block.setCreatureSpawner(spawner);
}
// Vector
Vector vector = getVector(config.getName());
// Return entry
return new AbstractMap.SimpleEntry<>(vector, block);
}
private Entry<Vector, List<BlueprintEntity>> convertEntity(ConfigurationSection en) {
// Position
Vector vector = getVector(en.getName());
// Create a list of entities at this position
List<BlueprintEntity> list = en.getKeys(false).stream()
.map(en::getConfigurationSection)
.map(this::createEntity)
.filter(Objects::nonNull)
.collect(Collectors.toList());
return new AbstractMap.SimpleEntry<>(vector, list);
}
/**
* Try to create a blueprint entity
* @param cs - yaml configuration section
* @return blueprint entity, or null if it fails
*/
private BlueprintEntity createEntity(ConfigurationSection cs) {
try {
BlueprintEntity be = new BlueprintEntity();
if (cs.contains("type")) {
be.setType(EntityType.valueOf(cs.getString("type")));
}
if (cs.contains("name")) {
be.setCustomName(cs.getString("name"));
}
if (cs.contains(COLOR)) {
be.setColor(DyeColor.valueOf(cs.getString(COLOR)));
}
if (cs.contains("tamed")) {
be.setTamed(cs.getBoolean("tamed"));
}
if (cs.contains("chest")) {
be.setChest(cs.getBoolean("chest"));
}
if (!cs.getBoolean("adult")) {
be.setAdult(false);
}
if (cs.contains("style")) {
be.setStyle(Horse.Style.valueOf(cs.getString("style", "NONE")));
}
if (cs.contains("domestication")) {
be.setDomestication(cs.getInt("domestication"));
}
if (cs.isConfigurationSection(INVENTORY)) {
ConfigurationSection inv = cs.getConfigurationSection(INVENTORY);
be.setInventory(inv.getKeys(false).stream()
.collect(Collectors.toMap(i -> Integer.valueOf(i), i -> (ItemStack)inv.get(i))));
}
return be;
} catch (Exception e) {
Bukkit.getLogger().severe("Failed to import entity, skipping...");
}
return null;
}
private Vector getVector(String name) {
String[] pos = name.split(",");
int x = Integer.valueOf(pos[0]);
int y = Integer.valueOf(pos[1]);
int z = Integer.valueOf(pos[2]);
return new Vector(x,y,z);
}
}

View File

@ -0,0 +1,102 @@
package world.bentobox.bentobox.schems;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import world.bentobox.bentobox.BentoBox;
/**
* This class loads schems so they can be converted to blueprints
* @author tastybento
* @since 1.5.0
*/
public class SchemLoader {
private static final String LOAD_ERROR = "Could not load schems file - does not exist : ";
private YamlConfiguration blockConfig;
private BentoBox plugin;
private File schemFolder;
public SchemLoader(BentoBox plugin, File schemFolder) {
this.plugin = plugin;
this.schemFolder = schemFolder;
blockConfig = new YamlConfiguration();
}
/**
* @return the blockConfig
*/
public YamlConfiguration getBlockConfig() {
return blockConfig;
}
/**
* Load a file to clipboard
* @param fileName - filename in schems folder
* @throws FileNotFoundException - if a file cannot be found
* @throws IOException - if there's a load error with unziping or name
* @throws InvalidConfigurationException - the YAML of the schem is at fault
*/
public void load(String fileName) throws FileNotFoundException, IOException, InvalidConfigurationException {
File zipFile = new File(schemFolder, fileName + ".schem");
if (!zipFile.exists()) {
plugin.logError(LOAD_ERROR + zipFile.getName());
throw new FileNotFoundException(LOAD_ERROR + zipFile.getName());
}
unzip(zipFile.getAbsolutePath());
File file = new File(schemFolder, fileName);
if (!file.exists()) {
plugin.logError(LOAD_ERROR + file.getName());
throw new FileNotFoundException(LOAD_ERROR + file.getName());
}
blockConfig.load(file);
Files.delete(file.toPath());
}
private void unzip(final String zipFilePath) throws IOException {
Path path = Paths.get(zipFilePath);
if (!(path.toFile().exists())) {
throw new FileNotFoundException("No file exists to unzip!");
}
try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipFilePath))) {
ZipEntry entry = zipInputStream.getNextEntry();
while (entry != null) {
Path filePath = Paths.get(path.getParent().toString(), entry.getName());
if (!entry.isDirectory()) {
unzipFiles(zipInputStream, filePath);
} else {
Files.createDirectories(filePath);
}
zipInputStream.closeEntry();
entry = zipInputStream.getNextEntry();
}
}
}
private void unzipFiles(final ZipInputStream zipInputStream, final Path unzipFilePath) throws IOException {
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(unzipFilePath.toAbsolutePath().toString()))) {
byte[] bytesIn = new byte[1024];
int read;
while ((read = zipInputStream.read(bytesIn)) != -1) {
bos.write(bytesIn, 0, read);
}
}
}
}

View File

@ -0,0 +1,129 @@
package world.bentobox.bentobox.schems;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.Objects;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.World;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.blueprints.Blueprint;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBundle;
import world.bentobox.bentobox.managers.BlueprintsManager;
public class SchemToBlueprint {
public static final @NonNull String DEFAULT_SCHEM_NAME = "island";
public static final @NonNull String FILE_EXTENSION = ".schem";
public static final @NonNull String FOLDER_NAME = "schems";
private BentoBox plugin;
/**
* @param plugin - plugin
*/
public SchemToBlueprint(BentoBox plugin) {
this.plugin = plugin;
}
/**
* Converts schems to blueprints and blueprint bundles
* @param addon - GameModeAddon
*/
public void convertSchems(GameModeAddon addon) {
File schems = new File(addon.getDataFolder(), FOLDER_NAME);
if (!schems.exists()) {
return;
}
// Convert all schems in folder
// Look through the folder
FilenameFilter schemFilter = (File dir, String name) -> name.toLowerCase(java.util.Locale.ENGLISH).endsWith(FILE_EXTENSION)
&& !name.toLowerCase(java.util.Locale.ENGLISH).startsWith("nether-")
&& !name.toLowerCase(java.util.Locale.ENGLISH).startsWith("end-");
Arrays.stream(Objects.requireNonNull(schems.list(schemFilter)))
.map(name -> name.substring(0, name.length() - FILE_EXTENSION.length()))
.forEach(name -> importSchemSet(addon, schems, name));
File newDir = new File(addon.getDataFolder(), FOLDER_NAME + "_converted");
try {
Files.move(schems.toPath(), newDir.toPath());
} catch (IOException e) {
plugin.logError("Could not move schems folder: " + e.getLocalizedMessage());
}
}
/**
* Imports one schem set to the game mode
* @param addon - game mode addon
* @param schems
* @param name
*/
private void importSchemSet(GameModeAddon addon, File schems, String name) {
// Make a new blueprint bundle
BlueprintBundle bb = new BlueprintBundle();
// TODO: This is just placeholder text
if (name.equalsIgnoreCase("island")) {
bb.setUniqueId(BlueprintsManager.DEFAULT_BUNDLE_NAME);
bb.setDisplayName(ChatColor.YELLOW + "The Original");
bb.setDescription(ChatColor.AQUA + "Standard set of islands");
bb.setIcon(Material.GRASS);
} else {
bb.setUniqueId(name);
bb.setDisplayName(name + " island");
bb.setIcon(Material.GRASS_PATH);
}
Blueprint bp = loadSchemSaveBlueprint(addon, schems, name);
if (bp != null) {
bb.setBlueprint(World.Environment.NORMAL, bp);
plugin.getBlueprintsManager().saveBlueprint(addon, bp);
bb.setDescription(ChatColor.GREEN + "Includes an Overworld island");
}
bp = loadSchemSaveBlueprint(addon, schems, "nether-" + name);
if (bp != null) {
bb.setBlueprint(World.Environment.NETHER, bp);
plugin.getBlueprintsManager().saveBlueprint(addon, bp);
bb.setDescription(ChatColor.RED + "Includes a Nether island");
}
bp = loadSchemSaveBlueprint(addon, schems, "end-" + name);
if (bp != null) {
bb.setBlueprint(World.Environment.THE_END, bp);
plugin.getBlueprintsManager().saveBlueprint(addon, bp);
bb.setDescription(ChatColor.GOLD + "Includes an End island");
}
// Add it to the blueprint manager
plugin.getBlueprintsManager().saveBlueprintBundle(addon, bb);
// Done!
}
private Blueprint loadSchemSaveBlueprint(GameModeAddon addon, File schems, String name) {
try {
SchemLoader loader = new SchemLoader(plugin, schems);
loader.load(name);
plugin.log("Loaded " + name + ".schem");
// Convert blueprint
plugin.log("Converting " + name + ".schem to a blueprint");
Blueprint bp = new Converter().convert(loader.getBlockConfig());
bp.setName(name);
plugin.log("Saving blueprint");
plugin.getBlueprintsManager().saveBlueprint(addon, bp);
return bp;
} catch (FileNotFoundException ignore) {
// Ignore
} catch (Exception e) {
plugin.logError("Could not convert " + name + " schem, skipping!");
e.printStackTrace();
}
return null;
}
}

View File

@ -80,7 +80,7 @@ island:
# These set the minimum and maximum size of a name.
min-length: 4
max-length: 20
# Number of blocks to paste per tick when pasting a schem
# Number of blocks to paste per tick when pasting blueprints
# Smaller values will help reduce noticeable lag but will make pasting take longer
paste-speed: 1000
web:

View File

@ -185,10 +185,10 @@ commands:
already-spawn: "&cThis island is already a spawn!"
no-island-here: "&cThere is no island here."
confirmation: "&cAre you sure you want to set this Island as the spawn for this world?"
schem:
blueprint:
parameters: "<load/copy/paste/pos1/pos2/save>"
description: "manipulate schems"
copy-first: "&cCopy a schem first!"
description: "manipulate blueprints"
copy-first: "&cCopy first!"
file-exists: "&cFile already exists, overwrite?"
no-such-file: "&cNo such file!"
could-not-load: "&cCould not load that file!"
@ -206,14 +206,14 @@ commands:
parameters: "[air]"
description: "copy the clipboard set by pos1 and pos2 and optionally the air blocks"
load:
parameters: "<schem name>"
description: "load schem into the clipboard"
parameters: "<name>"
description: "load blueprint into the clipboard"
list:
description: "list available schems"
no-schems: "&cNo schems in schems folder!"
available-schems: "&aThese schems are available for loading:"
description: "list available blueprints"
no-blueprints: "&cNo blueprints in blueprints folder!"
available-blueprints: "&aThese blueprints are available for loading:"
origin:
description: "set the schem's origin to your position"
description: "set the blueprint's origin to your position"
paste:
description: "paste the clipboard to your location"
pasting: "&aPasting..."
@ -222,7 +222,7 @@ commands:
pos2:
description: "set 2nd corner of cuboid clipboard"
save:
parameters: "<schem name>"
parameters: "<blueprint name>"
description: "save the copied clipboard"
resetflags:
description: "Reset all islands to default flag settings in config.yml"
@ -307,13 +307,13 @@ commands:
teleporting: "&aTeleporting you to the spawn."
no-spawn: "&cThere is no spawn in this world."
create:
description: "create an island, using optional schem (requires permission)"
parameters: "<schem>"
description: "create an island, using optional blueprint (requires permission)"
parameters: "<blueprint>"
too-many-islands: "&cThere are too many islands in this world: there isn't enough room for yours to be created."
unable-create-island: "&cYour island could not be generated, please contact an administrator."
creating-island: "&aCreating your island, please wait a moment..."
pick-world: "&cPick a world from [worlds]."
unknown-schem: "&cThat schem has not been loaded yet."
pick: "&aPick an island"
unknown-blueprint: "&cThat blueprint has not been loaded yet."
info:
description: "display info about your island or the player's island"
parameters: "<player>"
@ -329,7 +329,7 @@ commands:
no-neighbors: "&cYou have no immediate neighboring islands!"
reset:
description: "restart your island and remove the old one"
parameters: "<schem>"
parameters: "<blueprint>"
must-remove-members: "&cYou must remove all members from your island before you can restart it (/island team kick <player>)."
none-left: "&cYou have no more resets left!"
resets-left: "&cYou have [number] resets left"
@ -1009,9 +1009,9 @@ management:
gamemodes:
name: "&6Gamemodes"
description: "&eClick &ato display currently loaded Gamemodes"
schems:
name: "&6Schems"
description: "&aOpens the Admin Schem menu."
blueprints:
name: "&6Blueprints"
description: "&aOpens the Admin Blueprint menu."
gamemode:
name: "&f[name]"
description: |+

View File

@ -184,7 +184,7 @@ commands:
already-spawn: "&cEsta isla ya es un spawn!"
no-island-here: "&cNo hay isla aqui."
confirmation: "&cEstás seguro de que quieres establecer esta isla como el spawn de este mundo?"
schem:
blueprint:
parameters: "<load/copy/paste/pos1/pos2/save>"
description: "manipular esquemas"
copy-first: "&cCopia un esquema primero!"
@ -202,12 +202,12 @@ commands:
parameters: "[air]"
description: "Copie el conjunto de portapapeles por Posición 1 y Posición 2 y, opcionalmente, los bloques de aire."
load:
parameters: "<schem name>"
parameters: "<blueprints name>"
description: "Cargar esquema en el portapapeles"
list:
description: "listar esquemas disponibles"
no-schems: "&cNo hay esquemas en la carpeta de esquemas!"
available-schems: "&aEstos esquemas están disponibles para cargar:"
no-blueprints: "&cNo hay esquemas en la carpeta de esquemas!"
available-blueprints: "&aEstos esquemas están disponibles para cargar:"
origin:
description: "Establece el origen del esquema a tu posición"
paste:
@ -218,7 +218,7 @@ commands:
pos2:
description: "establecer la 2da esquina del portapapeles cuboide"
save:
parameters: "<schem name>"
parameters: "<blueprint name>"
description: "Guardar el portapapeles copiado"
resetflags:
description: "Restablecer todas las islas a la configuración de las banderas predeterminadas en config.yml"
@ -287,18 +287,18 @@ commands:
no-spawn: "&cNo hay un spawn en este mundo."
create:
description: "crear una isla, usando un esquema opcional (requiere permiso)"
parameters: "<schem>"
parameters: "<blueprint>"
too-many-islands: "&cHay demasiadas islas en este mundo: no hay suficiente espacio para que las tuyas sean creadas."
unable-create-island: "&cSu isla no se pudo generar, póngase en contacto con un administrador."
creating-island: "&aCreando tu isla, espera un momento..."
pick-world: "&cElige un mundo: [worlds]."
unknown-schem: "&cEse esquema no se ha cargado todavía."
unknown-blueprint: "&cEse esquema no se ha cargado todavía."
info:
description: "Muestra información sobre tu isla o la isla del jugador."
parameters: "<player>"
reset:
description: "reinicia tu isla y elimina la antigua"
parameters: "<schem>"
parameters: "<blueprint>"
must-remove-members: "&cDebes eliminar todos los miembros de tu isla antes de poder reiniciarla (/island team kick <player>)."
none-left: "&cNo te quedan más reinicios.!"
resets-left: "&cTienes [number] reinicios mas"
@ -959,9 +959,9 @@ management:
gamemodes:
name: "&6Modos de juegos"
description: "&eClick &apara mostrar los modos de juegos cargados actualmente"
schems:
name: "&6Schems"
description: "&aAbre el menú Admin de Schem."
blueprints:
name: "&6Blueprints"
description: "&aAbre el menú Admin de Blueprint."
addons:
name: "&6Addons"
description: "&eClick &apara mostrar los Addons cargados actualmente"

View File

@ -148,10 +148,10 @@ commands:
description: "プレイヤーのランクを設定する"
unknown-rank: "&c不明ランク!"
rank-set: "&2[from] から [to] に設定されたランク。"
schem:
blueprint:
parameters: "<load><copy><paste><pos1><pos2><save>"
description: "schems の操作"
copy-first: "&c最初に schem をコピー!"
description: "blueprints の操作"
copy-first: "&c最初に blueprint をコピー!"
file-exists: "&cファイルは既に存在し、上書きしますか?"
no-such-file: "&cそのようなファイルはありません!"
could-not-load: "&cそのファイルを読み込めませんでした!"

View File

@ -184,7 +184,7 @@ commands:
already-spawn: "&cŠī sala jau ir uzstādīta kā sākuma sala!"
no-island-here: "&cŠeit nav neveinas salas."
confirmation: "&cVai tiešām vēlies uzstādīt šo salu kā sākuma salu?"
schem:
blueprint:
parameters: "<load/copy/paste/pos1/pos2/save>"
description: "manipulē ar shēmām"
copy-first: "&cKopē shēmu sākumā!"
@ -206,8 +206,8 @@ commands:
description: "ielādē shēmu starpliktuvē"
list:
description: "attaino visas pieejamās shēmas"
no-schems: "&cNav shēmas iekš schems mapītes!"
available-schems: "&aŠīs shēmas ir pieejamas ielādei:"
no-blueprints: "&cNav shēmas iekš blueprints mapītes!"
available-blueprints: "&aŠīs shēmas ir pieejamas ielādei:"
origin:
description: "uzstāda shēmas sākuma punktu tavā pozīcijā"
paste:
@ -310,7 +310,7 @@ commands:
unable-create-island: "&cNeizdevās izveidot tavu salu, ziņo par kļūdu administratoram."
creating-island: "&aTiek veidota tava sala. Uzgaidi mirklīti..."
pick-world: "&cIzvēkies pasauli no [worlds]."
unknown-schem: "&cŠī shēma nav ielādēta vai tā neeksistē."
unknown-blueprint: "&cŠī shēma nav ielādēta vai tā neeksistē."
info:
description: "parāda informāciju par tavu vai spēlētāja salu"
parameters: "<spēlētājs>"
@ -1022,9 +1022,9 @@ management:
gamemodes:
name: "&6Spēles režīmi"
description: "&eUzspied&a, lai redzētu uzstādītos spēles režīmus."
schems:
name: "&6Shēmas"
description: "&aAtver admina shēmu izvēlni."
blueprints:
name: "&6Blueprints"
description: "&aAtver admina blueprint izvēlni."
addons:
name: "&6Papildinājumi"
description: "&eUzspied&a, lai redzētu uzstādītos spēles papildinājumus."

View File

@ -121,10 +121,10 @@ commands:
description: "ustawia role gracza na swojej wyspie"
unknown-rank: "&cNieznana rola!"
rank-set: "&aRola ustawiona z [from] na [to]."
schem:
blueprint:
parameters: "<load><copy><paste><pos1><pos2><save>"
description: "manipuluj schematem"
copy-first: "&cNajpierw skopiuj schemat!"
description: "manipuluj blueprint"
copy-first: "&cNajpierw skopiuj blueprint!"
file-exists: "&cPlik już istnieje, nadpisać?"
no-such-file: "&cNie ma takiego pliku!"
could-not-load: "&cNie można załadować tego pliku!"

View File

@ -147,7 +147,7 @@ commands:
description: "设置玩家在他们岛屿上的头衔"
unknown-rank: "&c未知头衔"
rank-set: "&a头衔由 [from] 设置为 [to]。"
schem:
blueprint:
parameters: "<load/copy/paste/pos1/pos2/save>"
description: "调整规划方案"
copy-first: "&c请先复制一份规划方案"
@ -165,7 +165,7 @@ commands:
parameters: "[air]"
description: "复制 pos1 和 pos2 之间设置的方块(或使用空气方块)到剪切板"
load:
parameters: "<schem name>"
parameters: "<blueprint name>"
description: "加载规划文件到剪切板"
origin:
parameters: ""
@ -180,7 +180,7 @@ commands:
parameters: ""
description: "设置立方体剪切板的第二个顶点"
save:
parameters: "<schem name>"
parameters: "<blueprint name>"
description: "保存已复制的剪切板"
world:
description: "管理世界设置"

View File

@ -159,7 +159,7 @@ commands:
already-spawn: "&c這個島嶼早就設定了重生點!"
no-island-here: "&c沒有在您的位置找到任何島嶼。"
confirmation: "&c您確定要在這個世界中把現在的位置設置為島嶼的重生點?"
schem:
blueprint:
parameters: "<load/copy/paste/pos1/pos2/save>"
description: "調整規劃方案"
copy-first: "&c請先複製一份規劃方案!"
@ -177,7 +177,7 @@ commands:
parameters: "[air]"
description: "複製 pos1 和 pos2 之間設置的方塊(或使用空氣方塊)到剪切板"
load:
parameters: "<schem name>"
parameters: "<blueprint name>"
description: "加載規劃文件到剪切板"
origin:
parameters: ""
@ -192,7 +192,7 @@ commands:
parameters: ""
description: "設置立方體剪切板的第二個頂點"
save:
parameters: "<schem name>"
parameters: "<blueprint name>"
description: "保存已復制的剪切板"
world:
description: "管理世界設置"
@ -250,19 +250,19 @@ commands:
teleporting: "&a正在把您傳送到重生點。"
no-spawn: "&c這個世界並沒有重生點。"
create:
description: "創建島嶼, 可以使用指定的Schem (需要權限)"
parameters: "<schem>"
description: "創建島嶼, 可以使用指定的blueprint (需要權限)"
parameters: "<blueprint>"
too-many-islands: "&c這個世界已經有太多島嶼了: 所以這裏沒有足夠的空間去創建您的島嶼。"
unable-create-island: "&c您的島嶼無法被生成, 請聯繫管理員。"
creating-island: "&a正在創建島嶼, 請耐心等候......"
pick-world: "&c請從 [worlds] 中選擇世界。"
unknown-schem: "&c這一個Schem還未被加載。"
unknown-blueprint: "&c這一個blueprint還未被加載。"
info:
description: "顯示關於您或某一個玩家島嶼的信息"
parameters: "<player>"
reset:
description: "重置您的島嶼, 並且刪除舊的島嶼"
parameters: "<schem>"
parameters: "<blueprint>"
must-remove-members: "&c在您可以重製您的島嶼之前, 您必須移除掉所有的島上成員(/island team kick <player>)。"
none-left: "&c您沒有重置次數了!"
resets-left: "&c您還有 [number] 次重置機會"

View File

@ -1,7 +1,7 @@
/**
*
*/
package world.bentobox.bentobox.api.commands.admin.schem;
package world.bentobox.bentobox.api.commands.admin.blueprints;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@ -31,7 +31,10 @@ import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.Settings;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.commands.admin.blueprints.AdminBlueprintCommand;
import world.bentobox.bentobox.api.commands.admin.blueprints.AdminBlueprintListCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.managers.BlueprintsManager;
import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.LocalesManager;
@ -41,15 +44,15 @@ import world.bentobox.bentobox.managers.LocalesManager;
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class, BentoBox.class, User.class })
public class AdminSchemListCommandTest {
public class AdminBlueprintsListCommandTest {
@Mock
private AdminSchemCommand ac;
private AdminBlueprintCommand ac;
@Mock
private Addon addon;
@Mock
private User user;
private AdminSchemListCommand list;
private AdminBlueprintListCommand list;
private File dataFolder;
/**
@ -75,7 +78,7 @@ public class AdminSchemListCommandTest {
// Parent command has no aliases
when(ac.getAddon()).thenReturn(addon);
when(ac.getLabel()).thenReturn("schem");
when(ac.getLabel()).thenReturn("blueprint");
when(ac.getSubCommandAliases()).thenReturn(new HashMap<>());
when(ac.getTopLabel()).thenReturn("admin");
@ -90,7 +93,7 @@ public class AdminSchemListCommandTest {
when(addon.getDataFolder()).thenReturn(dataFolder);
// Class
list = new AdminSchemListCommand(ac);
list = new AdminBlueprintListCommand(ac);
}
@ -108,24 +111,24 @@ public class AdminSchemListCommandTest {
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.schem.AdminSchemListCommand#AdminSchemListCommand(world.bentobox.bentobox.api.commands.admin.schem.AdminSchemCommand)}.
* Test method for {@link world.bentobox.bentobox.api.commands.admin.blueprints.AdminBlueprintListCommand#AdminBlueprintListCommand(world.bentobox.bentobox.api.commands.admin.blueprints.AdminBlueprintCommand)}.
*/
@Test
public void testAdminSchemListCommand() {
public void testAdminBlueprintListCommand() {
assertEquals("list", list.getLabel());
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.schem.AdminSchemListCommand#setup()}.
* Test method for {@link world.bentobox.bentobox.api.commands.admin.blueprints.AdminBlueprintListCommand#setup()}.
*/
@Test
public void testSetup() {
assertEquals("commands.admin.schem.list.description", list.getDescription());
assertEquals("commands.admin.blueprint.list.description", list.getDescription());
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.schem.AdminSchemListCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
* Test method for {@link world.bentobox.bentobox.api.commands.admin.blueprints.AdminBlueprintListCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testCanExecute() {
@ -134,53 +137,53 @@ public class AdminSchemListCommandTest {
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.schem.AdminSchemListCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
* Test method for {@link world.bentobox.bentobox.api.commands.admin.blueprints.AdminBlueprintListCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringNoSchemsFolder() {
public void testExecuteUserStringListOfStringNoBlueprintsFolder() {
assertFalse(list.execute(user, "", Collections.emptyList()));
Mockito.verify(user).sendMessage("commands.admin.schem.list.no-schems");
Mockito.verify(user).sendMessage("commands.admin.blueprint.list.no-blueprints");
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.schem.AdminSchemListCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
* Test method for {@link world.bentobox.bentobox.api.commands.admin.blueprints.AdminBlueprintListCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringNoSchemsFilesEmptyFolder() {
File schemFolder = new File(dataFolder, "schems");
schemFolder.mkdirs();
public void testExecuteUserStringListOfStringNoBlueprintsFilesEmptyFolder() {
File blueprintFolder = new File(dataFolder, "blueprints");
blueprintFolder.mkdirs();
assertFalse(list.execute(user, "", Collections.emptyList()));
Mockito.verify(user).sendMessage("commands.admin.schem.list.no-schems");
Mockito.verify(user).sendMessage("commands.admin.blueprint.list.no-blueprints");
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.schem.AdminSchemListCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
* Test method for {@link world.bentobox.bentobox.api.commands.admin.blueprints.AdminBlueprintListCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
* @throws IOException
*/
@Test
public void testExecuteUserStringListOfStringNoSchemsFiles() throws IOException {
File schemFolder = new File(dataFolder, "schems");
schemFolder.mkdirs();
new File(schemFolder, "random.txt").createNewFile();
public void testExecuteUserStringListOfStringNoBlueprintsFiles() throws IOException {
File blueprintFolder = new File(dataFolder, "blueprints");
blueprintFolder.mkdirs();
new File(blueprintFolder, "random.txt").createNewFile();
assertFalse(list.execute(user, "", Collections.emptyList()));
Mockito.verify(user).sendMessage("commands.admin.schem.list.no-schems");
Mockito.verify(user).sendMessage("commands.admin.blueprint.list.no-blueprints");
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.schem.AdminSchemListCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
* Test method for {@link world.bentobox.bentobox.api.commands.admin.blueprints.AdminBlueprintListCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
* @throws IOException
*/
@Test
public void testExecuteUserStringListOfStringWithSchemsFiles() throws IOException {
File schemFolder = new File(dataFolder, "schems");
schemFolder.mkdirs();
new File(schemFolder, "island.schem").createNewFile();
new File(schemFolder, "nether-island.schem").createNewFile();
new File(schemFolder, "end-island.schem").createNewFile();
new File(schemFolder, "random.txt").createNewFile();
public void testExecuteUserStringListOfStringWithBlueprintsFiles() throws IOException {
File blueprintFolder = new File(dataFolder, BlueprintsManager.FOLDER_NAME);
blueprintFolder.mkdirs();
new File(blueprintFolder, "island" + BlueprintsManager.BLUEPRINT_SUFFIX).createNewFile();
new File(blueprintFolder, "nether-island" + BlueprintsManager.BLUEPRINT_SUFFIX).createNewFile();
new File(blueprintFolder, "end-island" + BlueprintsManager.BLUEPRINT_SUFFIX).createNewFile();
new File(blueprintFolder, "random.txt").createNewFile();
assertTrue(list.execute(user, "", Collections.emptyList()));
Mockito.verify(user).sendMessage("commands.admin.schem.list.available-schems");
Mockito.verify(user).sendMessage("commands.admin.blueprint.list.available-blueprints");
Mockito.verify(user).sendRawMessage("island");
Mockito.verify(user).sendRawMessage("nether-island");
Mockito.verify(user).sendRawMessage("end-island");

View File

@ -6,13 +6,16 @@ package world.bentobox.bentobox.api.commands.island;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.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.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
@ -33,17 +36,16 @@ 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.commands.CompositeCommand;
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.blueprints.Clipboard;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.BlueprintsManager;
import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.PlayersManager;
import world.bentobox.bentobox.managers.SchemsManager;
import world.bentobox.bentobox.managers.island.NewIsland;
import world.bentobox.bentobox.managers.island.NewIsland.Builder;
@ -65,17 +67,18 @@ public class IslandCreateCommandTest {
@Mock
private Builder builder;
@Mock
private SchemsManager sm;
@Mock
private BentoBox plugin;
@Mock
private Settings settings;
@Mock
private CompositeCommand ic;
@Mock
private BlueprintsManager bpm;
/**
* @throws java.lang.Exception
*/
@SuppressWarnings("deprecation")
@Before
public void setUp() throws Exception {
// Set up plugin
@ -101,6 +104,10 @@ public class IslandCreateCommandTest {
// Set up user already
User.getInstance(player);
// Addon
GameModeAddon addon = mock(GameModeAddon.class);
// Parent command has no aliases
when(ic.getSubCommandAliases()).thenReturn(new HashMap<>());
when(ic.getParameters()).thenReturn("parameters");
@ -108,13 +115,14 @@ public class IslandCreateCommandTest {
when(ic.getPermissionPrefix()).thenReturn("permission.");
when(ic.getUsage()).thenReturn("");
when(ic.getSubCommand(Mockito.anyString())).thenReturn(Optional.empty());
when(ic.getAddon()).thenReturn(addon);
// No island for player to begin with (set it later in the tests)
when(im.hasIsland(Mockito.any(), Mockito.eq(uuid))).thenReturn(false);
when(im.isOwner(Mockito.any(), Mockito.eq(uuid))).thenReturn(false);
when(im.hasIsland(any(), eq(uuid))).thenReturn(false);
when(im.isOwner(any(), eq(uuid))).thenReturn(false);
// Has team
when(im.inTeam(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
when(im.inTeam(any(), eq(uuid))).thenReturn(true);
when(plugin.getIslands()).thenReturn(im);
@ -127,23 +135,21 @@ public class IslandCreateCommandTest {
when(Bukkit.getScheduler()).thenReturn(sch);
// IWM friendly name
when(iwm.getFriendlyName(Mockito.any())).thenReturn("BSkyBlock");
when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
when(plugin.getIWM()).thenReturn(iwm);
// NewIsland
PowerMockito.mockStatic(NewIsland.class);
when(NewIsland.builder()).thenReturn(builder);
when(builder.player(Mockito.any())).thenReturn(builder);
when(builder.player(any())).thenReturn(builder);
when(builder.name(Mockito.anyString())).thenReturn(builder);
when(builder.world(Mockito.any())).thenReturn(builder);
when(builder.reason(Mockito.any())).thenReturn(builder);
when(builder.world(any())).thenReturn(builder);
when(builder.addon(addon)).thenReturn(builder);
when(builder.reason(any())).thenReturn(builder);
when(builder.build()).thenReturn(mock(Island.class));
// Schems manager
Map<String, Clipboard> map = new HashMap<>();
when(sm.get(Mockito.any())).thenReturn(map);
when(plugin.getSchemsManager()).thenReturn(sm);
// Bundles manager
when(plugin.getBlueprintsManager()).thenReturn(bpm);
// Command
cc = new IslandCreateCommand(ic);
@ -182,9 +188,9 @@ public class IslandCreateCommandTest {
*/
@Test
public void testCanExecuteUserStringListOfStringHasIsland() {
when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(true);
when(im.hasIsland(any(), Mockito.any(UUID.class))).thenReturn(true);
assertFalse(cc.canExecute(user, "", Collections.emptyList()));
Mockito.verify(user).sendMessage(Mockito.eq("general.errors.already-have-island"));
verify(user).sendMessage(eq("general.errors.already-have-island"));
}
/**
@ -192,10 +198,10 @@ public class IslandCreateCommandTest {
*/
@Test
public void testCanExecuteUserStringListOfStringInTeam() {
when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(false);
when(im.inTeam(Mockito.any(), Mockito.any(UUID.class))).thenReturn(true);
when(im.hasIsland(any(), Mockito.any(UUID.class))).thenReturn(false);
when(im.inTeam(any(), Mockito.any(UUID.class))).thenReturn(true);
assertFalse(cc.canExecute(user, "", Collections.emptyList()));
Mockito.verify(user).sendMessage(Mockito.eq("general.errors.already-have-island"));
verify(user).sendMessage(eq("general.errors.already-have-island"));
}
@ -204,12 +210,12 @@ public class IslandCreateCommandTest {
*/
@Test
public void testCanExecuteUserStringListOfStringTooManyIslands() {
when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(false);
when(im.inTeam(Mockito.any(), Mockito.any(UUID.class))).thenReturn(false);
when(iwm.getMaxIslands(Mockito.any())).thenReturn(100);
when(im.getIslandCount(Mockito.any())).thenReturn(100);
when(im.hasIsland(any(), Mockito.any(UUID.class))).thenReturn(false);
when(im.inTeam(any(), Mockito.any(UUID.class))).thenReturn(false);
when(iwm.getMaxIslands(any())).thenReturn(100);
when(im.getIslandCount(any())).thenReturn(100);
assertFalse(cc.canExecute(user, "", Collections.emptyList()));
Mockito.verify(user).sendMessage(Mockito.eq("commands.island.create.too-many-islands"));
verify(user).sendMessage(eq("commands.island.create.too-many-islands"));
}
@ -219,13 +225,18 @@ public class IslandCreateCommandTest {
*/
@Test
public void testExecuteUserStringListOfStringSuccess() throws IOException {
assertTrue(cc.execute(user, "", Collections.emptyList()));
Mockito.verify(builder).player(Mockito.eq(user));
Mockito.verify(builder).world(Mockito.any());
Mockito.verify(builder).reason(Mockito.eq(Reason.CREATE));
Mockito.verify(builder).name(Mockito.eq("island"));
Mockito.verify(builder).build();
Mockito.verify(user).sendMessage("commands.island.create.creating-island");
// Bundle exists
when(bpm.validate(any(), any())).thenReturn("custom");
// Has permission
when(bpm.checkPerm(any(), any(), any())).thenReturn(true);
assertTrue(cc.execute(user, "", Collections.singletonList("custom")));
verify(builder).player(eq(user));
verify(builder).addon(any());
verify(builder).reason(eq(Reason.CREATE));
verify(builder).name(eq("custom"));
verify(builder).build();
verify(user).sendMessage("commands.island.create.creating-island");
}
/**
@ -234,32 +245,49 @@ public class IslandCreateCommandTest {
*/
@Test
public void testExecuteUserStringListOfStringThrowException() throws IOException {
// Bundle exists
when(bpm.validate(any(), any())).thenReturn("custom");
// Has permission
when(bpm.checkPerm(any(), any(), any())).thenReturn(true);
when(builder.build()).thenThrow(new IOException("message"));
assertFalse(cc.execute(user, "", Collections.emptyList()));
Mockito.verify(user).sendMessage("commands.island.create.creating-island");
Mockito.verify(user).sendMessage("commands.island.create.unable-create-island");
Mockito.verify(plugin).logError("Could not create island for player. message");
assertFalse(cc.execute(user, "", Collections.singletonList("custom")));
verify(user).sendMessage("commands.island.create.creating-island");
verify(user).sendMessage("commands.island.create.unable-create-island");
verify(plugin).logError("Could not create island for player. message");
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.island.IslandCreateCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringSchemNoPermission() {
when(user.hasPermission(Mockito.anyString())).thenReturn(false);
public void testExecuteUserStringListOfStringBundleNoPermission() {
// Bundle exists
when(bpm.validate(any(), any())).thenReturn("custom");
// No permission
when(bpm.checkPerm(any(), any(), any())).thenReturn(false);
assertFalse(cc.execute(user, "", Collections.singletonList("custom")));
Mockito.verify(user).sendMessage(Mockito.eq("general.errors.no-permission"), Mockito.eq(TextVariables.PERMISSION), Mockito.eq("permission.island.create.custom"));
Mockito.verify(user, Mockito.never()).sendMessage("commands.island.create.creating-island");
verify(user, never()).sendMessage("commands.island.create.creating-island");
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.island.IslandCreateCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringUnknownSchem() {
public void testExecuteUserStringListOfStringUnknownBundle() {
assertFalse(cc.execute(user, "", Collections.singletonList("custom")));
Mockito.verify(user).sendMessage(Mockito.eq("commands.island.create.unknown-schem"));
Mockito.verify(user, Mockito.never()).sendMessage("commands.island.create.creating-island");
verify(user).sendMessage(eq("commands.island.create.unknown-blueprint"));
verify(user, never()).sendMessage("commands.island.create.creating-island");
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.island.IslandCreateCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringNoBundle() {
assertTrue(cc.execute(user, "", Collections.emptyList()));
//verify(bpm).showPanel(any(), any(), any());
//TODO verify it is calling the panel
}
/**
@ -267,15 +295,17 @@ public class IslandCreateCommandTest {
* @throws IOException
*/
@Test
public void testExecuteUserStringListOfStringKnownSchem() throws IOException {
when(sm.validate(Mockito.any(), Mockito.any())).thenReturn("custom");
public void testExecuteUserStringListOfStringKnownBundle() throws IOException {
// Has permission
when(bpm.checkPerm(any(), any(), any())).thenReturn(true);
when(bpm.validate(any(), any())).thenReturn("custom");
assertTrue(cc.execute(user, "", Collections.singletonList("custom")));
Mockito.verify(builder).player(Mockito.eq(user));
Mockito.verify(builder).world(Mockito.any());
Mockito.verify(builder).reason(Mockito.eq(Reason.CREATE));
Mockito.verify(builder).name(Mockito.eq("custom"));
Mockito.verify(builder).build();
Mockito.verify(user).sendMessage("commands.island.create.creating-island");
verify(builder).player(eq(user));
verify(builder).addon(any());
verify(builder).reason(eq(Reason.CREATE));
verify(builder).name(eq("custom"));
verify(builder).build();
verify(user).sendMessage("commands.island.create.creating-island");
}
/**
@ -284,7 +314,7 @@ public class IslandCreateCommandTest {
@Test
public void testExecuteUserStringListOfStringCooldown() {
assertTrue(cc.execute(user, "", Collections.emptyList()));
Mockito.verify(ic, Mockito.never()).getSubCommand(Mockito.eq("reset"));
verify(ic, never()).getSubCommand(eq("reset"));
}
/**
@ -294,6 +324,5 @@ public class IslandCreateCommandTest {
public void testExecuteUserStringListOfStringNoCooldown() {
when(settings.isResetCooldownOnCreate()).thenReturn(true);
assertTrue(cc.execute(user, "", Collections.emptyList()));
Mockito.verify(ic).getSubCommand(Mockito.eq("reset"));
}
}

View File

@ -2,11 +2,13 @@ package world.bentobox.bentobox.api.commands.island;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.UUID;
@ -17,9 +19,10 @@ import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@ -30,11 +33,11 @@ import world.bentobox.bentobox.Settings;
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.BlueprintsManager;
import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.PlayersManager;
import world.bentobox.bentobox.managers.SchemsManager;
import world.bentobox.bentobox.managers.island.NewIsland;
/**
@ -53,6 +56,8 @@ public class IslandResetCommandTest {
private PlayersManager pm;
private World world;
private IslandWorldManager iwm;
@Mock
private BlueprintsManager bpm;
/**
* @throws java.lang.Exception
@ -91,20 +96,20 @@ public class IslandResetCommandTest {
// No island for player to begin with (set it later in the tests)
im = mock(IslandsManager.class);
when(im.hasIsland(Mockito.any(), Mockito.eq(uuid))).thenReturn(false);
when(im.isOwner(Mockito.any(), Mockito.eq(uuid))).thenReturn(false);
when(im.hasIsland(any(), eq(uuid))).thenReturn(false);
when(im.isOwner(any(), eq(uuid))).thenReturn(false);
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);
// Server & Scheduler
BukkitScheduler sch = mock(BukkitScheduler.class);
BukkitTask task = mock(BukkitTask.class);
when(sch.runTaskLater(Mockito.any(), Mockito.any(Runnable.class), Mockito.any(Long.class))).thenReturn(task);
when(sch.runTaskLater(any(), any(Runnable.class), any(Long.class))).thenReturn(task);
PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.getScheduler()).thenReturn(sch);
@ -112,13 +117,12 @@ public class IslandResetCommandTest {
// IWM friendly name
iwm = mock(IslandWorldManager.class);
when(iwm.getFriendlyName(Mockito.any())).thenReturn("BSkyBlock");
when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
when(plugin.getIWM()).thenReturn(iwm);
// Schems manager - custom schem
SchemsManager sm = mock(SchemsManager.class);
when(sm.validate(Mockito.any(), Mockito.any())).thenReturn("custom");
when(plugin.getSchemsManager()).thenReturn(sm);
// Bundles manager
when(plugin.getBlueprintsManager()).thenReturn(bpm);
when(bpm.validate(any(), any())).thenReturn("custom");
}
/**
@ -129,142 +133,139 @@ public class IslandResetCommandTest {
IslandResetCommand irc = new IslandResetCommand(ic);
// Test the reset command
// Does not have island
assertFalse(irc.execute(user, irc.getLabel(), new ArrayList<>()));
Mockito.verify(user).sendMessage("general.errors.no-island");
assertFalse(irc.canExecute(user, irc.getLabel(), Collections.emptyList()));
verify(user).sendMessage("general.errors.no-island");
}
@Test
public void testNotOwner() {
IslandResetCommand irc = new IslandResetCommand(ic);
// Now has island, but is not the owner
when(im.hasIsland(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
assertFalse(irc.execute(user, irc.getLabel(), new ArrayList<>()));
Mockito.verify(user).sendMessage("general.errors.not-owner");
when(im.hasIsland(any(), eq(uuid))).thenReturn(true);
assertFalse(irc.canExecute(user, irc.getLabel(), Collections.emptyList()));
verify(user).sendMessage("general.errors.not-owner");
}
@Test
public void testHasTeam() {
IslandResetCommand irc = new IslandResetCommand(ic);
// Now has island, but is not the owner
when(im.hasIsland(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
when(im.hasIsland(any(), eq(uuid))).thenReturn(true);
// Now is owner, but still has team
when(im.isOwner(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
assertFalse(irc.execute(user, irc.getLabel(), new ArrayList<>()));
Mockito.verify(user).sendMessage("commands.island.reset.must-remove-members");
when(im.isOwner(any(), eq(uuid))).thenReturn(true);
assertFalse(irc.canExecute(user, irc.getLabel(), Collections.emptyList()));
verify(user).sendMessage("commands.island.reset.must-remove-members");
}
@Test
public void testNoResetsLeft() {
IslandResetCommand irc = new IslandResetCommand(ic);
// Now has island, but is not the owner
when(im.hasIsland(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
when(im.hasIsland(any(), eq(uuid))).thenReturn(true);
// Now is owner, but still has team
when(im.isOwner(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
when(im.isOwner(any(), eq(uuid))).thenReturn(true);
// Now has no team
when(im.inTeam(Mockito.any(), Mockito.eq(uuid))).thenReturn(false);
when(im.inTeam(any(), eq(uuid))).thenReturn(false);
// Block based on no resets left
when(pm.getResets(Mockito.eq(world),Mockito.eq(uuid))).thenReturn(3);
when(pm.getResets(eq(world),eq(uuid))).thenReturn(3);
assertFalse(irc.execute(user, irc.getLabel(), new ArrayList<>()));
Mockito.verify(user).sendMessage("commands.island.reset.none-left");
assertFalse(irc.canExecute(user, irc.getLabel(), Collections.emptyList()));
verify(user).sendMessage("commands.island.reset.none-left");
}
@Ignore("NPE with ChatColor")
@Test
public void testNoConfirmationRequired() throws IOException {
IslandResetCommand irc = new IslandResetCommand(ic);
// Now has island, but is not the owner
when(im.hasIsland(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
when(im.hasIsland(any(), eq(uuid))).thenReturn(true);
// Now is owner, but still has team
when(im.isOwner(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
when(im.isOwner(any(), eq(uuid))).thenReturn(true);
// Now has no team
when(im.inTeam(Mockito.any(), Mockito.eq(uuid))).thenReturn(false);
when(im.inTeam(any(), eq(uuid))).thenReturn(false);
// Give the user some resets
when(pm.getResetsLeft(Mockito.eq(world), Mockito.eq(uuid))).thenReturn(2);
when(pm.getResetsLeft(eq(world), eq(uuid))).thenReturn(2);
// Set so no confirmation required
when(s.isResetConfirmation()).thenReturn(false);
// Old island mock
Island oldIsland = mock(Island.class);
when(im.getIsland(Mockito.any(), Mockito.eq(uuid))).thenReturn(oldIsland);
when(im.getIsland(any(), eq(uuid))).thenReturn(oldIsland);
// Mock up NewIsland builder
NewIsland.Builder builder = mock(NewIsland.Builder.class);
when(builder.player(Mockito.any())).thenReturn(builder);
when(builder.oldIsland(Mockito.any())).thenReturn(builder);
when(builder.reason(Mockito.any())).thenReturn(builder);
when(builder.name(Mockito.any())).thenReturn(builder);
when(builder.player(any())).thenReturn(builder);
when(builder.oldIsland(any())).thenReturn(builder);
when(builder.reason(any())).thenReturn(builder);
when(builder.name(any())).thenReturn(builder);
when(builder.addon(any())).thenReturn(builder);
when(builder.build()).thenReturn(mock(Island.class));
PowerMockito.mockStatic(NewIsland.class);
when(NewIsland.builder()).thenReturn(builder);
// Reset command, no confirmation required
assertTrue(irc.execute(user, irc.getLabel(), new ArrayList<>()));
// Verify that build new island was called and the number of resets left shown
Mockito.verify(builder).build();
Mockito.verify(user).sendMessage("commands.island.reset.resets-left", "[number]", "2");
assertTrue(irc.execute(user, irc.getLabel(), Collections.emptyList()));
// TODO Verify that panel was shown
// verify(bpm).showPanel(any(), eq(user), eq(irc.getLabel()));
}
@Test
public void testUnlimitedResets() throws IOException {
IslandResetCommand irc = new IslandResetCommand(ic);
// Now has island, but is not the owner
when(im.hasIsland(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
when(im.hasIsland(any(), eq(uuid))).thenReturn(true);
// Now is owner, but still has team
when(im.isOwner(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
when(im.isOwner(any(), eq(uuid))).thenReturn(true);
// Now has no team
when(im.inTeam(Mockito.any(), Mockito.eq(uuid))).thenReturn(false);
when(im.inTeam(any(), eq(uuid))).thenReturn(false);
// Set so no confirmation required
when(s.isResetConfirmation()).thenReturn(false);
// Old island mock
Island oldIsland = mock(Island.class);
when(im.getIsland(Mockito.any(), Mockito.eq(uuid))).thenReturn(oldIsland);
when(im.getIsland(any(), eq(uuid))).thenReturn(oldIsland);
// Mock up NewIsland builder
NewIsland.Builder builder = mock(NewIsland.Builder.class);
when(builder.player(Mockito.any())).thenReturn(builder);
when(builder.oldIsland(Mockito.any())).thenReturn(builder);
when(builder.reason(Mockito.any())).thenReturn(builder);
when(builder.name(Mockito.any())).thenReturn(builder);
when(builder.player(any())).thenReturn(builder);
when(builder.oldIsland(any())).thenReturn(builder);
when(builder.reason(any())).thenReturn(builder);
when(builder.name(any())).thenReturn(builder);
when(builder.addon(any())).thenReturn(builder);
when(builder.build()).thenReturn(mock(Island.class));
PowerMockito.mockStatic(NewIsland.class);
when(NewIsland.builder()).thenReturn(builder);
// Test with unlimited resets
when(pm.getResetsLeft(Mockito.eq(world), Mockito.eq(uuid))).thenReturn(-1);
when(pm.getResetsLeft(eq(world), eq(uuid))).thenReturn(-1);
// Reset
assertTrue(irc.execute(user, irc.getLabel(), new ArrayList<>()));
// Verify that build new island was called and the number of resets left shown
Mockito.verify(builder).build();
// This should not be shown
Mockito.verify(user, Mockito.never()).sendMessage("commands.island.reset.resets-left", "[number]", "1");
assertTrue(irc.canExecute(user, irc.getLabel(), Collections.emptyList()));
}
@Test
public void testConfirmationRequired() throws IOException {
IslandResetCommand irc = new IslandResetCommand(ic);
// Now has island, but is not the owner
when(im.hasIsland(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
when(im.hasIsland(any(), eq(uuid))).thenReturn(true);
// Now is owner, but still has team
when(im.isOwner(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
when(im.isOwner(any(), eq(uuid))).thenReturn(true);
// Now has no team
when(im.inTeam(Mockito.any(), Mockito.eq(uuid))).thenReturn(false);
when(im.inTeam(any(), eq(uuid))).thenReturn(false);
// Give the user some resets
when(pm.getResetsLeft(Mockito.eq(world), Mockito.eq(uuid))).thenReturn(1);
// Set so no confirmation required
when(s.isResetConfirmation()).thenReturn(false);
when(pm.getResetsLeft(eq(world), eq(uuid))).thenReturn(1);
// Old island mock
Island oldIsland = mock(Island.class);
when(im.getIsland(Mockito.any(), Mockito.eq(uuid))).thenReturn(oldIsland);
when(im.getIsland(any(), eq(uuid))).thenReturn(oldIsland);
// Mock up NewIsland builder
NewIsland.Builder builder = mock(NewIsland.Builder.class);
when(builder.player(Mockito.any())).thenReturn(builder);
when(builder.oldIsland(Mockito.any())).thenReturn(builder);
when(builder.reason(Mockito.any())).thenReturn(builder);
when(builder.name(Mockito.any())).thenReturn(builder);
when(builder.player(any())).thenReturn(builder);
when(builder.oldIsland(any())).thenReturn(builder);
when(builder.reason(any())).thenReturn(builder);
when(builder.name(any())).thenReturn(builder);
when(builder.addon(any())).thenReturn(builder);
when(builder.build()).thenReturn(mock(Island.class));
PowerMockito.mockStatic(NewIsland.class);
when(NewIsland.builder()).thenReturn(builder);
@ -274,118 +275,72 @@ public class IslandResetCommandTest {
when(s.getConfirmationTime()).thenReturn(20);
// Reset
assertTrue(irc.execute(user, irc.getLabel(), new ArrayList<>()));
assertTrue(irc.execute(user, irc.getLabel(), Collections.emptyList()));
// Check for message
Mockito.verify(user).sendMessage("commands.confirmation.confirm", "[seconds]", String.valueOf(s.getConfirmationTime()));
verify(user).sendMessage("commands.confirmation.confirm", "[seconds]", String.valueOf(s.getConfirmationTime()));
// Send command again to confirm
assertTrue(irc.execute(user, irc.getLabel(), new ArrayList<>()));
assertTrue(irc.execute(user, irc.getLabel(), Collections.emptyList()));
}
@Test
public void testNewIslandError() throws IOException {
public void testNoConfirmationRequiredUnknownBlueprint() throws IOException {
IslandResetCommand irc = new IslandResetCommand(ic);
// Now has island, but is not the owner
when(im.hasIsland(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
// Now is owner, but still has team
when(im.isOwner(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
// Now has no team
when(im.inTeam(Mockito.any(), Mockito.eq(uuid))).thenReturn(false);
// Give the user some resets
when(pm.getResetsLeft(Mockito.eq(world), Mockito.eq(uuid))).thenReturn(1);
// Set so no confirmation required
when(s.isResetConfirmation()).thenReturn(false);
// Old island mock
Island oldIsland = mock(Island.class);
when(im.getIsland(Mockito.any(), Mockito.eq(uuid))).thenReturn(oldIsland);
// Mock up NewIsland builder
NewIsland.Builder builder = mock(NewIsland.Builder.class);
when(builder.player(Mockito.any())).thenReturn(builder);
when(builder.oldIsland(Mockito.any())).thenReturn(builder);
when(builder.reason(Mockito.any())).thenReturn(builder);
when(builder.name(Mockito.any())).thenReturn(builder);
when(builder.build()).thenThrow(new IOException());
PowerMockito.mockStatic(NewIsland.class);
when(NewIsland.builder()).thenReturn(builder);
// Require no confirmation
when(s.isResetConfirmation()).thenReturn(false);
// Reset
assertFalse(irc.execute(user, irc.getLabel(), new ArrayList<>()));
Mockito.verify(user).sendMessage("commands.island.create.unable-create-island");
}
@Test
public void testNoConfirmationRequiredCustomSchemNoPermission() throws IOException {
IslandResetCommand irc = new IslandResetCommand(ic);
// Now has island, but is not the owner
when(im.hasIsland(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
// Now is owner, but still has team
when(im.isOwner(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
// Now has no team
when(im.inTeam(Mockito.any(), Mockito.eq(uuid))).thenReturn(false);
// Give the user some resets
when(pm.getResetsLeft(Mockito.eq(world), Mockito.eq(uuid))).thenReturn(1);
// Set so no confirmation required
when(s.isResetConfirmation()).thenReturn(false);
// Old island mock
Island oldIsland = mock(Island.class);
when(im.getIsland(Mockito.any(), Mockito.eq(uuid))).thenReturn(oldIsland);
// Mock up NewIsland builder
NewIsland.Builder builder = mock(NewIsland.Builder.class);
when(builder.player(Mockito.any())).thenReturn(builder);
when(builder.oldIsland(Mockito.any())).thenReturn(builder);
when(builder.reason(Mockito.any())).thenReturn(builder);
when(builder.name(Mockito.any())).thenReturn(builder);
when(builder.build()).thenReturn(mock(Island.class));
PowerMockito.mockStatic(NewIsland.class);
when(NewIsland.builder()).thenReturn(builder);
// No such bundle
when(bpm.validate(any(), any())).thenReturn(null);
// Reset command, no confirmation required
assertFalse(irc.execute(user, irc.getLabel(), Collections.singletonList("custom")));
verify(user).sendMessage(
"commands.island.create.unknown-blueprint"
);
}
@Test
public void testNoConfirmationRequiredBlueprintNoPerm() throws IOException {
IslandResetCommand irc = new IslandResetCommand(ic);
// Bundle exists
when(bpm.validate(any(), any())).thenReturn("custom");
// No permission
when(bpm.checkPerm(any(), any(), any())).thenReturn(false);
// Reset command, no confirmation required
assertFalse(irc.execute(user, irc.getLabel(), Collections.singletonList("custom")));
Mockito.verify(user).sendMessage("general.errors.no-permission","[permission]","nullisland.create.custom");
}
@Test
public void testNoConfirmationRequiredCustomSchemHasPermission() throws IOException {
IslandResetCommand irc = new IslandResetCommand(ic);
// Now has island, but is not the owner
when(im.hasIsland(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
when(im.hasIsland(any(), eq(uuid))).thenReturn(true);
// Now is owner, but still has team
when(im.isOwner(Mockito.any(), Mockito.eq(uuid))).thenReturn(true);
when(im.isOwner(any(), eq(uuid))).thenReturn(true);
// Now has no team
when(im.inTeam(Mockito.any(), Mockito.eq(uuid))).thenReturn(false);
when(im.inTeam(any(), eq(uuid))).thenReturn(false);
// Give the user some resets
when(pm.getResetsLeft(Mockito.eq(world), Mockito.eq(uuid))).thenReturn(1);
when(pm.getResetsLeft(eq(world), eq(uuid))).thenReturn(1);
// Set so no confirmation required
when(s.isResetConfirmation()).thenReturn(false);
// Old island mock
Island oldIsland = mock(Island.class);
when(im.getIsland(Mockito.any(), Mockito.eq(uuid))).thenReturn(oldIsland);
when(im.getIsland(any(), eq(uuid))).thenReturn(oldIsland);
// Mock up NewIsland builder
NewIsland.Builder builder = mock(NewIsland.Builder.class);
when(builder.player(Mockito.any())).thenReturn(builder);
when(builder.oldIsland(Mockito.any())).thenReturn(builder);
when(builder.reason(Mockito.any())).thenReturn(builder);
when(builder.name(Mockito.any())).thenReturn(builder);
when(builder.player(any())).thenReturn(builder);
when(builder.oldIsland(any())).thenReturn(builder);
when(builder.reason(any())).thenReturn(builder);
when(builder.name(any())).thenReturn(builder);
when(builder.addon(any())).thenReturn(builder);
when(builder.build()).thenReturn(mock(Island.class));
PowerMockito.mockStatic(NewIsland.class);
when(NewIsland.builder()).thenReturn(builder);
// Permission
when(user.hasPermission(Mockito.anyString())).thenReturn(true);
// Bundle exists
when(bpm.validate(any(), any())).thenReturn("custom");
// Has permission
when(bpm.checkPerm(any(), any(), any())).thenReturn(true);
// Reset command, no confirmation required
assertTrue(irc.execute(user, irc.getLabel(), Collections.singletonList("custom")));
// Verify that build new island was called and the number of resets left shown
Mockito.verify(builder).build();
Mockito.verify(user).sendMessage("commands.island.reset.resets-left", "[number]", "1");
verify(user).sendMessage("commands.island.create.creating-island");
}
}

View File

@ -1,301 +0,0 @@
package world.bentobox.bentobox.schems;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.DyeColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Chest;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.block.Sign;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Cow;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Horse;
import org.bukkit.entity.Horse.Color;
import org.bukkit.entity.Horse.Style;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Pig;
import org.bukkit.entity.Player;
import org.bukkit.entity.Sheep;
import org.bukkit.inventory.HorseInventory;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.MaterialData;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.util.Vector;
import org.junit.Before;
import org.junit.Ignore;
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.Settings;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.Clipboard;
@SuppressWarnings("deprecation")
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class})
public class ClipboardTest {
private BentoBox plugin;
private File schemFolder;
private Location loc;
private User user;
private Location loc2;
private Sheep sheep;
private Horse horse;
private Block block;
private World world;
private BukkitScheduler sched;
@Before
public void setUp() throws Exception {
plugin = mock(BentoBox.class);
schemFolder = mock(File.class);
when(schemFolder.exists()).thenReturn(true);
loc = mock(Location.class);
world = mock(World.class);
block = mock(Block.class);
when(block.getType()).thenReturn(Material.GRASS);
when(block.getLocation()).thenReturn(loc);
BlockData bd = mock(BlockData.class);
when(bd.getAsString()).thenReturn("Block_data");
when(block.getBlockData()).thenReturn(bd);
when(world.getBlockAt(Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt())).thenReturn(block);
when(loc.getWorld()).thenReturn(world);
when(loc.getBlockX()).thenReturn(1);
when(loc.getBlockY()).thenReturn(2);
when(loc.getBlockZ()).thenReturn(3);
when(loc.getBlock()).thenReturn(block);
when(loc.toVector()).thenReturn(new Vector(1,2,3));
when(loc.getX()).thenReturn(1D);
when(loc.getY()).thenReturn(2D);
when(loc.getZ()).thenReturn(3D);
loc2 = mock(Location.class);
when(loc2.getWorld()).thenReturn(world);
when(loc2.getBlockX()).thenReturn(2);
when(loc2.getBlockY()).thenReturn(3);
when(loc2.getBlockZ()).thenReturn(4);
when(loc2.getBlock()).thenReturn(block);
when(loc2.toVector()).thenReturn(new Vector(2,3,4));
when(loc2.getX()).thenReturn(2D);
when(loc2.getY()).thenReturn(3D);
when(loc2.getZ()).thenReturn(4D);
// Living entities
List<LivingEntity> ents = new ArrayList<>();
Pig pig = mock(Pig.class);
Player player = mock(Player.class);
Cow cow = mock(Cow.class);
Creeper creeper = mock(Creeper.class);
sheep = mock(Sheep.class);
horse = mock(Horse.class);
when(pig.getLocation()).thenReturn(loc);
when(cow.getLocation()).thenReturn(loc);
when(creeper.getLocation()).thenReturn(loc);
when(player.getLocation()).thenReturn(loc);
when(sheep.getLocation()).thenReturn(loc);
when(horse.getLocation()).thenReturn(loc);
when(pig.getType()).thenReturn(EntityType.PIG);
when(player.getType()).thenReturn(EntityType.PLAYER);
when(cow.getType()).thenReturn(EntityType.COW);
when(creeper.getType()).thenReturn(EntityType.CREEPER);
when(sheep.getType()).thenReturn(EntityType.SHEEP);
when(sheep.getColor()).thenReturn(DyeColor.LIGHT_BLUE);
when(horse.getType()).thenReturn(EntityType.HORSE);
when(horse.getColor()).thenReturn(Color.CREAMY);
when(horse.getStyle()).thenReturn(Style.BLACK_DOTS);
HorseInventory inv = mock(HorseInventory.class);
when(horse.getInventory()).thenReturn(inv);
// UUIDs (I'm going to assume these will all be unique (prays to god of randomness)
when(creeper.getUniqueId()).thenReturn(UUID.randomUUID());
when(player.getUniqueId()).thenReturn(UUID.randomUUID());
when(cow.getUniqueId()).thenReturn(UUID.randomUUID());
when(pig.getUniqueId()).thenReturn(UUID.randomUUID());
when(sheep.getUniqueId()).thenReturn(UUID.randomUUID());
when(horse.getUniqueId()).thenReturn(UUID.randomUUID());
ents.add(creeper);
ents.add(player);
ents.add(cow);
ents.add(pig);
ents.add(sheep);
ents.add(horse);
when(world.getLivingEntities()).thenReturn(ents);
user = mock(User.class);
User.setPlugin(plugin);
when(user.getLocation()).thenReturn(loc);
// Scheduler
PowerMockito.mockStatic(Bukkit.class);
sched = mock(BukkitScheduler.class);
when(Bukkit.getScheduler()).thenReturn(sched);
// Settings
Settings settings = mock(Settings.class);
when(settings.getPasteSpeed()).thenReturn(200);
when(plugin.getSettings()).thenReturn(settings);
// Default block state
BlockState bs = mock(BlockState.class);
when(block.getState()).thenReturn(bs);
MaterialData md = mock(MaterialData.class);
when(bs.getData()).thenReturn(md);
}
@Test
public void testClipboard() {
new Clipboard();
}
@Test
public void testSetGetPos1() {
Clipboard cb = new Clipboard();
assertNull(cb.getPos1());
cb.setPos1(loc);
assertEquals(loc, cb.getPos1());
assertNull(cb.getOrigin());
}
@Test
public void testSetGetPos2() {
Clipboard cb = new Clipboard();
assertNull(cb.getPos2());
cb.setPos2(loc);
assertEquals(loc, cb.getPos2());
}
@Test
public void testSetGetOrigin() {
Clipboard cb = new Clipboard();
assertNull(cb.getOrigin());
cb.setOrigin(loc);
assertEquals(loc, cb.getOrigin());
}
@Test
public void testCopyNoPos1Pos2() {
Clipboard cb = new Clipboard();
cb.copy(user, false);
Mockito.verify(user).sendMessage(Mockito.eq("commands.admin.schem.need-pos1-pos2"));
}
@Test
public void testCopyNoPos2() {
Clipboard cb = new Clipboard();
cb.setPos1(loc);
cb.copy(user, false);
Mockito.verify(user).sendMessage(Mockito.eq("commands.admin.schem.need-pos1-pos2"));
}
/**
* Copy is now done async so these copy tests are invalid
*/
@Test
@Ignore
public void testCopy() {
Clipboard cb = new Clipboard();
cb.setPos1(loc);
cb.setPos2(loc2);
cb.copy(user, false);
Mockito.verify(user).sendMessage("commands.admin.schem.copied-blocks", TextVariables.NUMBER, "8");
}
@Test
@Ignore
public void testCopySigns() {
when(block.getType()).thenReturn(Material.SIGN);
Sign bs = mock(Sign.class);
String[] lines = {"line1", "line2", "line3", "line4"};
when(bs.getLines()).thenReturn(lines);
when(block.getState()).thenReturn(bs);
Clipboard cb = new Clipboard();
cb.setPos1(loc);
cb.setPos2(loc2);
cb.copy(user, false);
Mockito.verify(user).sendMessage("commands.admin.schem.copied-blocks", TextVariables.NUMBER, "8");
// Every block is a sign, so this should be called 8 times
Mockito.verify(bs, Mockito.times(8)).getLines();
}
@Test
@Ignore
public void testCopyChests() {
when(block.getType()).thenReturn(Material.CHEST);
Chest bs = mock(Chest.class);
Inventory inv = mock(Inventory.class);
ItemStack[] contents = { new ItemStack(Material.ACACIA_BOAT, 1), new ItemStack(Material.GLASS, 23)};
when(inv.getContents()).thenReturn(contents);
when(bs.getInventory()).thenReturn(inv);
when(block.getState()).thenReturn(bs);
Clipboard cb = new Clipboard();
cb.setPos1(loc);
cb.setPos2(loc2);
cb.copy(user, false);
Mockito.verify(user).sendMessage("commands.admin.schem.copied-blocks", TextVariables.NUMBER, "8");
// Every block is a sign, so this should be called 8 times
Mockito.verify(bs, Mockito.times(8)).getInventory();
}
@Test
@Ignore
public void testCopyCreatureSpawners() {
when(block.getType()).thenReturn(Material.SPAWNER);
CreatureSpawner bs = mock(CreatureSpawner.class);
when(bs.getSpawnedType()).thenReturn(EntityType.CAVE_SPIDER);
when(block.getState()).thenReturn(bs);
Clipboard cb = new Clipboard();
cb.setPos1(loc);
cb.setPos2(loc2);
cb.copy(user, false);
Mockito.verify(user).sendMessage("commands.admin.schem.copied-blocks", TextVariables.NUMBER, "8");
// Every block is a sign, so this should be called 8 times
Mockito.verify(bs, Mockito.times(8)).getMaxNearbyEntities();
}
@Test
@Ignore
public void testCopyAir() {
// No entities
when(world.getLivingEntities()).thenReturn(new ArrayList<>());
when(block.getType()).thenReturn(Material.AIR);
BlockState bs = mock(BlockState.class);
when(block.getState()).thenReturn(bs);
Clipboard cb = new Clipboard();
cb.setPos1(loc);
cb.setPos2(loc2);
// Do not copy air
cb.copy(user, false);
Mockito.verify(user).sendMessage("commands.admin.schem.copied-blocks", TextVariables.NUMBER, "0");
cb.copy(user, true);
Mockito.verify(user).sendMessage("commands.admin.schem.copied-blocks", TextVariables.NUMBER, "8");
}
}