Moved /signalstrength to its own file, added default configurability, added basecommands documentation, added can_build() to helpers

This commit is contained in:
Dico200
2015-10-20 18:03:05 +02:00
parent 2db8142b35
commit 9119c3d150
4 changed files with 68 additions and 94 deletions

View File

@@ -1,13 +1,66 @@
from helpers import *
to_see_permission = "utils.showpermission" # See cmd permission in help
"""
@simplecommand is a decorator which is meant to replace @hook.command in redstoner-utils, where useful.
It takes care of checks such as whether the sender is a player, whether they have permission,
whether there are enough argumens, and also takes care of a help message.
On top of that, it makes the code shorter and easier to write with features like Validate, and returning a message instead of a boolean value.
@simplecommand has an inbuilt tracing feature, so you won't have to put all your code in a try/except statement anymore.
Make sure to `from basecommands import simplecommand` before using this decorator.
The arguments are as follows:
* cmd: the command, self explanatory (required);
* aliases: A list containing any aliases for the command, like shortcuts;
* usage: a String defining the expected arguments for the command. Example:
Let's say I have a command /tp <player_to_teleport> <destination_player>. The usage is: "<player_to_teleport> <destination_player>".
I suggest we use the same format throughout redstoner-utils:
- Separate arguments by spaces;
- Use <> if the argument is required, and [] if the argument is optional;
- Add .. to the argument's identifier (name) if it is for example a message (containing spaces).
for example in /msg, the usage would be "<player> <msg..>"
* description: a description of what the command does. Defaults to "Handles cmd".
This is used for the help message, where the description is (meant to be) indented. To keep this indentation
with longer descriptions, call the help message (with the command, ingame) and add '\n'
when it jumps to a new line in the chat. The decorator will take care of the indentation after that.
* senderLimit: an integer resembling the accepted sender type. Defaults to -1. Use:
-1 for console as well as players;
0 for players only;
1 for console only.
* amin: an integer resembling the minimum amount of arguments. Defaults to 0
* amax: an integer resembling the maximum amount of arguments. Defaults to -1, which means that there is no maximum.
* helpNoargs: a boolean value resembling whether the help message should be displayed when no arguments are given.
Defaults to False.
* helpSubcmd: a boolean value resembling whether the help message should be displayed when the first argument.lower() equals "help".
Defaults to False.
Comments on the function added to the decorator:
It should return a message to send to the player. Color codes are translated automatically. It can return None or an empty string to send nothing.
Inside the function, calls to static methods in the class Validate can be used to make the code shorter and easier to write (maybe not easier to read).
For example, to make sure that a condition is met, use Validate.isTrue(condition, message to send to the player if the condition is not met)
Don't forget to `from basecommands import Validate` if you wish to make use of this.
For all other Validate checks, see the code below. Feel free to add your own.
Instead of returning a message mid-code to describe an error, you can also use raise CommandException(msg), but it is almost always possible
to replace this return statement with a call to one of the functions in the Validate class. Once again, if you use raise CommandException(msg),
don't forget to `from basecommands import CommandException`.
"""
to_see_permission = "utils.showpermission" # See cmd permission in help
def isSenderValid(senderLimit, isPlayer):
return True if senderLimit == -1 else senderLimit != isPlayer
def invalidSenderMsg(isPlayer):
return "&cThat command can only be run from the console" if isPlayer else "&cThat command can only be run by players"
return "&cThat command can only be used by " + ("the console" if isPlayer else "players")
def helpMsg(sender, cmd, description, usage, aliases, permission):
help_msg = "&aInformation about command /%s:\n &9%s" % (cmd, description.replace("\n", "\n "))
@@ -65,7 +118,7 @@ def simplecommand(cmd,
except CommandException, e:
return e.message
except Exception, e:
error(e.message, trace())
error(trace())
return "&cAn internal error occurred while attempting to perform this command"
return call

View File

@@ -6,6 +6,7 @@ import org.bukkit as bukkit
import org.bukkit.Location as Location
import org.bukkit.entity.Player as Player
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause as TeleportCause
import org.bukkit.event.block.BlockBreakEvent as BlockBreakEvent
import org.bukkit.block as bblock
import org.bukkit.event.entity as entity
import org.bukkit.command.ConsoleCommandSender
@@ -143,6 +144,15 @@ def is_player(obj):
return (isinstance(obj, Player))
def can_build(player, block):
"""
return True if the player can change/build at the location of given block
"""
event = BlockBreakEvent(block, player)
server.getPluginManager().callEvent(event)
return not event.isCancelled()
def checkargs(sender, args, amin, amax):
"""
check if a command has a valid amount of args, otherwise notify the sender

View File

@@ -54,6 +54,8 @@ shared["load_modules"] = [
"webtoken",
# Adds /lol, broadcasts random funyy messages. A bit like the splash text in the menu
"saylol",
# Adds /signalstrength, lets you request a signal strength and an amount of items will be inserted into target container to meet that strength.
"signalstrength",
# Shows the owner of a skull when right-clicked
"skullclick",
# Adds /listen, highlights chat and plays a sound when your name was mentioned

91
misc.py
View File

@@ -4,11 +4,7 @@ from time import time as now
from time import sleep
from sys import exc_info
import thread
import org.bukkit.inventory.ItemStack as ItemStack
import org.bukkit.Material as Material
from math import ceil
import org.bukkit.Bukkit as Bukkit
from basecommands import simplecommand, Validate
@@ -145,93 +141,6 @@ def on_sudo_command(sender, command, label, args):
return "&cPlayer %s not found!" % target
"""
Suggestion by Armadillo28, see thread: http://redstoner.com/forums/threads/2213?page=1#reply-14507
Clarification on these formulas on http://minecraft.gamepedia.com/Redstone_Comparator#Containers
"""
def required_item_count(strength, slots, stack):
if strength == 0:
count = 0
elif strength == 1:
count = 1
else:
count = int(ceil(slots * stack / 14.0 * (strength - 1)))
resulting_strength = int(1 + 14.0 * count / stack / slots)
return count if resulting_strength == strength else None
@simplecommand("signalstrength",
usage = "<signal strength> [item] [data]",
aliases = ["ss", "level"],
description = "Fills the targeted container with the correct amount of items to achieve the desired signal strength.",
amin = 1,
amax = 3,
helpNoargs = True,
helpSubcmd = True,
senderLimit = 0)
def on_signalstrength_command(sender, command, label, args):
target_block = sender.getTargetBlock(None, 5)
Validate.notNone(target_block, "&cThat command can only be used when a container is targeted")
try:
inv = target_block.getState().getInventory()
except AttributeError:
return "&cThat command can only be used when a container is targeted"
#---------Define the requested strength, item type and item data----------
Validate.isTrue(args[0].isdigit() and 0 <= int(args[0]) <= 15, "&cThe signal strength has to be a value from 0 to 15")
strength = int(args[0])
item_type = Material.REDSTONE if len(args) < 2 else Material.getMaterial(int(args[1]) if args[1].isdigit() else args[1])
Validate.notNone(item_type, "&cThat item id does not exist")
item_data = 0 if len(args) < 3 else int(args[2]) if args[2].isdigit() else -1
Validate.isTrue(0 <= item_data <= 15, "&cThe data has to be a value from 0 to 15")
#--------Get the stack size and required amount of items to achieve the desired signal strength---------
stack_size = item_type.getMaxStackSize()
item_count = required_item_count(strength, inv.getSize(), stack_size)
Validate.notNone(item_count, "&cThe desired signal strength could not be achieved with the requested item type")
#------------Add the other side of the chest if target is a double chest--------------
target_blocks = [target_block]
target_type = target_block.getType()
if target_type in (Material.CHEST, Material.TRAPPED_CHEST):
loc = target_block.getLocation()
x = loc.getBlockX()
y = loc.getBlockY()
z = loc.getBlockZ()
world = loc.getWorld()
target_blocks += [
block for block in (
world.getBlockAt(x + 1, y, z),
world.getBlockAt(x - 1, y, z),
world.getBlockAt(x, y, z + 1),
world.getBlockAt(x, y, z - 1),
) if block.getType() == target_type
]
#----------------Insert items-------------
full_stack_count, remaining = divmod(item_count, stack_size)
inv.clear()
for block in target_blocks:
for i in range(full_stack_count):
inv.setItem(i, ItemStack(item_type, stack_size, item_data))
if remaining > 0:
inv.setItem(full_stack_count, ItemStack(item_type, remaining, item_data))
return "&aSuccesfully edited the targeted %s to give out a signal strenth of %s to comparators" % (
str(target_type).lower().replace("_", " "), strength)
@simplecommand("me",
usage = "[message..]",