package me.desht.scrollingmenusign.views.redout; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import me.desht.dhutils.LogUtils; import me.desht.dhutils.MiscUtil; import me.desht.dhutils.PersistableLocation; import me.desht.dhutils.block.BlockUtil; import me.desht.scrollingmenusign.SMSException; import me.desht.scrollingmenusign.SMSInteractableBlock; import me.desht.scrollingmenusign.SMSValidate; import me.desht.scrollingmenusign.ScrollingMenuSign; import me.desht.scrollingmenusign.views.SMSGlobalScrollableView; import org.bukkit.Bukkit; 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.configuration.ConfigurationSection; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockDamageEvent; import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockRedstoneEvent; import org.bukkit.material.Lever; import org.bukkit.material.Redstone; public class Switch implements Comparable<Switch>, SMSInteractableBlock { private static final Map<String, Set<ConfigurationSection>> deferred = new HashMap<String, Set<ConfigurationSection>>(); private final SMSGlobalScrollableView view; private final PersistableLocation location; private final String trigger; private final String name; public Switch(SMSGlobalScrollableView view, String trigger, Location loc) { this.view = view; this.location = new PersistableLocation(loc); this.trigger = trigger; this.name = makeUniqueName(loc); ScrollingMenuSign.getInstance().getLocationManager().registerLocation(loc, this); } public Switch(SMSGlobalScrollableView view, ConfigurationSection conf) throws SMSException { String worldName = conf.getString("world"); World w = Bukkit.getWorld(worldName); SMSValidate.notNull(w, "World not available"); this.view = view; Location loc = new Location(w, conf.getInt("x"), conf.getInt("y"), conf.getInt("z")); this.location = new PersistableLocation(loc); this.trigger = MiscUtil.parseColourSpec(conf.getString("trigger")); this.name = makeUniqueName(loc); ScrollingMenuSign.getInstance().getLocationManager().registerLocation(loc, this); } /** * Get the view this output switch belongs to. * * @return The owning view */ public SMSGlobalScrollableView getView() { return view; } /** * Get the name of this output switch. * * @return The switch's name */ public String getName() { return name; } /** * Get this output switch's location. * * @return The switch's location */ public Location getLocation() { return location.getLocation(); } /** * Get the trigger string for this switch. * * @return The switch's trigger string */ public String getTrigger() { return trigger; } /** * Remove this switch from its owning view. */ public void delete() { view.removeSwitch(this); ScrollingMenuSign.getInstance().getLocationManager().unregisterLocation(getLocation()); } /** * Get the Material for this switch. (Right now, only Lever is supported). * * @return The switch's material */ private Material getSwitchType() { return getLocation().getBlock().getType(); } /** * Check if this switch is currently powered. * * @return true if powered, false otherwise */ public boolean getPowered() { Block b = getLocation().getBlock(); if (getSwitchType() == Material.LEVER) { return ((Redstone) b.getState().getData()).isPowered(); } else { LogUtils.warning("Found " + getSwitchType() + " at " + location + " - expecting LEVER!"); return false; } } /** * Set the powered status of this switch. * * @param powered true to switch on, false to switch off */ public void setPowered(boolean powered) { if (getSwitchType() == Material.LEVER) { setLeverPowered(getLocation().getBlock(), powered); } else { LogUtils.warning("Found " + getSwitchType() + " at " + location + " - expecting LEVER!"); } } private void setLeverPowered(Block b, boolean powered) { BlockState bs = b.getState(); Lever lever = (Lever) bs.getData(); lever.setPowered(powered); bs.setData(lever); bs.update(); } public Map<String, Object> freeze() { Map<String, Object> map = new HashMap<String, Object>(); map.put("trigger", MiscUtil.unParseColourSpec(trigger)); map.put("world", location.getWorldName()); map.put("x", location.getX()); map.put("y", location.getY()); map.put("z", location.getZ()); return map; } private String makeUniqueName(Location loc) { return String.format("%s-%d-%d-%d", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); } public static void deferLoading(SMSGlobalScrollableView view, ConfigurationSection conf) { conf.set("viewName", view.getName()); String world = conf.getString("world"); Set<ConfigurationSection> set = deferred.get(world); if (set == null) { set = new HashSet<ConfigurationSection>(); deferred.put(conf.getString("world"), set); } set.add(conf); } public static void loadDeferred(World world) { Set<ConfigurationSection> set = deferred.get(world.getName()); if (set == null) { return; } for (ConfigurationSection conf : set) { String viewName = conf.getString("viewName"); try { SMSGlobalScrollableView view = (SMSGlobalScrollableView) ScrollingMenuSign.getInstance().getViewManager().getView(viewName); view.addSwitch(new Switch(view, conf)); } catch (SMSException e) { LogUtils.warning("Can't load deferred switch for view " + viewName + ": " + e.getMessage()); } } deferred.remove(world.getName()); } @Override public int compareTo(Switch other) { return name.compareTo(other.getName()); } @Override public void processEvent(ScrollingMenuSign plugin, BlockDamageEvent event) { // ignore } @Override @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) public void processEvent(ScrollingMenuSign plugin, BlockBreakEvent event) { MiscUtil.statusMessage(event.getPlayer(), String.format("Output switch @ &f%s&- was removed from view &e%s / %s.", MiscUtil.formatLocation(event.getBlock().getLocation()), getView().getName(), getTrigger())); delete(); } @Override public void processEvent(ScrollingMenuSign plugin, BlockPhysicsEvent event) { if (plugin.getConfigCache().isPhysicsProtected()) { event.setCancelled(true); } else if (BlockUtil.isAttachableDetached(event.getBlock())) { LogUtils.info("Redstone output switch @ " + location + " (for " + getView().getName() + ") has become detached: deleting"); delete(); } } @Override public void processEvent(ScrollingMenuSign plugin, BlockRedstoneEvent event) { // ignore } }