11 Commits

Author SHA1 Message Date
Dico200
4027cf7268 Fix most of wrapper_command 2015-11-26 17:41:47 +01:00
Dico200
c76f8373ef I didn't like the fire name but whatever 2015-11-26 15:14:42 +01:00
Dico200
a59f67785c Small changes really 2015-11-26 15:10:02 +01:00
PanFritz
f7626300ea merge conflicts 2015-11-25 18:26:50 +01:00
PanFritz
14b6c6905a Lots of fixes, added player loading/ unloading, login.py custom event system, mysql_utils.columns property 2015-11-25 18:22:08 +01:00
PanFritz
513996a351 Lots of fixes, added player loading/ unloading, login.py custom event system, mysql_utils.columns property 2015-11-25 18:20:29 +01:00
Dico200
3bc7963a7a wrapper_player progress 2015-11-25 18:03:36 +01:00
Dico200
37d425bb65 Remove get_py_player function I added 2015-11-25 15:56:35 +01:00
Dico200
b3b6d15a32 wrapper_command WIP... to wrapper branch now? 2015-11-25 15:55:25 +01:00
PanFritz
a85194d7be Added cancelled event property, added player loading 2015-11-24 00:33:56 +01:00
PanFritz
760dc48968 Added loading of properties 2015-11-24 00:02:45 +01:00
26 changed files with 1275 additions and 1279 deletions

View File

