2 Commits

Author SHA1 Message Date
jomo
7cf1be67e9 Fixed hypercommand exceptions
Apparently jython, nested functions, decorators, and wildcard import don't work well together.
I changed the import to non-wildcard and prefixed all function calls with the module name
2015-08-16 02:28:13 +02:00
NEMESIS13cz
e184a6d4e1 Created hopefully the ultimate cmd manager 2015-08-15 18:48:15 +02:00
34 changed files with 418 additions and 2430 deletions

View File

@@ -1,67 +1,13 @@
from helpers import *
"""
@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.
Returning "HELP" makes it show the help message.
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 used by " + ("the console" if isPlayer else "players")
return "&cThat command can only be run from the console" if isPlayer else "&cThat command can only be run by players"
def helpMsg(sender, cmd, description, usage, aliases, permission):
help_msg = "&aInformation about command /%s:\n &9%s" % (cmd, description.replace("\n", "\n "))
@@ -119,7 +65,7 @@ def simplecommand(cmd,
except CommandException, e:
return e.message
except Exception, e:
error(trace())
error(e.message, trace())
return "&cAn internal error occurred while attempting to perform this command"
return call

View File

@@ -24,7 +24,7 @@ settingInformation = dict( #[setting type, identifying description, detailed des
],
furnace = [1,
"automatically filling furnaces upon placement",
"Sets your preferred default furnace contents to your currently held itemstack. Use an empty hand to empty a slot, or /toggle furnace clear to clear all slots.",
"Sets your preferred default furnace contents to your currently held itemstack. Use an empty hand to empty a slot, or /toggle dropper clear to clear all slots.",
["cooker", "fillf"], 2
],
#torch = [0,
@@ -44,7 +44,7 @@ settingInformation = dict( #[setting type, identifying description, detailed des
],
hopper = [1,
"automatically filling hoppers upon placement",
"Sets your preferred default hopper contents to your currently held itemstack. Use an empty hand to empty a slot, or /toggle hopper clear to clear all slots.",
"Sets your preferred default hopper contents to your currently held itemstack. Use an empty hand to empty a slot, or /toggle dropper clear to clear all slots.",
["itemtransporter", "fillh"], 4
]
)

View File

@@ -10,12 +10,6 @@ calc_perm = "utils.calc"
calc_perm_power = "utils.calc.power"
def calc(sender, text):
try:
return do_calc(sender, text.lower())
except:
return None
def do_calc(sender, text):
"""
extracts a mathematical expression from `text`
returns (expression, result) or None

View File

@@ -1,138 +0,0 @@
# Chat Aliasing plugin by Curs3d #
##################################
# Allows users to alias words,
# so that when they send a
# message in chat, it gets
# replaced by their specified
# word. The JSON file for this
# plugin is generated if not
# present. Set values to -1
# for "unlimited" setting.
from helpers import *
import re
from traceback import format_exc as trace
data = None
max_entries = 10
max_alias_length = 35
# Minecraft message limit is 100 so I decided to give a little tolerance (and I added a bit more)
max_overall_length = 100 + max_alias_length
alias_perm = "utils.alias.allowed"
exceed_length = "utils.alias.exceedlimit"
exceed_entries = "utils.alias.exceedlimit"
exceed_overall_length = "utils.alias.exceedlimit"
def safe_open_json():
global data
if data is not None:
return data
data = open_json_file("aliases")
if data is None:
data = {}
save_json_file("aliases", data)
return data
def multiple_replace(aliases, text):
regex = re.compile("|".join(map(re.escape, aliases.keys())))
return regex.sub(lambda mo: aliases[mo.group(0)], text)
@hook.command("alias",
usage="/<command> [to_alias] [alias...]",
desc="Aliases words in chat")
def on_alias_command(sender, cmd, label, args):
if not is_player(sender):
msg(sender, "Sorry, non-players cannot alias words")
return True
if not sender.hasPermission(alias_perm):
plugin_header(recipient=sender, name="Chat Alias")
noperm(sender)
return True
if len(args) == 0:
plugin_header(recipient=sender, name="Chat Alias")
msg(sender, "&7This is a plugin that allows you to get words" +
"replaced by other ones automatically!")
msg(sender, "&7\nCommands:")
msg(sender, "&e/alias <word> &7removes <word> from your aliases. " +
"Use &e/alias * &7to remove all aliases.")
msg(sender, "&e/alias <word> <replacement> &7will change &e<word> " +
"&7to &e<replacement> &7in chat")
msg(sender, "&7\nYour Aliases:")
data = safe_open_json()
try:
for alias, value in data[str(sender.getUniqueId())].items():
msg(sender, "&7%s &7==> %s" % (alias, value))
except KeyError:
pass
return True
elif len(args) == 1:
data = safe_open_json()
if args[0] == "*":
try:
del data[str(sender.getUniqueId())]
except KeyError:
plugin_header(recipient=sender, name="Chat Alias")
msg(sender, "&7No alias data to remove!")
return True
save_json_file("aliases", data)
plugin_header(recipient=sender, name="Chat Alias")
msg(sender, "&cALL &7alias data successfuly removed!")
return True
try:
if data[str(sender.getUniqueId())].pop(args[0], None) is None:
plugin_header(recipient=sender, name="Chat Alias")
msg(sender, "&7Could not remove: alias not present!")
return True
except KeyError:
plugin_header(recipient=sender, name="Chat Alias")
msg(sender, "&7Could not remove: you do not have any aliases!")
return True
save_json_file("aliases", data)
plugin_header(recipient=sender, name="Chat Alias")
msg(sender, "&7Alias for %s &7successfuly removed" % args[0])
return True
elif len(args) >= 2:
data = safe_open_json()
alias = " ".join(args[1:])
try:
if (len(alias) > max_alias_length) and (max_alias_length >= 0) and (not sender.hasPermission(exceed_length)):
plugin_header(recipient=sender, name="Chat Alias")
msg(sender, "&7Please do not alias long words/sentences.")
return True
if (len(data[str(sender.getUniqueId())]) >= max_entries) and (max_entries >= 0) and (not sender.hasPermission(exceed_entries)):
plugin_header(recipient=sender, name="Chat Alias")
msg(sender, "&7You have reached your alias limit!")
return True
except KeyError:
data[str(sender.getUniqueId())] = {}
data[str(sender.getUniqueId())][args[0]] = alias
save_json_file("aliases", data)
plugin_header(recipient=sender, name="Chat Alias")
msg(sender, "&7Chat Alias %s &7==> %s &7successfully created!" % (args[0], alias))
return True
else:
return False
@hook.event("player.AsyncPlayerChatEvent", "high")
def on_player_chat(event):
playerid = str(event.getPlayer().getUniqueId())
data = safe_open_json()
if event.isCancelled():
return
if not playerid in data:
return
event.setMessage(multiple_replace(data[playerid], event.getMessage()))
if (event.getPlayer().hasPermission("essentials.chat.color")):
event.setMessage(colorify(event.getMessage()))
if (max_overall_length >= 0) and (len(event.getMessage()) > max_overall_length) and (not event.getPlayer().hasPermission(exceed_overall_length)):
event.setCancelled(True)
plugin_header(recipient=event.getPlayer(), name="Chat Alias")
msg(event.getPlayer(), "&7The message generated was too long and was not sent. :/")

View File

@@ -43,18 +43,11 @@ def on_chatgroup_command(sender, command, label, args):
msg(sender, "&aUse chat like '&e%s<message>' to send messages to this group." % get_key(sender_id))
elif len(args) == 1 and args[0] == "key":
msg(sender, "&aYour chatgroup key is currently: '&c%s&a'" % get_key(sender_id))
elif len(args) == 1 and args[0] == "tpahere":
if sender_id in groups.keys():
do_for_chatgroup(groups[sender_id], send_tpa_request, sender)
msg(sender, "&aSent a tpahere request to all users in your chatgroup")
else:
msg(sender, "&cYou have to be in a chatgroup to do that")
else:
msg(sender, "&e/chatgroup join <name>")
msg(sender, "&e/chatgroup leave")
msg(sender, "&e/chatgroup info")
msg(sender, "&e/chatgroup key")
msg(sender, "&e/chatgroup tpahere")
@hook.command("cgt")
@@ -79,19 +72,11 @@ def groupchat(sender, message, ann = False):
mesg = "&8[&bCG&8] &e&o%s&e&o %s" % (name, message)
else:
mesg = "&8[&bCG&8] &f%s&f: &6%s" % (name, message)
mesg = colorify(mesg)
info("[ChatGroups] %s (%s): %s" % (sender.getDisplayName(), group, message))
do_for_chatgroup(group, msg, mesg, usecolor = False)
def do_for_chatgroup(group, func, *args, **kwargs):
for receiver in server.getOnlinePlayers():
if groups.get(uid(receiver)) == group:
func(receiver, args, kwargs)
groups.get(uid(receiver)) == group and msg(receiver, mesg)
def send_tpa_request(receiver, sender):
if not receiver == sender:
runas(sender, "/tpahere " + receiver.getName())
def save_groups():
save_json_file("chatgroups", groups)
@@ -130,6 +115,5 @@ def chatgroupkey_command(sender, command, label, args):
save_keys()
return "&aYour chatgroup key was set to: '&c%s&a'" % key
def save_keys():
save_json_file("chatgroup_keys", cg_keys)

View File

@@ -86,10 +86,7 @@ def on_hook_command(sender, command, label, args):
plugin_header(sender, "Check")
msg(sender, "&7Please notice that the data may not be fully accurate!")
player = server.getOfflinePlayer(args[0]) if len(args) > 0 else None
t = threading.Thread(target=get_all_data, args=(sender, player))
t.daemon = True
t.start()
get_all_data(sender, player)
else:
msg(sender, "&4You don't have the required permissions to execute this command!")
return True

View File

