From d00301ccc3de42c6b66bf986e79ce84ca2c09d07 Mon Sep 17 00:00:00 2001 From: Dico200 Date: Mon, 30 May 2016 15:45:05 +0200 Subject: Updated damnspam, made block breaking check attached levers and buttons, denied clicking now mentions timeout left, tweaked command slightly to perceive setting the timeout to 0 as removing it. --- damnspam.py | 165 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 108 insertions(+), 57 deletions(-) diff --git a/damnspam.py b/damnspam.py index e9f9b84..a72c254 100644 --- a/damnspam.py +++ b/damnspam.py @@ -1,12 +1,15 @@ #pylint: disable = F0401 from helpers import * from time import time as now -import org.bukkit.event.block.BlockBreakEvent as BlockBreakEvent +import org.bukkit.Material as Material +import org.bukkit.block.BlockFace as BlockFace inputs = open_json_file("damnspam", {}) # format "x;y;z;World" accepted_inputs = ["WOOD_BUTTON", "STONE_BUTTON", "LEVER"] changing_input = False removing_input = False +max_timeout = 240 +timeout_error_str = "&cThe timeout must be -1 or within 0 and %d" % max_timeout def save_inputs(): @@ -26,29 +29,35 @@ def add_input(creator, block, timeout_off, timeout_on): } +def is_acceptable_timeout(timeout): + return (0 < timeout <= max_timeout) or timeout == -1 + + @hook.command("damnspam") def on_dammnspam_command(sender, command, label, args): - global changing_input - plugin_header(sender, "DamnSpam") + if not checkargs(sender, args, 1, 2): msg(sender, "&c/damnspam &e(Buttons/Levers)") msg(sender, "&c/damnspam &e(Levers only)") return True #Gittestlol if not is_creative(sender): - msg(sender, "&cYou can only do this in Creative mode.") + msg(sender, "&cYou can only do this in Creative mode") return True # /damnspam + destroying_input = False # if both timeouts are 0, the plugin will attempt to remove the protection if len(args) == 1: timeout_on = args[0] try: timeout_on = round(float(timeout_on), 2) - timeout_off = timeout_on - if 60 >= timeout_on <= -2 or timeout_on == 0: - msg(sender, "&cThe timeout must be within 0-60 or -1.") + if timeout_on == 0: + destroying_input = True + elif not is_acceptable_timeout(timeout_on): + msg(sender, "&cThe timeout must be -1 or within 0 and %d" % max_timeout) return True + timeout_off = timeout_on except ValueError: msg(sender, "&cThe timeout must be a number") return True @@ -60,12 +69,10 @@ def on_dammnspam_command(sender, command, label, args): try: timeout_on = round(float(timeout_on), 2) timeout_off = round(float(timeout_off), 2) - if 60 >= timeout_on <= -2 or timeout_on == 0: - timeout_on = False - if 60 >= timeout_off <= -2 or timeout_off == 0: - timeout_off = False - if timeout_on == False or timeout_off == False: - msg(sender, "&cThe timeout must be within 0-60 or -1.") + if timeout_on == 0 and timeout_off == 0: + destroying_input = True + elif not (is_acceptable_timeout(timeout_on) and is_acceptable_timeout(timeout_off)): + msg(sender, "&cThe timeout must be -1 or within 0 and %d" % max_timeout) return True except ValueError: msg(sender, "&cThe timeout must be a number") @@ -78,72 +85,116 @@ def on_dammnspam_command(sender, command, label, args): msg(sender, "&cPlease look at a button or lever while executing this command!") return True - if location_str(target) in inputs: + global changing_input + target_loc_str = location_str(target) + if target_loc_str in inputs: changing_input = True # this input already has a timeout + + type_str = ttype.lower().replace("_", " ") + # test if player is allowed to build here - test_event = BlockBreakEvent(target, sender) - server.getPluginManager().callEvent(test_event) + build_check = can_build(sender, target) changing_input = False - if test_event.isCancelled(): - msg(sender, "&cYou are not allowed to modify this %s" % str(target.getType()).lower()) + if not build_check: + msg(sender, "&cYou are not allowed to modify this %s" % type_str) return True # add block to inputs - add_input(sender, target, timeout_off, timeout_on) + if destroying_input: + if target_loc_str not in inputs: + msg(sender, "&cThere is no timeout to remove on this %s (by setting the timeout to 0)" % type_str) + return True + del inputs[target_loc_str] + msg(sender, "&aSuccessfully removed the timeout for this %s" % type_str) + else: + add_input(sender, target, timeout_off, timeout_on) + msg(sender, "&aSuccessfully set a timeout for this %s" % type_str) save_inputs() - msg(sender, "&aSuccessfully set a timeout for this %s." % ttype.lower().replace("_", " ")) return True -@hook.event("block.BlockBreakEvent", "normal") -def on_block_break(event): - global removing_input - - if removing_input: +def check_block_break(break_event, block): + if str(block.getType()) not in accepted_inputs: return - sender = event.getPlayer() - block = event.getBlock() - btype = str(block.getType()).lower() - if str(block.getType()) in accepted_inputs and not event.isCancelled(): - pos_str = location_str(block) - if inputs.get(pos_str): - if sender.isSneaking(): - # test if player is allowed to build here - removing_input = True - test_event = BlockBreakEvent(block, sender) - server.getPluginManager().callEvent(test_event) - removing_input = False - if test_event.isCancelled(): - event.setCancelled(True) - msg(sender, "&cYou are not allowed to remove this %s" % btype) - return True - inputs.pop(pos_str) # remove - save_inputs() - msg(sender, "&eSuccessfully removed this %s!" % btype) - return True - elif not changing_input: - event.setCancelled(True) - msg(sender, "&cYou cannot destroy this %s!" % btype) - msg(sender, "&c&nSneak&c and break if you want to remove it.") - return True + pos_str = location_str(block) + if pos_str not in inputs: + return + sender = break_event.getPlayer() + input_str = ("this %s" if block is break_event.getBlock() else "the %s attached to that block") % str(block.getType()).lower().replace("_", " ") + if not sender.isSneaking(): + msg(sender, "&cYou cannot destroy " + input_str) + msg(sender, "&c&nSneak&c and break or set the timeout to 0 if you want to remove it.") + break_event.setCancelled(True) + return + global removing_input + removing_input = True + success = can_build(sender, block) + removing_input = False + if success: + del inputs[pos_str] + save_inputs() + msg(sender, "&aSuccessfully removed %s!" % input_str) + else: + msg(sender, "&cYou are not allowed to remove " + input_str) + break_event.setCancelled(True) + + +# a dict for levers and buttons, with a tuple of tuples as value. The tuples in the tuple represent +# the data values which the block must have if the block were placed towards the linked blockface to be affected. +# The order is DOWN, UP, NORTH, SOUTH, WEST, EAST +attached_blocks = { + + Material.LEVER: ((0, 7, 8, 15), (5, 6, 13, 14), (4, 12), (3, 11), (2, 10), (1, 9)), + Material.STONE_BUTTON: ((0, 8), (5, 6, 7, 13, 14, 15), (4, 12), (3, 11), (2, 10), (1, 9)), + Material.WOOD_BUTTON: ((0, 8), (5, 6, 7, 13, 14, 15), (4, 12), (3, 11), (2, 10), (1, 9)), + +} + +# returns a generator containing the levers or buttons that would be broken if this block were broken +def get_attached_blocks(block): + for i, face in ((0, BlockFace.DOWN), (1, BlockFace.UP), (2, BlockFace.NORTH), (3, BlockFace.SOUTH), (4, BlockFace.WEST), (5, BlockFace.EAST)): + side = block.getRelative(face) + dvalues = attached_blocks.get(side.getType()) + if dvalues is not None and side.getData() in dvalues[i]: + yield side + + +@hook.event("block.BlockBreakEvent", "highest") +def on_block_break(event): + try: + if removing_input or changing_input or event.isCancelled(): + return + block = event.getBlock() + check_block_break(event, event.getBlock()) + for affected_block in get_attached_blocks(block): + check_block_break(event, affected_block) + except: + error(trace()) @hook.event("player.PlayerInteractEvent", "normal") def on_interact(event): if (str(event.getAction()) == "RIGHT_CLICK_BLOCK") and not event.isCancelled(): - sender = event.getPlayer() + sender = event.getPlayer() + if sender.isSneaking(): + return block = event.getClickedBlock() - btype = str(block.getType()).lower() - powered = (block.getData() & 0x8) == 0x8 if btype == "lever" else False # data > 7, but this is how bukkit does it pos_str = location_str(block) data = inputs.get(pos_str) if data: - checktime = data["timeout_on"] if powered else data["timeout_off"] + sender = event.getPlayer() + btype = str(block.getType()).lower().replace("_", " ") + if btype == "lever" and block.getData() < 8: + checktime = data["timeout_off"] + else: + checktime = data["timeout_on"] + time_left = data["last_time"] + checktime - now() + if checktime == -1: event.setCancelled(True) msg(sender, "&cThis %s is locked permanently by /damnspam." % (btype)) - elif data["last_time"] + checktime > now(): + elif time_left > 0: event.setCancelled(True) - msg(sender, "&cThis %s has a damnspam timeout of %ss." % (btype, checktime)) + msg(sender, "&cThis %s has a damnspam timeout of %.2fs, with %.2fs left." % (btype, checktime, time_left)) else: - inputs[pos_str]["last_time"] = round(now(), 2) + data["last_time"] = round(now(), 2) -- cgit v1.2.3