summaryrefslogtreecommitdiff
path: root/src/main/java/com/redstoner/modules/blockplacemods
diff options
context:
space:
mode:
authorDavid <david@panic.tk>2018-11-07 23:50:06 +0100
committerDavid <david@panic.tk>2018-11-07 23:50:06 +0100
commit604cf01967ede98bf5024e4926bb0777fc4e8eee (patch)
treee2fa63d7e683769ee3bf3eddc75280648e92eb04 /src/main/java/com/redstoner/modules/blockplacemods
parente86c52ef7c0e1e33c6af0e8674b038976bec11cc (diff)
Converted Modules to gradle
Diffstat (limited to 'src/main/java/com/redstoner/modules/blockplacemods')
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/BlockPlaceMods.java206
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/Mod.java24
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/ModAbstract.java94
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/ModInventory.java195
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledAbstract.java80
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledCauldron.java49
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledLogPlaceAbstract.java40
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledObserver.java43
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledPiston.java46
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledStep.java40
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledTorch.java91
11 files changed, 908 insertions, 0 deletions
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/BlockPlaceMods.java b/src/main/java/com/redstoner/modules/blockplacemods/BlockPlaceMods.java
new file mode 100644
index 0000000..6befbae
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/BlockPlaceMods.java
@@ -0,0 +1,206 @@
+package com.redstoner.modules.blockplacemods;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import org.bukkit.ChatColor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Listener;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.Main;
+import com.redstoner.modules.Module;
+import com.redstoner.modules.blockplacemods.mods.Mod;
+import com.redstoner.modules.blockplacemods.mods.ModAbstract;
+import com.redstoner.modules.blockplacemods.mods.ModToggledAbstract;
+import com.redstoner.utils.CommandException;
+import com.redstoner.utils.CommandMap;
+
+@Commands(CommandHolderType.None)
+@AutoRegisterListener
+@Version(major = 4, minor = 1, revision = 1, compatible = 4)
+public final class BlockPlaceMods implements Module, Listener
+{
+ @Override
+ public boolean onEnable()
+ {
+ ModAbstract.registerAll(getLogger());
+ for (Mod mod : new ArrayList<>(ModAbstract.getMods().values()))
+ {
+ mod.registerListeners();
+ }
+ try
+ {
+ Map<String, org.bukkit.command.Command> commandMap = CommandMap.getCommandMap();
+ org.bukkit.command.Command command = new BlockPlaceModsCommand();
+ for (String alias : getCommandAliases())
+ {
+ commandMap.put(alias, command);
+ }
+ }
+ catch (ReflectiveOperationException ex)
+ {
+ ex.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void postEnable()
+ {
+ setPrefix("BPM");
+ }
+
+ @Override
+ public void onDisable()
+ {
+ for (Mod mod : ModAbstract.getMods().values())
+ {
+ mod.unregisterListeners();
+ }
+ try
+ {
+ Map<String, org.bukkit.command.Command> commandMap = CommandMap.getCommandMap();
+ for (String alias : getCommandAliases())
+ {
+ org.bukkit.command.Command command = commandMap.get(alias);
+ if (command != null && command.getClass() == BlockPlaceModsCommand.class)
+ {
+ commandMap.remove(alias);
+ }
+ }
+ }
+ catch (Exception ignored)
+ {}
+ }
+
+ private static String[] getCommandAliases()
+ {
+ String pluginName = Main.plugin.getName().toLowerCase();
+ // @noformat
+ return new String[]{"mod", pluginName + ":mod",
+ "set", pluginName + ":set",
+ "toggle", pluginName + ":toggle"
+ };
+ // @format
+ }
+
+ @Command(hook = "mod_empty")
+ public void onModEmptyCommand(CommandSender sender)
+ {
+ onModCommand(sender, "");
+ }
+
+ @Command(hook = "mod")
+ public void onModCommand(CommandSender sender, String input)
+ {
+ String[] args = new ArrayList<>(Arrays.asList(input.split(" "))).stream()
+ .filter(x -> x != null && !x.trim().isEmpty()).toArray(String[]::new);
+ String prefix = "";
+ String message;
+ try
+ {
+ if (args.length > 0)
+ {
+ Mod target = ModAbstract.getMod(args[0].toLowerCase());
+ if (target != null)
+ {
+ prefix += "&7[&2" + capitalize(target.getName()) + "&7]:&a ";
+ if (!(sender instanceof Player))
+ {
+ message = "&cYou must be a player to use any block place mod";
+ }
+ else
+ {
+ message = target.runCommand((Player) sender, Arrays.copyOfRange(args, 1, args.length));
+ }
+ }
+ else if (args[0].equalsIgnoreCase("help"))
+ {
+ message = commandHelp(sender, args);
+ }
+ else
+ {
+ message = "&cThat argument could not be recognized";
+ }
+ }
+ else
+ {
+ message = commandHelp(sender, args);
+ }
+ }
+ catch (CommandException ex)
+ {
+ message = " &c" + ex.getMessage();
+ }
+ catch (Throwable t)
+ {
+ message = " &cAn unexpected error occurred while executing this command.";
+ t.printStackTrace();
+ }
+ getLogger().message(sender, prefix + message);
+ }
+
+ private String commandHelp(CommandSender sender, String[] args)
+ {
+ StringBuilder result = new StringBuilder("ยง7BlockPlaceMods adds some redstone-centric utilities");
+ result.append("\n").append(ChatColor.GRAY.toString()).append("Available mods:");
+ List<Mod> mods = new ArrayList<>(new HashSet<>(ModAbstract.getMods().values()));
+ mods.sort(Comparator.<Mod> comparingInt(m -> ModToggledAbstract.class.isInstance(m) ? 1 : -1)
+ .thenComparing(Mod::getName));
+ for (Mod mod : mods)
+ {
+ result.append("\n").append(ChatColor.AQUA.toString()).append("/mod ").append(ChatColor.ITALIC.toString())
+ .append(mod.getName());
+ for (String alias : mod.getAliases())
+ {
+ result.append('|').append(alias);
+ }
+ result.append(ChatColor.GRAY.toString()).append(" - ").append(mod.getDescription());
+ }
+ return result.toString();
+ }
+
+ private static String capitalize(String modName)
+ {
+ if (modName.isEmpty())
+ {
+ return modName;
+ }
+ char first = modName.charAt(0);
+ if (first != (first = Character.toUpperCase(first)))
+ {
+ char[] result = modName.toCharArray();
+ result[0] = first;
+ return String.valueOf(result);
+ }
+ return modName;
+ }
+
+ private class BlockPlaceModsCommand extends org.bukkit.command.Command
+ {
+ public BlockPlaceModsCommand()
+ {
+ super("mod");
+ String[] aliases = getCommandAliases();
+ setAliases(Arrays.asList(Arrays.copyOfRange(aliases, 1, aliases.length)));
+ }
+
+ @Override
+ public boolean execute(CommandSender sender, String label, String[] args)
+ {
+ onModCommand(sender, String.join(" ", args));
+ return true;
+ }
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/Mod.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/Mod.java
new file mode 100644
index 0000000..9a2fcad
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/Mod.java
@@ -0,0 +1,24 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import org.bukkit.entity.Player;
+
+import com.redstoner.utils.CommandException;
+
+import java.util.Set;
+
+public interface Mod
+{
+ String getName();
+
+ String getDescription();
+
+ Set<String> getAliases();
+
+ Object getDefault();
+
+ String runCommand(Player sender, String[] args) throws CommandException;
+
+ void registerListeners();
+
+ void unregisterListeners();
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/ModAbstract.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModAbstract.java
new file mode 100644
index 0000000..5a383d8
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModAbstract.java
@@ -0,0 +1,94 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryType;
+
+import com.redstoner.misc.Main;
+import com.redstoner.modules.ModuleLogger;
+import com.redstoner.modules.datamanager.DataManager;
+
+public abstract class ModAbstract implements Mod, Listener
+{
+ private static final Map<String, Mod> mods = new HashMap<>();
+ private final String name;
+ private final Set<String> aliases;
+ private static ModuleLogger logger;
+
+ public static Map<String, Mod> getMods()
+ {
+ return Collections.unmodifiableMap(mods);
+ }
+
+ public static Mod getMod(String name)
+ {
+ return mods.get(name);
+ }
+
+ public static void registerMod(Mod mod)
+ {
+ mods.put(mod.getName(), mod);
+ for (String alias : mod.getAliases())
+ {
+ mods.putIfAbsent(alias, mod);
+ }
+ }
+
+ public static void registerAll(final ModuleLogger logger)
+ {
+ ModAbstract.logger = logger;
+ registerMod(new ModToggledCauldron());
+ registerMod(new ModToggledPiston());
+ registerMod(new ModToggledObserver());
+ registerMod(new ModToggledStep());
+ registerMod(new ModToggledTorch());
+ registerMod(new ModInventory("dropper", InventoryType.DROPPER));
+ registerMod(new ModInventory("furnace", InventoryType.FURNACE));
+ registerMod(new ModInventory("hopper", InventoryType.HOPPER));
+ }
+
+ public ModAbstract(String name)
+ {
+ this.name = Objects.requireNonNull(name);
+ this.aliases = new HashSet<>(2);
+ logger.info("Loaded mod " + name);
+ }
+
+ @Override
+ public String getName()
+ {
+ return name;
+ }
+
+ @Override
+ public Set<String> getAliases()
+ {
+ return aliases;
+ }
+
+ @Override
+ public void registerListeners()
+ {
+ Bukkit.getPluginManager().registerEvents(this, Main.plugin);
+ }
+
+ @Override
+ public void unregisterListeners()
+ {
+ HandlerList.unregisterAll(this);
+ }
+
+ protected void reset(Player player)
+ {
+ DataManager.removeData(player.getUniqueId().toString(), "BlockPlaceMods", getName());
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/ModInventory.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModInventory.java
new file mode 100644
index 0000000..c6e483e
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModInventory.java
@@ -0,0 +1,195 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import com.redstoner.modules.datamanager.DataManager;
+import com.redstoner.utils.CommandException;
+import com.redstoner.utils.ItemProperties;
+import org.bukkit.GameMode;
+import org.bukkit.Material;
+import org.bukkit.block.BlockState;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.event.inventory.InventoryType;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.InventoryHolder;
+import org.bukkit.inventory.ItemStack;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+import java.util.Arrays;
+
+public class ModInventory extends ModAbstract
+{
+ protected InventoryType inventoryType;
+
+ public ModInventory(String name, InventoryType inventoryType)
+ {
+ super(name);
+ this.inventoryType = inventoryType;
+ }
+
+ private static int highestUsedIndex(ItemStack[] items)
+ {
+ for (int i = items.length - 1; i >= 0; i--)
+ {
+ if (items[i] != null)
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return "Controls " + inventoryType.name().toLowerCase() + " placement content";
+ }
+
+ @Override
+ public String runCommand(Player sender, String[] args) throws CommandException
+ {
+ if (args.length > 0)
+ {
+ if (args[0].equalsIgnoreCase("clear"))
+ {
+ reset(sender);
+ return "Reset data successfully";
+ }
+ try
+ {
+ int slot = Integer.parseInt(args[0]);
+ if (slot >= inventoryType.getDefaultSize())
+ {
+ throw new CommandException(
+ "Slot number " + slot + " is too high for " + inventoryType.toString().toLowerCase() + "s");
+ }
+ if (slot < 0)
+ {
+ throw new CommandException("Slot number " + slot + " is negative");
+ }
+ // Set the stored item to the item in the sender's hand
+ ItemStack item = sender.getInventory().getItemInMainHand();
+ if (item == null || item.getType() == Material.AIR || item.getAmount() == 0)
+ {
+ // Remove the item.
+ // Set item to null to ensure correct itemName below.
+ item = null;
+ if (present(sender))
+ {
+ set(sender, slot, null);
+ }
+ }
+ else
+ {
+ set(sender, slot, item);// don't need to clone because the reference isn't kept
+ }
+ String itemName = item == null ? "nothing"
+ : item.getAmount() + " " + item.getType().toString().toLowerCase().replace("_", "");
+ return "Set the item in slot " + slot + " to " + itemName;
+ }
+ catch (NumberFormatException ex)
+ {
+ if (!args[0].equalsIgnoreCase("help"))
+ {
+ throw new CommandException("Expected a number indicating the slot that you want to set");
+ }
+ }
+ }
+ StringBuilder message = new StringBuilder();
+ message.append(" &a### &3Container Mod&a Help ###\n");
+ message.append("&7").append(getDescription()).append('\n');
+ message.append("&6/mod ").append(getName().toLowerCase())
+ .append("&o <slot> &bsets the item in slot to your hand\n");
+ message.append("&6/mod ").append(getName().toLowerCase()).append("&o clear &bclears the data\n");
+ message.append("&6/mod ").append(getName().toLowerCase()).append("&o help &bshows this help page\n");
+ return message.toString();
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onBlockPlace(BlockPlaceEvent event)
+ {
+ if (present(event.getPlayer()) && event.getPlayer().getGameMode() == GameMode.CREATIVE)
+ {
+ BlockState state = event.getBlock().getState();
+ if (state instanceof InventoryHolder)
+ {
+ Inventory inv = ((InventoryHolder) state).getInventory();
+ if (inv.getType() == inventoryType)
+ {
+ ItemStack[] data = get(event.getPlayer());
+ inv.setContents(data);
+ state.update();
+ }
+ }
+ }
+ }
+
+ protected ItemStack[] get(Player player)
+ {
+ Object obj = DataManager.getData(player.getUniqueId().toString(), "BlockPlaceMods", getName());
+ if (obj == null)
+ return getDefault();
+ JSONArray array = (JSONArray) obj;
+ ItemStack[] items = new ItemStack[Math.min(inventoryType.getDefaultSize(), array.size())];
+ for (int i = 0, n = items.length; i < n; i++)
+ {
+ Object obj2 = array.get(i);
+ if (obj2 instanceof JSONObject)
+ { // if null, items[i] remains null
+ items[i] = new ItemProperties().loadFrom((JSONObject) obj2).toItemStack();
+ }
+ }
+ return items;
+ }
+
+ protected void set(Player player, int index, ItemStack item)
+ {
+ ItemStack[] data = get(player);
+ if (item == null)
+ {
+ if (index < data.length)
+ {
+ data[index] = null;
+ }
+ }
+ else
+ {
+ if (index >= data.length)
+ {
+ data = Arrays.copyOf(data, index + 1);
+ }
+ data[index] = item;
+ }
+ set(player, data);
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void set(Player player, ItemStack[] data)
+ {
+ if (highestUsedIndex(data) == -1)
+ reset(player);
+ else
+ {
+ JSONArray array = new JSONArray();
+ for (int i = 0, n = highestUsedIndex(data); i < n; i++)
+ {
+ ItemStack item = data[i];
+ array.add(item == null ? null : new ItemProperties(item).toJSONObject());
+ }
+ DataManager.setData(player.getUniqueId().toString(), "BlockPlaceMods", getName(), array);
+ }
+ }
+
+ protected boolean present(Player player)
+ {
+ return get(player) != null;
+ }
+
+ @Override
+ public ItemStack[] getDefault()
+ {
+ return new ItemStack[0];
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledAbstract.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledAbstract.java
new file mode 100644
index 0000000..b9b2a7c
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledAbstract.java
@@ -0,0 +1,80 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import com.redstoner.modules.datamanager.DataManager;
+import com.redstoner.utils.CommandException;
+import org.bukkit.entity.Player;
+
+public abstract class ModToggledAbstract extends ModAbstract
+{
+ protected boolean enabledByDefault;
+
+ public ModToggledAbstract(String name, boolean enabledByDefault) {
+ super(name);
+ this.enabledByDefault = enabledByDefault;
+ }
+
+ @Override
+ public Boolean getDefault() {
+ return enabledByDefault;
+ }
+
+ protected boolean hasEnabled(Player player)
+ {
+ return (boolean) DataManager.getOrDefault(player.getUniqueId().toString(), "BlockPlaceMods", getName(),
+ enabledByDefault);
+ }
+
+ protected boolean setEnabled(Player sender, boolean enabled)
+ {
+ if (enabled == hasEnabled(sender))
+ return false;
+ if (enabled == enabledByDefault)
+ reset(sender);
+ else
+ DataManager.setData(sender.getUniqueId().toString(), "BlockPlaceMods", getName(), enabled);
+ return true;
+ }
+
+ @Override
+ public String runCommand(Player sender, String[] args) throws CommandException
+ {
+ if (args.length == 0 || args[0].equalsIgnoreCase("toggle"))
+ {
+ boolean enabled = hasEnabled(sender);
+ setEnabled(sender, !enabled);
+ return !enabled ? "Enabled" : "Disabled";
+ }
+ if (args[0].equalsIgnoreCase("help"))
+ {
+ StringBuilder message = new StringBuilder();
+ message.append(" &a### &3Toggled Mod&a Help ###");
+ message.append("\n&7").append(getDescription());
+ message.append("\n&6/mod ").append(getName()).append("&o (toggle) &btoggles state");
+ message.append("\n&6/mod ").append(getName()).append("&o on/off &bsets state");
+ message.append("\n&6/mod ").append(getName()).append("&o help &bshows this help page");
+ return message.toString();
+ }
+ final boolean enable;
+ switch (args[0].toLowerCase())
+ {
+ case "on":
+ case "enable":
+ case "true":
+ enable = true;
+ break;
+ case "off":
+ case "disable":
+ case "false":
+ enable = false;
+ break;
+ default:
+ throw new CommandException("Input '" + args[0] + "' was not understood. "
+ + "Use one of: \non, enable, true, off, disable, false.");
+ }
+ if (!setEnabled(sender, enable))
+ {
+ throw new CommandException("Was already " + (enable ? "enabled" : "disabled"));
+ }
+ return enable ? "Enabled" : "Disabled";
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledCauldron.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledCauldron.java
new file mode 100644
index 0000000..669f093
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledCauldron.java
@@ -0,0 +1,49 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import org.bukkit.GameMode;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+
+public class ModToggledCauldron extends ModToggledAbstract
+{
+ public ModToggledCauldron()
+ {
+ super("cauldron", false);
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return "If active, placed cauldrons are filled, and they cycle on shiftless right click with redstone or fist";
+ }
+
+ @SuppressWarnings("deprecation")
+ @EventHandler
+ public void onPlayerInteract(PlayerInteractEvent event)
+ {
+ if (event.getAction() == Action.RIGHT_CLICK_BLOCK && !event.getPlayer().isSneaking()
+ && event.getClickedBlock().getType() == Material.CAULDRON && hasEnabled(event.getPlayer())
+ && (event.getPlayer().getGameMode() == GameMode.CREATIVE)
+ && (event.getPlayer().getInventory().getItemInMainHand().getType() == Material.AIR))
+ {
+ Block block = event.getClickedBlock();
+ block.setData((byte) ((block.getData() - 1) & 0x3));
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onBlockPlace(BlockPlaceEvent event)
+ {
+ if (event.getBlock().getType() == Material.CAULDRON && !event.getPlayer().isSneaking()
+ && hasEnabled(event.getPlayer()) && (event.getPlayer().getGameMode() == GameMode.CREATIVE))
+ {
+ event.getBlock().setData((byte) 3);
+ }
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledLogPlaceAbstract.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledLogPlaceAbstract.java
new file mode 100644
index 0000000..17c414b
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledLogPlaceAbstract.java
@@ -0,0 +1,40 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import org.bukkit.GameMode;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.block.BlockPlaceEvent;
+
+/**
+ * A mod that makes placement of directional blocks act the way placement of logs does normally.
+ * Quartz pillar placement works like this too.
+ *
+ * Placed blocks face the block you clicked to place them.
+ */
+public abstract class ModToggledLogPlaceAbstract extends ModToggledAbstract {
+
+ protected ModToggledLogPlaceAbstract(String name, boolean enabledByDefault) {
+ super(name, enabledByDefault);
+ }
+
+ @SuppressWarnings("deprecation")
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onBlockPlace(BlockPlaceEvent event)
+ {
+ Player player = event.getPlayer();
+ Block block;
+ if (hasEnabled(player) && !player.isSneaking() && player.getGameMode() == GameMode.CREATIVE
+ && isApplicableToPlacedBlock(block = event.getBlock()))
+ {
+ block.setData((byte) getBlockDataForFacing(block.getFace(event.getBlockAgainst())));
+ }
+ }
+
+ protected abstract int getBlockDataForFacing(BlockFace direction);
+
+ protected abstract boolean isApplicableToPlacedBlock(Block block);
+
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledObserver.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledObserver.java
new file mode 100644
index 0000000..8084bf4
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledObserver.java
@@ -0,0 +1,43 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+
+public class ModToggledObserver extends ModToggledLogPlaceAbstract {
+
+ protected ModToggledObserver() {
+ super("observer", false);
+ }
+
+ @Override
+ public String getDescription() {
+ return "If active, observers face the block you place them against";
+ }
+
+ @Override
+ protected boolean isApplicableToPlacedBlock(Block block) {
+ return block.getType() == Material.OBSERVER;
+ }
+
+ @Override
+ protected int getBlockDataForFacing(BlockFace direction) {
+ switch (direction) {
+ case UP:
+ return 0;
+ default:
+ case DOWN:
+ return 1;
+ case SOUTH:
+ return 2;
+ case NORTH:
+ return 3;
+ case EAST:
+ return 4;
+ case WEST:
+ return 5;
+ }
+ }
+
+
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledPiston.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledPiston.java
new file mode 100644
index 0000000..29e810c
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledPiston.java
@@ -0,0 +1,46 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+
+public class ModToggledPiston extends ModToggledLogPlaceAbstract
+{
+ public ModToggledPiston()
+ {
+ super("piston", false);
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return "If active, pistons face the block you place them against";
+ }
+
+ @Override
+ protected boolean isApplicableToPlacedBlock(Block block) {
+ Material type = block.getType();
+ return type == Material.PISTON_BASE || type == Material.PISTON_STICKY_BASE;
+ }
+
+ @Override
+ protected int getBlockDataForFacing(BlockFace direction) {
+ switch (direction)
+ {
+ default:
+ case DOWN:
+ return 0;
+ case UP:
+ return 1;
+ case NORTH:
+ return 2;
+ case SOUTH:
+ return 3;
+ case WEST:
+ return 4;
+ case EAST:
+ return 5;
+ }
+ }
+
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledStep.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledStep.java
new file mode 100644
index 0000000..fe42fa4
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledStep.java
@@ -0,0 +1,40 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import org.bukkit.Material;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.block.BlockPlaceEvent;
+
+public class ModToggledStep extends ModToggledAbstract
+{
+ public ModToggledStep()
+ {
+ super("step", true);
+ getAliases().add("slab");
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return "If active, placed steps will always turn upside-down";
+ }
+
+ @SuppressWarnings("deprecation")
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onBlockPlace(BlockPlaceEvent event)
+ {
+ if (isStep(event.getBlock().getType()) && !event.getPlayer().isSneaking() && hasEnabled(event.getPlayer()))
+ {
+ byte data = event.getBlock().getData();
+ if (data != (data |= 0x8))
+ {
+ event.getBlock().setData(data);
+ }
+ }
+ }
+
+ private boolean isStep(Material block)
+ {
+ return block == Material.STEP || block == Material.STONE_SLAB2;
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledTorch.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledTorch.java
new file mode 100644
index 0000000..188bce2
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledTorch.java
@@ -0,0 +1,91 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.bukkit.Bukkit;
+import org.bukkit.GameMode;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.block.BlockPlaceEvent;
+
+import com.redstoner.misc.Main;
+
+public class ModToggledTorch extends ModToggledAbstract
+{
+ private final Set<Block> torchesPlaced = new HashSet<>();
+
+ public ModToggledTorch()
+ {
+ super("torch", true);
+ Bukkit.getScheduler().scheduleSyncRepeatingTask(Main.plugin, this::updateTorches, 2, 2);
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return "If active, redstone torches placed on a redstone block disappear quickly";
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onBlockPlace(BlockPlaceEvent event)
+ {
+ final Player player = event.getPlayer();
+ if (!player.isSneaking() && player.getGameMode() == GameMode.CREATIVE && hasEnabled(player)
+ && event.getBlock().getType() == Material.REDSTONE_TORCH_ON)
+ {
+ if (isAttachedToRedstoneBlock(event.getBlock()))
+ {
+ torchesPlaced.add(event.getBlock());
+ }
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ private boolean isAttachedToRedstoneBlock(Block block)
+ {
+ BlockFace towardsAgainst = getFaceTowardsBlockAgainst(block.getData());
+ return towardsAgainst != null && block.getRelative(towardsAgainst).getType() == Material.REDSTONE_BLOCK;
+ }
+
+ private BlockFace getFaceTowardsBlockAgainst(byte data)
+ {
+ switch (data)
+ {
+ case 1:
+ return BlockFace.WEST;
+ case 2:
+ return BlockFace.EAST;
+ case 3:
+ return BlockFace.NORTH;
+ case 4:
+ return BlockFace.SOUTH;
+ case 5:
+ return BlockFace.DOWN;
+ default:
+ return null;
+ }
+ }
+
+ private void updateTorches()
+ {
+ for (Iterator<Block> it = torchesPlaced.iterator(); it.hasNext();)
+ {
+ Block block = it.next();
+ if (block.getType() == Material.REDSTONE_TORCH_OFF)
+ {
+ block.setType(Material.AIR);
+ it.remove();
+ }
+ else if (block.getType() != Material.REDSTONE_TORCH_ON || !isAttachedToRedstoneBlock(block))
+ {
+ it.remove();
+ }
+ }
+ }
+}