Merge pull request #412 from BentoBoxWorld/schematic-choice

Uses current API to enable multiple schems.
This commit is contained in:
Florian CUNY 2018-12-24 09:29:40 +01:00 committed by GitHub
commit a321045451
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 163 additions and 81 deletions

View File

@ -286,10 +286,9 @@ public abstract class Addon {
/**
* Set the file that contains this addon
*
* @param f
* the file to set
* @param f the file to set
*/
public void setAddonFile(File f) {
public void setFile(File f) {
file = f;
}

View File

@ -2,9 +2,11 @@ package world.bentobox.bentobox.api.commands.island;
import java.io.IOException;
import java.util.List;
import java.util.Set;
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;
@ -27,6 +29,7 @@ public class IslandCreateCommand extends CompositeCommand {
public void setup() {
setPermission("island.create");
setOnlyPlayer(true);
setParametersHelp("commands.island.create.parameters");
setDescription("commands.island.create.description");
}
@ -45,11 +48,30 @@ public class IslandCreateCommand extends CompositeCommand {
}
user.sendMessage("commands.island.create.creating-island");
// Default schem is 'island'
String name = "island";
if (!args.isEmpty()) {
name = args.get(0).toLowerCase(java.util.Locale.ENGLISH);
// Permission check
String permission = this.getPermissionPrefix() + "island.create." + name;
if (!user.isOp() && !user.hasPermission(permission)) {
user.sendMessage("general.errors.no-permission", TextVariables.PERMISSION, permission);
return false;
}
// Check the schem name exists
Set<String> validNames = getPlugin().getSchemsManager().get(getWorld()).keySet();
if (!validNames.contains(name)) {
user.sendMessage("commands.island.create.unknown-schem");
return false;
}
}
try {
NewIsland.builder()
.player(user)
.world(getWorld())
.reason(Reason.CREATE)
.name(name)
.build();
return true;
} catch (IOException e) {

View File

@ -2,6 +2,7 @@ package world.bentobox.bentobox.api.commands.island;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
@ -24,6 +25,7 @@ public class IslandResetCommand extends ConfirmableCommand {
public void setup() {
setPermission("island.create");
setOnlyPlayer(true);
setParametersHelp("commands.island.reset.parameters");
setDescription("commands.island.reset.description");
}
@ -56,17 +58,35 @@ public class IslandResetCommand extends ConfirmableCommand {
user.sendMessage("commands.island.reset.resets-left", TextVariables.NUMBER, String.valueOf(resetsLeft));
}
}
// Default schem is 'island'
String name = args.isEmpty() ? "island" : args.get(0).toLowerCase(java.util.Locale.ENGLISH);
if (!args.isEmpty()) {
// Permission check
String permission = this.getPermissionPrefix() + "island.create." + name;
if (!user.isOp() && !user.hasPermission(permission)) {
user.sendMessage("general.errors.no-permission", TextVariables.PERMISSION, permission);
return false;
}
// Check the schem name exists
Set<String> validNames = getPlugin().getSchemsManager().get(getWorld()).keySet();
if (!validNames.contains(name)) {
user.sendMessage("commands.island.create.unknown-schem");
return false;
}
}
// Request confirmation
if (getSettings().isResetConfirmation()) {
this.askConfirmation(user, () -> resetIsland(user));
this.askConfirmation(user, () -> resetIsland(user, name));
return true;
} else {
return resetIsland(user);
return resetIsland(user, name);
}
}
private boolean resetIsland(User user) {
private boolean resetIsland(User user, String name) {
// Reset the island
Player player = user.getPlayer();
player.setGameMode(GameMode.SPECTATOR);
@ -92,6 +112,7 @@ public class IslandResetCommand extends ConfirmableCommand {
.player(user)
.reason(Reason.RESET)
.oldIsland(oldIsland)
.name(name)
.build();
} catch (IOException e) {
getPlugin().logError("Could not create island for player. " + e.getMessage());

View File

@ -131,11 +131,11 @@ public class AddonsManager {
addon = addonClassLoader.getAddon();
// Initialize some settings
addon.setDataFolder(new File(f.getParent(), addon.getDescription().getName()));
addon.setAddonFile(f);
addon.setFile(f);
File localeDir = new File(plugin.getDataFolder(), LOCALE_FOLDER + File.separator + addon.getDescription().getName());
// Obtain any locale files and save them
for (String localeFile : listJarYamlFiles(jar, LOCALE_FOLDER)) {
for (String localeFile : listJarFiles(jar, LOCALE_FOLDER, ".yml")) {
addon.saveResource(localeFile, localeDir, false, true);
}
plugin.getLocalesManager().loadLocalesFromFile(addon.getDescription().getName());
@ -206,12 +206,13 @@ public class AddonsManager {
}
/**
* Lists all the yml files found in the jar in the folder
* Lists files found in the jar in the folderPath with the suffix given
* @param jar - the jar file
* @param folderPath - the path within the jar
* @param suffix - the suffix required
* @return a list of files
*/
public List<String> listJarYamlFiles(JarFile jar, String folderPath) {
public List<String> listJarFiles(JarFile jar, String folderPath, String suffix) {
List<String> result = new ArrayList<>();
Enumeration<JarEntry> entries = jar.entries();
@ -223,7 +224,7 @@ public class AddonsManager {
continue;
}
if (entry.getName().endsWith(".yml")) {
if (entry.getName().endsWith(suffix)) {
result.add(entry.getName());
}

View File

@ -52,12 +52,12 @@ public class LocalesManager {
// No translation could be gotten from the player's locale, trying more generic solutions
return get(reference);
}
/**
* Gets the translated String corresponding to the reference from the locale file for this user.
* @param user the User
* @param reference a reference that can be found in a locale file
* @param default to return if the reference cannot be found anywhere
* @param defaultText to return if the reference cannot be found anywhere
* @return the translated String from the User's locale or from the server's locale or from the en-US locale, or null.
*/
public String getOrDefault(User user, String reference, String defaultText) {
@ -88,12 +88,12 @@ public class LocalesManager {
}
return null;
}
/**
* Gets the translated String corresponding to the reference from the server's or the en-US locale file
* or if it cannot be found anywhere, use the default text supplied.
* @param reference a reference that can be found in a locale file
* @param default text to return if the reference cannot be found anywhere
* @param defaultText text to return if the reference cannot be found anywhere
* @return the translated String from the server's locale or from the en-US locale, or default.
*/
public String getOrDefault(String reference, String defaultText) {

View File

@ -1,10 +1,13 @@
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.Optional;
import java.util.Objects;
import java.util.jar.JarFile;
import org.bukkit.World;
import org.bukkit.configuration.InvalidConfigurationException;
@ -17,9 +20,7 @@ import world.bentobox.bentobox.schems.Clipboard;
public class SchemsManager {
private BentoBox plugin;
private Map<World, Clipboard> islandSchems;
private static final String SCHEM = ".schem";
private Map<World, Map<String, Clipboard>> islandSchems;
/**
* @param plugin - plugin
@ -29,89 +30,108 @@ public class SchemsManager {
islandSchems = new HashMap<>();
}
/**
* @param schems - schems folder for either the addon or the plugin
* @param world - world
* @param name - name of the schem to save (excluding .schem)
*/
private void copySchems(File schems, World world, String name) {
private void copySchems(Addon addon, File schems) {
if (schems.exists()) {
// If the folder exists, do not copy anything from the jar
return;
}
if (!schems.exists() && !schems.mkdirs()) {
plugin.logError("Could not make schems folder!");
return;
}
File schem = new File(schems, name + SCHEM);
if (schem.exists()) {
// No overwriting
return;
// Save any schems that
try (JarFile jar = new JarFile(addon.getFile())) {
plugin.getAddonsManager().listJarFiles(jar, "schems", ".schem").forEach(name -> {
addon.saveResource("schems/" + name, false);
});
} catch (IOException e) {
plugin.logError("Could not load schem files from addon jar " + e.getMessage());
}
Optional<Addon> addon = plugin.getIWM().getAddon(world);
if (addon.isPresent()) {
addon.get().saveResource("schems/" + name + SCHEM, false);
} else {
plugin.saveResource("schems/" + name + SCHEM, false);
}
}
public Clipboard get(World world) {
return islandSchems.get(world);
}
/**
* Load schems for world. Will try and load nether and end schems too if settings are set.
* Get all the schems for this world
* @param world world
* @return map of schems for this world or an empty map if there are none registered
*/
public Map<String, Clipboard> get(World world) {
return islandSchems.getOrDefault(world, new HashMap<>());
}
/**
* Load schems for addon. Will try and load nether and end schems too if settings are set.
* @param world - world
*/
public void loadIslands(World world) {
if (!plugin.getSchemsManager().loadSchem(world, "island")) {
plugin.logError("Could not load island.schem for " + plugin.getIWM().getFriendlyName(world));
}
if (plugin.getIWM().isNetherGenerate(world) && plugin.getIWM().isNetherIslands(world)
&& !plugin.getSchemsManager().loadSchem(plugin.getIWM().getNetherWorld(world), "nether-island")) {
plugin.logError("Could not load nether-island.schem for " + plugin.getIWM().getFriendlyName(world));
}
if (plugin.getIWM().isEndGenerate(world) && plugin.getIWM().isEndIslands(world)
&& !plugin.getSchemsManager().loadSchem(plugin.getIWM().getEndWorld(world), "end-island")) {
plugin.logError("Could not load end-island.schem for " + plugin.getIWM().getFriendlyName(world));
}
plugin.getIWM().getAddon(world).ifPresent(addon -> {
File schems = new File(addon.getDataFolder(), "schems");
// 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(".schem")
&& !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 -> {
if (!plugin.getSchemsManager().loadSchem(world, schems, name)) {
plugin.logError("Could not load " + name + ".schem for " + plugin.getIWM().getFriendlyName(world));
}
if (plugin.getIWM().isNetherGenerate(world) && plugin.getIWM().isNetherIslands(world)
&& !plugin.getSchemsManager().loadSchem(plugin.getIWM().getNetherWorld(world), schems, "nether-" + name)) {
plugin.logError("Could not load nether-" + name + ".schem for " + plugin.getIWM().getFriendlyName(world));
}
if (plugin.getIWM().isEndGenerate(world) && plugin.getIWM().isEndIslands(world)
&& !plugin.getSchemsManager().loadSchem(plugin.getIWM().getEndWorld(world), schems, "end-" + name)) {
plugin.logError("Could not load end-" + name + ".schem for " + plugin.getIWM().getFriendlyName(world));
}
});
});
}
private boolean loadSchem(World world, String name) {
private boolean loadSchem(World world, File schems, String name) {
plugin.log("Loading " + name + ".schem for " + world.getName());
File schems = new File(plugin.getIWM().getDataFolder(world), "schems");
copySchems(schems, world, name);
Map<String, Clipboard> schemList = islandSchems.getOrDefault(world, new HashMap<>());
try {
Clipboard cb = new Clipboard(plugin, schems);
cb.load(name);
islandSchems.put(world, cb);
schemList.put(name, cb);
islandSchems.put(world, schemList);
} catch (IOException | InvalidConfigurationException e) {
plugin.logError("Could not load " + name + " schem");
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, Runnable task) {
if (islandSchems.containsKey(world)) {
islandSchems.get(world).pasteIsland(world, island, task);
public void paste(World world, Island island, String name, Runnable task) {
if (islandSchems.containsKey(world) && islandSchems.get(world).containsKey(name)) {
islandSchems.get(world).get(name).pasteIsland(world, island, task);
} else {
plugin.logError("Tried to paste schem for " + world.getName() + " but the schem is not loaded!");
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.");
}
}
/**
* Paste the schem to world for island
* @param world - world
* @param island - island
*/
public void paste(World world, Island island) {
paste(world, island, null);
}
}

View File

@ -30,6 +30,8 @@ public class NewIsland {
private final User user;
private final Reason reason;
private final World world;
private final String name;
private enum Result {
ISLAND_FOUND,
BLOCK_AT_CENTER,
@ -37,12 +39,13 @@ public class NewIsland {
FREE
}
private NewIsland(Island oldIsland, User user, Reason reason, World world) {
private NewIsland(Island oldIsland, User user, Reason reason, World world, String name) {
super();
plugin = BentoBox.getInstance();
this.user = user;
this.reason = reason;
this.world = world;
this.name = name;
newIsland();
if (oldIsland != null) {
// Delete the old island
@ -75,6 +78,7 @@ public class NewIsland {
private User user2;
private Reason reason2;
private World world2;
private String name2 = "island";
public Builder oldIsland(Island oldIsland) {
this.oldIsland2 = oldIsland;
@ -98,9 +102,17 @@ public class NewIsland {
return this;
}
/**
* @param name - filename of schematic
*/
public Builder name(String name) {
this.name2 = name;
return this;
}
public Island build() throws IOException {
if (user2 != null) {
NewIsland newIsland = new NewIsland(oldIsland2, user2, reason2, world2);
NewIsland newIsland = new NewIsland(oldIsland2, user2, reason2, world2, name2);
return newIsland.getIsland();
}
throw new IOException("Insufficient parameters. Must have a schematic and a player");
@ -142,7 +154,7 @@ public class NewIsland {
return;
}
// Create island
plugin.getSchemsManager().paste(world, island, () -> {
plugin.getSchemsManager().paste(world, island, name, () -> {
// Set initial spawn point if one exists
if (island.getSpawnPoint(Environment.NORMAL) != null) {
plugin.getPlayers().setHomeLocation(user, island.getSpawnPoint(Environment.NORMAL), 1);
@ -156,12 +168,12 @@ public class NewIsland {
});
// 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);
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);
plugin.getSchemsManager().paste(plugin.getIWM().getEndWorld(world), island, "end-" + name);
}
// Set default settings

View File

@ -240,16 +240,19 @@ commands:
spawn:
description: "teleport you to the spawn"
create:
description: "create an island"
description: "create an island, using optional schem (requires permission)"
parameters: "<schem>"
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..."
pick-world: "&cPick a world from [worlds]."
unknown-schem: "&cThat schem has not been loaded yet."
info:
description: "display info about your island or the player's island"
parameters: "<player>"
reset:
description: "restart your island and remove the old one"
parameters: "<schem>"
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"

View File

@ -129,7 +129,7 @@ public class AddonTest {
TestClass test = new TestClass();
File file = mock(File.class);
assertNull(test.getFile());
test.setAddonFile(file);
test.setFile(file);
assertEquals(file, test.getFile());
}
@ -173,7 +173,7 @@ public class AddonTest {
File jarFile = new File("addon.jar");
File dataFolder = new File("dataFolder");
test.setDataFolder(dataFolder);
test.setAddonFile(jarFile);
test.setFile(jarFile);
test.saveDefaultConfig();
}
@ -195,7 +195,7 @@ public class AddonTest {
File jarFile = new File("addon.jar");
File dataFolder = new File("dataFolder");
test.setDataFolder(dataFolder);
test.setAddonFile(jarFile);
test.setFile(jarFile);
test.saveResource("no_such_file", true);
}
@ -205,7 +205,7 @@ public class AddonTest {
File jarFile = new File("addon.jar");
File dataFolder = new File("dataFolder");
test.setDataFolder(dataFolder);
test.setAddonFile(jarFile);
test.setFile(jarFile);
test.saveResource("no_such_file", jarFile, false, false);
test.saveResource("no_such_file", jarFile, false, true);
test.saveResource("no_such_file", jarFile, true, false);
@ -219,7 +219,7 @@ public class AddonTest {
File jarFile = new File("addon.jar");
File dataFolder = new File("dataFolder");
test.setDataFolder(dataFolder);
test.setAddonFile(jarFile);
test.setFile(jarFile);
assertNull(test.getResource("nothing"));
}
@ -227,7 +227,7 @@ public class AddonTest {
public void testSetAddonFile() {
TestClass test = new TestClass();
File jarFile = new File("addon.jar");
test.setAddonFile(jarFile);
test.setFile(jarFile);
assertEquals(jarFile, test.getFile());
}

View File

@ -192,6 +192,7 @@ public class IslandResetCommandTest {
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);
@ -226,6 +227,7 @@ public class IslandResetCommandTest {
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);
@ -263,6 +265,7 @@ public class IslandResetCommandTest {
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);
@ -304,6 +307,7 @@ public class IslandResetCommandTest {
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);