@@ -1,30 +1,17 @@
#pylint: disable = F0401
import org.bukkit as bukkit
import org.bukkit.block as bblock
import org.bukkit.Location as Location
import org.bukkit.event.entity as entity
import org.bukkit.entity.Player as Player
import org.bukkit.command.ConsoleCommandSender
import org.bukkit.event.block.BlockBreakEvent as BlockBreakEvent
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause as TeleportCause
from re import sub
from thread_utils import *
from player import py_players
from org.bukkit.entity import *
from player import get_py_player
from traceback import format_exc as trace
from java.util.UUID import fromString as juuid
from json import dumps as json_dumps, loads as json_loads
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.block as bblock
import org.bukkit.event.entity as entity
import org.bukkit.command.ConsoleCommandSender
from org.bukkit.entity import *
#Imports for async query
import threading
import mysqlhack
from secrets import *
from com.ziclix.python.sql import zxJDBC
from traceback import format_exc as trace
shared = {} # this dict can be used to share stuff across modules
@@ -91,7 +78,7 @@ def colorify(text):
"""
replace &-codes with real color codes
"""
return sub("&" + u"\u00A7", "&", "%s" % sub("&(?=[?\\da-fk-or])", u"\u00A7", "%s" % text))
return sub("&(?=[?\\da-fk-or])", u"\u00A7", "%s" % text)
def stripcolors(text):
@@ -148,15 +135,6 @@ 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
@@ -185,16 +163,6 @@ def is_creative(player):
return str(player.getGameMode()) == "CREATIVE"
def is_rank(player, rank):
"""
rank: a string equal to the PEX group name found in /pex groups
returns True if one of the following conditions are met:
- the player is of the given rank,
- their rank inherits the given rank.
"""
return player.hasPermission("groups." + rank)
def uid(player):
"""
returns the player's UUID
@@ -218,6 +186,7 @@ def known_player(player):
"""
return player.hasPlayedBefore()
def open_json_file(filename, default = None):
"""
opens the given json file and returns an object or returns None on error
@@ -254,27 +223,4 @@ def toggle(player, ls, name = "Toggle", add = None):
msg(player, "&a%s turned off!" % name)
elif add != False:
ls.append(pid)
msg(player, "&a%s turned on!" % name)
def send_JSON_message(playername, message):
bukkit.Bukkit.getServer().dispatchCommand(bukkit.Bukkit.getServer().getConsoleSender(), "tellraw " + playername + " " + message)
def isIP(tocheck):
subsets = ["","","",""]
i = 0
for j in range(0,len(tocheck)):
if not (tocheck[j] in "0123456789."):
return False
elif tocheck[j] == ".":
i += 1
if (i >= 4):
return False
else:
subsets[i] += tocheck[j]
if not (i == 3):
return False
for j in range(0,3):
if not ((int(subsets[j]) >= 0) & (int(subsets[j]) <= 255)):
return False
return True
msg(player, "&a%s turned on!" % name)

87
hypercommand.py Normal file
View File

@@ -0,0 +1,87 @@
# can't import * because that's not working with nested functions & decorators
import helpers
# cmd = the actual command
# tree = e.g. [{ "name": "subcommand", "perm": "utils.cmd.command.subcommand", "func": <function>, "type": "cmd", "cont": [<tree>] }]
# helpnoargs = print help if no args given, else run the command function below decorator
# console = can be ran by console
def hypercommand(cmd, tree = [], helpnoargs = False, console = False):
def help_msg_get(tree):
holder = ""
for data in tree:
if len(data["cont"]) > 0:
holder += ("(" + help_msg_get(data["cont"]) + ")")
else:
holder += (data["name"] if data["type"] == "cmd" else ("<" + data["name"] + ">"))
return holder
def help_msg(sender, tree):
for data in tree:
if len(data["cont"]) > 0:
helpers.msg(sender, "&e-&a " + (data["name"] if data["type"] == "cmd" else ("<" + data["name"] + ">")) + " " + help_msg_get(data["cont"]))
else:
helpers.msg(sender, "&e-&a " + (data["name"] if data["type"] == "cmd" else ("<" + data["name"] + ">")))
return None
has_help = False
for data in tree:
if data["name"] == "help" and data["type"] == "cmd":
has_help = True
break
cmd = cmd.lower()
if not has_help:
tree.append({"name": "help", "perm": "utils." + cmd + ".help", "func": help_msg, "type": "cmd", "cont": []}) # type = "cmd" for subcommands or "arg" for arguments
def decorator(function):
def get_next(sender, tree, args, all_args):
if len(args) == 0: # ran out of arguments but command is supposed to continue, print usage
data = []
for comm in tree:
if comm["type"] == "cmd":
data.append(comm["name"])
else:
data.append("<" + comm["name"] + ">")
return "&c" + " ".join(all_args) + " " + "/".join(data) + "..."
for comm in tree:
if comm["type"] == "cmd":
if comm["name"] == args[0]: # argument exists as a subcommand
if sender.hasPermission(comm["perm"]):
if len(comm["cont"]) > 0: # command continues
return get_next(sender, comm["cont"], args[1:], all_args) # continue in the recursive stack
else:
return comm["func"](sender, args[1:]) # run function with sender and all trailing arguments incase they are relevant
else:
return "&cNo permission"
for comm in tree:
if comm["type"] == "arg":
if len(comm["cont"]) > 0: # command continues, but this is an argument
# run the function its pointing at and substitute itself with the returned subcommand to chose
# continue in stack as if the arg was a subcommand returned by its pointer function
return get_next(sender, comm["cont"], args[0:(len(args) - 1)].insert(0, comm["func"](sender, args[0])), all_args)
else:
return comm["func"](sender, args) # run the function arg is pointing at with current arguments including this one as args[0]
return get_next(sender, tree, [], all_args[0:(len(all_args) - 1)])
@hook.command(cmd)
def call(sender, command, label, args):
message = run(sender, command, label, args)
if message:
helpers.msg(sender, message)
return True
def run(sender, command, label, args):
if not helpers.is_player(sender) and not console:
return "&cThis command can only be executed by players"
try:
if len(args) == 0:
if helpnoargs:
help_msg(sender, tree)
return None
else:
return function(sender, command, label, args)
return get_next(sender, tree, args, args)
except:
helpers.error(helpers.trace())
return "&cInternal Error. Please report to staff!"
return call
return decorator

107
imbusy.py
View File

@@ -1,107 +0,0 @@
# I'M BUSY! Plugin by Curs3d #
##############################
# Concept by CookieManors :D #
# http://bit.ly/1GnNPW8 #
##############################
# This plugin permits users to
# send a command that renders
# them "busy", not letting them
# to get tpa requests or direct
# messages, except from console.
# On restart, all busy data will
# be cleared.
from helpers import *
from basecommands import simplecommand
from traceback import format_exc as trace
busy_players = []
def unclear():
msg(sender, "Umm, what? Sorry, directions unlclear, got head stuck in washing machine")
@hook.command("busy",
aliases = ["focus"],
usage = "/<command> <on|off|status>",
description = "Sets busy mode on, you cannot recieve tpas and MSGs"
)
def on_busy_command(sender, cmd, label, args):
if not is_player(sender):
msg(sender, "Sorry, Console cannot be busy")
return True
if not sender.hasPermission("utils.busy.allowed"):
plugin_header(recipient = sender, name = "I'M BUSY!")
noperm(sender)
return True
if len(args) == 0:
plugin_header(recipient = sender, name = "I'M BUSY!")
msg(sender, "This plugin allows being busy, and when turned on you will not recieve any direct messages or tpa requests.")
msg(sender, "\nCommands:")
msg(sender, "/busy on: turns on busy mode")
msg(sender, "/busy off: turns off busy mode")
msg(sender, "/busy status [player]: shows your or [player]'s current busy status.")
return True
elif len(args) == 1:
if args[0] == "on":
if sender.getName() in busy_players:
plugin_header(recipient = sender, name = "I'M BUSY!")
msg(sender, "You cannot be even more focused than this without being a jedi!")
return True
busy_players.append(sender.getName())
plugin_header(recipient = sender, name = "I'M BUSY!")
broadcast(None, "%s is now SUPER busy! Don't even TRY bothering them, it will not work!" % sender.getName())
return True
elif args[0] == "off":
plugin_header(recipient = sender, name = "I'M BUSY!")
try:
busy_players.remove(sender.getName())
msg(sender, "Master has sent /busy command, %s is freeee!" % sender.getName())
return True
except ValueError:
msg(sender, "You are not busy! You cannot be even less busy! Are you perhaps bored?")
return True
elif args[0] == "status":
plugin_header(recipient = sender, name = "I'M BUSY!")
if sender.getName() in busy_players:
msg(sender, "You are super-duper busy and concentrated right now. Think, think, think!")
return True
else:
msg(sender, "You are completely unable to focus right now.")
return True
else:
plugin_header(recipient = sender, name = "I'M BUSY!")
unclear()
return False
elif len(args) == 2 and args[0] == "status":
plugin_header(recipient = sender, name = "I'M BUSY!")
if args[1] in busy_players:
msg(sender, "Yes, %s is busy. Shhh..." % args[1])
return True
else:
msg(sender, "No, you're good. Feel free to chat with %s!" % args[1])
return True
else:
plugin_header(recipient = sender, name = "I'M BUSY!")
unclear()
return False
@hook.event("player.PlayerCommandPreprocessEvent", "monitor")
def on_cmd_preprocess_event(event):
message = event.getMessage().split(" ")
if message[0] == "/msg" or message[0] == "/w" or message[0] == "/m" or \
message[0] == "/tell" or message[0] == "/tpa" or message[0] == "/tpahere":
if message[1] in busy_players:
plugin_header(recipient = event.getPlayer(), name = "I'M BUSY!")
msg(event.getPlayer(), "We are sorry, but %s is currently busy. Please try again later." % message[1])
event.setCancelled(True)

View File

@@ -1,107 +0,0 @@
import mysqlhack
import org.bukkit as bukkit
import json
from java.util import UUID as UUID
from helpers import *
from org.bukkit import *
from traceback import format_exc as trace
from iptracker_secrets import *
iptrack_permission = "utils.iptrack"
@hook.event("player.PlayerJoinEvent", "low")
def on_player_join(event):
t = threading.Thread(target=on_player_join_thread, args=(event, ))
t.daemon = True
t.start()
def on_player_join_thread(event):
player = event.getPlayer()
ip = player.getAddress().getHostString()
uuid = uid(player)
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.cursor()
curs.execute("SELECT ips FROM uuid2ips WHERE uuid = ?", (uuid, ))
results = curs.fetchall()
if len(results) == 0:
ips = []
else:
ips = json.loads(results[0][0])
curs.execute("SELECT uuids FROM ip2uuids WHERE ip = ?", (ip, ))
results = curs.fetchall()
if len(results) == 0:
uuids = []
else:
uuids = json.loads(results[0][0])
new_ip_entry = (len(ips) == 0)
new_uuid_entry = (len(uuids) == 0)
if ip not in ips:
ips.append(ip)
if new_ip_entry:
curs.execute("INSERT INTO uuid2ips VALUES (?,?)", (uuid, json.dumps(ips), ))
else:
curs.execute("UPDATE uuid2ips SET ips = ? WHERE uuid = ?", (uuid, json.dumps(ips), ))
if uuid not in uuids:
uuids.append(uuid)
if new_uuid_entry:
curs.execute("INSERT INTO ip2uuids VALUES (?,?)", (ip, json.dumps(uuids), ))
else:
curs.execute("UPDATE ip2uuids SET uuids = ? WHERE uuid = ?", (ip, json.dumps(uuids), ))
conn.commit()
curs.close()
conn.close()
@hook.command("getinfo")
def on_getinfo_command(sender, args):
t = threading.Thread(target=on_player_join_thread, args=(sender, args))
t.daemon = True
t.start()
def on_getinfo_command_thread(sender, args):
if(sender.hasPermission(iptrack_permission)):
if not checkargs(sender, args, 1, 1):
return False
else:
if isIP(args[0]):
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.cursor()
curs.execute("SELECT uuids FROM ip2uuids WHERE ip = ?", (args[0], ))
results = curs.fetchall()
curs.close()
conn.close()
if len(results) == 0:
msg(sender, "IP " + args[0] + " is not registered in the database, maybe you got a number wrong?")
else:
uuids = json.loads(results[0][0])
msg(sender, "IP " + args[0] + " was seen with " + str(len(uuids)) + " different Accounts:")
for i in range(0, len(uuids)):
p=Bukkit.getOfflinePlayer(UUID.fromString(uuids[i]))
if is_player(sender):
send_JSON_message(sender.getName(), '["",{"text":"' + p.getName() + ' - (uuid: ' + uuids[i] + '","color":"gold","clickEvent":{"action":"run_command","value":"/getinfo ' + p.getName() + '"},"hoverEvent":{"action":"show_text","value":{"text":"","extra":[{"text":"To search for ' + p.getName() + ' in the database, simply click the name!","color":"gold"}]}}}]')
else:
msg(sender,p.getName() + " - (uuid: " + uuids[i] + ")")
else:
target = Bukkit.getOfflinePlayer(args[0])
uuid = target.getUniqueId()
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.cursor()
curs.execute("SELECT ips FROM uuid2ips WHERE uuid = ?", (uuid.toString(), ))
results = curs.fetchall()
curs.close()
conn.close()
if len(results) == 0:
msg(sender, "Player " + args[0] + " is not registered in the database, maybe you misspelled the name?")
else:
ips = json.loads(results[0][0])
msg(sender, "Player " + args[0] + " was seen with " + str(len(ips)) + " different IPs:")
for i in range(0, len(ips)):
if is_player(sender):
send_JSON_message(sender.getName(), '["",{"text":"' + ips[i] + '","color":"gold","clickEvent":{"action":"run_command","value":"/getinfo ' + ips[i] + '"},"hoverEvent":{"action":"show_text","value":{"text":"","extra":[{"text":"To search for the IP ' + ips[i] + ' in the database, simply click the IP!","color":"gold"}]}}}]')
else:
msg(sender,ips[i])
else:
noperm(sender)
return True

129
login.py
View File

@@ -1,129 +0,0 @@
from wrapper import *
from passlib.hash import pbkdf2_sha256 as crypt
@event_handler("player_login","normal", utils = True)
def player_join(*args):
player = args[1]
if not player.registered:
player.authenticated = True
player.msg("Successfully logged in!")
"""
@event_handler("player.PlayerCommandPreprocessEvent", "lowest")
def on_login_command(event):
player = event.player
password = event.message.replace("/login", "").replace(" ", "")
event.message = event.player.name + " Attempting to login!"
event.cancelled = True
@async(daemon = True)
def check_pass(player, password):
print password
if not player.registered:
player.msg("You are not registered! use /register <password> to register!")
return
else:
if crypt.verify(password, player.password):
player.authenticated = True
player.msg("Successfully logged in!")
else:
print event.message
player.msg("Wrong password!")
check_pass(player, password)"""
@command("login")
@async(daemon = True)
def on_login_command(**kwargs):
player = kwargs["sender"]
args = kwargs["args"]
if not player.registered:
player.msg("You are not registered! use /register <password> to register!")
return
if len(args) > 1:
player.msg("The syntax is /login <password>")
return
elif len(args) is 1:
if crypt.verify(args[0], player.password):
player.authenticated = True
player.msg("Successfully logged in!")
else:
player.msg("Wrong password!")
@command("changepass")
@async(daemon = True)
def on_changepass_command(**kwargs):
player = kwargs["sender"]
args = kwargs["args"]
if not player.registered:
player.msg("You are not registered! use /register <password> to register!")
return
if len(args) < 2:
player.msg("The syntax is /login <current_password> <new_password>")
return
elif len(args) is 2:
if crypt.verify(args[0], player.password):
player.password = crypt.encrypt(args[1], rounds=200000, salt_size=16)
player.msg("Successfully changed your password!")
player.save()
else:
player.msg("You have entered an incorrect current password!")
@command("removepass")
@async(daemon = True)
def on_removepass_command(**kwargs):
player = kwargs["sender"]
args = kwargs["args"]
if not player.registered:
player.msg("You are not registered! use /register <password> to register!")
return
if len(args) < 1:
player.msg("The syntax is /removepass <current_password>")
return
elif len(args) is 1:
if crypt.verify(args[0], player.password):
player.password = "None"
player.registered = False
player.save()
player.msg("Successfully removed your password!")
else:
player.msg("You have entered an incorrect current password!")
@command("register")
@async(daemon = True)
def on_register_command(**kwargs):
player = kwargs["sender"]
args = kwargs["args"]
if len(args) > 1:
player.msg("The syntax is /register <password>")
return
elif len(args) is 1:
if player.registered:
player.msg("You are already registered!")
return
player.password = crypt.encrypt(args[0], rounds=200000, salt_size=16)
player.registered = True
print player.password
player.save()
player.msg("Successfully registered!")
blocked_events = ["block.BlockBreakEvent", "block.BlockPlaceEvent", "player.PlayerMoveEvent",
"player.AsyncPlayerChatEvent","player.PlayerTeleportEvent",
"player.PlayerInteractEvent"]
for event in blocked_events:
@event_handler(event_name = event, priority = "highest")
def on_blocked_event(event):
if not event.player.authenticated:
event.cancelled = True

211
loginsecurity.py Normal file
View File

@@ -0,0 +1,211 @@
from helpers import *
from passlib.hash import pbkdf2_sha256 as crypt
from basecommands import simplecommand
import time
import threading
from login_secrets import * #Don't forget to make login_secrets aswell
import mysqlhack
from com.ziclix.python.sql import zxJDBC
from java.lang import Runnable
wait_time = 30 #seconds
admin_perm = "utils.loginsecurity.admin"
min_pass_length = 8
blocked_events = ["block.BlockBreakEvent", "block.BlockPlaceEvent", "player.PlayerMoveEvent","player.AsyncPlayerChatEvent"]
logging_in = {}
def matches(password,user):
thread = threading.Thread(target=matches_thread, args = (password,user))
thread.start()
def matches_thread(password, user):
hashed = get_pass(uid(user))
if crypt.verify(password, hashed):
if user.getName() in logging_in:
del logging_in[user.getName()]
msg(user, "&aLogged in successfully!")
else:
if user.getName() in logging_in:
msg(user, "&cInvalid password")
@simplecommand("cgpass",
usage = "<password> <new password>",
description = "Changes your password",
senderLimit = 0,
helpNoargs = True)
def change_pass_command(sender, command, label, args):
if sender.getName() in logging_in:
return "&cYou are not logged in"
if not len(args) == 2:
return "&cInvalid arguments"
password = args[0]
new_password = args[1]
uuid = uid(sender)
if is_registered(uuid):
change_pass(uuid, crypt.encrypt(new_password, rounds=200000, salt_size=16))
return "&aPassword changed"
return "&cYou are not registered"
@simplecommand("login",
usage = "<password>",
description = "Logs you in if <password> matches your password.",
senderLimit = 0,
helpNoargs = True)
def login_command(sender, command, label, args):
password = args[0]
matches(password, sender)
@simplecommand("register",
usage = "<password>",
description = "Registers you with <password>. Next time you join, log in with /login",
senderLimit = 0,
helpNoargs = True)
def register_command(sender, command, label, args):
if len(args) > 1:
return "&cPassword can only be one word!"
uuid = uid(sender)
if is_registered(uuid):
return "&cYou are already registered!"
password = args[0]
if len(password) < min_pass_length:
return "&cThe password has to be made up of at least %s characters!" % min_pass_length
create_pass(uuid, password)
return "&cPassword set. Use /login <password> upon join."
@simplecommand("rmpass",
description = "Removes your password if the password matches",
senderLimit = 0,
amax = 0,
helpNoargs = False)
def rmpass_command(sender, command, label, args):
if sender.getName() in logging_in:
return "&cYou are not logged in"
if not is_registered(uid(sender)):
return "&cYou are not registered!"
if not sender.getName() in logging_in:
delete_pass(uid(sender))
return "&aPassword removed successfully. You will not be prompted anymore."
return "&cFailed to remove password, please contact a staff member"
@simplecommand("rmotherpass",
aliases = ["lacrmpass"],
usage = "<user>",
description = "Removes password of <user> and sends them a notification",
helpNoargs = True)
def rmotherpass_command(sender, command, label, args):
if sender.getName() in logging_in:
return "&cYou are not logged in"
if not sender.hasPermission(admin_perm):
noperm(sender)
return
user = server.getOfflinePlayer(args[0])
if is_registered(uid(user)):
delete_pass(uid(user))
runas(server.getConsoleSender(), colorify("mail send %s &cYour password was reset by a staff member. Use &6/register&c to set a new one." % user.getName()))
return "&aPassword of %s reset successfully" % user.getName()
return "&cThat player could not be found (or is not registered)"
def change_pass(uuid, pw):
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.cursor()
curs.execute("UPDATE secret SET pass = ? WHERE uuid = ?", (pw,uuid,))
conn.commit()
curs.close()
conn.close()
def get_pass(uuid):
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.cursor()
curs.execute("SELECT pass FROM secret WHERE uuid = ?", (uuid,))
results = curs.fetchall()
curs.close()
conn.close()
return results[0][0]
def create_pass(uuid,pw):
thread = threading.Thread(target=create_pass_thread, args=(uuid,pw))
thread.start()
def create_pass_thread(uuid, pw):
pw = crypt.encrypt(pw, rounds=200000, salt_size=16)
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.cursor()
curs.execute("INSERT INTO secret VALUES (?,?)", (uuid,pw,))
conn.commit()
curs.close()
conn.close()
def is_registered(uuid):
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.cursor()
curs.execute("SELECT EXISTS(SELECT * FROM secret WHERE uuid = ?)", (uuid,))
results = curs.fetchall()
curs.close()
conn.close()
if results[0][0] == 1:
return True
return False
def delete_pass(uuid):
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.cursor()
curs.execute("DELETE FROM secret WHERE uuid = ?", (uuid,))
conn.commit()
curs.close()
conn.close()
@hook.event("player.PlayerJoinEvent", "high")
def on_join(event):
user = event.getPlayer()
if is_registered(uid(user)):
msg(event.getPlayer(), "&6You will be disconnected after 60 seconds if you don't &alogin")
msg(user, "&cUse /login <password>")
logging_in[user.getName()] = time.time()
@hook.event("player.PlayerQuitEvent", "high")
def on_quit(event):
if event.getPlayer().getName() in logging_in:
del logging_in[event.getPlayer().getName()]
##Threading start
class kick_class(Runnable):
def __init__(self, player):
self.player = player
def run(self):
if self.player.isOnline():
self.player.kickPlayer(colorify("&aLogin timed out"))
def kick_thread():
while True:
time.sleep(1)
now = time.time()
for name, jointime in logging_in.iteritems():
if now - jointime > wait_time:
player = server.getPlayer(name)
kick = kick_class(player)
server.getScheduler().runTask(server.getPluginManager().getPlugin("RedstonerUtils"), kick)
if name in logging_in:
del logging_in[name]
break
thread = threading.Thread(target = kick_thread)
thread.daemon = True
thread.start()
##Threading end
for blocked_event in blocked_events:
@hook.event(blocked_event, "high")
def on_blocked_event(event):
user = event.getPlayer()
if user.getName() in logging_in:
event.setCancelled(True)

62
main.py
View File

@@ -11,10 +11,11 @@ sys.path += ['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/l
try:
# Library that adds a bunch of re-usable methods which are used in nearly all other modules
from helpers import *
#from wrapper import *
except:
error("[RedstonerUtils] ERROR: Failed to import Wrapper:")
error(print_traceback())
print("[RedstonerUtils] ERROR: Failed to import helpers:")
print(print_traceback())
@hook.enable
def on_enable():
@@ -23,20 +24,63 @@ def on_enable():
@hook.disable
def on_disable():
#shared["modules"]["reports"].stop_reporting()
shared["modules"]["reports"].stop_reporting()
info("RedstonerUtils disabled!")
info("Loading RedstonerUtils...")
# Import all modules, in this order
shared["load_modules"] = [
"test",
# "login",
# Collection of tiny utilities
"misc",
# Adds chat for staff using /ac <text or ,<text>
"adminchat",
# Adds /badge, allows to give players achievements
"badges",
# Adds a few block placement corrections/mods
"blockplacemods",
# Adds /calc, toggles automatic solving of Math expressions in chat
"calc",
# Plugin to locate laggy chunks. /lc <n> lists chunks with more than n entities
"lagchunks",
# Adds /report and /rp, Stores reports with time and location
"reports",
# Adds group-chat with /chatgroup and /cgt to toggle normal chat into group mode
"chatgroups",
# Adds /token, reads and writes from the database to generate pronouncable (and thus memorable) registration-tokens for the website
"webtoken",
# Adds /lol, broadcasts random funyy messages. A bit like the splash text in the menu
"saylol",
# Shows the owner of a skull when right-clicked
"skullclick",
# Adds /listen, highlights chat and plays a sound when your name was mentioned
"mentio",
# Adds /cycler, swaps the hotbar with inventory when player changes slot from right->left or left->right
"cycle",
# Adds /getmotd & /setmotd to update the motd on the fly (no reboot)
"motd",
# AnswerBot. Hides stupid questions from chat and tells the sender about /faq or the like
"abot",
# Adds '/forcefield', creates forcefield for players who want it.
"forcefield",
# Adds /damnspam, creates timeout for buttons/levers to mitigate button spam.
"damnspam",
# Adds /check, useful to lookup details about a player
"check",
# Adds /an, a command you can use to share thoughts/plans/news
"adminnotes",
# Adds /imout, displays fake leave/join messages
"imout",
#adds snowbrawl minigame
"snowbrawl",
# Adds /tm [player] for a messages to be sent to this player via /msg
"pmtoggle",
# Replacement for LoginSecurity
"loginsecurity",
# Centralized Player class
"playermanager"
]
shared["modules"] = {}
for module in shared["load_modules"]:
try:

View File

@@ -4,7 +4,7 @@ from traceback import format_exc as print_traceback
mentions = open_json_file("mentio", {}) # contains a list of keywords for each player (uuid)
max_amount = 1000
max_amount = 3
arrow = colorify(u"&r&7\u2192&r")
colors_reg = reg_compile(u"\u00A7[\\da-fk-or]") # finds color codes
@@ -13,7 +13,7 @@ def saveMentions():
save_json_file("mentio", mentions)
@hook.event("player.AsyncPlayerChatEvent", "monitor")
@hook.event("player.AsyncPlayerChatEvent", "high")
def onChat(event):
if not event.isCancelled():
sender = event.getPlayer()
@@ -70,7 +70,7 @@ def add_keyword(sender, args):
keywords = get_keywords(sender)
new_word = stripcolors(args[1].lower())
if (len(keywords) >= max_amount) and (max_amount >= 0):
if len(keywords) >= max_amount:
msg(sender, "&cYou are already listening for %s words! Try &6/mentio del <word>" % max_amount)
return True
@@ -146,4 +146,4 @@ def onListenCommand(sender, command, label, args):
show_help(sender)
else:
show_help(sender)
return True
return True

44
misc.py
View File

@@ -6,8 +6,7 @@ from sys import exc_info
import thread
import org.bukkit.inventory.ItemStack as ItemStack
import org.bukkit.Bukkit as Bukkit
from basecommands import simplecommand, Validate
import java.util.Arrays as Arrays
from basecommands import simplecommand
@@ -71,6 +70,7 @@ def cmd_event2(event):
""" Disabled while builder can't access Trusted
@hook.event("player.PlayerGameModeChangeEvent", "low")
def on_gamemode(event):
@@ -114,9 +114,7 @@ def rs_material_broken_by_flow(material):
length = len(parts)
return length > 1 and (parts[0] == "DIODE" or parts[1] in ("TORCH", "WIRE", "BUTTON", "HOOK") or (length == 3 and parts[1] == "COMPARATOR"))
sudo_blacklist = ["pyeval", "script_backup_begin", "script_backup_end", "script_backup_error", "script_backup_database_begin", "script_backup_database_dumps", "script_backup_database_end",
"script_backup_database_error", "script_backup_database_abort", "script_trim", "script_trim_result", "script_spigot_update", "script_disk_filled", "script_restart", "script_restart_abort",
"script_stop", "script_stop_abort", "script_shutdown", "stop", "esudo", "essentials:sudo"]
@simplecommand("sudo",
usage = "<player> [cmd..]",
@@ -129,14 +127,11 @@ def on_sudo_command(sender, command, label, args):
msg(sender, "&2[SUDO] &rRunning '&e%s&r' as &3%s" % (cmd, target))
is_cmd = cmd[0] == "/"
is_console = target.lower() in ["server", "console"]
first_cmd = (args[1])[1:] if is_cmd else None
if first_cmd in sudo_blacklist and (is_player(sender) and uid(sender) not in pythoners):
return "&cYou can't sudo this command"
if is_console:
server.dispatchCommand(server.getConsoleSender(), cmd[1:] if is_cmd else cmd)
return None
target_player = server.getPlayer(target)
if target_player:
if target_player and uid(target_player) not in pythoners:
target_player.chat(cmd)
return None
return "&cPlayer %s not found!" % target
@@ -162,8 +157,7 @@ def on_pluginversions_command(sender, command, label, args):
"""
try:
plugin_header(sender, "Plugin versions")
raw_plugins = server.getPluginManager().getPlugins() # Plugin[]
plugins = [raw_plugins[i].getDescription() for i in range(len(raw_plugins))]
plugins = [pl.getDescription() for pl in list(ArrayList(java_array_to_list(server.getPluginManager().getPlugins())))]
info(type(plugins[0]).__name__)
plugins.sort(key = lambda pl: pl.getDescription().getName())
msg(sender, "&3Listing all " + str(len(plugins)) + " plugins and their version:")
@@ -204,8 +198,7 @@ def eval_thread(sender, code):
pythoners = [
"e452e012-2c82-456d-853b-3ac8e6b581f5", # Nemes
"ae795aa8-6327-408e-92ab-25c8a59f3ba1", # jomo
"305ccbd7-0589-403e-a45b-d791dcfdee7d", # PanFritz
"51f2ad3c-6cc8-40ea-aa2b-f25970316921" # Dico
"305ccbd7-0589-403e-a45b-d791dcfdee7d" # PanFritz
]
@simplecommand("pyeval",
@@ -259,31 +252,6 @@ def on_modules_command(sender, command, label, args):
msg(sender, ", ".join([(("&a" if mod in shared["modules"] else "&c") + mod) for mod in shared["load_modules"]]))
@simplecommand("warn",
usage = "",
description = "Warns everybody on the server that you will cause lag shortly",
amax = 0,
helpSubcmd = True)
def warn_command(sender, command, label, args):
if sender.hasPermission("utils.warn"):
broadcast(None, " &b= &2&lLag incoming! &r-%s" % sender.getDisplayName())
else:
noperm(sender)
@simplecommand("warnp",
usage = "",
description = "Warns everybody on the server that you might cause lag shortly",
amax = 0,
helpSubcmd = True)
def warnp_command(sender, command, label, args):
if sender.hasPermission("utils.warnp"):
broadcast(None, " &b= &2&lPossible lag incoming! &r-%s" % sender.getDisplayName())
else:
noperm(sender)
""" Something I'm planning for schematics
@hook.event("player.PlayerCommandPreprocessEvent", "low")
def on_command(event):

View File

@@ -1,45 +0,0 @@
import mysqlhack
from secrets import *
from thread_utils import *
from com.ziclix.python.sql import zxJDBC
from traceback import format_exc as trace
class mysql_connect:
def __init__(self):
self.conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
self.curs = self.conn.cursor()
def execute(self, query, args=None):
if args is None:
return self.curs.execute(query)
else:
print query
print args
return self.curs.execute(query, args)
def fetchall(self):
return self.curs.fetchall()
@property
def columns(self):
self.execute("SHOW COLUMNS FROM utils_players")
fetched = self.fetchall()
columns = []
for row in fetched:
columns.append(row[0])
return columns
def __enter__(self):
return self
def __exit__(self, exc_type, exc_inst, exc_tb):
if exc_type is None:
try:
self.conn.commit()
self.curs.close()
self.conn.close()
except:
print(trace())
else:
print(exc_tb)

View File

@@ -4,12 +4,12 @@ A library that makes use of the so called ClassPathHack for jython
to allow proper loading of mysql-connector.jar at runtime.
Import only, no methods.
"""
import jarray
import java.net.URL
import java.io.File
from java.lang import Class
import java.net.URLClassLoader
import java.lang.reflect.Method
import java.io.File
import java.net.URL
import java.net.URLClassLoader
import jarray
from java.lang import Class
# hacky code to add mysql-connector to java's classpath ('classPathHack')

View File

@@ -1,29 +1,27 @@
from helpers import *
py_players = []
players = []
class py_player:
def __init__(self,player):
def __init__(player):
self.player = player
self.logging_in = False
self.login_time = 0
#Properties TODO
#Example:
self.logging_in = False
def get_py_player(player):
#py_player = py_players[py_players.index(player)]
for py_player in py_players:
if py_player.player.getName() == player.getName():
return py_player
py_player = players[players.index(player)]
return py_player
@hook.event("player.PlayerJoinEvent","lowest")
@hook.event("player.PlayerJoinEvent","highest")
def on_join(event):
player = py_player(event.getPlayer())
py_players.append(player)
print str(len(py_players))+event.getPlayer().getName()
players.append(player)
@hook.event("player.PlayerQuitEvent","highest")
def on_leave(event):
py_players.remove(get_py_player(event.getPlayer()))
players.remove(get_py_player(event.getPlayer()))

View File

@@ -1,129 +0,0 @@
from helpers import *
from java.util.UUID import fromString as juuid
import org.bukkit.Material as Material
spawn_world = "Spawn"
punish_world = "Punishments"
slave_perm = "utils.minerslaves"
slaves = []
def save_slaves():
buf = []
for slave in slaves:
buf.append(slave.get_data())
save_json_file("miner_slaves", buf)
def load_slaves():
buf = open_json_file("miner_slaves", [])
for data in buf:
slave = Slave(True, None, None)
slave.load_data(data)
slaves.append(slave)
def get_slave(player):
for slave in slaves:
if slave.get_uuid() == player:
return slave
return None
class Slave(object):
def __init__(self, from_file, player, amount):
if from_file:
self.players = None
self.blocks = None
return
slave = get_slave(uid(player))
if slave != None:
slave.set_blocks(slave.get_blocks() + amount)
else:
self.player = uid(player)
self.blocks = amount
slaves.append(self)
def get_uuid(self):
return self.player
def get_blocks(self):
return self.blocks
def set_blocks(self, amount):
self.blocks = amount
def update(self):
self.blocks -= 1
if self.blocks <= 0:
server.getPlayer(juuid(self.get_uuid())).teleport(server.getWorld(spawn_world).getSpawnLocation())
slaves.remove(self)
save_slaves()
def get_data(self):
return {
"player": self.player,
"amount": self.blocks
}
def load_data(self, data):
self.player = str(data["player"])
self.blocks = int(data["amount"])
load_slaves()
@hook.event("block.BlockBreakEvent", "low")
def event(event):
if event.getPlayer().getWorld().getName() != punish_world:
return
slave = get_slave(uid(event.getPlayer()))
if slave != None and event.getBlock().getType() == Material.OBSIDIAN:
slave.update()
@hook.command("miner")
def command(sender, cmd, label, args):
if not sender.hasPermission(slave_perm):
noperm(sender)
return True
if len(args) == 0 or (len(args) != 1 and args[0] == "list") or (len(args) != 2 and args[0] == "rem") or (len(args) != 3 and args[0] == "add"):
msg(sender, "&e-&a /miner add/rem/list <name> <amount>")
return True
if args[0] == "add":
try:
int(args[2])
except:
msg(sender, "&cArgument <amount> is not a number")
return True
if args[0] == "list":
if len(slaves) == 0:
msg(sender, "&e-&a There are no people mining obsidian")
return True
for slave in slaves:
msg(sender, "&e-&a %s: %s blocks" % (server.getOfflinePlayer(juuid(slave.get_uuid())).getName(), slave.get_blocks()))
return True
elif args[0] == "add":
player = server.getOfflinePlayer(str(args[1]))
if player.isOnline():
player.teleport(server.getWorld(punish_world).getSpawnLocation())
Slave(False, player, int(args[2]))
save_slaves()
msg(player, "&e-&a You have been punished, mine %s blocks of obsidian to get out!" % args[2])
msg(sender, "&e-&a Player %s has been added into punishments for %s blocks of obsidian" % (player.getName(), args[2]))
else:
msg(sender, "&cYou can only punish online players")
return True
elif args[0] == "rem":
player = server.getOfflinePlayer(str(args[1]))
if player.isOnline():
slave = get_slave(uid(player))
if slave != None:
server.getPlayer(juuid(slave.get_uuid())).teleport(server.getWorld(spawn_world).getSpawnLocation())
slaves.remove(slave)
save_slaves()
else:
msg(sender, "&e-&a Player not in punishments")
else:
msg(sender, "&cYou can only remove online players")
return True
else:
msg(sender, "&e-&a /miner add/rem/list <name> <amount>")
return True

View File

@@ -149,7 +149,7 @@ arg 0 size of backup
@hook.command("script_backup_database_end")
def print_backup_db_end(sender, command, label, args):
if not is_player(sender):
broadcast(None, "&6 =&2 Database backup completed.")
broadcast(None, "&6 =&2 Databse backup completed.")
server.dispatchCommand(server.getConsoleSender(), "ac &abackup size: &2%sMB&a." % args[0])
else:
noperm(sender)

View File

@@ -1,115 +0,0 @@
from helpers import *
import socket
import threading
import time
from java.lang import Runnable
from adminchat import adminchat
"""
Module to allow our servercontrol telnet server forward chat and speak in AC
"""
host = ""
port = 1122
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
try:
sock.bind((host,port))
sock.setblocking(True)
sock.listen(5)
except socket.error as e:
print(str(e))
def command_process(text):
text = list(text)
args = []
arg = ""
for char in text:
if char != " " and char != "\n" and char != "\r" and char != "\t":
arg += char
elif arg != "":
args.append(arg)
arg = ""
if arg != "":
args.append(arg)
return args
clients = []
clients_l = threading.Lock()
class client():
def __init__(self,conn,address,name):
self.conn = conn
self.address = address
self.name = name
with clients_l:
clients.append(self)
self.conn.setblocking(False)
self.client_thread = threading.Thread(target=self.client_t)
self.client_thread.daemon = True
self.client_thread.start()
def getName(self):
return self.name
def close_connection(self):
try:
self.conn.close()
with clients_l:
clients.remove(self)
except:
pass
def client_t(self):
while True:
time.sleep(0.1)
try:
data = self.conn.recv(1024)
except:
if self not in clients:
self.close_connection()
continue
if self not in clients: #If the connection was closed, kill the thread
break
adminchat(self,data)
def handle_conn():
while True:
try:
conn, address = sock.accept()
except:
time.sleep(0.1)
continue
#Send name
data = conn.recv(1024)
data = command_process(data)
print "servercontrol connected! %s " %data[0]
client_c = client(conn, address,data[0])
handle_conn_t = threading.Thread(target=handle_conn)
handle_conn_t.daemon = True
handle_conn_t.start()
@hook.event("player.AsyncPlayerChatEvent","low")
def on_chat(event):
sender = event.getPlayer().getName()
msg = event.getMessage()
for entry in clients:
entry.conn.sendall(sender + " " + msg)

View File

@@ -1,312 +0,0 @@
from helpers import *
from basecommands import simplecommand, Validate
import org.bukkit.Material as Material
import java.util.UUID as UUID
import org.bukkit.Material as Material
import org.bukkit.block.BlockFace as BlockFace
"""
# About permissions:
# To use the command, the user needs to have utils.serversigns.
# To use ANY subcommand, the user needs to have utils.serversigns.<subcommand> IN ADDITION to the previously mentioned node.
# To be able to add commands as messages to a sign, a user will need the node utils.serversigns.command.
# To be able to claim a sign for another player or to edit signs that the user doesn't own, they will need utils.serversigns.admin.
"""
blocked_cmds = ("pex", "kick", "ban", "tempban", "pyeval", "sudo", "stop", "reload", "op", "deop", "whitelist")
def load_signs():
signs_obj = open_json_file("serversigns", [])
loaded = {}
for entry in signs_obj:
loaded[tuple(entry[:4])] = list(entry[4:])
return loaded
def save_signs():
signs_obj = []
for key, value in signs.iteritems():
signs_obj.append(key + tuple(value))
save_json_file("serversigns", signs_obj)
signs = load_signs() # {("world", x, y, z): ["owner_id", "msg1", "msg2"]}
lines = {} # Accumulated messages so players can have longer messages: {"Dico200": "Message...........", ""}
@hook.enable
def check_all_signs():
# Check if all saved signs actually represent a sign block. There are ways to break the signs without the plugin knowing.
for loc in dict(signs): # Can't change dict size during iteration, using a copy
world = server.getWorld(loc[0])
if world and world.getBlockAt(loc[1], loc[2], loc[3]).getType() in (Material.SIGN_POST, Material.WALL_SIGN):
continue
del signs[loc]
info("[Server Signs] Couldn't find a %s, removed the data for the sign that was once there." % identifySign(loc))
save_signs()
def fromLoc(bLoc):
"""
# Returns a tuple containing the (bukkit)location's world's name and its x, y and z coordinates
# The format for the tuple is ("world_name", x, y, z)
"""
return (bLoc.getWorld().getName(), bLoc.getBlockX(), bLoc.getBlockY(), bLoc.getBlockZ())
def equals(loc1, loc2):
"""
# Returns whether loc1 and loc2 represent the same block
"""
for i in range(4):
if loc1[i] != loc2[i]:
return False
return True
def getOwner(sign):
"""
# Returns the name of the sign its owner
"""
return retrieve_player(sign[0]).getName()
def isOwner(sign, player):
"""
# Returns whether the given player owns the sign
"""
return sign and sign[0] == uid(player)
def canEdit(sign, player):
"""
# Returns whether the given player can edit the sign.
# Returns False if the sign wasn't claimed.
"""
return (sign and player.hasPermission("utils.serversigns.admin")) or isOwner(sign, player)
def getSign(locAt):
"""
# If data was found for a sign at the given location, returns the data.
# This data follows the format of ["owner_id", "msg1", "msg2"...].
"""
for loc, sign in signs.iteritems():
if equals(locAt, loc):
return sign
return None
def identifySign(loc):
"""
# Returns a string from which the user can tell what sign you're talking about.
# The string follows the format of "sign at (x,y,z) in world_name".
"""
return "sign at (%s) in %s" % (",".join((str(i) for i in loc[1:])), loc[0])
def signsMsg(msg, colour = '4'):
"""
# Returns the given msg, prefixed with '[Signs] '.
# The given colour is after applied to the msg.
# The colour defaults to 4 (dark red).
"""
return "&c[Signs] &" + colour + msg
@simplecommand(cmd = "serversigns", aliases = ["svs", "signmsg"],
description = "Makes something happen when you right click signs. \nUse /svs help for more details.",
usage = "<claim|reset|add <msg>[++]|remove <ID>|clear|info|help>",
helpNoargs = True,
senderLimit = 0)
def svs_command(sender, command, label, args):
arg1 = args[0].lower()
Validate.isTrue(arg1 in ("claim", "reset", "add", "remove", "info", "clear", "help", "switch", "reverse", "unclaim"),
signsMsg("That argument could not be recognized, use &o/svs help &4for expected arguments"))
Validate.isAuthorized(sender, "utils.serversigns." + arg1)
#-------------------- Sub commands that don't require any conditions -----------------------
if arg1 == "help":
admin = sender.hasPermission("utils.serversigns.admin")
msg = signsMsg("Server signs lets you add messages to a sign.", 'a')
msg += "\nRight clicking the sign will display all the messages. Commands"
msg += "\ncan also be added, by prefixing the message with a '/'."
msg += "\nHow to use &b/serversigns&a:"
msg += "\n&b/svs claim" + ("" if not sender.hasPermission("utils.serversigns.admin") else " [owner]")
msg += "\n&a- Claims the sign so that you can add messages to it"
msg += "\n&b/svs info"
msg += "\n&a- Displays information about the (claimed) sign"
msg += "\n&b/svs add <message>[++]"
msg += "\n&a- Adds the message to the sign. Use ++ at the end"
msg += "\n&a- to add the message to your buffer. You can then use"
msg += "\n&a- the same command again to create a longer message."
msg += "\n&b/svs remove <message ID>"
msg += "\n&a- Removes the message with the given ID from the sign."
msg += "\n&a- The ID is given before each message by &b/svs info&a."
msg += "\n&b/svs switch|reverse <message ID 1> <message ID 2>"
msg += "\n&a- Reverses the order in which the given messages are shown."
msg += "\n&b/svs clear"
msg += "\n&a- Removes all messages from the sign."
msg += "\n&b/svs reset|unclaim"
msg += "\n&a- Resets the sign, removing all messages and its owner."
return msg
#-------------------------------------------------------------------------------------------
block = sender.getTargetBlock(None, 5)
Validate.isTrue(block.getType() in (Material.SIGN_POST, Material.WALL_SIGN), signsMsg("You have to be looking at a sign to use that!"))
loc = fromLoc(block.getLocation())
sign = getSign(loc)
signName = identifySign(loc)
arg2 = args[1].lower() if len(args) > 1 else None
#------------------------ Sub commands that require the block to be a sign -------------------------------
if arg1 == "claim":
Validate.isTrue(not sign, signsMsg("The %s was already claimed" % signName))
Validate.isTrue(can_build2(sender, block), signsMsg("You are not permitted to claim signs here"))
target = sender
if arg2:
Validate.isTrue(player.hasPermission("utils.serversigns.admin"), signsMsg("You are not authorized to claim signs for other players"))
target = server.getOfflinePlayer(arg2)
Validate.notNone(target, signsMsg("That player could not be found"))
Validate.isTrue(target.isOnline(), signsMsg("The target has to be online"))
uuid = uid(target)
if sign != None:
if sign[0] == uuid:
return signsMsg("The" + signName + " was already owned by that player")
else:
sign[0] = uuid
else:
signs[loc] = [uuid]
save_signs()
return signsMsg("Claimed the " + signName + ((" for %s" % target.getName()) if (target != sender) else ""), 'a')
#----------------------------------------------------------------------------------------------------------
Validate.notNone(sign, signsMsg("The %s has not been claimed" % signName))
#----------------------Sub commands that require the sign to be claimed as well------------------------------------
if arg1 == "info":
sign_lines = ""
for id, line in enumerate(sign[1:]):
sign_lines += ("\n &a%s: \"&f%s&a\"" % (id + 1, line))
return signsMsg("Properties of the %s:\n Owner: %s\n Lines: %s" % (signName, getOwner(sign), sign_lines), 'a')
#---------------------------------------------------------------------------------------------------------------
Validate.isTrue(canEdit(sign, sender), signsMsg("You do not own the %s!" % signName))
#---------------------- Sub commands that require you to own targeted sign as well -------------------------
if arg1 == "add":
line = " ".join(args[1:])
Validate.isTrue(line != "" and line != None, signsMsg("You have to enter a message to add or accumulate"))
key = sender.getName()
global lines
Validate.isTrue(key in lines or line[:1] != "/" or sender.hasPermission("utils.serversigns.command"), signsMsg("You cannot add commands to a sign!"))
if line[-2:] == "++":
if key not in lines:
lines[key] = ""
lines[key] += " " + line[:-2]
return signsMsg("Added given message to the message you're accumulating. \nYour accumulated message is now as follows: \n&f%s" % lines[key], 'a')
if key in lines:
line = (lines[key] + " " + line)[1:]
Validate.isTrue(line[0] != "/" or line.split(" ")[0][1:] not in blocked_cmds, signsMsg("Usage of that command with server signs is prohibited"))
sign.append(colorify(line) if line[0] != "/" else line)
save_signs()
return signsMsg("Added line \"&f%s&a\" to the %s" % (line, signName), 'a')
if arg1 == "remove":
Validate.notNone(arg2, signsMsg("You have to enter the ID of the message to remove!"))
try:
id = int(arg2)
except:
return signsMsg("The ID of the message has to be a number and can be found by using &o/svs info")
Validate.isTrue(id != 0 and id < len(sign), signsMsg("The %s has no message with an ID of %s, use &o/svs info &4for all messages." % (signName, id)))
del sign[id]
return signsMsg("Removed message with id %s from the %s" % (id, signName), 'a')
if arg1 in ("switch", "reverse"):
Validate.isTrue(len(args) == 3, signsMsg("You have to enter the 2 IDs of the messages to reverse"))
try:
id1 = int(args[1])
id2 = int(args[2])
except:
return signsMsg("The ID of the message has to be a number and can be found by using &o/svs info")
for id in (id1, id2):
Validate.isTrue(id != 0 and id < len(sign), signsMsg("The %s has no message with an ID of %s, use &o/svs info &4for all messages." % (signName, id)))
sign[id1], sign[id2] = sign[id2], sign[id1]
save_signs()
return signsMsg("Reversed the messages with IDs %s and %s of the %s" % (id1, id2, signName), 'a')
if arg1 == "clear":
signs[loc] = [sign[0]]
save_signs()
return signsMsg("Removed all messages from the %s" % signName, 'a')
if arg1 in ("reset", "unclaim"):
del signs[loc]
save_signs()
return signsMsg("Removed all messages and the owner from the %s, it can now be claimed" % signName, 'a')
#-------------------------------------------------------------------------------------------------------
@hook.event("player.PlayerInteractEvent")
def on_click(event):
if str(event.getAction()) != "RIGHT_CLICK_BLOCK":
return
block = event.getClickedBlock()
if block.getType() not in (Material.WALL_SIGN, Material.SIGN_POST):
return
sign = getSign(fromLoc(block.getLocation()))
if sign != None:
player = event.getPlayer()
for message in sign[1:]:
if message[:1] == "/":
server.dispatchCommand(player, message[1:])
else:
msg(player, message, usecolor = False)
# ---------------------------Sign breaking--------------------------------
checking_block = False
faces = {
BlockFace.NORTH : (0,1,2,),
BlockFace.SOUTH : (3,),
BlockFace.WEST : (4,),
BlockFace.EAST : (5,),
}
@hook.event("block.BlockBreakEvent", "monitor")
def on_break(event):
global checking_block
if checking_block or event.isCancelled():
return
block = event.getBlock()
if block.getType() in (Material.SIGN_POST, Material.WALL_SIGN):
check_sign(event, block, attached = False)
for block_face, data_values in faces.iteritems():
block2 = block.getRelative(block_face)
if block2.getType() == Material.WALL_SIGN and block2.getData() in data_values:
check_sign(event, block2)
block3 = block.getRelative(BlockFace.UP)
if block3.getType() == Material.SIGN_POST:
check_sign(event, block3)
def check_sign(event, block, attached = True):
player = event.getPlayer()
sign = getSign(fromLoc(block.getLocation()))
if not can_build2(player, block):
event.setCancelled(True)
msg(event.getPlayer(), signsMsg("You cannot break %s" % ("the sign attached to that block" if attached else "that sign")))
else:
loc = fromLoc(block.getLocation())
del signs[loc]
save_signs()
msg(player, signsMsg("Reset the %s which you just broke" % identifySign(loc)))
def can_build2(player, block):
global checking_block
event = BlockBreakEvent(block, player)
checking_block = True
server.getPluginManager().callEvent(event)
checking_block = False
return not event.isCancelled()

View File

@@ -4,7 +4,7 @@
set -e
for cmd in curl java unzip git pip; do
if ! which "$cmd" >/dev/null; then
if ! which -s "$cmd"; then
tput setf 4 >&2
echo "Error: please install '$cmd' to proceed" >&2
tput sgr0 >&2
@@ -91,7 +91,7 @@ echo -e "\n> All plugins downloaded"
cd "redstoner-utils.py.dir"
echo -e "\n> Duplicating sample files"
for file in ./*.example; do
for file in ls ./*.example; do
cp -v "$file" "$(echo "$file" | rev | cut -d "." -f 2- | rev)"
done
@@ -172,4 +172,4 @@ echo "eula=true" > eula.txt
echo -e "\n> $(tput setf 2)All Done! $(tput sgr0)Don't forget to configure plugins for your needs."
echo "> Run redstoner/server/start.sh to start the server"
echo "> Our plugins are in redstoner/server/plugins/redstoner-utils.py.dir"
echo "> Our plugins are in redstoner/server/plugins/redstoner-utils.py.dir"

View File

@@ -1,159 +0,0 @@
from helpers import *
import org.bukkit.inventory.ItemStack as ItemStack
import org.bukkit.Material as Material
from math import ceil
from basecommands import simplecommand, Validate, CommandException
""" Suggestion by Armadillo28, see thread: http://redstoner.com/forums/threads/2213?page=1#reply-14507 """
disallowed_item_types = (
Material.getMaterial(0),
Material.getMaterial(175),
Material.getMaterial(383),
)
default_args = open_json_file("signalstrengthdefaults", {})
def save_defaults():
save_json_file("signalstrengthdefaults", default_args)
def item_name(item_type, remove_underscores = True):
typ = str(item_type).lower()
return typ.replace("_", "") if remove_underscores else typ
def item_type_allowed(item_type):
return not item_type in disallowed_item_types
def required_item_count(strength, stack_size, slot_count):
if strength == 0:
item_count = 0
elif strength == 1:
item_count = 1
else:
item_count = int(ceil(slot_count * stack_size / 14.0 * (strength - 1)))
resulting_strength = 0 if item_count == 0 else int(1 + 14.0 * item_count / stack_size / slot_count)
#Clarification on these formulas at http://minecraft.gamepedia.com/Redstone_Comparator#Containers
return item_count if resulting_strength == strength else None
def get_data(player, args):
uuid = uid(player)
if uuid in default_args:
strength, item_type, item_data = default_args[uuid]
item_type = Material.getMaterial(item_type)
else:
strength = 1
item_type = Material.REDSTONE
item_data = 0
if len(args) > 0:
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])
if len(args) > 1:
if args[1].isdigit():
item_type = Material.getMaterial(int(args[1]))
else:
item_type = Material.matchMaterial(args[1])
Validate.notNone(item_type, "&cThat item type could not be found")
Validate.isTrue(item_type not in disallowed_item_types, "&cThat item type may not be used")
if len(args) > 2:
Validate.isTrue(args[2].isdigit() and 0 <= int(args[2]) <= 15, "&cThe data has to be a value from 0 to 15")
item_data = int(args[2])
return (strength, item_type, item_data)
def get_inventory(block):
try:
return block.getState().getInventory()
except AttributeError:
return None
def get_entire_container(container):
container_blocks = [container]
container_type = container.getType()
if container_type in (Material.CHEST, Material.TRAPPED_CHEST):
loc = container.getLocation()
x = loc.getBlockX()
y = loc.getBlockY()
z = loc.getBlockZ()
world = loc.getWorld()
container_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() == container_type
]
return container_blocks
@simplecommand("signalstrength",
usage = "(default) [signalstrength] [item] [data]",
aliases = ["ss", "level"],
description = "Fills the targeted container with the correct amount of items to achieve the desired signal strength.",
amin = 0,
amax = 4,
helpSubcmd = True,
senderLimit = 0)
def on_signalstrength_command(sender, command, label, args):
if len(args) > 0 and args[0].lower() in ("default", "defaults", "setdefaults"):
strength, item_type, item_data = get_data(sender, args[1:])
uuid = uid(sender)
if strength == 1 and item_type == Material.REDSTONE and item_data == 0:
if uuid in default_args:
del default_args[uuid]
save_defaults()
else:
default_args[uuid] = (strength, str(item_type), item_data)
save_defaults()
return "&aSet your signal strength defaults to (%s, %s, %s)" % (strength, item_name(item_type, False), item_data)
Validate.isTrue(len(args) <= 3, "&cExpected at most 3 arguments")
target_block = sender.getTargetBlock(None, 5)
Validate.notNone(target_block, "&cThat command can only be used when a container is targeted")
inventory = get_inventory(target_block)
Validate.notNone(inventory, "&cThat command can only be used if a container is targeted")
strength, item_type, item_data = get_data(sender, args)
#--------Get the stack size and required amount of items to achieve the desired signal strength---------
stack_size = item_type.getMaxStackSize()
slot_count = inventory.getSize()
item_count = required_item_count(strength, stack_size, slot_count)
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 and check if player can build---------
container_blocks = get_entire_container(target_block)
for block in container_blocks:
Validate.isTrue(can_build(sender, block), "&cYou do not have permission to do that here")
#----------------Insert items-------------
full_stack_count, remaining = divmod(item_count, stack_size)
for block in container_blocks:
inv = block.getState().getInventory()
inv.clear()
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 "&aComparators attached to that %s will now put out a signal strength of %s" % (item_name(target_block.getType()), strength)