@@ -11,17 +11,6 @@ import org.bukkit.event.block.Action as Action
import org.bukkit.block.BlockFace as BlockFace import org.bukkit.block.BlockFace as BlockFace
import org.bukkit.scheduler.BukkitRunnable as Runnable import org.bukkit.scheduler.BukkitRunnable as Runnable
"""
# Permissions:
# - utils.toggle: for use of the command
# - utils.toggle.cauldron
# - utils.toggle.slab
# - utils.toggle.furnace
# - utils.toggle.piston
# - utils.toggle.dropper
# - utils.toggle.hopper
"""
settingInformation = dict( #[setting type, identifying description, detailed description, aliases, (optional) max slot id], setting types: 0 = toggle, default on. 1 = Set your setting to held itemstack, 2 = toggle, default off settingInformation = dict( #[setting type, identifying description, detailed description, aliases, (optional) max slot id], setting types: 0 = toggle, default on. 1 = Set your setting to held itemstack, 2 = toggle, default off
cauldron = [0, cauldron = [0,
"easy cauldron water level control", "easy cauldron water level control",
@@ -151,7 +140,6 @@ def toggle_command(sender, command, label, args):
if enabled: if enabled:
del values[uuid] del values[uuid]
return " &aDisabled " + details[1] return " &aDisabled " + details[1]
return " &cAlready disabled: " + details[1]
if arg2 == "details": if arg2 == "details":
return " &aSetting %s:\n &9%s \n&6Accepted arguments: [<slot>|clear|details]" % (setting, details[2]) return " &aSetting %s:\n &9%s \n&6Accepted arguments: [<slot>|clear|details]" % (setting, details[2])

View File

@@ -1,352 +1,138 @@
############################################ # Chat Aliasing plugin by Curs3d #
# Alias v2.0 by Pepich # ##################################
# Changes to previous version from curs3d: # # Allows users to alias words,
# Dynamic alias limit from permissions # # so that when they send a
# AC/CG/MSG support # # message in chat, it gets
# Color support # # replaced by their specified
# Bugfixes # # word. The JSON file for this
# # # plugin is generated if not
# TODO: # # present. Set values to -1
# Add command support... # # for "unlimited" setting.
############################################
import os
import mysqlhack
import org.bukkit as bukkit
from org.bukkit import *
from helpers import * from helpers import *
import re
from traceback import format_exc as trace from traceback import format_exc as trace
from secrets import *
# Version number and requirements data = None
alias_version = "2.0.0" max_entries = 10
helpers_versions = ["1.1.0", "2.0.0"] max_alias_length = 35
enabled = False # Minecraft message limit is 100 so I decided to give a little tolerance (and I added a bit more)
error = colorify("&cUnspecified error") max_overall_length = 100 + max_alias_length
commands_per_page = 5
global_aliases = {"./":"/"} 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 = {} data = {}
# DON'T SET THIS TO TRUE! MySQL requestst are NOT ASYNC yet! (And for some reason it doesn't want to store any data ._.) save_json_file("aliases", data)
use_mysql = False return data
# Permissions: def multiple_replace(aliases, text):
regex = re.compile("|".join(map(re.escape, aliases.keys())))
# Grants full access immediately return regex.sub(lambda mo: aliases[mo.group(0)], text)
permission_ALL = "utils.alias.*"
# Access to the command to display the help screen
permission_BASE = "utils.alias"
# Make replacements only when the user has this permission
permission_USE = "utils.alias.use"
# Modify aliases
permission_MODIFY = "utils.alias.modify"
permission_MODIFY_OTHERS = "utils.alias.modify.others"
# List aliases
permission_LIST = "utils.alias.list"
permission_LIST_OTHERS = "utils.alias.list.others"
# Set alias amounts/length limits, e.g. utils.alias.amount.420
permission_AMOUNT = "utils.alias.amount."
permission_LENGTH = "utils.alias.length."
# See when the plugin was disabled due to version errors
permission_INFO = "utils.alias.info"
permission_FINFO = "utils.alias.finfo"
########
# CODE #
########
# OnEnable
enabled = helpers_version in helpers_versions
if not enabled:
error = colorify("&6Incompatible versions detected (&chelpers.py&6)")
def safe_open_json(uuid):
if not os.path.exists("plugins/redstoner-utils.py.dir/files/aliases"):
os.makedirs("plugins/redstoner-utils.py.dir/files/aliases")
value = open_json_file("aliases/" + uuid)
if value is None:
value = global_aliases
save_json_file("aliases/" + uuid, value)
return value
@hook.command("alias", @hook.command("alias",
usage="/<command> <add, remove, list, help> [...]", usage="/<command> [to_alias] [alias...]",
desc="Allows aliasing of words") desc="Aliases words in chat")
def on_alias_command(sender, cmd, label, args): def on_alias_command(sender, cmd, label, args):
try:
args = array_to_list(args) if not is_player(sender):
if not enabled: msg(sender, "Sorry, non-players cannot alias words")
disabled_fallback(sender)
return True return True
if not hasPerm(sender, permission_BASE): if not sender.hasPermission(alias_perm):
plugin_header(recipient=sender, name="Alias") plugin_header(recipient=sender, name="Chat Alias")
noperm(sender) noperm(sender)
return True return True
return subcommands[args[0].lower()](sender, args[1:]) if len(args) == 0:
except: plugin_header(recipient=sender, name="Chat Alias")
return subcommands["help"](sender, "1") msg(sender, "&7This is a plugin that allows you to get words" +
"replaced by other ones automatically!")
msg(sender, "&7\nCommands:")
def help(sender, args): msg(sender, "&e/alias <word> &7removes <word> from your aliases. " +
commands = [colorify("&e/alias help [page]")] "Use &e/alias * &7to remove all aliases.")
if hasPerm(sender, permission_LIST): msg(sender, "&e/alias <word> <replacement> &7will change &e<word> " +
commands += [colorify("&e/alias list &7- Lists all your aliases")] "&7to &e<replacement> &7in chat")
if hasPerm(sender, permission_MODIFY): msg(sender, "&7\nYour Aliases:")
commands += [colorify("&e/alias add <word> <alias> &7- Add an alias")] data = safe_open_json()
commands += [colorify("&e/alias remove <word> &7- Remove an alias")] try:
if can_remote(sender): for alias, value in data[str(sender.getUniqueId())].items():
while len(commands) < commands_per_page: msg(sender, "&7%s &7==> %s" % (alias, value))
commands += [""] except KeyError:
commands += [colorify("&7Following commands will be executed on <player> yet all output will be redirected to you, except when you set silent to false, then <player> will see it too.")] pass
if hasPerm(sender, permission_LIST_OTHERS): return True
commands += [colorify("&e/alias player <name> list [silent]")] elif len(args) == 1:
if hasPerm(sender, permission_MODIFY_OTHERS): data = safe_open_json()
commands += [colorify("&e/alias player <name> add <word> <alias> [silent]")] if args[0] == "*":
commands += [colorify("&e/alias player <name> remove <word> [silent]")] try:
pages = (len(commands)-1)/commands_per_page + 1 del data[str(sender.getUniqueId())]
page = 1 except KeyError:
if len(args) != 0: plugin_header(recipient=sender, name="Chat Alias")
page = int(args[0]) msg(sender, "&7No alias data to remove!")
if (page > pages): return True
page = pages save_json_file("aliases", data)
if page < 1: plugin_header(recipient=sender, name="Chat Alias")
page = 1 msg(sender, "&cALL &7alias data successfuly removed!")
msg(sender, colorify("&e---- &6Help &e-- &6Page &c" + str(page) + "&6/&c" + str(pages) + " &e----")) return True
page -= 1 try:
to_display = commands[5*page:5*page+5] if data[str(sender.getUniqueId())].pop(args[0], None) is None:
for message in to_display: plugin_header(recipient=sender, name="Chat Alias")
msg(sender, message) msg(sender, "&7Could not remove: alias not present!")
if page+1 < pages: return True
msg(sender, colorify("&6To display the next page, type &c/alias help " + str(page+2))) 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 return True
@hook.event("player.PlayerJoinEvent", "high")
def on_join(event):
if enabled:
t = threading.Thread(target=load_data, args=(uid(event.getPlayer()), ))
t.daemon = True
t.start()
else: else:
if event.getPlayer().hasPermission(permission_FINFO): return False
disabled_fallback(event.getPlayer())
@hook.event("player.AsyncPlayerChatEvent", "high") @hook.event("player.AsyncPlayerChatEvent", "high")
def on_player_chat(event): def on_player_chat(event):
try: playerid = str(event.getPlayer().getUniqueId())
if enabled: data = safe_open_json()
if event.isCancelled(): if event.isCancelled():
return return
if not hasPerm(event.getPlayer(), permission_USE): if not playerid in data:
return return
for alias, value in data[str(uid(event.getPlayer()))].items():
if not event.getPlayer().hasPermission(permission_ALL) and len(event.getMessage()) > int(get_permission_content(event.getPlayer(), permission_LENGTH)):
event.setCanceled(True)
plugin_header(event.getPlayer, "Alias")
msg(event.getPlayer(), "The message you wanted to generate would exceed your limit. Please make it shorter!")
return
if event.getPlayer().hasPermission("essentials.chat.color"):
event.setMessage(event.getMessage().replace(colorify(alias), colorify(value)))
else:
event.setMessage(event.getMessage().replace(alias, value))
except:
print(trace())
event.setMessage(multiple_replace(data[playerid], event.getMessage()))
def hasPerm(player, permission): if (event.getPlayer().hasPermission("essentials.chat.color")):
return (player.hasPermission(permission)) or (player.hasPermission(permission_ALL)) 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)
def disabled_fallback(receiver): plugin_header(recipient=event.getPlayer(), name="Chat Alias")
if not hasPerm(receiver, permission_INFO): msg(event.getPlayer(), "&7The message generated was too long and was not sent. :/")
msg(receiver, colorify("&cUnknown command. Use &e/help&c, &e/plugins &cor ask a mod."))
else:
msg(receiver, colorify("&cPlugin alias v" + alias_version + " has experienced an &eEMERGENCY SHUTDOWN:"))
msg(receiver, error)
msg(receiver, colorify("&cPlease contact a dev/admin (especially pep :P) about this to take a look at it."))
def can_remote(player):
return hasPerm(player, permission_LIST_OTHERS) or hasPerm(player, permission_MODIFY_OTHERS)
def add(sender, args):
plugin_header(sender, "Alias")
if not sender.hasPermission(permission_ALL) and len(data[uid(sender)]) >= int(get_permission_content(sender, permission_AMOUNT)):
msg(sender, "&cCould not create alias: Max_limit reached!")
return True
args = [args[0]] + [" ".join(args[1:])]
if not add_alias_data(uid(sender), str(args[0]), args[1]):
msg(sender, colorify("&c") + "Could not add an alias for this sequence because a priorly added alias contains it")
return True
msg(sender, colorify("&7Alias: ") + args[0] + colorify("&7 -> " + args[1] + colorify("&7 was succesfully created!")), usecolor=sender.hasPermission("essentials.chat.color"))
return True
def radd(sender, args):
plugin_header(sender, "Alias")
args = args[0:2] + [" ".join(args[2:len(args)-1])] + [args[len(args)-1]]
if is_player(sender):
sender_name = colorify(sender.getDisplayName())
else:
sender_name = colorify("&6Console")
target = get_player(args[0])
if args[3].lower() == "false":
plugin_header(target, "Alias")
msg(target, "&cPlayer " + sender_name + " &cis creating an alias for you!")
if not sender.hasPermission(permission_ALL) and len(data[uid(sender)]) >= int(get_permission_content(target, permission_AMOUNT)):
msg(sender, "&cCould not create alias: Max_limit reached!")
if args[3].lower() == "false":
msg(target, "&cCould not create alias: Max_limit reached!")
return True
if len(args) == 3:
args += ["true"]
if not add_alias_data(uid(target), str(args[1]), str(args[2])):
message = colorify("&c") + "Could not add an alias for this sequence because a priorly added alias contains it"
msg(sender, message)
if args[3].lower() == "false":
msg(target, message)
return True
msg(sender, colorify("&7Alias: ") + args[1] + colorify("&7 -> " + args[2] + colorify("&7 was succesfully created!")), usecolor=target.hasPermission("essentials.chat.color"))
if args[3].lower() == "false":
msg(target, colorify("&7Alias: ") + args[1] + colorify("&7 -> " + args[2] + colorify("&7 was succesfully created!")), usecolor=target.hasPermission("essentials.chat.color"))
return True
def add_alias_data(puuid, aliased, new_alias):
prior = data[puuid]
if aliased not in prior:
for alias in prior.values():
if aliased in alias:
return False
prior[aliased] = new_alias
save_data(puuid)
return True
def remove(sender, args):
plugin_header(sender, "Alias")
try:
msg(sender, colorify("&7Successfully removed alias ") + args[0] + colorify(" &7-> ") + data[uid(sender)].pop(args[0]) + colorify("&7!"), usecolor=sender.hasPermission("essentials.chat.color"))
save_data(uid(sender))
except:
msg(sender, colorify("&cCould not remove alias ") + args[0] + colorify(", it does not exist."), usecolor=sender.hasPermission("essentials.chat.color"))
return True
def rremove(sender, args):
plugin_header(sender, "Alias")
target = get_player(args[0])
if is_player(sender):
sender_name = colorify(sender.getDisplayName())
else:
sender_name = colorify("&6Console")
if args[2].lower() == "false":
plugin_header(target, "Alias")
msg(target, "&cPlayer " + sender_name + " &cis removing an alias for you!")
try:
alias = data[uid(target)].pop(args[1])
msg(sender, colorify("&7Successfully removed alias ") + args[1] + colorify(" &7-> ") + alias + colorify("&7!"), usecolor=sender.hasPermission("essentials.chat.color"))
if args[2].lower() == "false":
msg(target, colorify("&7Successfully removed alias ") + args[1] + colorify(" &7-> ") + alias + colorify("&7!"), usecolor=sender.hasPermission("essentials.chat.color"))
save_data(uid(target))
except:
msg(sender, colorify("&cCould not remove alias ") + args[1] + colorify(", it does not exist."), usecolor=sender.hasPermission("essentials.chat.color"))
if args[2].lower() == "false":
msg(target, colorify("&cCould not remove alias ") + args[1] + colorify(", it does not exist."), usecolor=sender.hasPermission("essentials.chat.color"))
return True
def list_alias(sender, args):
plugin_header(sender, "Alias")
msg(sender, "&7You have a total of " + str(len(data[uid(sender)])) + " aliases:")
for word, alias in data[str(uid(sender))].items():
msg(sender, colorify("&7") + word + colorify("&7 -> ") + alias, usecolor=sender.hasPermission("essentials.chat.color"))
return True
def rlist_alias(sender, args):
plugin_header(sender, "Alias")
target = get_player(args[0])
if is_player(sender):
sender_name = colorify(sender.getDisplayName)
else:
sender_name = colorify("&6Console")
if len(args) == 1:
args += ["true"]
msg(sender, "Player " + args[0] + " has following aliases (" + str(len(data[uid(target)])) + " in total):")
if args[1].lower() == "false":
plugin_header(target, "Alias")
msg(target, "&cPlayer " + sender_name + " &cis listing your aliases (" + str(len(data[uid(target)])) + " in total):")
for word, alias in data[str(uid(target))].items():
msg(sender, colorify("&7") + word + colorify("&7 -> ") + alias, usecolor=target.hasPermission("essentials.chat.color"))
if args[1].lower() == "false":
msg(target, colorify("&7") + word + colorify("&7 -> ") + alias, usecolor=target.hasPermission("essentials.chat.color"))
return True
def remote(sender, args):
try:
return remotes[args[1].lower()](sender, [args[0]] + args[2:])
except:
return subcommands["help"](sender, ["2"])
def load_data(uuid):
try:
load_data_thread(uuid)
# t = threading.Thread(target=load_data_thread, args=(uuid))
# t.daemon = True
# t.start()
except:
print(trace())
def load_data_thread(uuid):
if use_mysql:
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.cursor()
curs.execute("SELECT alias FROM alias WHERE uuid = ?", (uuid, ))
results = curs.fetchall()
if len(results) == 0:
results = global_aliases
curs.execute("INSERT INTO alias VALUES (?,?)", (uuid, results, ))
data[uuid] = results
else:
data[uuid] = safe_open_json(uuid)
def save_data(uuid):
try:
save_data_thread(uuid)
# t = threading.Thread(target=save_data_thread, args=(uuid))
# t.daemon = True
# t.start()
except:
print(trace())
def save_data_thread(uuid):
if use_mysql:
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.cursor()
curs.execute("UPDATE alias SET alias = ? WHERE uuid = ?", (data[uuid], uuid, ))
else:
save_json_file("aliases/" + uuid, data[uuid])
# Subcommands:
subcommands = {
"help": help,
"add": add,
"remove": remove,
"player": remote,
"list": list_alias
}
remotes = {
"add": radd,
"remove": rremove,
"list": rlist_alias,
}

View File

@@ -21,8 +21,6 @@ def on_chatgroup_command(sender, command, label, args):
if len(args) == 1 and args[0] == "leave": if len(args) == 1 and args[0] == "leave":
if sender_id in groups.keys(): if sender_id in groups.keys():
groupchat(sender, "left the group", True) groupchat(sender, "left the group", True)
if sender in cg_toggle_list:
cg_toggle_list.remove(p)
group = groups[sender_id] group = groups[sender_id]
del(groups[sender_id]) del(groups[sender_id])
save_groups() save_groups()
@@ -89,7 +87,7 @@ def groupchat(sender, message, ann = False):
def do_for_chatgroup(group, func, *args, **kwargs): def do_for_chatgroup(group, func, *args, **kwargs):
for receiver in server.getOnlinePlayers(): for receiver in server.getOnlinePlayers():
if groups.get(uid(receiver)) == group: if groups.get(uid(receiver)) == group:
func(receiver, *args, **kwargs) func(receiver, args, kwargs)
def send_tpa_request(receiver, sender): def send_tpa_request(receiver, sender):
if not receiver == sender: if not receiver == sender:

View File

@@ -47,6 +47,8 @@ def on_dammnspam_command(sender, command, label, args):
timeout_on = round(float(timeout_on), 2) timeout_on = round(float(timeout_on), 2)
timeout_off = timeout_on timeout_off = timeout_on
if 60 >= timeout_on <= -2 or timeout_on == 0: if 60 >= timeout_on <= -2 or timeout_on == 0:
timeout_on = False
if timeout_on == False:
msg(sender, "&cThe timeout must be within 0-60 or -1.") msg(sender, "&cThe timeout must be within 0-60 or -1.")
return True return True
except ValueError: except ValueError:

View File

@@ -5,10 +5,6 @@ friends = open_json_file("friends", {}) # {Player_UUID:[List_of_friend
friend_join_sound = "random.orb" friend_join_sound = "random.orb"
def is_friend_of(player, other):
lst = friends.get(uid(player))
return lst is not None and uid(other) in lst
@hook.event("player.PlayerJoinEvent", "high") # creates sound and sends a bold message on friend join @hook.event("player.PlayerJoinEvent", "high") # creates sound and sends a bold message on friend join
def fjm(event): # friend join message def fjm(event): # friend join message

104
helpers.py Executable file → Normal file
View File

@@ -1,28 +1,32 @@
#pylint: disable = F0401 #pylint: disable = F0401
from re import sub
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 as bukkit
import org.bukkit.Location as Location
import org.bukkit.entity.Player as Player
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause as TeleportCause
import org.bukkit.event.block.BlockBreakEvent as BlockBreakEvent
import org.bukkit.block as bblock import org.bukkit.block as bblock
import org.bukkit.Location as Location
import org.bukkit.event.entity as entity import org.bukkit.event.entity as entity
import org.bukkit.entity.Player as Player
import org.bukkit.command.ConsoleCommandSender 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 org.bukkit.entity import *
from player import get_py_player from player import get_py_player
from player import py_players 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
#Imports for async query #Imports for async query
from secrets import *
import mysqlhack
from com.ziclix.python.sql import zxJDBC
import threading import threading
import mysqlhack
from secrets import *
from com.ziclix.python.sql import zxJDBC
from traceback import format_exc as trace
helpers_version = "2.0.0"
shared = {} # this dict can be used to share stuff across modules shared = {} # this dict can be used to share stuff across modules
server = bukkit.Bukkit.getServer() server = bukkit.Bukkit.getServer()
@@ -87,7 +91,7 @@ def colorify(text):
""" """
replace &-codes with real color codes replace &-codes with real color codes
""" """
return sub("&(?=[?\\da-fk-or])", u"\u00A7", "%s" % text) return sub("&" + u"\u00A7", "&", "%s" % sub("&(?=[?\\da-fk-or])", u"\u00A7", "%s" % text))
def stripcolors(text): def stripcolors(text):
@@ -181,6 +185,16 @@ def is_creative(player):
return str(player.getGameMode()) == "CREATIVE" 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): def uid(player):
""" """
returns the player's UUID returns the player's UUID
@@ -204,31 +218,6 @@ def known_player(player):
""" """
return player.hasPlayedBefore() return player.hasPlayedBefore()
"""
Runs a async query, calls target function with fetchall as an argument, it will be an empty list if there is nothing to fetch.
(So make sure your function takes that argument.)
If you want your function to run sync in the case you are doing something spigot wouldn't like to be async use the bukkit scheduler.
Example can be found in loginsecurity.py
"""
def async_query(mysql_database,query,query_args,target,*target_args,**target_kwargs):
def async_query_t(mysql_database,query,query_args,target,target_args,target_kwargs):
db_conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
db_curs = db_conn.cursor()
db_curs.execute(query,query_args)
db_conn.commit()
fetchall = db_curs.fetchall()
db_curs.close()
db_conn.close()
target(fetchall,target_args,target_kwargs)
t = threading.Thread(target=async_query_t,args=(mysql_database,query,query_args,target,target_args,target_kwargs))
t.daemon = True
t.start()
def open_json_file(filename, default = None): def open_json_file(filename, default = None):
""" """
opens the given json file and returns an object or returns None on error opens the given json file and returns an object or returns None on error
@@ -271,8 +260,7 @@ def send_JSON_message(playername, message):
bukkit.Bukkit.getServer().dispatchCommand(bukkit.Bukkit.getServer().getConsoleSender(), "tellraw " + playername + " " + message) bukkit.Bukkit.getServer().dispatchCommand(bukkit.Bukkit.getServer().getConsoleSender(), "tellraw " + playername + " " + message)
# Allows to check if a String is a valid IPv4 or not. Accepts any string, returns true if the String is a valid IPv4 def isIP(tocheck):
def is_ip(tocheck):
subsets = ["","","",""] subsets = ["","","",""]
i = 0 i = 0
for j in range(0,len(tocheck)): for j in range(0,len(tocheck)):
@@ -290,37 +278,3 @@ def is_ip(tocheck):
if not ((int(subsets[j]) >= 0) & (int(subsets[j]) <= 255)): if not ((int(subsets[j]) >= 0) & (int(subsets[j]) <= 255)):
return False return False
return True return True
# Allows the use of e.g. numeric permission nodes like "permission.amount.5" and similar.
# To get the data fetch the player and the start of the permission node, looking like "permission.amount."
def get_permission_content(player, permnode):
perms = player.getEffectivePermissions()
for perm in perms:
if str(perm.getPermission()).startswith(permnode):
return str(perm.getPermission()).replace(permnode, "")
# Gets an online player from their name
def get_player(name):
for p in bukkit.Bukkit.getServer().getOnlinePlayers():
if p.getName().lower() == name.lower():
return p
return None
def array_to_list(array):
return_list = []
for a in array:
return_list += [a]
return return_list
#debug wrapper
def debug(func):
def wrap(*args, **kwargs):
try:
func(*args, **kwargs)
except:
print(trace())
return wrap

343
imbusy.py
View File

@@ -1,308 +1,107 @@
##################################
# I'M BUSY! Plugin by Curs3d # # I'M BUSY! Plugin by Curs3d #
##############################
# Concept by CookieManors :D # # Concept by CookieManors :D #
################################## # http://bit.ly/1GnNPW8 #
# This plugin permits users to # ##############################
# send a command that renders # # This plugin permits users to
# them "busy", not letting them # # send a command that renders
# to get tpa requests or direct # # them "busy", not letting them
# messages, except from console. # # to get tpa requests or direct
# On restart, all busy data will # # messages, except from console.
# be cleared. # # On restart, all busy data will
################################## # be cleared.
from helpers import * from helpers import *
from friends import is_friend_of from basecommands import simplecommand
import org.bukkit.command.Command as Command from traceback import format_exc as trace
busy_players = []
imbusy_version = "v1.1.0"
base_permission = "utils.busy" # for /busy status
use_permission = "utils.busy.use" # for being busy
override_permission = "utils.busy.override" # for being able to bother busy people
busy_players = {} # name : false/true where false is normal busy and true is super busy def unclear():
msg(sender, "Umm, what? Sorry, directions unlclear, got head stuck in washing machine")
@hook.command("imbusy", @hook.command("busy",
aliases = ["busy"], aliases = ["focus"],
usage = "/<command> [on, off, status/check]", usage = "/<command> <on|off|status>",
description = "Offers control over your busy status" description = "Sets busy mode on, you cannot recieve tpas and MSGs"
) )
def on_busy_command(sender, cmd, label, args): def on_busy_command(sender, cmd, label, args):
if not is_player(sender): if not is_player(sender):
msg(sender, "&7Sorry, Console cannot be busy") msg(sender, "Sorry, Console cannot be busy")
return True return True
if not sender.hasPermission("utils.busy.allowed"):
plugin_header(recipient = sender, name = "I'M BUSY!") plugin_header(recipient = sender, name = "I'M BUSY!")
#args = array_to_list(args)
if not sender.hasPermission(base_permission):
noperm(sender) noperm(sender)
return True return True
if len(args) == 0: if len(args) == 0:
return toggle(sender) 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.")
arg0 = args[0].lower() msg(sender, "\nCommands:")
if arg0 == "on": msg(sender, "/busy on: turns on busy mode")
return on(sender) msg(sender, "/busy off: turns off busy mode")
if arg0 == "off": msg(sender, "/busy status [player]: shows your or [player]'s current busy status.")
return off(sender)
if arg0 in ("status", "check"):
return status(sender, args[1:])
if arg0 == "super":
return super_cmd(sender)
return help(sender)
def toggle(sender):
if not sender.hasPermission(use_permission):
noperm(sender)
return True
sender_name = sender.getName()
if sender_name in busy_players:
del busy_players[sender_name]
broadcast(None, sender.getDisplayName() + " &7is no longer busy...")
else:
busy_players.append(sender_name)
broadcast(None, sender.getDisplayName() + " &7is now busy...")
return True return True
elif len(args) == 1:
def help(sender): if args[0] == "on":
msg(sender, "Let's you put yourself in busy status, preventing pms and tpa requests from other players")
msg(sender, "\n&eCommands:")
msg(sender, "&e/busy &7- Toggles busy status")
msg(sender, "&e/busy on &7- Turns on busy status")
msg(sender, "&e/busy off &7- Turns off busy status")
msg(sender, "&e/busy status [player] &7- shows your or [player]'s current busy status")
msg(sender, "&e/busy super &7- sets your status to SUPER busy such that even friends can not bother you")
return True
def on(sender):
if not sender.hasPermission(use_permission):
noperm(sender)
return True
sender_name = sender.getName()
if busy_players.get(sender_name) is False: # can be None, False or True
msg(sender, "&7You are already busy!")
else:
busy_players[sender_name] = False # busy but not super busy
broadcast(None, sender.getDisplayName() + " &7is now busy...")
return True
def off(sender):
if not sender.hasPermission(use_permission):
noperm(sender)
return True
sender_name = sender.getName()
if sender_name not in busy_players:
msg(sender, "&7You are not busy! You cannot be even less busy! Are you perhaps bored?")
return True
del busy_players[sender_name]
broadcast(None, sender.getDisplayName() + " &7is no longer busy...")
return True
def status(sender, args):
if not sender.hasPermission(base_permission):
noperm(sender)
return True
if len(args) == 0:
if sender.getName() in busy_players: if sender.getName() in busy_players:
if busy_players[sender_name] is False: plugin_header(recipient = sender, name = "I'M BUSY!")
msg(sender, "&7You are currently busy.") msg(sender, "You cannot be even more focused than this without being a jedi!")
else: return True
msg(sender, "&7You are currently SUPER busy.") busy_players.append(sender.getName())
else: plugin_header(recipient = sender, name = "I'M BUSY!")
msg(sender, "&7You are currently not busy.") broadcast(None, "%s is now SUPER busy! Don't even TRY bothering them, it will not work!" % sender.getName())
else:
target = server.getPlayer(args[0])
if target is None:
msg(sender, "&7That player is not online")
elif target.getName() in busy_players:
if busy_players[target.getName()] is False:
msg(sender, "&7Player %s &7is currently busy." % target.getDisplayName())
else:
msg(sender, "&7Player %s &7is currently SUPER busy." % target.getDisplayName())
else:
msg(sender, "&7Player %s &7is currently not busy." % target.getDisplayName())
return True return True
elif args[0] == "off":
def super_cmd(sender): plugin_header(recipient = sender, name = "I'M BUSY!")
if not sender.hasPermission(use_permission):
noperm(sender)
return True
sender_name = sender.getName()
if busy_players.get(sender_name) is True:
msg(sender, "&7You are already SUPER busy!")
else:
busy_players[sender_name] = True # SUPER busy
broadcast(None, sender.getDisplayName() + " &7is now SUPER busy...")
return True
@hook.event("player.PlayerQuitEvent", "lowest")
def on_player_leave(event):
player_name = event.getPlayer().getName()
if player_name in busy_players:
del busy_players[player_name]
#---- Dicode for catching any bothering of busy people ----
reply_targets = {}
def can_send(sender, target):
if not target.getName() in busy_players:
return True
if target is sender or sender.hasPermission(override_permission):
return True
return busy_players[target.getName()] is False and is_friend_of(target, sender)
def whisper(sender, target_name):
target = server.getPlayer(target_name)
if target is not None:
if not can_send(sender, target):
msg(sender, "&c[&fBUSY&c] %s&r is busy!" % target.getDisplayName())
return False
reply_targets[sender.getName()] = target.getName()
# allow the target to reply regardless of sender being busy
if target.getName() in reply_targets:
del reply_targets[target.getName()]
return True
def reply(sender):
if sender.getName() in reply_targets:
target = server.getPlayer(reply_targets[sender.getName()])
if target is not None:
if not can_send(sender, target):
msg(sender, "&c[&fBUSY&c] %s&r is busy!" % target.getDisplayName())
return False
# allow the target to reply regardless of sender being busy
if target.getName() in reply_targets:
del reply_targets[target.getName()]
return True
class CommandWrapper(Command):
def __init__(self, wrapped, checker):
Command.__init__(self, wrapped.getName())
self.setDescription(wrapped.getDescription())
self.setPermission(wrapped.getPermission())
self.setUsage(wrapped.getUsage())
self.setAliases(wrapped.getAliases())
self.wrapped = wrapped
self.checker = checker
def execute(self, sender, label, args):
try: try:
if not is_player(sender) or self.checker(sender, args): busy_players.remove(sender.getName())
return self.wrapped.execute(sender, label, args) msg(sender, "Master has sent /busy command, %s is freeee!" % sender.getName())
except: return True
error(trace()) except ValueError:
msg(sender, "You are not busy! You cannot be even less busy! Are you perhaps bored?")
return True return True
def tabComplete(self, sender, alias, args): elif args[0] == "status":
return self.wrapped.tabComplete(sender, alias, args) 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!")
def msg_command_checker(sender, args):
return len(args) <= 1 or whisper(sender, args[0])
def reply_command_checker(sender, args):
return len(args) == 0 or reply(sender)
def tpa_command_checker(sender, args):
if len(args) == 0:
return True return True
target = server.getPlayer(args[0]) else:
if target is not None and not can_send(sender, target): msg(sender, "You are completely unable to focus right now.")
msg(sender, "&c[&fBUSY&c] %s&r is busy!" % target.getDisplayName()) return True
else:
plugin_header(recipient = sender, name = "I'M BUSY!")
unclear()
return False 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 return True
def tpahere_command_checker(sender, args): else:
return tpa_command_checker(sender, args) plugin_header(recipient = sender, name = "I'M BUSY!")
unclear()
def mail_command_checker(sender, args):
info("Mail command executed")
if len(args) < 3 or args[0].lower() != "send":
return True
target = server.getPlayer(args[1])
if target is not None and not can_send(sender, target):
msg(sender, "&c[&fBUSY&c] %s&r is busy!" % target.getDisplayName())
return False return False
return True
@hook.event("player.PlayerCommandPreprocessEvent", "monitor") @hook.event("player.PlayerCommandPreprocessEvent", "monitor")
def on_player_command_preprocess(event): def on_cmd_preprocess_event(event):
message = event.getMessage().split(" ") message = event.getMessage().split(" ")
if len(message) > 1 and message[0].lower() in ("/tell", "/minecraft:tell") and not whisper(event.getPlayer(), message[1]): 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) event.setCancelled(True)
@hook.enable
def replace_ess_commands():
try:
map_field = server.getPluginManager().getClass().getDeclaredField("commandMap")
map_field.setAccessible(True)
command_map = map_field.get(server.getPluginManager())
commands_field = command_map.getClass().getDeclaredField("knownCommands")
commands_field.setAccessible(True)
map = commands_field.get(command_map)
ess_msg_cmd = map.get("essentials:msg")
ess_reply_cmd = map.get("essentials:reply")
ess_tpa_cmd = map.get("essentials:tpa")
ess_tpahere_cmd = map.get("essentials:tpahere")
ess_mail_cmd = map.get("essentials:mail")
msg_cmd_wrapper = CommandWrapper(ess_msg_cmd, msg_command_checker)
reply_cmd_wrapper = CommandWrapper(ess_reply_cmd, reply_command_checker)
tpa_cmd_wrapper = CommandWrapper(ess_tpa_cmd, tpa_command_checker)
tpahere_cmd_wrapper = CommandWrapper(ess_tpahere_cmd, tpahere_command_checker)
mail_cmd_wrapper = CommandWrapper(ess_mail_cmd, mail_command_checker)
iterator = map.entrySet().iterator()
wrapped_commands = []
while iterator.hasNext():
entry = iterator.next()
value = entry.getValue()
changed = True
if value is ess_msg_cmd:
entry.setValue(msg_cmd_wrapper)
elif value is ess_reply_cmd:
entry.setValue(reply_cmd_wrapper)
elif value is ess_tpa_cmd:
entry.setValue(tpa_cmd_wrapper)
elif value is ess_tpahere_cmd:
entry.setValue(tpahere_cmd_wrapper)
elif value is ess_mail_cmd:
entry.setValue(mail_cmd_wrapper)
else:
changed = False
if changed:
wrapped_commands.append(entry.getKey())
info("[imbusy] wrapped commands: /" + ", /".join(wrapped_commands))
except:
error("[Imbusy] Failed to wrap essentials commands")
error(trace())

