diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d3ffd2d --- /dev/null +++ b/.gitignore @@ -0,0 +1,119 @@ +# IntelliJ project files +.idea +*.iml +out +gen + +### Java template +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### Maven template +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +# https://github.com/takari/maven-wrapper#usage-without-binary-jar +.mvn/wrapper/maven-wrapper.jar +.settings/ +.classpath +.project + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser diff --git a/contributors.txt b/contributors.txt index 9c7a332..e763408 100755 --- a/contributors.txt +++ b/contributors.txt @@ -1 +1,3 @@ Paddy Lamont +Darkilen +FabioZumbi12 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 7b09bfa..c69ecc9 100755 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.sothatsit flyingcarpet - 1.4.1 + 1.4.4 jar @@ -26,40 +26,44 @@ https://hub.spigotmc.org/nexus/content/repositories/snapshots/ - - vault-repo - http://nexus.theyeticave.net/content/repositories/pub_releases - - sk89q-repo - http://maven.sk89q.com/repo/ + https://maven.enginehub.org/repo/ - - bstats - https://repo.bstats.org/content/repositories/releases/ - org.spigotmc spigot-api - LATEST + 1.21.5-R0.1-SNAPSHOT provided com.sk89q.worldguard worldguard-core - 7.0.0-SNAPSHOT + 7.0.9 com.sk89q.worldedit worldedit-bukkit - LATEST + 7.3.0 + + + + io.github.fabiozumbi12.RedProtect + RedProtect-Core + 8.1.2 + + + + io.github.fabiozumbi12.RedProtect + RedProtect-Spigot + 8.1.2 + \ No newline at end of file diff --git a/releases/FlyingCarpet-1.4.2.jar b/releases/FlyingCarpet-1.4.2.jar new file mode 100644 index 0000000..f5fc31a Binary files /dev/null and b/releases/FlyingCarpet-1.4.2.jar differ diff --git a/releases/FlyingCarpet-1.4.3.jar b/releases/FlyingCarpet-1.4.3.jar new file mode 100644 index 0000000..86c9a48 Binary files /dev/null and b/releases/FlyingCarpet-1.4.3.jar differ diff --git a/src/main/java/me/sothatsit/flyingcarpet/FCCommand.java b/src/main/java/me/sothatsit/flyingcarpet/FCCommand.java index 83de068..6315bd1 100755 --- a/src/main/java/me/sothatsit/flyingcarpet/FCCommand.java +++ b/src/main/java/me/sothatsit/flyingcarpet/FCCommand.java @@ -1,36 +1,42 @@ package me.sothatsit.flyingcarpet; import me.sothatsit.flyingcarpet.message.Messages; - +import org.bukkit.Material; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; import org.bukkit.entity.Player; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class FCCommand implements CommandExecutor, TabCompleter { -public class FCCommand implements CommandExecutor { - @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if(args.length != 0 && args[0].equalsIgnoreCase("worldguard")) { - if(!sender.hasPermission("flyingcarpet.worldguard")) { + if (args.length != 0 && args[0].equalsIgnoreCase("worldguard")) { + if (!sender.hasPermission("flyingcarpet.worldguard")) { Messages.get("error.no-permissions.worldguard").send(sender); return true; } - if(!FlyingCarpet.isWorldGuardHooked()) { + if (FlyingCarpet.pluginHooks.stream().noneMatch(p -> p.hookName().equals("WorldGuard"))) { Messages.get("error.worldguard-not-hooked").send(sender); return true; } - if(args.length == 1) { + if (args.length == 1) { Messages.get("error.invalid-arguments").argument("%valid%", "/mc worldguard ").send(sender); return true; } - if(args[1].equalsIgnoreCase("add")) { - if(args.length != 3) { + if (args[1].equalsIgnoreCase("add")) { + if (args.length != 3) { Messages.get("error.invalid-arguments").argument("%valid%", "/mc worldguard add ").send(sender); return true; } @@ -40,8 +46,8 @@ public boolean onCommand(CommandSender sender, Command command, String label, St return true; } - if(args[1].equalsIgnoreCase("remove")) { - if(args.length != 3) { + if (args[1].equalsIgnoreCase("remove")) { + if (args.length != 3) { Messages.get("error.invalid-arguments").argument("%valid%", "/mc worldguard remove ").send(sender); return true; } @@ -51,22 +57,22 @@ public boolean onCommand(CommandSender sender, Command command, String label, St return true; } - if(args[1].equalsIgnoreCase("list")) { - if(args.length != 2) { + if (args[1].equalsIgnoreCase("list")) { + if (args.length != 2) { Messages.get("error.invalid-arguments").argument("%valid%", "/mc worldguard list").send(sender); return true; } Set regions = FlyingCarpet.getMainConfig().getWorldguardBlacklistedRegions(); - if(regions.size() == 0) { + if (regions.size() == 0) { Messages.get("message.wg.list-none").send(sender); return true; } Messages.get("message.wg.list-header").send(sender); - for(String region : regions) { + for (String region : regions) { Messages.get("message.wg.list-line").argument("%region%", region).send(sender); } @@ -77,170 +83,298 @@ public boolean onCommand(CommandSender sender, Command command, String label, St return true; } + if (args.length == 1 && args[0].equalsIgnoreCase("reload")) { + if (!sender.hasPermission("flyingcarpet.reload")) { + Messages.get("error.no-permissions.reload").send(sender); + return false; + } + + FlyingCarpet.getMainConfig().reloadConfiguration(); + + Messages.get("message.reload").send(sender); + return true; + } + if (!(sender instanceof Player)) { Messages.get("error.must-be-player").send(sender); return true; } - + Player p = (Player) sender; - + if (!p.hasPermission("flyingcarpet.use")) { Messages.get("error.no-permissions.carpet").send(sender); return true; } - + UPlayer up = FlyingCarpet.getInstance().getUPlayer(p); - + if (args.length == 0) { - if(!up.isEnabled() && !FlyingCarpet.getInstance().isCarpetAllowed(p.getLocation())) { + if (!up.isEnabled() && !FlyingCarpet.getInstance().isCarpetAllowed(p.getLocation())) { Messages.get("error.region-blocked").send(sender); return true; } up.setEnabled(!up.isEnabled()); - + if (up.isEnabled()) { Messages.get("message.carpet-on").send(sender); } else { Messages.get("message.carpet-off").send(sender); } - + return true; } - + if (args[0].equalsIgnoreCase("on")) { if (args.length != 1) { Messages.get("error.invalid-arguments").argument("%valid%", "/mc on").send(sender); return true; } - if(!FlyingCarpet.getInstance().isCarpetAllowed(p.getLocation())) { + if (!FlyingCarpet.getInstance().isCarpetAllowed(p.getLocation())) { Messages.get("error.region-blocked").send(sender); return true; } up.setEnabled(true); - + Messages.get("message.carpet-on").send(sender); return true; } - + if (args[0].equalsIgnoreCase("off")) { if (args.length != 1) { Messages.get("error.invalid-arguments").argument("%valid%", "/mc off").send(sender); return true; } - + up.setEnabled(false); - + Messages.get("message.carpet-off").send(sender); return true; } - - if (args[0].equalsIgnoreCase("reload")) { - if (!p.hasPermission("flyingcarpet.reload")) { - Messages.get("error.no-permissions.reload").send(sender); + + if (Stream.of(Material.values()).anyMatch(m->m.name().equalsIgnoreCase(args[0])) && !args[0].equalsIgnoreCase("light")) { + String mat = args[0]; + if (!mat.equalsIgnoreCase("glass") && !p.hasPermission("flyingcarpet.material." + mat)) { + Messages.get("error.no-permissions.material").send(sender); return false; } - + if (args.length != 1) { - Messages.get("error.invalid-arguments").argument("%valid%", "/mc off").send(sender); + Messages.get("error.invalid-arguments").argument("%valid%", "/mc ").send(sender); return true; } - - FlyingCarpet.getMainConfig().reloadConfiguration(); - - Messages.get("message.reload").send(sender); + + up.setMaterial(mat); + Messages.get("message.material").argument("%block%", mat).send(sender); + return true; + } + + if (args[0].equalsIgnoreCase("color")) { + if (!p.hasPermission("flyingcarpet.color")) { + Messages.get("error.no-permissions.color").send(sender); + return false; + } + + String[] validColors = {"none", "white", "orange", "magenta", "light_blue", "yellow", "lime", "pink", "gray", "light_gray", "cyan", "purple", "blue", "brown", "green", "red", "black"}; + String[] colorCodes = {"&f", "&f", "&6", "&5", "&b", "&e", "&a", "&d", "&8", "&7", "&3", "&5", "&9", "&4", "&2", "&c", "&0"}; + String possible_color_str = "<" + String.join("|", validColors) + ">"; + + if (args.length != 2) { + Messages.get("error.invalid-arguments").argument("%valid%", "/mc color " + possible_color_str).send(sender); + return true; + } + + String color = args[1].toLowerCase(); + + int colorIdx = -1; + for (int i = 0 ; i < validColors.length; i++ ) { + if (validColors[i].equals(color)) { + colorIdx = i; + break; + } + } + + if (colorIdx < 0) { + Messages.get("error.invalid-arguments").argument("%valid%", "/mc color " + possible_color_str).send(sender); + return true; + } + + up.setColor(color); + + String color_str = colorCodes[colorIdx] + "&l" + color; + Messages.get("message.color").argument("%color%", color_str).send(sender); + return true; + } + + if (args[0].equalsIgnoreCase("size")) { + try { + int size = Integer.parseInt(args[1]); + if (size != 2 && !p.hasPermission("flyingcarpet.size." + size)) { + Messages.get("error.no-permissions.size").send(sender); + return false; + } + + if (args.length != 2 || (size < 2 || size > 10)) { + Messages.get("error.invalid-arguments").argument("%valid%", "/mc size ").send(sender); + return true; + } + + up.setSize(size); + Messages.get("message.size").argument("%size%", String.valueOf(size)).send(sender); + } catch (Exception ex) { + Messages.get("error.invalid-arguments").argument("%valid%", "/mc size ").send(sender); + } return true; } - + + if (args[0].equalsIgnoreCase("touch")) { + if (!p.hasPermission("flyingcarpet.touch")) { + Messages.get("error.no-permissions.touch").send(sender); + return false; + } + + if (args.length != 1 && args.length != 2) { + Messages.get("error.invalid-arguments").argument("%valid%", "/mc touch [on:off]").send(sender); + } + + if (args.length == 1) { + up.setTouch(!up.isTouch()); + if (up.isTouch()) + Messages.get("message.touch-on").send(sender); + else + Messages.get("message.touch-off").send(sender); + + return true; + } + + if (args[1].equalsIgnoreCase("on")) { + up.setTouch(true); + + Messages.get("message.touch-on").send(sender); + return true; + } + + if (args[1].equalsIgnoreCase("off")) { + up.setTouch(false); + + Messages.get("message.touch-off").send(sender); + return true; + } + } + if (args[0].equalsIgnoreCase("tools")) { if (!p.hasPermission("flyingcarpet.tools")) { Messages.get("error.no-permissions.tools").send(sender); return false; } - + if (args.length != 1 && args.length != 2) { Messages.get("error.invalid-arguments").argument("%valid%", "/mc tools [on:off]").send(sender); return true; } - + if (args.length == 1) { up.setTools(!up.isTools()); - + if (up.isTools()) Messages.get("message.tools-on").send(sender); else Messages.get("message.tools-off").send(sender); - + return true; } - + if (args[1].equalsIgnoreCase("on")) { up.setTools(true); - + Messages.get("message.tools-on").send(sender); return true; } - + if (args[1].equalsIgnoreCase("off")) { up.setTools(false); - + Messages.get("message.tools-off").send(sender); return true; } - + Messages.get("error.invalid-arguments").argument("%valid%", "/mc tools [on:off]").send(sender); return true; } - + if (args[0].equalsIgnoreCase("light")) { if (!p.hasPermission("flyingcarpet.light")) { Messages.get("error.no-permissions.light").send(sender); return true; } - + if (args.length != 1 && args.length != 2) { Messages.get("error.invalid-arguments").argument("%valid%", "/mc light [on:off]").send(sender); return true; } - + if (args.length == 1) { up.setLight(!up.isLight()); - + if (up.isLight()) Messages.get("message.light-on").send(sender); else Messages.get("message.light-off").send(sender); - + return true; } - + if (args[1].equalsIgnoreCase("on")) { up.setLight(true); - + Messages.get("message.light-on").send(sender); return true; } - + if (args[1].equalsIgnoreCase("off")) { up.setLight(false); - + Messages.get("message.light-off").send(sender); return true; } - + Messages.get("error.invalid-arguments").argument("%valid%", "/mc light [on:off]").send(sender); return true; } - String arguments = "on:off:tools:light"; + String arguments = "on:off:tools:light:touch:size:"; - if(FlyingCarpet.isWorldGuardHooked() && p.hasPermission("flyingcarpet.worldguard")) { + if (FlyingCarpet.pluginHooks.stream().anyMatch(pl -> pl.hookName().equals("WorldGuard")) && p.hasPermission("flyingcarpet.worldguard")) { arguments += ":worldguard"; } Messages.get("error.invalid-arguments").argument("%valid%", "/mc [" + arguments + "]").send(sender); return true; } + + @Override + public List onTabComplete(CommandSender commandSender, Command command, String s, String[] strings) { + List tab = new ArrayList<>(); + if (strings.length == 1) { + if (commandSender.hasPermission("flyingcarpet.tools")) + tab.add("tools"); + if (commandSender.hasPermission("flyingcarpet.light")) + tab.add("light"); + if (commandSender.hasPermission("flyingcarpet.touch")) + tab.add("touch"); + if (commandSender.hasPermission("flyingcarpet.reload")) + tab.add("reload"); + tab.add("size"); + tab.add("color"); + tab.addAll(Arrays.stream(Material.values()).filter(m->commandSender.hasPermission("flyingcarpet.material."+m.name().toLowerCase())).map(m->m.name().toLowerCase()).collect(Collectors.toList())); + } else if (strings.length == 2 && strings[0].equalsIgnoreCase("color")) { + // Add color options for tab completion + tab.addAll(Arrays.asList("none", "white", "orange", "magenta", "light_blue", "yellow", "lime", "pink", "gray", "light_gray", "cyan", "purple", "blue", "brown", "green", "red", "black")); + } + + return tab; + } } diff --git a/src/main/java/me/sothatsit/flyingcarpet/FCConfig.java b/src/main/java/me/sothatsit/flyingcarpet/FCConfig.java index 6479f4e..ba1f530 100755 --- a/src/main/java/me/sothatsit/flyingcarpet/FCConfig.java +++ b/src/main/java/me/sothatsit/flyingcarpet/FCConfig.java @@ -1,8 +1,8 @@ package me.sothatsit.flyingcarpet; import me.sothatsit.flyingcarpet.message.ConfigWrapper; -import me.sothatsit.flyingcarpet.model.Model; import me.sothatsit.flyingcarpet.model.BlockData; +import me.sothatsit.flyingcarpet.model.Model; import org.bukkit.block.Block; import org.bukkit.configuration.ConfigurationSection; @@ -22,6 +22,26 @@ public class FCConfig { private Set worldguardRegionBlacklist = new HashSet<>(); + private static void copySection(ConfigurationSection defaults, + ConfigurationSection config, + ConfigurationSection section, + AtomicBoolean requiresSave) { + + for (String key : defaults.getKeys(true)) { + if (!key.startsWith(section.getCurrentPath()) || config.isSet(key)) + continue; + + if (defaults.isConfigurationSection(key)) { + config.createSection(key); + requiresSave.set(true); + continue; + } + + config.set(key, defaults.get(key)); + requiresSave.set(true); + } + } + public Model getBaseModel() { return base; } @@ -74,6 +94,7 @@ public void reloadConfiguration() { passThrough = new HashSet<>(); passThrough.add(BlockData.AIR); + passThrough.add(BlockData.CAVE_AIR); List passThroughStrings = config.getStringList("pass-through"); List passThroughReformatted = new ArrayList<>(passThroughStrings); @@ -98,7 +119,7 @@ public void reloadConfiguration() { } } - if(requiresSave.get()) { + if (requiresSave.get()) { config.set("pass-through", passThroughReformatted); } @@ -144,41 +165,21 @@ public void reloadConfiguration() { tools = Model.fromConfig(toolsSec, requiresSave); light = Model.fromConfig(lightSec, requiresSave); - if(FlyingCarpet.isWorldGuardHooked()) { + if (FlyingCarpet.pluginHooks.stream().anyMatch(p -> p.hookName().equals("WorldGuard"))) { reloadWorldguardConfiguration(config); } - if(requiresSave.get()) { + if (requiresSave.get()) { configWrapper.save(); } } - private static void copySection(ConfigurationSection defaults, - ConfigurationSection config, - ConfigurationSection section, - AtomicBoolean requiresSave) { - - for (String key : defaults.getKeys(true)) { - if(!key.startsWith(section.getCurrentPath()) || config.isSet(key)) - continue; - - if (defaults.isConfigurationSection(key)) { - config.createSection(key); - requiresSave.set(true); - continue; - } - - config.set(key, defaults.get(key)); - requiresSave.set(true); - } - } - public void reloadWorldguardConfiguration(ConfigurationSection config) { - if(!config.isSet("wg-region-blacklist") || !config.isList("wg-region-blacklist")) { + if (!config.isSet("wg-region-blacklist") || !config.isList("wg-region-blacklist")) { config.set("wg-region-blacklist", new ArrayList<>(worldguardRegionBlacklist)); } - for(String region : config.getStringList("wg-region-blacklist")) { + for (String region : config.getStringList("wg-region-blacklist")) { worldguardRegionBlacklist.add(region.toLowerCase()); } diff --git a/src/main/java/me/sothatsit/flyingcarpet/FlyingCarpet.java b/src/main/java/me/sothatsit/flyingcarpet/FlyingCarpet.java index fb23cc3..68ceedd 100755 --- a/src/main/java/me/sothatsit/flyingcarpet/FlyingCarpet.java +++ b/src/main/java/me/sothatsit/flyingcarpet/FlyingCarpet.java @@ -2,11 +2,15 @@ import java.util.*; +import me.sothatsit.flyingcarpet.hooks.PluginHooks; +import me.sothatsit.flyingcarpet.hooks.RedProtectHook; +import me.sothatsit.flyingcarpet.hooks.WorldGuardHook; import me.sothatsit.flyingcarpet.message.ConfigWrapper; import me.sothatsit.flyingcarpet.message.Messages; import me.sothatsit.flyingcarpet.model.BlockOffset; import org.bukkit.Bukkit; +import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.entity.Entity; @@ -22,73 +26,79 @@ import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.hanging.HangingBreakEvent; -import org.bukkit.event.player.PlayerKickEvent; -import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.event.player.PlayerTeleportEvent; -import org.bukkit.event.player.PlayerToggleSneakEvent; +import org.bukkit.event.player.*; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.potion.PotionEffectType; import org.bukkit.scheduler.BukkitRunnable; public class FlyingCarpet extends JavaPlugin implements Listener { - + private static FlyingCarpet instance; private FCConfig mainConfig; - private WorldGuardHook worldGuardHook; - + static List pluginHooks; private List players = new ArrayList<>(); - + @Override public void onEnable() { instance = this; - + getCommand("flyingcarpet").setExecutor(new FCCommand()); Bukkit.getPluginManager().registerEvents(this, this); - + Messages.setConfig(new ConfigWrapper(this, "lang.yml")); - hookWorldGuard(); + pluginHooks = new ArrayList<>(); + setupHooks(); mainConfig = new FCConfig(); mainConfig.reloadConfiguration(); + info("FlyingCarpet Enabled!"); } @Override public void onDisable() { instance = null; - + for (UPlayer up : players) { up.setEnabled(false); } } public boolean isCarpetAllowed(Location loc) { - return !isWorldGuardHooked() || worldGuardHook.isCarpetAllowed(loc); + for (PluginHooks plugin : pluginHooks) { + if (!plugin.isCarpetAllowed(loc)) + return false; + } + return true; } - private void hookWorldGuard() { - Plugin plugin = getServer().getPluginManager().getPlugin("WorldGuard"); - if (plugin == null) - return; + private void setupHooks() { + Plugin worldGuard = getServer().getPluginManager().getPlugin("WorldGuard"); + if (worldGuard != null) { + pluginHooks.add(new WorldGuardHook()); + info("Hooked WorldGuard"); + } - worldGuardHook = new WorldGuardHook(); - info("Hooked WorldGuard"); + Plugin redProtect = getServer().getPluginManager().getPlugin("RedProtect"); + if (redProtect != null) { + pluginHooks.add(new RedProtectHook()); + info("Hooked RedProtect"); + } } - public UPlayer getUPlayer(Player p) { for (UPlayer up : players) { if (up.getPlayer().getUniqueId().equals(p.getUniqueId())) return up; } - + UPlayer up = new UPlayer(p); players.add(up); return up; } - + public UPlayer getUPlayer(UUID uuid) { for (UPlayer up : players) { if (up.getPlayer().getUniqueId().equals(uuid)) @@ -96,33 +106,33 @@ public UPlayer getUPlayer(UUID uuid) { } return null; } - + public void removeUPlayer(Player p) { UPlayer up = getUPlayer(p); - + if (up == null) return; - + players.remove(up); - + up.setEnabled(false); } - + @EventHandler public void onPlayerQuit(PlayerQuitEvent e) { removeUPlayer(e.getPlayer()); } - + @EventHandler public void onPlayerKick(PlayerKickEvent e) { removeUPlayer(e.getPlayer()); } - + @EventHandler public void onBlockBreak(BlockBreakEvent e) { for (UPlayer up : players) { Player p = up.getPlayer(); - + if (!up.isCarpetBlock(e.getBlock())) { if (up.isEnabled()) { final UUID uuid = p.getUniqueId(); @@ -130,30 +140,30 @@ public void onBlockBreak(BlockBreakEvent e) { @Override public void run() { UPlayer up = getUPlayer(uuid); - + if (up == null) return; - + up.createCarpet(); } }.runTask(this); } - + continue; } - + e.setCancelled(true); return; } } - + @EventHandler public void onBlockPistonExtend(BlockPistonExtendEvent e) { for (Block b : e.getBlocks()) { for (UPlayer up : players) { if (!up.isCarpetBlock(b)) continue; - + e.setCancelled(true); return; } @@ -172,26 +182,26 @@ public void onBlockPistonRetract(BlockPistonRetractEvent e) { } } } - + @EventHandler public void onHangingBreak(HangingBreakEvent e) { for (UPlayer up : players) { if (!up.isCarpetBlock(e.getEntity().getLocation())) continue; - + e.setCancelled(true); return; } } - + @EventHandler public void onEntityExplode(EntityExplodeEvent e) { List remove = new ArrayList<>(); - + for (Block b : e.blockList()) { for (UPlayer up : players) { Player p = up.getPlayer(); - + if (!up.isCarpetBlock(b)) { if (up.isEnabled()) { final UUID uuid = p.getUniqueId(); @@ -199,49 +209,49 @@ public void onEntityExplode(EntityExplodeEvent e) { @Override public void run() { UPlayer up = getUPlayer(uuid); - + if (up == null) return; - + up.createCarpet(); } }.runTask(this); } - + continue; } - + remove.add(b); } } - + for (Block block : remove) { e.blockList().remove(block); } } - + @EventHandler public void onEntityDamage(EntityDamageEvent e) { - if(e.getCause() != DamageCause.SUFFOCATION) + if (e.getCause() != DamageCause.SUFFOCATION) return; Entity entity = e.getEntity(); Location location = entity.getLocation(); - for(UPlayer up : players) { - if(!up.isCarpetBlock(location)) + for (UPlayer up : players) { + if (!up.isCarpetBlock(location)) continue; e.setCancelled(true); return; } - - if(entity instanceof LivingEntity) { + + if (entity instanceof LivingEntity) { LivingEntity livingEntity = (LivingEntity) entity; Location eyeLocation = livingEntity.getEyeLocation(); - for(UPlayer up : players) { - if(!up.isCarpetBlock(eyeLocation)) + for (UPlayer up : players) { + if (!up.isCarpetBlock(eyeLocation)) continue; e.setCancelled(true); @@ -249,7 +259,7 @@ public void onEntityDamage(EntityDamageEvent e) { } } } - + @EventHandler public void onPlayerDamage(EntityDamageEvent e) { if (e.getCause() != DamageCause.FALL || !(e.getEntity() instanceof Player)) @@ -257,24 +267,24 @@ public void onPlayerDamage(EntityDamageEvent e) { Player p = (Player) e.getEntity(); UPlayer up = getUPlayer(p); - + if (up.isEnabled()) { e.setCancelled(true); } } - + @EventHandler(priority = EventPriority.MONITOR) public void onPlayerTeleport(PlayerTeleportEvent e) { if (e.isCancelled() || BlockOffset.locEqual(e.getFrom(), e.getTo())) return; - + UPlayer up = getUPlayer(e.getPlayer()); - + if (BlockOffset.locColumnEqual(e.getFrom(), e.getTo()) && Math.abs(e.getFrom().getY() - e.getTo().getY()) <= 2) { up.setLocation(e.getTo().clone().subtract(0, 1, 0)); return; } - + if (up.isEnabled() && !e.getPlayer().hasPermission("flyingcarpet.teleport")) { up.setEnabled(false); Messages.get("message.teleport-remove").send(e.getPlayer()); @@ -282,39 +292,39 @@ public void onPlayerTeleport(PlayerTeleportEvent e) { up.setLocation(e.getTo().clone().subtract(0, 1, 0)); } } - + @EventHandler(priority = EventPriority.MONITOR) public void onPlayerMove(PlayerMoveEvent e) { if (e.isCancelled() || BlockOffset.locEqual(e.getFrom(), e.getTo())) return; - + UPlayer up = getUPlayer(e.getPlayer()); - + if (up.isEnabled() && up.getLocation().getBlockY() == e.getTo().getBlockY() && up.isCarpetBlock(e.getTo().getBlock())) { Location loc = e.getPlayer().getLocation(); - + loc.setY(up.getLocation().getBlockY() + 1.2d); - + e.getPlayer().teleport(loc); return; } - + up.setLocation(e.getTo().clone().subtract(0, 1, 0)); } - + @EventHandler public void onPlayerToggleSneak(PlayerToggleSneakEvent e) { if (!e.isSneaking()) { getUPlayer(e.getPlayer()).stopDescent(); return; } - + UPlayer up = getUPlayer(e.getPlayer()); - + up.setLocation(e.getPlayer().getLocation().subtract(0, 2, 0)); up.startDescent(); } - + public static FlyingCarpet getInstance() { return instance; } @@ -323,10 +333,6 @@ public static FCConfig getMainConfig() { return instance.mainConfig; } - public static boolean isWorldGuardHooked() { - return instance.worldGuardHook != null; - } - public static void info(String info) { instance.getLogger().info(info); } diff --git a/src/main/java/me/sothatsit/flyingcarpet/UPlayer.java b/src/main/java/me/sothatsit/flyingcarpet/UPlayer.java index bfda202..488496b 100755 --- a/src/main/java/me/sothatsit/flyingcarpet/UPlayer.java +++ b/src/main/java/me/sothatsit/flyingcarpet/UPlayer.java @@ -1,33 +1,39 @@ package me.sothatsit.flyingcarpet; -import java.util.*; - import me.sothatsit.flyingcarpet.message.Messages; -import me.sothatsit.flyingcarpet.model.Model; import me.sothatsit.flyingcarpet.model.BlockData; -import me.sothatsit.flyingcarpet.model.Region; import me.sothatsit.flyingcarpet.model.BlockOffset; - +import me.sothatsit.flyingcarpet.model.Model; +import me.sothatsit.flyingcarpet.model.Region; import me.sothatsit.flyingcarpet.util.Checks; 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.entity.Player; +import org.bukkit.potion.PotionEffectType; import org.bukkit.scheduler.BukkitRunnable; +import java.util.*; + public class UPlayer { - + private final Player player; private final Map blocks; + private String material; + private String color; + private int size = 0; + private boolean touch = false; + private Location loc; private boolean enabled; private boolean tools; private boolean light; - + private BukkitRunnable descendTimer; - + public UPlayer(Player player) { this.player = player; this.loc = player.getLocation().subtract(0, 1, 0); @@ -36,42 +42,112 @@ public UPlayer(Player player) { this.light = false; this.blocks = new HashMap<>(); } - + + public void setTouch(boolean touch) { + this.touch = touch; + } + + public boolean isTouch() { + return touch; + } + + public void setSize(int size) { + this.size = size; + createCarpet(); + } + + public void setMaterial(String material) { + this.material = material; + if (enabled) + createCarpet(); + } + + public void setColor(String color) { + this.color = color; + if (enabled) + createCarpet(); + } + public Player getPlayer() { return player; } - + public Location getLocation() { return loc; } - + + public void setLocation(Location loc) { + if (!enabled || BlockOffset.locEqual(this.loc, loc)) { + this.loc = loc; + return; + } + + this.loc = loc; + + createCarpet(); + } + public boolean isEnabled() { return enabled; } - + + public void setEnabled(boolean enabled) { + if (this.enabled == enabled) + return; + + this.enabled = enabled; + + if (enabled) + createCarpet(); + else + removeCarpet(); + } + public boolean isTools() { return tools; } - + + public void setTools(boolean tools) { + if (!enabled || this.tools == tools) { + this.tools = tools; + return; + } + + this.tools = tools; + + this.createCarpet(); + } + public boolean isLight() { return light; } + public void setLight(boolean light) { + if (!enabled || this.light == light) { + this.light = light; + return; + } + + this.light = light; + + this.createCarpet(); + } + public BukkitRunnable getDescendTimer() { return descendTimer; } - + public void stopDescent() { - if(descendTimer == null) + if (descendTimer == null) return; descendTimer.cancel(); descendTimer = null; } - + public void startDescent() { stopDescent(); - + descendTimer = new BukkitRunnable() { @Override public void run() { @@ -79,7 +155,7 @@ public void run() { this.cancel(); return; } - + setLocation(player.getLocation().subtract(0, 2, 0)); } }; @@ -95,58 +171,13 @@ public boolean isCarpetBlock(Location location) { public boolean isCarpetBlock(Block block) { return isCarpetBlock(BlockOffset.fromBlock(block)); } - + public boolean isCarpetBlock(BlockOffset location) { return blocks.containsKey(location); } - - public void setEnabled(boolean enabled) { - if (this.enabled == enabled) - return; - - this.enabled = enabled; - - if (enabled) - createCarpet(); - else - removeCarpet(); - } - - public void setLocation(Location loc) { - if (!enabled || BlockOffset.locEqual(this.loc, loc)) { - this.loc = loc; - return; - } - - this.loc = loc; - - createCarpet(); - } - - public void setTools(boolean tools) { - if (!enabled || this.tools == tools) { - this.tools = tools; - return; - } - - this.tools = tools; - - this.createCarpet(); - } - - public void setLight(boolean light) { - if (!enabled || this.light == light) { - this.light = light; - return; - } - - this.light = light; - - this.createCarpet(); - } public void removeCarpet() { - for(BlockState state : blocks.values()) { + for (BlockState state : blocks.values()) { state.update(true, false); } @@ -156,11 +187,31 @@ public void removeCarpet() { public List getModels() { List models = new ArrayList<>(3); - models.add(FlyingCarpet.getMainConfig().getBaseModel()); + String mat = FlyingCarpet.getMainConfig().getBaseModel().getBlockData(BlockOffset.from(loc,loc)).getType().name().toLowerCase(); - if(tools) + if (material != null) { + mat = material; + + if (mat.equals("glass") && color != null) + if (!color.equals("none")) + mat = color + "_stained_glass"; + } else if (color != null) { + if (!color.equals("none")) + mat = color + "_stained_glass"; + } + + if (player.getActivePotionEffects().stream().anyMatch(pot->pot.getType().equals(PotionEffectType.INVISIBILITY))) + mat = "barrier"; + + if (size == 0) { + models.add(Model.fromTypeAndSize(mat, FlyingCarpet.getMainConfig().getBaseModel().region.max.x, 0, FlyingCarpet.getMainConfig().getBaseModel().region.max.x)); + } else { + models.add(Model.fromTypeAndSize(mat, size, 0, size)); + } + + if (tools) models.add(FlyingCarpet.getMainConfig().getToolsModel()); - if(light) + if (light) models.add(FlyingCarpet.getMainConfig().getLightModel()); return models; @@ -170,12 +221,12 @@ public Region getCarpetRegion(List models) { Checks.ensureNonNull(models, "models"); Checks.ensureTrue(models.size() > 0, "models cannot be empty"); - if(models.size() == 1) + if (models.size() == 1) return models.get(0).region; List regions = new ArrayList<>(models.size()); - for(Model model : models) { + for (Model model : models) { regions.add(model.region); } @@ -183,7 +234,7 @@ public Region getCarpetRegion(List models) { } public void createCarpet() { - if(!FlyingCarpet.getInstance().isCarpetAllowed(player.getLocation())) { + if (!FlyingCarpet.getInstance().isCarpetAllowed(player.getLocation())) { setEnabled(false); Messages.get("message.region-remove").send(player); return; @@ -208,7 +259,7 @@ public void createCarpet() { BlockData data = Model.getBlockData(models, offset); - if(data == BlockData.AIR) + if (data == BlockData.AIR) continue; modelBlocks.put(location, data); @@ -219,7 +270,7 @@ public void createCarpet() { List restore = new ArrayList<>(); Iterator> placedIterator = blocks.entrySet().iterator(); - while(placedIterator.hasNext()) { + while (placedIterator.hasNext()) { Map.Entry entry = placedIterator.next(); BlockOffset location = entry.getKey(); @@ -227,7 +278,7 @@ public void createCarpet() { BlockData data = modelBlocks.get(location); - if(data == null) { + if (data == null) { restore.add(state); placedIterator.remove(); continue; @@ -237,20 +288,20 @@ public void createCarpet() { modelBlocks.remove(location); } - for(Map.Entry entry : modelBlocks.entrySet()) { + for (Map.Entry entry : modelBlocks.entrySet()) { BlockOffset location = entry.getKey(); Block block = location.getBlock(world); BlockData blockData = entry.getValue(); - if(!mainConfig.canPassThrough(block)) + if (!mainConfig.canPassThrough(block)) continue; blocks.put(location, block.getState()); blockData.apply(block); } - for(BlockState state : restore) { - state.update(true, false); + for (BlockState state : restore) { + state.update(true, touch && FlyingCarpet.pluginHooks.stream().anyMatch(pl->pl.canBuild(player))); } } } diff --git a/src/main/java/me/sothatsit/flyingcarpet/WorldGuardHook.java b/src/main/java/me/sothatsit/flyingcarpet/WorldGuardHook.java deleted file mode 100755 index ec7766f..0000000 --- a/src/main/java/me/sothatsit/flyingcarpet/WorldGuardHook.java +++ /dev/null @@ -1,28 +0,0 @@ -package me.sothatsit.flyingcarpet; - -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldguard.WorldGuard; -import com.sk89q.worldguard.protection.managers.RegionManager; -import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import com.sk89q.worldguard.protection.regions.RegionContainer; - -import org.bukkit.Location; - -public class WorldGuardHook { - - public boolean isCarpetAllowed(Location loc) { - RegionContainer hook = WorldGuard.getInstance().getPlatform().getRegionContainer(); - RegionManager manager = hook.get(BukkitAdapter.adapt(loc.getWorld())); - if(manager == null) - return true; - - for(String regionName : FlyingCarpet.getMainConfig().getWorldguardBlacklistedRegions()) { - ProtectedRegion region = manager.getRegion(regionName); - - if (region != null && region.contains(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())) - return false; - } - - return true; - } -} diff --git a/src/main/java/me/sothatsit/flyingcarpet/hooks/PluginHooks.java b/src/main/java/me/sothatsit/flyingcarpet/hooks/PluginHooks.java new file mode 100644 index 0000000..9007834 --- /dev/null +++ b/src/main/java/me/sothatsit/flyingcarpet/hooks/PluginHooks.java @@ -0,0 +1,13 @@ +package me.sothatsit.flyingcarpet.hooks; + +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public interface PluginHooks { + + String hookName(); + + boolean isCarpetAllowed(Location loc); + + boolean canBuild(Player player); +} diff --git a/src/main/java/me/sothatsit/flyingcarpet/hooks/RedProtectHook.java b/src/main/java/me/sothatsit/flyingcarpet/hooks/RedProtectHook.java new file mode 100644 index 0000000..bfdaae2 --- /dev/null +++ b/src/main/java/me/sothatsit/flyingcarpet/hooks/RedProtectHook.java @@ -0,0 +1,29 @@ +package me.sothatsit.flyingcarpet.hooks; + +import br.net.fabiozumbi12.RedProtect.Bukkit.RedProtect; +import br.net.fabiozumbi12.RedProtect.Bukkit.Region; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public class RedProtectHook implements PluginHooks { + @Override + public String hookName() { + return "RedProtect"; + } + + @Override + public boolean isCarpetAllowed(Location loc) { + Region r = RedProtect.get().getRegionManager().getTopRegion(loc); + if (r == null) return true; + + return r.getFlagBool("allow-magiccarpet"); + } + + @Override + public boolean canBuild(Player player) { + Region r = RedProtect.get().getRegionManager().getTopRegion(player.getLocation()); + if (r == null) return true; + + return r.canBuild(player); + } +} diff --git a/src/main/java/me/sothatsit/flyingcarpet/hooks/WorldGuardHook.java b/src/main/java/me/sothatsit/flyingcarpet/hooks/WorldGuardHook.java new file mode 100644 index 0000000..9843d8e --- /dev/null +++ b/src/main/java/me/sothatsit/flyingcarpet/hooks/WorldGuardHook.java @@ -0,0 +1,52 @@ +package me.sothatsit.flyingcarpet.hooks; + +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldguard.LocalPlayer; +import com.sk89q.worldguard.WorldGuard; +import com.sk89q.worldguard.protection.managers.RegionManager; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import com.sk89q.worldguard.protection.regions.RegionContainer; +import me.sothatsit.flyingcarpet.FlyingCarpet; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.util.BlockVector; + +public class WorldGuardHook implements PluginHooks { + @Override + public String hookName() { + return "WorldGuard"; + } + + @Override + public boolean isCarpetAllowed(Location loc) { + RegionContainer hook = WorldGuard.getInstance().getPlatform().getRegionContainer(); + RegionManager manager = hook.get(BukkitAdapter.adapt(loc.getWorld())); + if (manager == null) + return true; + + for (String regionName : FlyingCarpet.getMainConfig().getWorldguardBlacklistedRegions()) { + ProtectedRegion region = manager.getRegion(regionName); + + if (region != null && region.contains(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())) + return false; + } + + return true; + } + + @Override + public boolean canBuild(Player player) { + RegionContainer hook = WorldGuard.getInstance().getPlatform().getRegionContainer(); + RegionManager manager = hook.get(BukkitAdapter.adapt(player.getWorld())); + if (manager == null) + return true; + + for (ProtectedRegion r :manager.getApplicableRegions(BlockVector3.at(player.getLocation().getBlockX(),player.getLocation().getBlockY(),player.getLocation().getBlockZ())).getRegions()) { + if (r.isMember(player.getName()) || r.isOwner(player.getName())) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/me/sothatsit/flyingcarpet/message/Argument.java b/src/main/java/me/sothatsit/flyingcarpet/message/Argument.java index 4f801da..e9bb0fe 100755 --- a/src/main/java/me/sothatsit/flyingcarpet/message/Argument.java +++ b/src/main/java/me/sothatsit/flyingcarpet/message/Argument.java @@ -4,44 +4,44 @@ import org.bukkit.entity.Player; public class Argument { - + private String argument; private String value; - + public Argument(String argument, String value) { this.argument = argument; this.value = value; } - - public String getArgument() { - return argument; - } - - public String getValue() { - return value; - } - - public String replace(String str) { - return str.replace(argument, value); - } - + public static Argument sender(CommandSender sender) { return new Argument("%sender%", sender.getName()); } - + public static Argument player(Player p) { return new Argument("%player%", p.getName()); } - + public static Argument player(String name) { return new Argument("%player%", name); } - + public static Argument valid(String valid) { return new Argument("%valid%", valid); } - + public static Argument action(String action) { return new Argument("%action%", action); } + + public String getArgument() { + return argument; + } + + public String getValue() { + return value; + } + + public String replace(String str) { + return str.replace(argument, value); + } } diff --git a/src/main/java/me/sothatsit/flyingcarpet/message/ConfigWrapper.java b/src/main/java/me/sothatsit/flyingcarpet/message/ConfigWrapper.java index b94341c..d57f196 100755 --- a/src/main/java/me/sothatsit/flyingcarpet/message/ConfigWrapper.java +++ b/src/main/java/me/sothatsit/flyingcarpet/message/ConfigWrapper.java @@ -1,16 +1,16 @@ package me.sothatsit.flyingcarpet.message; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.Plugin; + import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; -import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.util.logging.Level; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.Plugin; - public class ConfigWrapper { private Plugin plugin; @@ -19,7 +19,7 @@ public class ConfigWrapper { private String name; private boolean autoReload; private long lastEdit; - + public ConfigWrapper(Plugin plugin, String name) { this.plugin = plugin; this.name = name; @@ -27,57 +27,53 @@ public ConfigWrapper(Plugin plugin, String name) { this.autoReload = true; this.reload(); } - + public ConfigWrapper(File file) { this.configFile = file; this.reload(); } - + public boolean isAutoReload() { return autoReload; } - + public void setAutoReload(boolean autoReload) { this.autoReload = autoReload; } - + public void reload() { config = YamlConfiguration.loadConfiguration(configFile); lastEdit = configFile.lastModified(); - + Reader defConfigStream = null; - try { - defConfigStream = new InputStreamReader(plugin.getResource(name), "UTF8"); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - + defConfigStream = new InputStreamReader(plugin.getResource(name), StandardCharsets.UTF_8); + if (defConfigStream != null) { YamlConfiguration defConfig = YamlConfiguration.loadConfiguration(defConfigStream); config.setDefaults(defConfig); } } - + public FileConfiguration getConfig() { if (config == null || (autoReload && configFile.lastModified() != lastEdit)) { reload(); } - + return config; } - + public void save() { if (config == null || configFile == null) { return; } - + try { getConfig().save(configFile); } catch (IOException ex) { plugin.getLogger().log(Level.SEVERE, "Could not save config " + configFile, ex); } } - + public void saveDefaults() { if (plugin != null) { if (!configFile.exists()) { @@ -87,14 +83,8 @@ public void saveDefaults() { reload(); } } - + public FileConfiguration getDefaultConfig() { - try { - return YamlConfiguration.loadConfiguration(new InputStreamReader(plugin.getResource(name), "UTF8")); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - - return null; + return YamlConfiguration.loadConfiguration(new InputStreamReader(plugin.getResource(name), StandardCharsets.UTF_8)); } } diff --git a/src/main/java/me/sothatsit/flyingcarpet/message/Message.java b/src/main/java/me/sothatsit/flyingcarpet/message/Message.java index 3077b6f..6375640 100755 --- a/src/main/java/me/sothatsit/flyingcarpet/message/Message.java +++ b/src/main/java/me/sothatsit/flyingcarpet/message/Message.java @@ -1,16 +1,19 @@ package me.sothatsit.flyingcarpet.message; -import java.util.*; - import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + public class Message { - + private String key; private List messages; private List arguments; - + public Message(String key) { this.key = key; this.messages = new ArrayList<>(); @@ -18,90 +21,90 @@ public Message(String key) { this.messages.add("Unable to find the message \"" + key + "\""); } - + public Message(String key, List messages) { this.key = key; this.messages = new ArrayList<>(messages); this.arguments = new ArrayList<>(); } - + public Message(String key, String message) { this.key = key; this.messages = new ArrayList<>(Collections.singletonList(message)); this.arguments = new ArrayList<>(); } - + public String getKey() { return key; } - + public List getMessages() { List coloured = new ArrayList<>(); - + for (String message : messages) { for (Argument a : arguments) { message = a.replace(message); } - + coloured.add(ChatColor.translateAlternateColorCodes('&', message)); } - + return coloured; } - + public String getMessage() { if (messages.size() > 0) { String message = messages.get(0); - + for (Argument a : arguments) { message = a.replace(message); } - + return ChatColor.translateAlternateColorCodes('&', message); } - + return ""; } - + public List getArguments() { return arguments; } - + public Message argument(String key, String value) { arguments.add(new Argument(key, value)); - + return this; } - + public Message arguments(Argument... arguments) { return arguments(Arrays.asList(arguments)); } - + public Message arguments(List arguments) { this.arguments.addAll(arguments); - + return this; } - + public Message message(String message) { messages.add(message); - + return this; } - + public void send(CommandSender sender) { for (String message : messages) { if (message == null || (messages.size() == 1 && message.isEmpty())) continue; - + for (Argument a : arguments) { message = a.replace(message); } - + message = new Argument("%reciever%", sender.getName()).replace(message); - + message = ChatColor.translateAlternateColorCodes('&', message); - + sender.sendMessage(message); } } diff --git a/src/main/java/me/sothatsit/flyingcarpet/message/Messages.java b/src/main/java/me/sothatsit/flyingcarpet/message/Messages.java index 7af25af..ca46919 100755 --- a/src/main/java/me/sothatsit/flyingcarpet/message/Messages.java +++ b/src/main/java/me/sothatsit/flyingcarpet/message/Messages.java @@ -3,44 +3,44 @@ import org.bukkit.configuration.file.FileConfiguration; public class Messages { - + private static ConfigWrapper config = null; - + public static Message get(String key) { if (config == null) { return new Message(key); } - + Message message = new Message(key); - + if (config.getConfig().isConfigurationSection(key)) { key += ".default"; } - + if (config.getConfig().isString(key)) { message = new Message(key, config.getConfig().getString(key)); } else if (config.getConfig().isList(key)) { message = new Message(key, config.getConfig().getStringList(key)); } - + return message; } - + public static void setConfig(ConfigWrapper config) { Messages.config = config; - + reload(); } - + public static void reload() { if (config == null) { return; } - + boolean changed = false; FileConfiguration defaults = config.getDefaultConfig(); FileConfiguration conf = config.getConfig(); - + for (String key : defaults.getKeys(true)) { if (!conf.isSet(key)) { if (conf.isConfigurationSection(key)) { @@ -48,12 +48,12 @@ public static void reload() { changed = true; continue; } - + conf.set(key, defaults.get(key)); changed = true; } } - + if (changed) { config.save(); } diff --git a/src/main/java/me/sothatsit/flyingcarpet/model/BlockData.java b/src/main/java/me/sothatsit/flyingcarpet/model/BlockData.java index 15ce6e0..de89af0 100755 --- a/src/main/java/me/sothatsit/flyingcarpet/model/BlockData.java +++ b/src/main/java/me/sothatsit/flyingcarpet/model/BlockData.java @@ -5,37 +5,78 @@ import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.event.block.BlockPhysicsEvent; -import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; public class BlockData { - + public static final BlockData AIR = new BlockData(Material.AIR); + public static final BlockData CAVE_AIR = new BlockData(Material.CAVE_AIR); public static final BlockData WATER = new BlockData(Material.WATER); @SuppressWarnings("deprecation") - public static final BlockData STATIONARY_WATER = new BlockData(Material.LEGACY_STATIONARY_WATER); + public static final BlockData STATIONARY_WATER = new BlockData(Material.LEGACY_STATIONARY_WATER); public static final BlockData LAVA = new BlockData(Material.LAVA); @SuppressWarnings("deprecation") - public static final BlockData STATIONARY_LAVA = new BlockData(Material.LEGACY_STATIONARY_LAVA); - + public static final BlockData STATIONARY_LAVA = new BlockData(Material.LEGACY_STATIONARY_LAVA); + private final Material type; - + public BlockData(Material type) { Checks.ensureNonNull(type, "type"); this.type = type; } - + + public static BlockData fromBlock(Block block) { + return new BlockData(block.getType()); + } + + public static BlockData fromString(String string) throws BlockDataParseException { + return new BlockData(parseType(string)); + } + + private static Material parseType(String typeName) throws BlockDataParseException { + Material type = Material.matchMaterial(typeName); + if (type == null) + throw new BlockDataParseException("Could not find block type " + typeName); + + return type; + } + + public static BlockData fromSection(ConfigurationSection section, AtomicBoolean shouldSave) { + if (!section.isSet("block-type")) { + FlyingCarpet.severe("Expected " + section.getCurrentPath() + " to have a block-type"); + return null; + } + + String typeString = section.getString("block-type"); + BlockData type; + + try { + type = fromString(typeString); + } catch (BlockDataParseException e) { + FlyingCarpet.severe("Unable to parse type for " + section.getCurrentPath() + ", " + e.getMessage() + + ", defaulting to glass"); + + return new BlockData(Material.GLASS); + } + + if (section.isSet("block-data")) { + section.set("block-data", null); + shouldSave.set(true); + } + + return type; + } + public Material getType() { return type; } public boolean isAir() { - return type == Material.AIR; + return type == Material.AIR || type == Material.CAVE_AIR; } @SuppressWarnings("deprecation") @@ -48,7 +89,7 @@ public void apply(Block b) { @Override public boolean equals(Object obj) { - if(!(obj instanceof BlockData)) + if (!(obj instanceof BlockData)) return false; BlockData other = (BlockData) obj; @@ -66,54 +107,12 @@ public String toString() { return type.name().toLowerCase(); } - public static BlockData fromBlock(Block block) { - return new BlockData(block.getType()); - } - public static class BlockDataParseException extends Exception { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - private BlockDataParseException(String reason) { + private BlockDataParseException(String reason) { super(reason); } } - - public static BlockData fromString(String string) throws BlockDataParseException { - return new BlockData(parseType(string)); - } - - private static Material parseType(String typeName) throws BlockDataParseException { - Material type = Material.matchMaterial(typeName); - if(type == null) - throw new BlockDataParseException("Could not find block type " + typeName); - - return type; - } - - public static BlockData fromSection(ConfigurationSection section, AtomicBoolean shouldSave) { - if(!section.isSet("block-type")) { - FlyingCarpet.severe("Expected " + section.getCurrentPath() + " to have a block-type"); - return null; - } - - String typeString = section.getString("block-type"); - BlockData type; - - try { - type = fromString(typeString); - } catch (BlockDataParseException e) { - FlyingCarpet.severe("Unable to parse type for " + section.getCurrentPath() + ", " + e.getMessage() + - ", defaulting to glass"); - - return new BlockData(Material.GLASS); - } - - if(section.isSet("block-data")) { - section.set("block-data", null); - shouldSave.set(true); - } - - return type; - } } diff --git a/src/main/java/me/sothatsit/flyingcarpet/model/BlockOffset.java b/src/main/java/me/sothatsit/flyingcarpet/model/BlockOffset.java index a3657ed..0800f34 100755 --- a/src/main/java/me/sothatsit/flyingcarpet/model/BlockOffset.java +++ b/src/main/java/me/sothatsit/flyingcarpet/model/BlockOffset.java @@ -7,44 +7,21 @@ import org.bukkit.configuration.ConfigurationSection; public class BlockOffset { - + public final int x; public final int y; public final int z; - + public BlockOffset(int x, int y, int z) { this.x = x; this.y = y; this.z = z; } - public Block getBlock(World world) { - return world.getBlockAt(x, y, z); - } - - public boolean equals(Object obj) { - if (!(obj instanceof BlockOffset)) - return super.equals(obj); - - BlockOffset other = (BlockOffset) obj; - - return other.x == x && other.y == y && other.z == z; - } - - @Override - public int hashCode() { - return Integer.hashCode(x) ^ Integer.hashCode(y) ^ Integer.hashCode(z); - } - - @Override - public String toString() { - return x + ", " + y + ", " + z; - } - public static BlockOffset fromString(String string) { String[] split = string.split(","); - if(split.length != 3) + if (split.length != 3) return null; try { @@ -53,7 +30,7 @@ public static BlockOffset fromString(String string) { int z = Integer.valueOf(split[2].trim()); return new BlockOffset(x, y, z); - } catch(NumberFormatException e) { + } catch (NumberFormatException e) { return null; } } @@ -98,11 +75,11 @@ public static BlockOffset fromBlock(Block loc) { public static BlockOffset fromConfig(ConfigurationSection section) { if (!section.isInt("x") || !section.isInt("y") || !section.isInt("z")) return null; - + int x = section.getInt("x"); int y = section.getInt("y"); int z = section.getInt("z"); - + return new BlockOffset(x, y, z); } @@ -117,4 +94,27 @@ public static boolean locColumnEqual(Location loc1, Location loc2) { && loc1.getBlockZ() == loc2.getBlockZ(); } + public Block getBlock(World world) { + return world.getBlockAt(x, y, z); + } + + public boolean equals(Object obj) { + if (!(obj instanceof BlockOffset)) + return super.equals(obj); + + BlockOffset other = (BlockOffset) obj; + + return other.x == x && other.y == y && other.z == z; + } + + @Override + public int hashCode() { + return Integer.hashCode(x) ^ Integer.hashCode(y) ^ Integer.hashCode(z); + } + + @Override + public String toString() { + return x + ", " + y + ", " + z; + } + } diff --git a/src/main/java/me/sothatsit/flyingcarpet/model/Model.java b/src/main/java/me/sothatsit/flyingcarpet/model/Model.java index 5c7fcaf..298e916 100755 --- a/src/main/java/me/sothatsit/flyingcarpet/model/Model.java +++ b/src/main/java/me/sothatsit/flyingcarpet/model/Model.java @@ -1,18 +1,18 @@ package me.sothatsit.flyingcarpet.model; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; - import me.sothatsit.flyingcarpet.FlyingCarpet; import me.sothatsit.flyingcarpet.util.Checks; - import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; public class Model { - - private final ModelElement[] elements; + public final Region region; + private final ModelElement[] elements; public Model(List elements) { Checks.ensureNonNull(elements, "elements"); @@ -21,30 +21,18 @@ public Model(List elements) { List regions = new ArrayList<>(elements.size()); - for(ModelElement element : elements) { + for (ModelElement element : elements) { regions.add(element.region); } this.region = Region.combine(regions); } - - public BlockData getBlockData(BlockOffset offset) { - if(!region.inBounds(offset)) - return BlockData.AIR; - - for(int index = elements.length - 1; index >= 0; --index) { - if(elements[index].inBounds(offset)) - return elements[index].blockData; - } - - return BlockData.AIR; - } public static BlockData getBlockData(List models, BlockOffset offset) { - for(int index = models.size() - 1; index >= 0; --index) { + for (int index = models.size() - 1; index >= 0; --index) { BlockData data = models.get(index).getBlockData(offset); - if(!data.isAir()) + if (!data.isAir()) return data; } @@ -53,28 +41,36 @@ public static BlockData getBlockData(List models, BlockOffset offset) { public static Model fromConfig(ConfigurationSection config, AtomicBoolean requiresSave) { List elements = new ArrayList<>(); - + for (String key : config.getKeys(false)) { if (!config.isConfigurationSection(key)) continue; - + ConfigurationSection section = config.getConfigurationSection(key); ModelElement element = loadModelElement(section, requiresSave); - if(element == null) + if (element == null) continue; elements.add(element); } - + return new Model(elements); } + public static Model fromTypeAndSize(String material, int x, int y, int z) { + ConfigurationSection section = new YamlConfiguration(); + section.set(material.toLowerCase() + ".block-type", material.toLowerCase()); + section.set(material.toLowerCase() + ".from", -x + ", " + y + ", " + -z); + section.set(material.toLowerCase() + ".to", x + ", " + y + ", " + z); + return fromConfig(section, new AtomicBoolean(false)); + } + private static void migrateModelElement(ConfigurationSection section) { String modelType = section.getString("model-type"); - if(modelType.equalsIgnoreCase("block")) { - if(!section.isConfigurationSection("offset")) { + if (modelType.equalsIgnoreCase("block")) { + if (!section.isConfigurationSection("offset")) { FlyingCarpet.warning("Unable to find offset while migrating " + section.getCurrentPath()); return; } @@ -92,7 +88,7 @@ private static void migrateModelElement(ConfigurationSection section) { return; } - if(modelType.equalsIgnoreCase("cuboid")) { + if (modelType.equalsIgnoreCase("cuboid")) { if (!section.isConfigurationSection("from")) { FlyingCarpet.warning("Unable to find from while migrating " + section.getCurrentPath()); return; @@ -121,7 +117,7 @@ private static void migrateModelElement(ConfigurationSection section) { } public static ModelElement loadModelElement(ConfigurationSection section, AtomicBoolean requiresSave) { - if(section.isSet("model-type")) { + if (section.isSet("model-type")) { migrateModelElement(section); requiresSave.set(true); @@ -130,13 +126,13 @@ public static ModelElement loadModelElement(ConfigurationSection section, Atomic BlockData data = BlockData.fromSection(section, requiresSave); - if(data == null) + if (data == null) return null; - if(section.isSet("at")) { + if (section.isSet("at")) { BlockOffset at = BlockOffset.fromString(section.getString("at")); - if(at == null) { + if (at == null) { FlyingCarpet.severe("Unable to parse location for " + section.getCurrentPath() + ", invalid format"); return null; } @@ -144,7 +140,7 @@ public static ModelElement loadModelElement(ConfigurationSection section, Atomic return new ModelElement(data, new Region(at)); } - if(section.isSet("from") && section.isSet("to")) { + if (section.isSet("from") && section.isSet("to")) { BlockOffset from = BlockOffset.fromString(section.getString("from")); BlockOffset to = BlockOffset.fromString(section.getString("to")); @@ -157,9 +153,20 @@ public static ModelElement loadModelElement(ConfigurationSection section, Atomic } FlyingCarpet.getInstance().getLogger().warning("Invalid model element " + section.getCurrentPath() - + ", expected to find an at location or a from and to location"); + + ", expected to find an at location or a from and to location"); return null; } + public BlockData getBlockData(BlockOffset offset) { + if (!region.inBounds(offset)) + return BlockData.AIR; + + for (int index = elements.length - 1; index >= 0; --index) { + if (elements[index].inBounds(offset)) + return elements[index].blockData; + } + + return BlockData.AIR; + } } diff --git a/src/main/java/me/sothatsit/flyingcarpet/model/ModelElement.java b/src/main/java/me/sothatsit/flyingcarpet/model/ModelElement.java index c6358d8..9f0ac2c 100755 --- a/src/main/java/me/sothatsit/flyingcarpet/model/ModelElement.java +++ b/src/main/java/me/sothatsit/flyingcarpet/model/ModelElement.java @@ -3,10 +3,10 @@ import me.sothatsit.flyingcarpet.util.Checks; public class ModelElement { - + public final BlockData blockData; public final Region region; - + public ModelElement(BlockData blockData, Region region) { Checks.ensureNonNull(blockData, "blockData"); Checks.ensureNonNull(region, "region"); diff --git a/src/main/java/me/sothatsit/flyingcarpet/model/Region.java b/src/main/java/me/sothatsit/flyingcarpet/model/Region.java index e45ab11..3c0cc36 100755 --- a/src/main/java/me/sothatsit/flyingcarpet/model/Region.java +++ b/src/main/java/me/sothatsit/flyingcarpet/model/Region.java @@ -5,7 +5,7 @@ import java.util.List; public class Region { - + public final BlockOffset min; public final BlockOffset max; @@ -21,7 +21,7 @@ private Region(BlockOffset from, BlockOffset to, boolean isMinMax) { Checks.ensureNonNull(from, "from"); Checks.ensureNonNull(to, "to"); - if(isMinMax) { + if (isMinMax) { min = from; max = to; } else { @@ -29,29 +29,11 @@ private Region(BlockOffset from, BlockOffset to, boolean isMinMax) { max = BlockOffset.max(from, to); } } - - public boolean inBounds(BlockOffset loc) { - return loc.x >= min.x && loc.x <= max.x - && loc.y >= min.y && loc.y <= max.y - && loc.z >= min.z && loc.z <= max.z; - } private static int abs(int val) { return (val < 0 ? val * -1 : val); } - public int getVolume() { - return abs(max.x - min.x) * abs(max.y - min.y) * abs(max.z - min.z); - } - - @Override - public String toString() { - if(min.equals(max)) - return "at (" + min + ")"; - - return "from (" + min + ") to (" + max + ")"; - } - public static Region combine(List regions) { Checks.ensureNonNull(regions, "regions"); Checks.ensureTrue(regions.size() > 0, "regions cannot be empty"); @@ -66,21 +48,21 @@ public static Region combine(List regions) { int maxy = first.max.y; int maxz = first.max.z; - for(int index = 1; index < regions.size(); ++index) { + for (int index = 1; index < regions.size(); ++index) { Region region = regions.get(index); - if(region.min.x < minx) + if (region.min.x < minx) minx = region.min.x; - if(region.min.y < miny) + if (region.min.y < miny) miny = region.min.y; - if(region.min.z < minz) + if (region.min.z < minz) minz = region.min.z; - if(region.max.x > maxx) + if (region.max.x > maxx) maxx = region.max.x; - if(region.max.y > maxy) + if (region.max.y > maxy) maxy = region.max.y; - if(region.max.z > maxz) + if (region.max.z > maxz) maxz = region.max.z; } @@ -89,5 +71,23 @@ public static Region combine(List regions) { return new Region(min, max, true); } - + + public boolean inBounds(BlockOffset loc) { + return loc.x >= min.x && loc.x <= max.x + && loc.y >= min.y && loc.y <= max.y + && loc.z >= min.z && loc.z <= max.z; + } + + public int getVolume() { + return abs(max.x - min.x) * abs(max.y - min.y) * abs(max.z - min.z); + } + + @Override + public String toString() { + if (min.equals(max)) + return "at (" + min + ")"; + + return "from (" + min + ") to (" + max + ")"; + } + } diff --git a/src/main/java/me/sothatsit/flyingcarpet/util/Checks.java b/src/main/java/me/sothatsit/flyingcarpet/util/Checks.java index b93cb68..f4a296e 100755 --- a/src/main/java/me/sothatsit/flyingcarpet/util/Checks.java +++ b/src/main/java/me/sothatsit/flyingcarpet/util/Checks.java @@ -9,7 +9,7 @@ public static void ensureNonNull(Object argument, String argName) { public static void ensureArrayNonNull(T[] array, String arrayName) { ensureNonNull(array, arrayName); - for(T element : array) { + for (T element : array) { ensureTrue(element != null, arrayName + " cannot contain null values"); } } @@ -19,7 +19,7 @@ public static void ensureWithinRange(int num, int min, int max, String argName) } public static void ensureTrue(boolean expression, String message) { - if(!expression) + if (!expression) throw new IllegalArgumentException(message); } diff --git a/src/main/java/me/sothatsit/flyingcarpet/util/Clock.java b/src/main/java/me/sothatsit/flyingcarpet/util/Clock.java index 0f309da..7b90839 100755 --- a/src/main/java/me/sothatsit/flyingcarpet/util/Clock.java +++ b/src/main/java/me/sothatsit/flyingcarpet/util/Clock.java @@ -14,6 +14,10 @@ public Clock() { this.end = -1; } + public static Clock start() { + return new Clock(); + } + public boolean hasEnded() { return end >= 0; } @@ -35,8 +39,4 @@ public String toString() { return "(" + millisecondsFormat.format(getDuration()) + " ms)"; } - public static Clock start() { - return new Clock(); - } - } diff --git a/src/main/resources/changelog.txt b/src/main/resources/changelog.txt index 8b378a9..8d94f5c 100755 --- a/src/main/resources/changelog.txt +++ b/src/main/resources/changelog.txt @@ -1,3 +1,11 @@ +1.4.3 +* Added commands Size to change the carpet size, material to change the carpet block type and Touch to allow physics like sponge +* Carpet will be invisible if the player get invisibility potion (barrier bocks) +* Added hook with RedProtect + +1.4.2 +* Added CAVE_AIR along with AIR to handle flyingcarpet in caves. + 1.3.7 * Added support for worldguard 7.0.0 * Added support for minecraft 1.13.1 diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 73bb928..980e16d 100755 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,9 +1,13 @@ pass-through: - water - lava -- grass +- short_grass +- short_dry_grass +- bush +- firefly_bush - fern - tall_grass +- tall_dry_grass - large_fern - dead_bush - vine diff --git a/src/main/resources/lang.yml b/src/main/resources/lang.yml index 33ff377..74c086e 100755 --- a/src/main/resources/lang.yml +++ b/src/main/resources/lang.yml @@ -1,4 +1,5 @@ message: + color: '&7 The color of your flying carpet has been set to %color%' reload: '&7The flying carpet config has been reloaded' carpet-on: '&7Your flying carpet has been toggled &a&lOn' carpet-off: '&7Your flying carpet has been toggled &c&lOff' @@ -6,8 +7,12 @@ message: tools-off: '&7Tools for your flying carpet has been toggled &c&lOff' light-on: '&7Light for your flying carpet has been toggled &a&lOn' light-off: '&7Light for your flying carpet has been toggled &c&lOff' + touch-on: '&7Touch for your flying carpet has been toggled &a&lOn' + touch-off: '&7Touch for your flying carpet has been toggled &c&lOff' teleport-remove: '&cYour carpet has been removed because you teleported' region-remove: '&7Your flying carpet has been toggled &c&lOff &7as you entered a no-fly zone' + material: '&7Your flying carpet has been toggled to %block% type' + size: '&7Your flying carpet has been changed the size to %size%' wg: add: '&7Added the region &6%region% &7to the no-fly zone' remove: '&7Removed the region &6%region% &7from the no-fly zones' @@ -23,6 +28,10 @@ error: light: '&4Error > &cYou do not have permission to use a light on your flying carpet' reload: '&4Error > &cYou do not have permission to reload the flying carpet config' worldguard: '&4Error > &cYou do not have permission to manage blacklisted WorldGuard regions' + material: '&4Error > &cYou do not have permission to change to this carpet material' + size: '&4Error > &cYou do not have permission to change to this carpet size' + touch: '&4Error > &cYou do not have permission to change the touch state of carpet' + color: '&4Error > &cYou do not have permission to change the color of your flying carpet' invalid-arguments: '&4Invalid Arguments > &c%valid%' worldguard-not-hooked: '&4Error > &cWorldGuard is not currently hooked' region-blocked: '&4Error > &cYou can not use your carpet in this area' \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index ff25a4f..8ca830b 100755 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,29 +1,35 @@ -main: me.sothatsit.flyingcarpet.FlyingCarpet -author: sothatsit -name: FlyingCarpet -version: 1.4.1 -api-version: 1.13 -soft-depend: [WorldGuard, WorldEdit] -commands: - flyingcarpet: - aliases: [mc,magiccarpet] - description: 'Toggle your Flying Carpet' -permissions: - flyingcarpet.use: - description: 'Permission to use the flying carpet' - default: op - flyingcarpet.tools: - description: 'Permission to add tools to your flying carpet' - default: op - flyingcarpet.light: - description: 'Permission to add a light to your flying carpet' - default: op - flyingcarpet.reload: - description: 'Permission to reload the flying carpet config' - default: op - flyingcarpet.teleport: - description: 'Allow players to keep their flying carpet on teleport' - default: false - flyingcarpet.worldguard: - description: 'Allow admins to add blacklisted worldguard regions' - default: false \ No newline at end of file +main: me.sothatsit.flyingcarpet.FlyingCarpet +author: sothatsit +name: FlyingCarpet +version: 1.4.4 +api-version: 1.13 +softdepend: [WorldGuard, WorldEdit, RedProtect] +commands: + flyingcarpet: + aliases: [mc,magiccarpet] + description: 'Toggle your Flying Carpet' +permissions: + flyingcarpet.use: + description: 'Permission to use the flying carpet' + default: op + flyingcarpet.tools: + description: 'Permission to add tools to your flying carpet' + default: op + flyingcarpet.light: + description: 'Permission to add a light to your flying carpet' + default: op + flyingcarpet.touch: + description: 'Permission to allow flying carpet to touch blocks and enable psychics' + default: op + flyingcarpet.reload: + description: 'Permission to reload the flying carpet config' + default: op + flyingcarpet.teleport: + description: 'Allow players to keep their flying carpet on teleport' + default: false + flyingcarpet.worldguard: + description: 'Allow admins to add blacklisted worldguard regions' + default: false + flyingcarpet.color: + description: 'Permission to change the color of your flying carpet' + default: op