View File

@@ -3,14 +3,6 @@ from secrets import *
import mysqlhack
from com.ziclix.python.sql import zxJDBC
"""
WORK IN PROGRESS
"""
#-----------------------Config--------------------------
config_file = "website-roles"
ranks = {
"member" : 3,
"builder" : 7,
@@ -21,42 +13,33 @@ ranks = {
"admin" : 5
}
ranks = open_json_file(config_file, ranks)
def save_ranks():
save_json_file(config_file, ranks)
#-----------------------Event---------------------------
@hook.event("player.PlayerJoinEvent", "normal")
def on_player_join(event):
user = event.getPlayer()
uuid = uid(player).replace("-", "")
role = get_role(uuid)
if role in [1, 2, 6]: #Disabled/Banned/Superadmin
return
if role:
for rank in ranks:
if user.hasPermission("group." + rank):
if role != ranks[rank]:
set_role(uuid, ranks[rank])
return
if not user.hasPlayedBefore():
return
if role == None:
msg(user, "&cYou haven't registed yet! Make sure to do so on redstoner.com")
sql_instruction
def callback_thing(role, args):
if role in [1, 2, 6]: #Disabled/Banned/Superadmin
return
if role != None:
for rank in ranks:
if user.hasPermission("group." + rank):
if role != ranks[rank]:
set_role(uuid, ranks[rank])
elif user.hasPlayedBefore():
msg(user, "&cYou haven't registed yet! Make sure to do so on redstoner.com")
def get_role(uuid):
results = execute_query("SELECT `role_id` FROM users WHERE `uuid` = ? LIMIT 1;", uuid)
return results[0][0]
# Returns a table with 1 row (LIMIT 1) and 1 column (SELECT `role_id`), so we're looking for the first row of the first column.
return execute_query("SELECT `role_id` FROM users WHERE `uuid` = ? LIMIT 1", uuid)[0][17]
def set_role(uuid, role_id):
execute_update("UPDATE users SET `role_id` = ? WHERE `uuid` = ?;", (role_id, uuid,))
# %d is like %s for integers (unlogically, you'd expect something like %i), though %s also works here.
execute_update("UPDATE users SET `role_id` = %d WHERE `uuid` = ?" % role_id, uuid)
def execute_query(query, uuid):
@@ -73,40 +56,5 @@ def execute_update(update, uuid):
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.cursor()
curs.execute(update, (uuid,))
conn.commit()
curs.close()
conn.close()
def get_role(uuid):
sql_instruction()
#--------------------------------Queries / Updates----------------------------
def sql_instruction(instruction, args, fetch = True, callback_func = ignored_func, callback_args = tuple()):
thread = threading.Thread(target = curs_instruction, args = (instruction_executor, instruction, fetch, callback_func, callback_args))
thread.start()
def curs_instruction(func, instruction, fetch, callback_func, callback_args):
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.getCursor()
if fetch:
returned = func(curs, instruction, fetch)
curs.close()
conn.close()
callback_func(returned, callback_args)
else:
func(curs, instruction, fetch)
conn.commit()
curs.close()
conn.close()
def instruction_executor(curs, instruction, fetch):
curs.execute(instruction)
return curs.fetchall() if fetch else None
def ignored_func(*args):
pass
conn.close()

78
tag.py
View File

@@ -1,78 +0,0 @@
from helpers import *
add_perm = "utils.tag.add"
del_perm = "utils.tag.del"
check_perm = "utils.tag.check"
data = open_json_file("tag", {})
@hook.command("tag")
def command(sender, command, label, args):
if len(args) > 0:
if str(args[0]) == "add":
if sender.hasPermission(add_perm):
if len(args) > 2:
add(sender, args[1:])
else:
msg(sender, "&a-&c Usage: /tag add <name> <reason>")
else:
noperm(sender)
elif str(args[0]) == "check":
if sender.hasPermission(check_perm):
if len(args) == 2:
check(sender, args[1:])
else:
msg(sender, "&a-&c Usage: /tag check <name>")
else:
noperm(sender)
elif str(args[0]) == "del":
if sender.hasPermission(del_perm):
if len(args) == 3:
delete(sender, args[1:])
else:
msg(sender, "&a-&c Usage: /tag del <id>")
else:
msg(sender, "&a-&c Unknown subcommand! (add, check, del)")
else:
msg(sender, "&a&c Usage: /tag add/check/del")
return True
def delete(sender, args):
player = server.getOfflinePlayer(args[0])
uuid = uid(player)
try:
if data[uuid] == None:
pass
except:
msg(sender, "&a-&e There are no notes about this player")
return
if int(args[1]) - 1 >= len(data[uuid]):
msg(sender, "&a-&c Id of note is out of range")
return
del (data[uuid])[int(args[1]) - 1]
save_json_file("tag", data)
msg(sender, "&a-&e Deleted note at %s" % args[1])
def add(sender, args):
player = server.getOfflinePlayer(args[0])
uuid = uid(player)
try:
if data[uuid] == None:
pass
except:
data[uuid] = []
data[uuid].append(" ".join(args[1:]))
msg(sender, "&a-&e Note added")
save_json_file("tag", data)
def check(sender, args):
player = server.getOfflinePlayer(args[0])
uuid = uid(player)
try:
num = 0
for tag in data[uuid]:
num += 1
msg(sender, "&a-&e %s: %s" % (str(num), str(tag)))
except:
msg(sender, "&a-&e There are no notes about this player")

View File

@@ -1,24 +0,0 @@
import threading
"""
Quick implementation of a @synchronized and @asynchronized decorators
"""
#To be replaced by bukkit scheduler.
"""
def sync(lock=None):
def decorator(wrapped):
def wrapper(*args, **kwargs):
with lock:
return wrapped(*args, **kwargs)
return wrapper
return decorator
"""
def async(daemon = True):
def decorator(function):
def wrapper(*args,**kwargs):
thread = threading.Thread(target=function,args=args,kwargs=kwargs)
thread.daemon = daemon
thread.start()
return wrapper
return decorator

View File

@@ -1,80 +0,0 @@
from thread_utils import *
MONITOR_PRIORITY = "monitor"
HIGHEST_PRIORITY = "highest"
HIGH_PRIORITY = "high"
NORMAL_PRIORITY = "normal"
LOW_PRIORITY = "low"
LOWEST_PRIORITY = "lowest"
priorities = ["lowest","low","normal","high","highest","monitor"]
events = []
class base_event():
def __init__(self,event_name):
self.name = event_name
self.cancelled = False
self._handlers = [ [],[],[],[],[],[] ]
self.cancelled_lock = threading.Lock()
def add_handler(self,function,priority):
for prior in priorities:
if prior == priority:
self._handlers[priorities.index(prior)].append(function)
def fire(self,*args):
for priority in self._handlers:
for handler in priority:
handler(self,*args)
def set_cancelled(self,state):
with self.cancelled_lock:
self.cancelled = state
class utils_events(base_event):
def __init__(self,event_name):
base_event.__init__(self,event_name)
def add_event(event_name, event_class = base_event):
"""
# Adds a new event type of the given class with the given name
"""
event = event_class(event_name)
events.append(event)
def fire_event(event_name,*args):
"""
# Calls the ehe event with the given arguments
"""
for event in events:
if event.name == event_name:
event.call(*args)
return event
def check_events(event_name):
"""
# Returns whether there is an event with the name event_name
"""
for event in events:
if event.name == event_name:
return True
return False
#Decorator
def utils_event(event_name, priority, create_event=base_event):
def event_decorator(function):
def wrapper(*args, **kwargs):
pass
if not check_events(event_name): #Check if the event exists, if not create it.
add_event(event_name,create_event)
for event in events: #Go through the list of events, find the one we need and call all of its handlers
if event.name == event_name:
event.add_handler(function,priority)
return wrapper
return event_decorator

116
vanish.py
View File

@@ -1,116 +0,0 @@
from helpers import *
from basecommands import simplecommand
from basecommands import Validate
vanished = []
def is_authorized(player):
return player.hasPermission("utils.vanish")
def is_vanished(player):
return uid(player) in vanished
#this can be used to silently set the vanished state of a player I guess.
def set_state(player, state):
if state == is_vanished(player):
return
if state:
enable_vanish(player)
else:
disable_vanish(player)
def enable_vanish(target):
vanished.append(uid(target))
for player in list(server.getOnlinePlayers()):
if not is_authorized(player):
player.hidePlayer(target)
def disable_vanish(target):
vanished.remove(uid(target))
for player in list(server.getOnlinePlayers()):
player.showPlayer(target)
def get_online_vanished_players():
return (player.getPlayer() for player in (retrieve_player(uuid) for uuid in vanished) if player.isOnline())
@simplecommand("vanish",
aliases = ["v"],
usage = "[on/off]",
description = "Toggles vanish mode, hiding you and your online status \nfrom other players.",
senderLimit = 0,
amin = 0,
amax = 1,
helpNoargs = False,
helpSubcmd = True
)
def vanish_command(sender, command, label, args):
current_state = is_vanished(sender)
new_state = not current_state
if len(args) == 1:
arg = args[0].lower()
if arg == "on":
new_state = True
elif arg == "off":
new_state = False
Validate.isTrue(current_state != new_state, "&cYou were %s vanished!" % ("already" if current_state else "not yet"))
set_state(sender, new_state)
return "&a%s vanish mode!" % ("Enabled" if new_state else "Disabled")
@hook.event("player.PlayerJoinEvent")
def on_player_join(event):
player = event.getPlayer()
if not is_authorized(player):
for vanished in get_online_vanished_players():
player.hidePlayer(vanished)
@hook.event("player.PlayerQuitEvent")
def on_player_quit(event):
player = event.getPlayer()
if not is_authorized(player):
for vanished in get_online_vanished_players():
player.showPlayer(vanished)
elif is_vanished(player):
disable_vanish(player)
@simplecommand("vanishother",
usage = "{player} [on/off]",
description = "Toggles vanish mode for someone, hiding them and their online status from other players.",
amin = 1,
amax = 2,
helpNoargs = True,
helpSubcmd = True)
def vanishother_command(sender, command, label, args):
target = server.getPlayer(args[0])
Validate.notNone(target, "&cThe specified player is not online")
current_state = is_vanished(target)
new_state = not current_state
if len(args) == 2:
arg = args[1].lower()
if arg == "on":
new_state = True
elif arg == "off":
new_state = False
Validate.isTrue(current_state != new_state, "&cThat player was %s vanished!" % ("already" if current_state else "not yet"))
set_state(target, new_state)
enabled_str = "enabled" if new_state else "disabled"
if target != sender:
msg(target, "&aVanish mode %s by %s" % (enabled_str, sender.getDisplayName() if is_player(sender) else "&9CONSOLE"))
return "&aVanish mode %s%s" % (enabled_str, " for " + target.getDisplayName() if target != sender else "")

View File

@@ -1,14 +0,0 @@
from helpers import *
from java.lang import Runnable
class run(Runnable):
def run(self):
players = server.getOnlinePlayers()
for player in players:
if player.hasPermission("essentials.vanish"):
player.performCommand("vanish")
player.performCommand("vanish")
def enabled():
server.getScheduler().runTaskTimer(server.getPluginManager().getPlugin("RedstonerUtils"), run(), 20, 1200)

View File

@@ -1,12 +0,0 @@
"""
Adapter classes for spigot api for more idiomatic python code.
Before you run away from this if the class you need to use isn't here, please create it.
"""
from helpers import *
from wrapper_event import *
from wrapper_player import *
from wrapper_command import *
from util_events import utils_event, fire_event, utils_events

View File

@@ -1,328 +0,0 @@
from wrapper_player import *
from helpers import *
class Command(object):
"""
# Documentation to come.s
"""
SENDER_ANY = 0
SENDER_PLAYER = 1
SENDER_CONSOLE = 2
ACTION_IGNORE = 3
ACTION_SYNTAXERROR = 4
ACTION_DISPLAYSYNTAX = 5
ACTION_DISPLAYHELP = 6
def __init__(self,
command,
parent = None,
aliases = tuple(),
permission = None,
description = "Description",
type = 0,
no_arg_action = 3,
help_request_action = 3,
arguments = tuple(),
):
self.command = command.lower()
self.aliases = tuple(alias.lower() for alias in aliases)
self.description = description
self.type = type
self.no_arg_action = no_arg_action
self.help_request_action = help_request_action
self.arguments = arguments
self.parent = parent
self.sub_commands = Command_dict()
# ---- Check if argument layout is valid ----
prev_arg = arguments[0] if len(arguments) > 0 else None
for arg_info in arguments[1:]:
if not prev_arg.required and arg_info.required:
raise Argument_exception("Command: %s; There may not be required arguments after non-required arguments" % command)
if prev_arg.type == Argument.MESSAGE:
raise Argument_exception("Command: %s; An argument of type MESSAGE may not be followed by other arguments" % command)
prev_arg = arg_info
# ---- Add self to parent sub_commands and set permission node ----
perm_builder = "utils"
if self.parent == None:
root_commands[self.command] = self
else:
try:
parent_route = self.parent.split(" ")
parent_sub_commands = root_commands
parent_obj = None
for cmd_name in parent_route:
parent_obj = parent_sub_commands[cmd_name]
parent_sub_commands = parent_obj.sub_commands
parent_obj.sub_commands[self.command] = self
except KeyError as e:
raise Argument_exception("Error occurred while setting up command hierarchy: " + e.message + "\n" + trace())
perm_builder += "." + (permission if permission else command).lower()
def __call__(self, handler):
"""
# To clarify: This function is called when you 'call' an instance of a class.
# This means, that Command() calls __init__() and Command()() calls __call__().
# This makes it possible to use class instances for decoration. The decorator is this function.
"""
self.handler = handler
if self.parent == None:
@hook.command(self.command, aliases = self.aliases)
def run(sender, command, label, args):
"""
# This function will take care of prefixing and colouring of messages in the future.
# So it's very much WIP.
"""
try:
message = self.execute(sender, command, label, args)
except Command_exception as e:
message = e.message
except Argument_exception as e:
message = e.message
except Exception:
error(trace())
return True
if message:
sender.sendMessage(message)
return True
return handler
def execute(self, sender, command, label, args):
try:
return self.sub_commands[args[0].lower()].execute(sender, command, label, args[1:])
except (KeyError, IndexError):
return self.execute_checks(sender, command, label, args)
def execute_checks(self, sender, command, label, args):
# ---- Check sender type ----
if is_player(sender):
Validate.is_true(self.type != Command.SENDER_CONSOLE, "That command can only be used by the console")
#sender = py_players.__getattr__(sender)
else:
Validate.is_true(self.type != Command.SENDER_PLAYER, "That command can only be used by players")
# ---- Check permission ----
Validate.is_authorized(sender, self.permission)
# ---- Check if a help message is expected ----
if len(args) == 0:
action = self.no_arg_action
elif args[0].lower() == "help":
action = self.help_request_action
else:
action = Command.ACTION_IGNORE
if action != Command.ACTION_IGNORE:
if action == Command.ACTION_SYNTAXERROR:
return "&cInvalid syntax, please try again."
if action == Command.ACTION_DISPLAYSYNTAX:
return self.syntax()
if action == Command.ACTION_DISPLAYHELP:
return self.help()
# ---- Set up passed arguments, prepare for handler call ----
scape = Command_scape(args, self.arguments, command, label)
if is_player(sender):
#sender = py_players[sender]
pass
return self.handler(sender, self, scape)
# @Command("hello") def on_hello_command(sender, command, scape/args)
def syntax(self):
return " ".join(tuple(arg_info.syntax() for arg_info in self.arguments))
def help(self):
syntax = self.syntax()
return syntax #WIP...
class Argument():
"""
# A more advanced implementation of amin and amax, though it doesn't do exactly the same.
# You can now pass a list of Argument objects which define what the argument represents.
# In the process of doing so, you can set an argument type, one of the ones mentioned below.
# For example, if Argument.PLAYER is given, the server will be searched for the given player, and
# they will be passed as the argument, instead of a string representing their name.
#
# Feel free to add your own argument types. If you want to make a change to the API to make it different,
# please don't do so on your own behalf.
"""
STRING = 0
INTEGER = 1
FLOAT = 2
PLAYER = 3
OFFLINE_PLAYER = 4
MESSAGE = 5
def __init__(self, name, type, definition, required = True):
self.name = name
self.type = type
self.definition = definition
self.required = required
def syntax(self):
syntax = self.name
if self.type == Argument.MESSAGE:
syntax += "..."
return (("<%s>" if self.required else "[%s]") % syntax)
class Validate():
"""
# Much like what you often see in Java.
# Instead of having to check if a condition is met, and if not,
# sending the player a message and returning true,
# You can use one of these methods to check the condition, and
# pass a message if it's not met.
#
# For example:
# > if not sender.hasPermission("utils.smth"):
# noperm(sender)
# return True
#
# Can be replaced with:
# > Validate.is_authorized(sender, "utils.smth")
#
"""
@staticmethod
def is_true(expression, fail_message):
if not expression:
raise Command_exception(fail_message)
@staticmethod
def not_none(obj, fail_message):
if obj == None:
raise Command_exception(fail_message)
@staticmethod
def is_authorized(player, permission, msg = "You do not have permission to use that command"):
if not player.hasPermission(permission):
raise Command_exception(msg)
@staticmethod
def is_player(sender):
if not is_player(sender):
raise Command_exception("That command can only be used by players")
@staticmethod
def is_console(sender):
if is_player(sender):
raise Command_exception("That command can only be used by the console")
"""
# ---------- API classes ----------
"""
class Command_dict(dict):
#{"cmd1" : cmd_object}
def __getattr__(self, alias):
for cmd_name, cmd_obj in self.iteritems():
if alias == cmd_name or alias in cmd_obj.aliases:
return cmd_obj
raise KeyError("Subcommand '%s' was not found" % alias)
root_commands = Command_dict() # {"command": command_object}
class Command_exception(Exception):
def __init__(self, message):
self.message = message
class Command_scape(list):
def __init__(self, args, arg_layout, command, label):
super(list, self).__init__()
self.raw = args
self.arg_layout = arg_layout
self.command = command
self.label = label
has_message = False
for i in range(len(arg_layout)):
arg_info = arg_layout[i]
given = (len(args) >= i + 1)
if arg_info.required and not given:
raise Argument_exception("You must specify the " + arg_info.name)
if not given:
self.append(None)
continue
given_arg = args[i]
arg_type = arg_info.type
if arg_type == Argument.STRING:
self.append(given_arg)
elif arg_type == Argument.INTEGER:
try:
value = int(given_arg)
except ValueError:
raise Argument_exception("The %s has to be a round number" % arg_info.name)
self.append(value)
elif arg_type == Argument.FLOAT:
try:
value = float(given_arg)
except ValueError:
raise Argument_exception("The %s has to be a number" % arg_info.name)
self.append(value)
elif arg_type == Argument.PLAYER:
target = server.getPlayer(given_arg)
if target == None:
raise Argument_exception("The %s has to be an online player" % arg_info.name)
self.append(target)
#self.append(py_players[target])
elif arg_type == Argument.OFFLINE_PLAYER:
try:
# Code to get the PY PLAYER by name. Possibly, uid(server.getOfflinePlayer(given_arg)) can be used?
pass
except KeyError:
raise Argument_exception("The %s has to be an existing player" % arg_info.name)
self.append(None)
elif arg_type == Argument.MESSAGE:
self.append(" ".join(args[i:]))
has_message = True
else:
error("Argument type not found: %d" % arg_type)
raise Argument_exception("A weird thing has happened, please contact an administrator")
if not has_message:
self.remainder = args[len(arg_layout):]
else:
self.remainder = None
def has_flag(self, flag, check_all = False):
return (("-" + flag) in self.raw) if check_all else (("-" + flag) in self.remainder)
def get_raw(self):
return self.raw
def get_arg_layout(self):
return self.arg_layout
class Argument_exception(Exception):
def __init__(self, message):
self.message = message

View File

@@ -1,56 +0,0 @@
from wrapper import *
from util_events import utils_event, utils_events
from wrapper_player import *
from traceback import format_exc as print_traceback
class py_event(object):
def __init__(self,event):
self.event = event
try:
self.player = py_players[event.getPlayer()]
except:
warn("Player doesn't exist")
@property
def cancelled(self):
return self.event.isCancelled()
@cancelled.setter
def cancelled(self, value):
self.event.setCancelled(value)
@property
def message(self):
try:
return self.event.getMessage()
except:
raise AttributeError
@message.setter
def message(self, msg):
try:
self.event.setMessage(msg)
except:
raise AttributeError
def event_handler(event_name = None, priority = "normal", utils = False):
if not utils:
def decorator(wrapped):
@hook.event(event_name, priority)
def wrapper(event):
try:
wrapped(py_event(event))
except:
print(print_traceback())
return decorator
elif utils:
def decorator(wrapped):
@utils_event(event_name, priority, create_event = utils_events)
def wrapper(*args):
try:
wrapped(*args)
except:
print(print_traceback())
return decorator

View File

@@ -1,186 +0,0 @@
import time
import mysqlhack
from mysql_utils import *
from util_events import fire_event
from thread_utils import *
#from players_secret import *
from datetime import datetime
from com.ziclix.python.sql import zxJDBC
from traceback import format_exc as print_traceback
class py_player(object):
def __init__(self,player):
self.player = player
self.logging_in = True
self.authenticated = False
self.login_time = time.time()
self.props = {
"uuid":self.uuid,
"name":self.name,
"nickname":self.name,
"registered":False,
"password":"None",
"banned":False,
"banned_reason":None,
"played_time":time.time() - self.login_time,
"last_login":datetime.now(),
"first_seen":datetime.now(),
}
def __setattr__(self, attribute, value):
if not attribute in dir(self):
if not 'props' in self.__dict__:
self.__dict__[attribute] = value
else:
self.props[attribute] = value
else:
object.__setattr__(self, attribute, value)
def __getattr__(self, attribute):
try:
return self.props[attribute]
except:
raise AttributeError("Attribute %s does not exist on this py_player" % attribute)
def save(self):
properties = []
keys = []
columns = []
with mysql_connect() as sql:
columns = sql.columns
for key, value in self.props.items():
if key not in columns:
with mysql_connect() as sql:
if isinstance(value, int):
sql.execute("ALTER TABLE utils_players ADD %s INT" % key)
elif isinstance(value, str):
sql.execute("ALTER TABLE utils_players ADD %s TEXT" % key)
elif isinstance(value, bool):
sql.execute("ALTER TABLE utils_players ADD %s TINYINT(1)" % key)
if key == "uuid":
continue
keys.append(key+"=?")
properties.append(value)
print value
properties.append(self.props["uuid"])
keys = str(tuple(keys)).replace("\'","").replace("(","").replace(")","")
with mysql_connect() as sql:
sql.execute("UPDATE utils_players set %s WHERE uuid = ?" % keys, properties)
def kick(self, kick_message = "You have been kicked from the server!"):
self.player.KickPlayer(kick_message)
def msg(self, message):
self.player.sendMessage(message)
@property
def name(self):
return self.player.getName()
@property
def uuid(self):
return str(self.player.getUniqueId())
class Py_players:
def __init__(self):
self.players = []
def __len__(self):
return len(self.players)
def __getitem__(self, player):
for py_player in self.players:
if py_player.name == player.getName():
return py_player
else:
return None
def remove(self, player):
self.players.remove(player)
def append(self, player):
self.players.append(player)
py_players = Py_players()
@async(daemon=True)
def fetch_player(player):
properties = []
keys = []
for key, value in player.props.iteritems():
keys.append(key)
properties.append(value)
with mysql_connect() as sql:
sql.execute("SELECT * FROM utils_players WHERE uuid = ?", (player.uuid,))
result = sql.fetchall()
if len(result) is 0:
with mysql_connect() as sql:
sql.execute("INSERT INTO utils_players %s \
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" % str(tuple(keys)).replace("\'","")
,args=tuple(properties))
elif len(result) is 1:
keys = []
props = result[0]
with mysql_connect() as sql:
sql.execute("SHOW COLUMNS FROM utils_players")
result = sql.fetchall()
for row in result:
keys.append(row[0])
for key in keys:
player.props[key] = props[keys.index(key)]
for prop in properties:
print str(prop)
else:
player.kick("Something went wrong while loading your player data, please contact an admin")
return
player.logging_in = False
player.msg("You have succesfully logged into redstoner!")
fire_event("player_login", player)
blocked_events = ["block.BlockBreakEvent", "block.BlockPlaceEvent", "player.PlayerMoveEvent",
"player.AsyncPlayerChatEvent","player.PlayerTeleportEvent",
"player.PlayerCommandPreprocessEvent", "player.PlayerInteractEvent"]
for event in blocked_events:
@hook.event(event,"highest")
def on_blocked_event(event):
"""player = py_players[event.getPlayer()]
if player.logging_in:
event.setCancelled(True)"""
pass
@hook.event("player.PlayerJoinEvent","lowest")
def on_join(event):
try:
player = py_player(event.getPlayer())
except:
error(print_traceback())
time.sleep(10)
py_players.append(player)
player.msg("Your input will be blocked for a short while")
#fetch_player(player)
@hook.event("player.PlayerQuitEvent","highest")
def on_leave(event):
py_players.remove(py_players[event.getPlayer()])