diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitInventoryUtil.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitInventoryUtil.java index 62136379a..00adeb892 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitInventoryUtil.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitInventoryUtil.java @@ -49,7 +49,8 @@ public class BukkitInventoryUtil extends InventoryUtil { @Override public void open(PlotInventory inv) { BukkitPlayer bp = (BukkitPlayer) inv.player; - Inventory inventory = Bukkit.createInventory(null, inv.size * 9, inv.getTitle()); + Inventory inventory = Bukkit.createInventory(null, inv.size * 9, + ChatColor.translateAlternateColorCodes('&', inv.getTitle())); PlotItemStack[] items = inv.getItems(); for (int i = 0; i < inv.size * 9; i++) { PlotItemStack item = items[i]; diff --git a/Core/src/main/java/com/plotsquared/core/PlotSquared.java b/Core/src/main/java/com/plotsquared/core/PlotSquared.java index 1d59b2565..452493181 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotSquared.java +++ b/Core/src/main/java/com/plotsquared/core/PlotSquared.java @@ -26,6 +26,7 @@ package com.plotsquared.core; import com.plotsquared.core.command.WE_Anywhere; +import com.plotsquared.core.components.ComponentPresetManager; import com.plotsquared.core.configuration.Caption; import com.plotsquared.core.configuration.CaptionUtility; import com.plotsquared.core.configuration.Captions; @@ -184,7 +185,6 @@ public class PlotSquared { // // Register configuration serializable classes // - // ConfigurationSerialization.registerClass(BlockState.class, "BlockState"); ConfigurationSerialization.registerClass(BlockBucket.class, "BlockBucket"); try { @@ -307,6 +307,15 @@ public class PlotSquared { .runTask(() -> EconHandler.manager = PlotSquared.this.IMP.getEconomyHandler()); } + if (Settings.Enabled_Components.COMPONENT_PRESETS) { + try { + new ComponentPresetManager(); + } catch (final Exception e) { + PlotSquared.log(Captions.PREFIX + "Failed to initialize the preset system"); + e.printStackTrace(); + } + } + // World generators: final ConfigurationSection section = this.worlds.getConfigurationSection("worlds"); if (section != null) { diff --git a/Core/src/main/java/com/plotsquared/core/components/ComponentCommand.java b/Core/src/main/java/com/plotsquared/core/components/ComponentCommand.java new file mode 100644 index 000000000..f79b68063 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/components/ComponentCommand.java @@ -0,0 +1,57 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.components; + +import com.plotsquared.core.command.CommandCategory; +import com.plotsquared.core.command.CommandDeclaration; +import com.plotsquared.core.command.RequiredType; +import com.plotsquared.core.command.SubCommand; +import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.plot.PlotInventory; + +@CommandDeclaration(command = "components", +permission = "plots.components", +description = "Open the component preset GUI", +usage = "/plot components", +category = CommandCategory.APPEARANCE, +requiredType = RequiredType.PLAYER) +public class ComponentCommand extends SubCommand { + + private final ComponentPresetManager componentPresetManager; + + public ComponentCommand(final ComponentPresetManager componentPresetManager) { + this.componentPresetManager = componentPresetManager; + } + + @Override public boolean onCommand(final PlotPlayer player, final String[] args) { + final PlotInventory inventory = componentPresetManager.buildInventory(player); + if (inventory != null) { + inventory.openInventory(); + } + return true; + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/components/ComponentPreset.java b/Core/src/main/java/com/plotsquared/core/components/ComponentPreset.java new file mode 100644 index 000000000..98150cc58 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/components/ComponentPreset.java @@ -0,0 +1,120 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.components; + +import com.plotsquared.core.configuration.serialization.ConfigurationSerializable; +import com.plotsquared.core.configuration.serialization.SerializableAs; +import com.plotsquared.core.generator.ClassicPlotManagerComponent; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.item.ItemTypes; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A preset that can be used to set a component from + * the component GUI + */ +@SerializableAs("preset") +public class ComponentPreset implements ConfigurationSerializable { + + private final ClassicPlotManagerComponent component; + private final String pattern; + private final double cost; + private final String permission; + private final String displayName; + private final List description; + private final ItemType icon; + + public ComponentPreset(ClassicPlotManagerComponent component, String pattern, double cost, + String permission, String displayName, List description, final ItemType icon) { + this.component = component; + this.pattern = pattern; + this.cost = cost; + this.permission = permission; + this.displayName = displayName; + this.description = description; + this.icon = icon; + } + + public static ComponentPreset deserialize(@NotNull final Map map) { + final ClassicPlotManagerComponent classicPlotManagerComponent = ClassicPlotManagerComponent + .fromString(map.getOrDefault("component", "").toString()).orElseThrow(() -> + new IllegalArgumentException("The preset needs a valid target component")); + final String pattern = map.getOrDefault("pattern", "").toString(); + final double cost = Double.parseDouble(map.getOrDefault("cost", "0.0").toString()); + final String permission = map.getOrDefault("permission", "").toString(); + final String displayName = map.getOrDefault("name", "New Package").toString(); + final List description = (List) map.getOrDefault("description", new ArrayList<>()); + final ItemType icon = ItemTypes.get(map.getOrDefault("icon", "dirt").toString()); + return new ComponentPreset(classicPlotManagerComponent, pattern, cost, permission, + displayName, description, icon); + } + + public ClassicPlotManagerComponent getComponent() { + return this.component; + } + + public String getPattern() { + return this.pattern; + } + + public double getCost() { + return this.cost; + } + + public String getPermission() { + return this.permission; + } + + public String getDisplayName() { + return this.displayName; + } + + public List getDescription() { + return this.description; + } + + public ItemType getIcon() { + return this.icon; + } + + @Override public Map serialize() { + final Map map = new HashMap<>(); + map.put("component", this.component.name().toLowerCase()); + map.put("pattern", this.pattern); + map.put("cost", this.cost); + map.put("permission", this.permission); + map.put("name", this.displayName); + map.put("description", this.description); + map.put("icon", this.icon.getId().replace("minecraft:", "")); + return map; + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/components/ComponentPresetManager.java b/Core/src/main/java/com/plotsquared/core/components/ComponentPresetManager.java new file mode 100644 index 000000000..e1b633a88 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/components/ComponentPresetManager.java @@ -0,0 +1,221 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.components; + +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.backup.BackupManager; +import com.plotsquared.core.command.MainCommand; +import com.plotsquared.core.configuration.Captions; +import com.plotsquared.core.configuration.file.YamlConfiguration; +import com.plotsquared.core.configuration.serialization.ConfigurationSerialization; +import com.plotsquared.core.generator.ClassicPlotManagerComponent; +import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotInventory; +import com.plotsquared.core.plot.PlotItemStack; +import com.plotsquared.core.queue.GlobalBlockQueue; +import com.plotsquared.core.util.EconHandler; +import com.plotsquared.core.util.MainUtil; +import com.plotsquared.core.util.PatternUtil; +import com.plotsquared.core.util.Permissions; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.world.item.ItemTypes; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +public class ComponentPresetManager { + + private final List presets; + private final String guiName; + + public ComponentPresetManager() { + final File file = new File(Objects.requireNonNull(PlotSquared.imp()).getDirectory(), "components.yml"); + if (!file.exists()) { + boolean created = false; + try { + created = file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + if (!created) { + PlotSquared.log(Captions.PREFIX + "Failed to create components.yml"); + this.guiName = "&cInvalid!"; + this.presets = new ArrayList<>(); + return; + } + } + + ConfigurationSerialization.registerClass(ComponentPreset.class, "ComponentPreset"); + + final YamlConfiguration yamlConfiguration = YamlConfiguration.loadConfiguration(file); + + if (!yamlConfiguration.contains("title")) { + yamlConfiguration.set("title", "&6Plot Components"); + try { + yamlConfiguration.save(file); + } catch (IOException e) { + PlotSquared.log(Captions.PREFIX + "Failed to save default values to components.yml"); + e.printStackTrace(); + } + } + this.guiName = yamlConfiguration.getString("title", "&6Plot Components"); + + if (!yamlConfiguration.contains("presets")) { + yamlConfiguration.createSection("presets"); + } + + if (yamlConfiguration.contains("presets")) { + this.presets = yamlConfiguration.getMapList("presets").stream().map(o -> (Map) o) + .map(ComponentPreset::deserialize).collect(Collectors.toList()); + } else { + final List defaultPreset = + Collections.singletonList(new ComponentPreset(ClassicPlotManagerComponent.FLOOR, + "##wool", 0, "", "&6D&ai&cs&ec&bo &2F&3l&do&9o&4r", + Arrays.asList("&6Spice up your plot floor"), ItemTypes.YELLOW_WOOL)); + yamlConfiguration.set("presets", defaultPreset.stream().map(ComponentPreset::serialize) + .collect(Collectors.toList())); + try { + yamlConfiguration.save(file); + } catch (final IOException e) { + PlotSquared.log(Captions.PREFIX + "Failed to save default values to components.yml"); + e.printStackTrace(); + } + this.presets = defaultPreset; + } + + MainCommand.getInstance().register(new ComponentCommand(this)); + } + + /** + * Build the component inventory for a player. This also checks + * if the player is in a compatible plot, and sends appropriate + * error messages if not + * + * @return Build inventory, if it could be created + */ + @Nullable public PlotInventory buildInventory(final PlotPlayer player) { + final Plot plot = player.getCurrentPlot(); + + if (plot == null) { + Captions.NOT_IN_PLOT.send(player); + return null; + } else if (!plot.hasOwner()) { + Captions.PLOT_UNOWNED.send(player); + return null; + } else if (!plot.isOwner(player.getUUID()) && !plot.getTrusted().contains(player.getUUID())) { + Captions.NO_PLOT_PERMS.send(player); + return null; + } + + final List allowedPresets = new ArrayList<>(this.presets.size()); + for (final ComponentPreset componentPreset : this.presets) { + if (!componentPreset.getPermission().isEmpty() && !Permissions + .hasPermission(player, componentPreset.getPermission())) { + continue; + } + allowedPresets.add(componentPreset); + } + final int size = (int) Math.ceil((double) allowedPresets.size() / 9.0D); + final PlotInventory plotInventory = new PlotInventory(player, size, this.guiName) { + @Override public boolean onClick(final int index) { + if (!player.getCurrentPlot().equals(plot)) { + return false; + } + + if (index < 0 || index >= allowedPresets.size()) { + return false; + } + + final ComponentPreset componentPreset = allowedPresets.get(index); + if (componentPreset == null) { + return false; + } + + if (plot.getRunning() > 0) { + Captions.WAIT_FOR_TIMER.send(player); + return false; + } + + final Pattern pattern = PatternUtil.parse(null, componentPreset.getPattern(), false); + if (pattern == null) { + Captions.PRESET_INVALID.send(player); + return false; + } + + if (componentPreset.getCost() > 0.0D && EconHandler.manager != null && plot.getArea().useEconomy()) { + if (EconHandler.manager.getMoney(player) < componentPreset.getCost()) { + Captions.PRESET_CANNOT_AFFORD.send(player); + return false; + } else { + EconHandler.manager.withdrawMoney(player, componentPreset.getCost()); + Captions.REMOVED_BALANCE.send(player, componentPreset.getCost() + ""); + } + } + + BackupManager.backup(player, plot, () -> { + plot.addRunning(); + for (Plot current : plot.getConnectedPlots()) { + current.setComponent(componentPreset.getComponent().name(), pattern); + } + MainUtil.sendMessage(player, Captions.GENERATING_COMPONENT); + GlobalBlockQueue.IMP.addEmptyTask(plot::removeRunning); + }); + return false; + } + }; + + + for (int i = 0; i < allowedPresets.size(); i++) { + final ComponentPreset preset = allowedPresets.get(i); + final List lore = new ArrayList<>(); + if (preset.getCost() > 0 && EconHandler.manager != null && plot.getArea().useEconomy()){ + lore.add(Captions.PRESET_LORE_COST.getTranslated().replace("%cost%", + String.format("%.2f", preset.getCost()))); + } + lore.add(Captions.PRESET_LORE_COMPONENT.getTranslated().replace("%component%", + preset.getComponent().name().toLowerCase())); + lore.removeIf(String::isEmpty); + if (!lore.isEmpty()) { + lore.add("&6"); + } + lore.addAll(preset.getDescription()); + plotInventory.setItem(i, new PlotItemStack(preset.getIcon().getId().replace("minecraft:", ""), + 1, preset.getDisplayName(), lore.toArray(new String[0]))); + } + + return plotInventory; + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/configuration/Captions.java b/Core/src/main/java/com/plotsquared/core/configuration/Captions.java index 17c0d7c4d..6238ec066 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Captions.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Captions.java @@ -769,6 +769,13 @@ public enum Captions implements Caption { BACKUP_AUTOMATIC_FAILURE("$2The automatic backup process failed. Your pending action has been canceled. Reason: %s", "Backups"), // + // + PRESET_CANNOT_AFFORD("$2You cannot afford that preset", "Preset"), + PRESET_INVALID("$2Could not generate a pattern from that preset", "Preset"), + PRESET_LORE_COST("$2Cost: $1%cost%", "Preset"), + PRESET_LORE_COMPONENT("$2Component: $1%component%", "Preset"), + // + // GENERIC_OTHER("other", "Generic"), GENERIC_MERGED("merged", "Generic"), diff --git a/Core/src/main/java/com/plotsquared/core/configuration/Settings.java b/Core/src/main/java/com/plotsquared/core/configuration/Settings.java index fe3edf6c3..044642baa 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Settings.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Settings.java @@ -529,6 +529,8 @@ public class Settings extends Config { PERSISTENT_ROAD_REGEN = false; @Comment("Try to guess plot owners from sign data. This may decrease server performance") public static boolean GUESS_PLOT_OWNER = false; + @Comment("Plot component preset GUI") + public static boolean COMPONENT_PRESETS = true; } } diff --git a/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManager.java b/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManager.java index ffd9bbdef..022f7037d 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManager.java +++ b/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManager.java @@ -41,6 +41,7 @@ import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.world.block.BlockTypes; import java.util.List; +import java.util.Optional; /** * A plot manager with square plots which tessellate on a square grid with the following sections: ROAD, WALL, BORDER (wall), PLOT, FLOOR (plot). @@ -55,23 +56,27 @@ public class ClassicPlotManager extends SquarePlotManager { } @Override public boolean setComponent(PlotId plotId, String component, Pattern blocks) { - switch (component) { - case "floor": - return setFloor(plotId, blocks); - case "wall": - return setWallFilling(plotId, blocks); - case "all": - return setAll(plotId, blocks); - case "air": - return setAir(plotId, blocks); - case "main": - return setMain(plotId, blocks); - case "middle": - return setMiddle(plotId, blocks); - case "outline": - return setOutline(plotId, blocks); - case "border": - return setWall(plotId, blocks); + final Optional componentOptional = + ClassicPlotManagerComponent.fromString(component); + if (componentOptional.isPresent()) { + switch (componentOptional.get()) { + case FLOOR: + return setFloor(plotId, blocks); + case WALL: + return setWallFilling(plotId, blocks); + case AIR: + return setAir(plotId, blocks); + case MAIN: + return setMain(plotId, blocks); + case MIDDLE: + return setMiddle(plotId, blocks); + case OUTLINE: + return setOutline(plotId, blocks); + case BORDER: + return setWall(plotId, blocks); + case ALL: + return setAll(plotId, blocks); + } } return false; } @@ -549,7 +554,7 @@ public class ClassicPlotManager extends SquarePlotManager { } @Override public String[] getPlotComponents(PlotId plotId) { - return new String[] {"main", "floor", "air", "all", "border", "wall", "outline", "middle"}; + return ClassicPlotManagerComponent.stringValues(); } /** @@ -564,4 +569,5 @@ public class ClassicPlotManager extends SquarePlotManager { return new Location(classicPlotWorld.getWorldName(), bot.getX() - 1, classicPlotWorld.ROAD_HEIGHT + 1, bot.getZ() - 2); } + } diff --git a/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManagerComponent.java b/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManagerComponent.java new file mode 100644 index 000000000..3856546a5 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManagerComponent.java @@ -0,0 +1,63 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.generator; + +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + +/** + * Plot components for {@link ClassicPlotManager} + */ +public enum ClassicPlotManagerComponent { + FLOOR, + WALL, + ALL, + AIR, + MAIN, + MIDDLE, + OUTLINE, + BORDER; + + public static String[] stringValues() { + final ClassicPlotManagerComponent[] classicPlotManagerComponents = values(); + final String[] stringValues = new String[classicPlotManagerComponents.length]; + for (int i = 0; i < classicPlotManagerComponents.length; i++) { + stringValues[i] = classicPlotManagerComponents[i].name().toLowerCase(); + } + return stringValues; + } + + public static Optional fromString(@NotNull final String string) { + for (final ClassicPlotManagerComponent classicPlotManagerComponent : values()) { + if (classicPlotManagerComponent.name().equalsIgnoreCase(string)) { + return Optional.of(classicPlotManagerComponent); + } + } + return Optional.empty(); + } + +}