9
iptracker.py Executable file → Normal file
View File

@@ -9,7 +9,6 @@ from iptracker_secrets import *
iptrack_permission = "utils.iptrack" iptrack_permission = "utils.iptrack"
iptrack_version = "1.1.0"
@hook.event("player.PlayerJoinEvent", "low") @hook.event("player.PlayerJoinEvent", "low")
@@ -43,13 +42,13 @@ def on_player_join_thread(event):
if new_ip_entry: if new_ip_entry:
curs.execute("INSERT INTO uuid2ips VALUES (?,?)", (uuid, json.dumps(ips), )) curs.execute("INSERT INTO uuid2ips VALUES (?,?)", (uuid, json.dumps(ips), ))
else: else:
curs.execute("UPDATE uuid2ips SET ips = ? WHERE uuid = ?", (json.dumps(ips), uuid, )) curs.execute("UPDATE uuid2ips SET ips = ? WHERE uuid = ?", (uuid, json.dumps(ips), ))
if uuid not in uuids: if uuid not in uuids:
uuids.append(uuid) uuids.append(uuid)
if new_uuid_entry: if new_uuid_entry:
curs.execute("INSERT INTO ip2uuids VALUES (?,?)", (ip, json.dumps(uuids), )) curs.execute("INSERT INTO ip2uuids VALUES (?,?)", (ip, json.dumps(uuids), ))
else: else:
curs.execute("UPDATE ip2uuids SET uuids = ? WHERE ip = ?", (json.dumps(uuids), ip, )) curs.execute("UPDATE ip2uuids SET uuids = ? WHERE uuid = ?", (ip, json.dumps(uuids), ))
conn.commit() conn.commit()
curs.close() curs.close()
conn.close() conn.close()
@@ -57,7 +56,7 @@ def on_player_join_thread(event):
@hook.command("getinfo") @hook.command("getinfo")
def on_getinfo_command(sender, args): def on_getinfo_command(sender, args):
t = threading.Thread(target=on_getinfo_command_thread, args=(sender, args)) t = threading.Thread(target=on_player_join_thread, args=(sender, args))
t.daemon = True t.daemon = True
t.start() t.start()
@@ -66,7 +65,7 @@ def on_getinfo_command_thread(sender, args):
if not checkargs(sender, args, 1, 1): if not checkargs(sender, args, 1, 1):
return False return False
else: else:
if is_ip(args[0]): if isIP(args[0]):
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver") conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.cursor() curs = conn.cursor()
curs.execute("SELECT uuids FROM ip2uuids WHERE ip = ?", (args[0], )) curs.execute("SELECT uuids FROM ip2uuids WHERE ip = ?", (args[0], ))

129
login.py Normal file
View File

@@ -0,0 +1,129 @@
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

View File

@@ -1,275 +0,0 @@
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"]
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))
py_player = get_py_player(user)
if crypt.verify(password, hashed):
if py_player.logging_in:
py_player.logging_in = False
msg(user, "&aLogged in successfully!")
else:
if py_player.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):
py_player = get_py_player(sender)
if py_player.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):
py_player = get_py_player(sender)
if not py_player.logging_in:
msg(sender,"&cAlready logged in!")
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):
py_player = get_py_player(sender)
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):
py_player = get_py_player(sender)
if py_player.logging_in:
return "&cYou are not logged in"
if not is_registered(uid(sender)):
return "&cYou are not registered!"
if py_player.logging_in == False:
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>",
senderLimit = -1,
description = "Removes password of <user> and sends them a notification",
helpNoargs = True)
def rmotherpass_command(sender, command, label, args):
py_player = get_py_player(sender)
if py_player.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", "highest")
def on_join(event):
user = event.getPlayer()
py_player = get_py_player(event.getPlayer())
if is_registered(uid(user)):
msg(event.getPlayer(), "&4You will be disconnected after 60 seconds if you don't &alogin")
msg(user, "&cUse /login <password>")
py_player.logging_in = True
py_player.login_time = time.time()
return
elif user.hasPermission(admin_perm):
pass #Do what? force them to make a password, lots of code, maybe just message us on slack?
#This shouldn't be needed anymore as py_player gets removed anyway.
"""
@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 py_player in py_players:
if py_player.logging_in:
if now - py_player.login_time > wait_time:
player = py_player.player
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 = get_py_player(event.getPlayer())
if user.logging_in:
event.setCancelled(True)
@hook.event("player.PlayerCommandPreprocessEvent","normal")
def pre_command_proccess(event):
player = get_py_player(event.getPlayer())
if player.logging_in:
args = event.getMessage().split(" ")
if not args[0].lower() == "/login":
msg(player.player, "&4You need to login before you do that!")
event.setCancelled(True)

88
main.py
View File

@@ -11,11 +11,10 @@ sys.path += ['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/l
try: try:
# Library that adds a bunch of re-usable methods which are used in nearly all other modules # Library that adds a bunch of re-usable methods which are used in nearly all other modules
from helpers import * from helpers import *
#from wrapper import *
except: except:
print("[RedstonerUtils] ERROR: Failed to import helpers:") error("[RedstonerUtils] ERROR: Failed to import Wrapper:")
print(print_traceback()) error(print_traceback())
@hook.enable @hook.enable
def on_enable(): def on_enable():
@@ -24,89 +23,20 @@ def on_enable():
@hook.disable @hook.disable
def on_disable(): def on_disable():
shared["modules"]["reports"].stop_reporting() #shared["modules"]["reports"].stop_reporting()
info("RedstonerUtils disabled!") info("RedstonerUtils disabled!")
info("Loading RedstonerUtils...") info("Loading RedstonerUtils...")
# Import all modules, in this order # Import all modules, in this order
shared["load_modules"] = [ shared["load_modules"] = [
# Collection of tiny utilities "test",
"misc", # "login",
# 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",
# Adds aliasing of chat words
"chatalias",
# For players to point friends
"friends",
# 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",
# Adds /signalstrength, lets you request a signal strength and an amount of items will be inserted into target container to meet that strength.
"signalstrength",
# Shows the owner of a skull when right-clicked
"skullclick",
# Adds /listen, highlights chat and plays a sound when your name was mentioned
"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 busy status to players
"imbusy",
# 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
"player",
# Servercontrol extension for telnet access to logs/AC
#"servercontrol",
# Script helper plugin
"scriptutils",
# Per-player notes
"tag",
# vanish toggle module - temporary fix
#"vanishfix",
# obisidian mining punishment plugin
"punishments",
# a simple replacement for the buggy essentials /vanish
"vanish",
# ip-tracking utility - disabled as of instability
#"iptracker",
#server signs for everyone
"serversigns",
# Makes player's names colored, sorts tab list by rank
"nametags"
] ]
shared["modules"] = {} shared["modules"] = {}
for module in shared["load_modules"]: for module in shared["load_modules"]:
try: try:

13
misc.py
View File

@@ -114,20 +114,9 @@ def rs_material_broken_by_flow(material):
length = len(parts) 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")) return length > 1 and (parts[0] == "DIODE" or parts[1] in ("TORCH", "WIRE", "BUTTON", "HOOK") or (length == 3 and parts[1] == "COMPARATOR"))
@hook.event("player.PlayerInteractEvent")
def on_interact(event):
if (not event.isCancelled()
and str(event.getAction()) == "RIGHT_CLICK_BLOCK"
and str(event.getMaterial()) in ("REDSTONE_COMPARATOR_OFF", "REDSTONE_COMPARATOR_ON")
and not can_build(player, event.getClickedBlock())
):
event.setCancelled(True)
sudo_blacklist = ["pyeval", "script_backup_begin", "script_backup_end", "script_backup_error", "script_backup_database_begin", "script_backup_database_dumps", "script_backup_database_end", 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_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", "sudo"] "script_stop", "script_stop_abort", "script_shutdown", "stop", "esudo", "essentials:sudo"]
@simplecommand("sudo", @simplecommand("sudo",
usage = "<player> [cmd..]", usage = "<player> [cmd..]",

45
mysql_utils.py Normal file
View File

@@ -0,0 +1,45 @@
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. to allow proper loading of mysql-connector.jar at runtime.
Import only, no methods. Import only, no methods.
""" """
import java.lang.reflect.Method
import java.io.File
import java.net.URL
import java.net.URLClassLoader
import jarray import jarray
import java.net.URL
import java.io.File
from java.lang import Class from java.lang import Class
import java.net.URLClassLoader
import java.lang.reflect.Method
# hacky code to add mysql-connector to java's classpath ('classPathHack') # hacky code to add mysql-connector to java's classpath ('classPathHack')

View File

@@ -1,37 +0,0 @@
from helpers import *
##############################################################
# #
# This module automatically puts people in the corresponding #
# scoreboard team so that their name is colored properly and #
# tab will be nicely sorted. #
# #
##############################################################
ranks = ["visitor", "member", "builder", "trusted", "trainingmod", "mod", "admin"]
# prefixes are used for sorting in the tab list
prefixes = {"admin":"a", "mod":"b", "trainingmod":"c", "trusted":"d", "builder":"e", "member":"f","visitor":"g"}
@hook.event("player.PlayerJoinEvent", "low")
def on_player_join(event):
player = event.getPlayer()
team = get_team(player)
if team:
cmd = "scoreboard teams join %s %s" % (team, player.getName())
server.dispatchCommand(server.getConsoleSender(), cmd)
def get_rank(player):
player_rank = None
for rank in ranks:
if not player.hasPermission("group.%s" % rank):
break
player_rank = rank
if not player_rank:
warn("Couldn't find rank for player %s" % player.getName())
return player_rank
def get_team(player):
rank = get_rank(player)
if rank:
prefix = prefixes.get(rank)
return "_".join([prefix, rank])

View File

@@ -2,3 +2,4 @@ name: RedstonerUtils
main: main.py main: main.py
version: 3.1.0 version: 3.1.0
author: redstone_sheep author: redstone_sheep

View File

@@ -5,11 +5,7 @@ from java.util.UUID import fromString as juuid
toggle_dict = {} toggle_dict = {}
permission = "utils.pmtoggle" permission = "utils.pmtoggle"
@hook.command("pmtoggle", @hook.command("tm")
aliases = ["tm", "mt", "tmsg", "msgt", "pmt", "tpm"],
usage = "/<command> [player]",
description = "Toggle automatic sending of messages"
)
def on_toggle_message_command(sender, command, label, args): def on_toggle_message_command(sender, command, label, args):
if not sender.hasPermission(permission) or not is_player(sender): if not sender.hasPermission(permission) or not is_player(sender):
noperm(sender) noperm(sender)

View File

@@ -5,7 +5,15 @@ import java.util.UUID as UUID
import org.bukkit.Material as Material import org.bukkit.Material as Material
import org.bukkit.block.BlockFace as BlockFace import org.bukkit.block.BlockFace as BlockFace
blocked_cmds = tuple(shared["modules"]["misc"].sudo_blacklist) + ("pex", "kick", "ban", "tempban", "reload", "op", "deop", "whitelist") """
# 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(): def load_signs():
signs_obj = open_json_file("serversigns", []) signs_obj = open_json_file("serversigns", [])
@@ -24,6 +32,18 @@ signs = load_signs() # {("world", x, y, z): ["owner_id", "msg1", "msg2"]}
lines = {} # Accumulated messages so players can have longer messages: {"Dico200": "Message...........", ""} 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): def fromLoc(bLoc):
""" """
# Returns a tuple containing the (bukkit)location's world's name and its x, y and z coordinates # Returns a tuple containing the (bukkit)location's world's name and its x, y and z coordinates
@@ -222,9 +242,6 @@ def svs_command(sender, command, label, args):
return signsMsg("Removed all messages and the owner from the %s, it can now be claimed" % signName, 'a') return signsMsg("Removed all messages and the owner from the %s, it can now be claimed" % signName, 'a')
#------------------------------------------------------------------------------------------------------- #-------------------------------------------------------------------------------------------------------
@hook.event("player.PlayerInteractEvent") @hook.event("player.PlayerInteractEvent")
def on_click(event): def on_click(event):
if str(event.getAction()) != "RIGHT_CLICK_BLOCK": if str(event.getAction()) != "RIGHT_CLICK_BLOCK":
@@ -254,7 +271,6 @@ faces = {
@hook.event("block.BlockBreakEvent", "monitor") @hook.event("block.BlockBreakEvent", "monitor")
def on_break(event): def on_break(event):
try:
global checking_block global checking_block
if checking_block or event.isCancelled(): if checking_block or event.isCancelled():
return return
@@ -271,8 +287,6 @@ def on_break(event):
block3 = block.getRelative(BlockFace.UP) block3 = block.getRelative(BlockFace.UP)
if block3.getType() == Material.SIGN_POST: if block3.getType() == Material.SIGN_POST:
check_sign(event, block3) check_sign(event, block3)
except:
error(trace())
def check_sign(event, block, attached = True): def check_sign(event, block, attached = True):
@@ -287,6 +301,7 @@ def check_sign(event, block, attached = True):
save_signs() save_signs()
msg(player, signsMsg("Reset the %s which you just broke" % identifySign(loc))) msg(player, signsMsg("Reset the %s which you just broke" % identifySign(loc)))
def can_build2(player, block): def can_build2(player, block):
global checking_block global checking_block
event = BlockBreakEvent(block, player) event = BlockBreakEvent(block, player)

View File

@@ -25,7 +25,7 @@ mkdir -v "build"
cd "build" cd "build"
echo -e "\n> Downloading Spigot build tools" echo -e "\n> Downloading Spigot build tools"
curl --progress-bar -Lo "BuildTools.jar" "https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar" curl --progress-bar -Lo "buildtools.jar" "https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar"
echo -e "\n> Building Spigot, this will take a while ..." echo -e "\n> Building Spigot, this will take a while ..."
java -jar BuildTools.jar > /dev/null java -jar BuildTools.jar > /dev/null

24
thread_utils.py Normal file
View File

@@ -0,0 +1,24 @@
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

80
util_events.py Normal file
View File

@@ -0,0 +1,80 @@
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

View File

@@ -13,7 +13,7 @@ def is_vanished(player):
return uid(player) in vanished return uid(player) in vanished
#this can be used to silently set the vanished state of a player #this can be used to silently set the vanished state of a player I guess.
def set_state(player, state): def set_state(player, state):
if state == is_vanished(player): if state == is_vanished(player):
return return
@@ -37,6 +37,10 @@ def disable_vanish(target):
player.showPlayer(target) 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", @simplecommand("vanish",
aliases = ["v"], aliases = ["v"],
usage = "[on/off]", usage = "[on/off]",
@@ -48,7 +52,6 @@ def disable_vanish(target):
helpSubcmd = True helpSubcmd = True
) )
def vanish_command(sender, command, label, args): def vanish_command(sender, command, label, args):
try:
current_state = is_vanished(sender) current_state = is_vanished(sender)
new_state = not current_state new_state = not current_state
@@ -59,34 +62,28 @@ def vanish_command(sender, command, label, args):
elif arg == "off": elif arg == "off":
new_state = False new_state = False
if current_state == new_state: Validate.isTrue(current_state != new_state, "&cYou were %s vanished!" % ("already" if current_state else "not yet"))
return "&cYou were %s vanished!" % ("already" if current_state else "not yet")
set_state(sender, new_state) set_state(sender, new_state)
return "&a%s vanish mode!" % ("Enabled" if new_state else "Disabled") return "&a%s vanish mode!" % ("Enabled" if new_state else "Disabled")
except:
error(trace())
@hook.event("player.PlayerJoinEvent") @hook.event("player.PlayerJoinEvent")
def on_player_join(event): def on_player_join(event):
player = event.getPlayer() player = event.getPlayer()
if not is_authorized(player): if not is_authorized(player):
for uuid in vanished: for vanished in get_online_vanished_players():
player.hidePlayer(retrieve_player(uuid)) player.hidePlayer(vanished)
elif is_vanished(player):
msg(player, "&cKeep in mind that you are still vanished! Use /vanish to disable.")
@hook.event("player.PlayerQuitEvent") @hook.event("player.PlayerQuitEvent")
def on_player_quit(event): def on_player_quit(event):
player = event.getPlayer() player = event.getPlayer()
if not is_authorized(player): if not is_authorized(player):
for uuid in vanished: for vanished in get_online_vanished_players():
player.showPlayer(retrieve_player(uuid)) player.showPlayer(vanished)
elif is_vanished(player):
disable_vanish(player)
@simplecommand("vanishother", @simplecommand("vanishother",
@@ -110,9 +107,7 @@ def vanishother_command(sender, command, label, args):
elif arg == "off": elif arg == "off":
new_state = False new_state = False
if current_state == new_state: Validate.isTrue(current_state != new_state, "&cThat player was %s vanished!" % ("already" if current_state else "not yet"))
return "&cThat player was already vanished!" if current_state else "&cThat player was not yet vanished!"
set_state(target, new_state) set_state(target, new_state)
enabled_str = "enabled" if new_state else "disabled" enabled_str = "enabled" if new_state else "disabled"

12
wrapper.py Normal file
View File

@@ -0,0 +1,12 @@
"""
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

328
wrapper_command.py Normal file
View File

@@ -0,0 +1,328 @@
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

56
wrapper_event.py Normal file
View File

@@ -0,0 +1,56 @@
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

186
wrapper_player.py Normal file
View File

@@ -0,0 +1,186 @@
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()])