Merge branch 'dev'

This commit is contained in:
PanFritz
2015-01-09 21:38:04 +01:00
29 changed files with 1792 additions and 1593 deletions
+1
View File
@@ -0,0 +1 @@
If you want to contribute, please [read through the pages on the wiki](https://github.com/RedstonerServer/redstoner-utils/wiki).
+21
View File
@@ -0,0 +1,21 @@
# The MIT License (MIT)
Copyright (c) Redstoner
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE
+3 -240
View File
@@ -2,245 +2,8 @@
Redstoner's custom plugins, written in python. Redstoner's custom plugins, written in python.
------
# Installation / Set-up ## Contributing
1-line-install-script for bash: If you want to contribute, please [read through the pages on the wiki](https://github.com/RedstonerServer/redstoner-utils/wiki).
`wget -O install.sh "http://pastie.org/pastes/9310905/download?key = 6byp4mrqmiui8yqeo3s6yw"; md5sum --check <<<"3499671c0832e561bc9c7d476d2167cb install.sh" && sh install.sh`
Detailed description:
0. Create a new directory called 'redstoner'
0. Download [the latest spigot](http://ci.md-5.net/job/Spigot/lastStableBuild/artifact/Spigot-Server/target/spigot.jar)
0. Run it once inside redstoner, then shut it down again
0. Create a new directory (inside redstoner) called 'lib'
0. Download [mysql-connector](https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-5.1.30.zip), extract 'mysql-connector-java-X.X.XX-bin.jar
' and save it as 'mysql-connector.jar' inside lib
0. Download [PyPluginLoader](http://bamboo.gserv.me/browse/PLUG-PYPL/latestSuccessful/artifact/JOB1/Version-agnostic-jar/PyPluginLoader.jar) (we're using [this fork](https://github.com/gdude2002/Python-Plugin-Loader)) into the plugins directory
0. inside plugins, clone this directory into 'redstoner-utils**.py.dir**':
`git clone git@bitbucket.org:redstonesheep/redstoner-utils.git redstoner-utils.py.dir`
0. Download [PEX](http://dev.bukkit.org/media/files/789/291/PermissionsEx.jar) into plugins
0. **if you want** to develop mysql things, set up a local MySQL server
# branches
* **dev**
Always use this branch to change code, please test before pushing. (If something goes wrong here, that's okay)
* **master**
Never commit into this branch directly! Only merge stable versions of *dev*:
```bash
git checkout master
git merge dev
```
# Deploying on the server
**Never** edit the files directly on the server!
The dev server uses the *dev* branch, the live server uses *master*.
**Do not use `git pull` on the server!** *(All files must be pulled/owned by the 'redstoner' user.)*
### Deploying on test server
* Push all changes
* Run `<server-dir>/git_pull_utils.sh`.
* Restart (You can try reloading here, but expect the unexpected)
### Deploying on production server
* Test all code carefully on the test server
***on your machine:***
* `git checkout master`
* `git pull`
* `git merge dev`
* `git push -u origin master`
* `git checkout dev`
***on the server:***
* `rs update_utils`
* Restart
# Modules / Files
If you add a new file, please update this list!
If you want the server to load a file (*module*) on startup, add it to the `modules` list in `main.py`.
* `files/`
> All config / storage files go here
* `plugin.yml`
> The plugin.yml file required for bukkut plugins
* `main.py`
> The only file loaded by PyPluginLoader, loads all other modules
> Contains a few methods that **need to be cleaned up**
* `helpers.py`
> Library that adds a bunch of re-usable methods which are used in nearly all other modules
* `adminchat.py`
> Adds chat for staff using `/ac <text` or `,<text>`
* `chatgroups.py`
> Adds group-chat with `/chatgroup` and `/cgt` to toggle normal chat into group mode
* `lagchunks.py`
> Plugin to locate laggy chunks. `/lc <n>` lists chunks with more than `n` entities
* `mysqlhack.py`
> 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.
* `plotter.py`
> Start of a custom plot-plugin like PlotMe, on hold because the PlotMe developer continued to develop PlotMe
* `reports.py`
> The `/report <text>` and `/rp` plugin
* `saylol.py`
> Remake of sheep's old SayLol plugin, originally written as a standalone plugin in Java
* `skullclick.py`
> Shows the owner of a skull when right-clicked
* `webtoken.py`
> Adds `/token`, reads and writes from the database to generate *pronouncable* (and thus memorable) registration-tokens for the website
* `spawnplayer.py`
> Code that was used once to create [this](http://www.reddit.com/r/Minecraft/comments/28le52/screenshot_of_all_players_that_joined_my_server/) awesome [screenshot](http://i.imgur.com/v4wg5kl.png)
* `tilehelper.py`
> A plugin that automatically tiles (stacks) blocks inside a selected region in configurable directions.
* `mentio.py`
> Adds `/listen`, highlights chat and plays a sound when your name was mentioned
* `cycler.py`
> Adds `/cycler`, swaps the hotbar with inventory when player changes slot from right->left or left->right
* `motd.py`
> Adds `/getmotd` & `/setmotd` to update the motd on the fly (no reboot).
* `abot.py`
> AnswerBot. Hides stupid questions from chat and tells the sender about `/faq` or the like
* `damnspam.py`
> Adds `/damnspam`, creates timeout for buttons/levers to mitigate button spam.
* `forcefield.py`
> Adds '/forcefield', creates forcefield for players who want it.
# Code styleguide & tips
## Indentation
Never use tabs!
Use 2 spaces to indent.
## Quotes
Always use double-quotes!
Only use single-quotes when the string contains double-quotes that would need to be escaped.
## Capitalization
Do not use camelCase for variable or function names! Use under_score naming.
camelCase is okay when used like `import foo.bar.camelCase as camelCase`.
## Aligning variable assignments
In case you have multiple variable assignments, align the equals sign:
```Python
# bad
foo = 1
foobar = 2
a = 3
# good
foo = 1
foobar = 2
a = 3
```
Pro Tip: Use the AlignTab plugin for Sublime Text!
## Horizontal spacing
Use at least one space left and one space right to equals signs, and one space right to colons.
## Vertical spacing
Leave two empty lines before function definitions. In case you need to use `@hook.something`, add the two lines before that, directly followed by the definition.
## Meaningful names
Give function and variable names meaningful names. If you want to shorten long names, that's fine, but leave a comment on assigment with the actual meaning.
## Readability
Don't create long lines with lots of function calls. Split into multiple lines instead.
Also avoid methods with lots of lines. Split into multiple methods instead.
```Python
# bad
foo = int(player_data[str(server.getPlayer(args[4]).getUniqueId())]["details"].["last_login"].strftime("%s"))
# good
player = server.getPlayer(args[4])
player_id = uid(player)
logintime = player_data[played_id]["last_login"]
epoch_time = int(logintime.strftime("%s"))
```
## Comments
Comments are good!
Please comment everything that's non-obious or makes it easier to understand
## Debugging
Debugging can be a bit special with jython/PyPluginLoader.
When something goes wrong, you probably see a weird traceback that's not telling you shit.
...unless you take a closer look.
You will not see a direct traceback of the python methods.
Instead, you'll probably see a bunch of java, bukkit and python things, because it tries to translate python into java, line per line.
Take a closer look at the method names, they might tell you what it's trying to do and where it's coming from.
Watch out for something like `org.python.pycode._pyx5.horribleCode$23(/path/to/badcode.py:214) ~[?:?]`
0. In this case, `_pyx5` is our module.
0. `horribleCode` is the method that was called
0. `/path/to/badcode.py` is the actual file of our module
0. `:214` is the line in which the error occured.
Please note that the line may not be accurate. You'll often get the start of a loop, or the end of a method - when the actual error was somewhere in there.
In many cases, this is enough to find your bug. If you still cannot find it,try to catch exceptions in your code, as follows:
## Catching exceptions
If you want to catch all exceptions (e.g. for debugging), do not `catch Exception`.
Since we're using jython, this will not catch Java exceptions.
This will give you some more deatails:
```python
from traceback import format_exc as trace
try:
#code
except: # everything
print(trace())
```
+137
View File
@@ -0,0 +1,137 @@
from helpers import *
badges = open_json_file("badges", {})
badges_available = {
"helpful" : "A very helpful player",
"expert_minecraft" : "An expert in Minecraft",
"expert_coder" : "A good coder",
"oldtimer" : "A long time player",
"good_builder" : "A very good builder",
"friendly" : "Many think that this player is friendly",
"very_active" : "A very active player",
"trustworthy" : "This player is very trustworthy",
}
badges_perm_add = "utils.badges.add"
badges_perm_del = "utils.badges.delete"
def save_badges():
save_json_file("badges", badges)
def get_badges(player):
sender_id = uid(player)
return badges.get(sender_id, [])
def show_badges(sender, player):
player_badges = get_badges(player)
if player_badges:
msg(sender, "&6Badges of " + player.getName())
for key in player_badges:
msg(sender, "&b> &3&o%s" % badges_available[key])
else:
msg(sender, "&eThis player has no badges yet")
def new_badge_event(player, badge):
msg(player, "")
msg(player, "&6Wow! You just received a badge!")
msg(player, "&b-> &3%s" % badges_available[badge])
msg(player, "&7Type /badge to see all your badges!")
msg(player, "")
player.playSound(player.getLocation(), "random.orb", 1, 1)
def del_badge_event(player, badge):
msg(player, "&cWe took your badge \"%s\"." % badges_available[badge])
def list_badges(sender):
if badges_available:
for key in badges_available.keys():
msg(sender, "&b> &3%s &7&o\"%s\"" % (key, badges_available[key]))
else:
msg(sender, "&cThere are currently no badges available")
def add_badge(sender, target, badge):
if badge in badges_available:
player_badges = get_badges(target)
if badge in player_badges:
msg(sender, "&cThis player got this badge already!")
return
player_badges.append(badge)
if player_badges:
badges[uid(target)] = player_badges
msg(sender, "&aYou just gave %s a new badge!" % target.getName())
new_badge_event(target, badge)
save_badges()
else:
msg(sender, "&cThere is no badge called %s. Check /badge list!" % badge)
def del_badge(sender, target, badge):
if badge in badges_available.keys():
player_badges = get_badges(target)
if badge in player_badges:
player_badges.remove(badge)
badges[uid(target)] = player_badges
msg(sender, "&aYou just took %s from %s!" % (badge, target.getName()))
save_badges()
del_badge_event(target, badge)
return
msg(sender, "&c%s doesn't have this badge!" % target.getName())
else:
msg(sender, "&cThere is no badge called %s. Check /badge list!" % badge)
@hook.command("badge", aliases=["badges", "rewards"])
def on_badge_command(sender, args):
argnum = int(len(args))
# No arguments
if argnum is 0:
show_badges(sender, sender)
# Length of arguments is 1
if argnum == 1:
# If only argument is "list"
if args[0].lower() == "list":
list_badges(sender)
return True
# If only argument is a player name
target = server.getPlayer(args[0])
if is_player(target):
show_badges(sender, target)
return True
else:
msg(sender, "&cThere is no player called %s online." % args[0])
return True
msg(sender, "&cUnknown syntax: /badge <playername> &o&c /badge list")
return True
# Length of arguments is 3
if argnum == 3:
cmd = args[0].lower()
target = server.getPlayer(args[1])
new_badge = args[2].lower()
if cmd == "add":
if not sender.hasPermission(badges_perm_add):
noperm(sender)
return True
add_badge(sender, target, new_badge)
return True
if cmd == "take" or cmd == "del":
if not sender.hasPermission(badges_perm_del):
noperm(sender)
return True
del_badge(sender, target, new_badge)
return True
msg(sender, "&cUnknown syntax: /badge <add|take> <playername> <badge>")
return True
+62
View File
@@ -0,0 +1,62 @@
from helpers import *
calc_users = open_json_file("calc", [])
math_operators = ["+", "-", "*", "/", "&", "|"]
ignore_operators = ["**", "&&", "||"] # ** may be too intensive, the others cause syntax errors
calc_perm = "utils.calc"
def calc(text):
"""
extracts a mathematical expression from `text`
returns (expression, result) or None
"""
expression = ""
should_calc = False
for char in text:
if char.isdigit() or (should_calc and char in [".", " "]):
expression += char
elif char in math_operators:
# calculation must include at least 1 operator
should_calc = True
expression += char
elif should_calc and char.isalpha():
# don't include any more text in the calculation
break
if should_calc and not any(op in expression for op in ignore_operators):
try:
result = str(eval(expression)) # pylint: disable = W0123
except: # pylint: disable = W0702
# we can run into all kinds of errors here
# most probably SyntaxError
return None
return (expression, result)
return None
@hook.event("player.AsyncPlayerChatEvent", "monitor")
def on_calc_chat(event):
sender = event.getPlayer()
message = event.getMessage()
if not event.isCancelled() and uid(sender) in calc_users and sender.hasPermission(calc_perm):
output = calc(message)
if output:
msg(sender, "&2=== Calc: &e" + output[0] + " &2= &c" + output[1])
@hook.command("calc", description="Toggles chat calculations")
def on_calc_command(sender, args):
plugin_header(sender, "Chat Calculator")
if not sender.hasPermission(calc_perm):
noperm(sender)
return True
if not checkargs(sender, args, 0, 1):
return True
if not is_player(sender):
msg(sender, "&cYou are not a player!" % sender)
return True
toggle(sender, calc_users, name = "Calc")
save_json_file("calc", calc_users)
return True
+101
View File
@@ -0,0 +1,101 @@
import json
import urllib2
import datetime
import mysqlhack #pylint: disable = unused-import
from traceback import format_exc as print_traceback
from com.ziclix.python.sql import zxJDBC
from secrets import *
from helpers import *
# receive info based on the user's IP. information provided by ipinfo.io
def ip_info(player):
if player.isOnline():
return json.load(urllib2.urlopen("http://ipinfo.io%s/json" % str(player.getAddress().getAddress())))
else:
return {}
# receive first join date based on the player data (may not be accurate)
def get_first_join(player):
first_join = int(player.getFirstPlayed())
dt = datetime.datetime.fromtimestamp(first_join/1000.0)
return dt.strftime("%Y-%m-%d %H:%M")
# receive last seen date based on the player data
def get_last_seen(player):
last_seen = int(player.getLastPlayed())
dt = datetime.datetime.fromtimestamp(last_seen/1000.0)
return dt.strftime("%Y-%m-%d %H:%M")
# receive link and email from website
def get_website_data(player):
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.cursor()
uuid = str(uid(player)).replace("-", "")
curs.execute("SELECT DISTINCT `id`, `email` FROM users WHERE `uuid` = ? LIMIT 1", (uuid,))
results = curs.fetchall()
curs.close()
conn.close()
if len(results) == 1:
if len(results[0]) == 2:
return {
"link": "http://redstoner.com/users/%s" % results[0][0],
"email": results[0][1]
}
else:
return {}
else:
return {}
# receive country based on the user's IP
def get_country(data):
return str(data.get("country"))
def get_all_names(player):
uuid = str(uid(player)).replace("-", "")
names = json.load(urllib2.urlopen("https://api.mojang.com/user/profiles/%s/names" % uuid))
# [ {"name": "some_name"}, {"name": "other_name"} ]
return ", ".join([name["name"] for name in names])
# combines data
def get_all_data(sender, player):
data = ip_info(player)
msg(sender, "")
try:
msg(sender, "&7 -- Data provided by Redstoner")
msg(sender, "&6> UUID: &e%s" % str(uid(player)))
msg(sender, "&6> First joined: &7(y-m-d h:m:s) &e%s" % get_first_join(player))
msg(sender, "&6> Last seen: &7(y-m-d h:m:s) &e%s" % get_last_seen(player))
website = get_website_data(player)
msg(sender, "&6> Website account: &e%s" % website.get("link"))
msg(sender, "&6> email: &e%s" % website.get("email"))
msg(sender, "&7 -- Data provided by ipinfo.io")
msg(sender, "&6> Country: &e%s" % get_country(data))
msg(sender, "&7 -- Data provided by Mojang")
msg(sender, "&6> All ingame names used so far: &e%s" % get_all_names(player))
except:
# can throw exceptions such as timeouts when Mojang API is down
warn(print_traceback())
msg(sender, "&cSorry, something went wrong while fetching data")
@hook.command("check", description="Displays useful stuff about a user", usage="/check <player>")
def on_hook_command(sender, args):
if sender.hasPermission("utils.check"):
if not checkargs(sender, args, 1, 1):
return True
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
get_all_data(sender, player)
else:
msg(sender, "&4You don't have the required permissions to execute this command!")
return True
+20 -11
View File
@@ -31,7 +31,10 @@ def on_dammnspam_command(sender, args):
global changing_input global changing_input
plugin_header(sender, "DamnSpam") plugin_header(sender, "DamnSpam")
if len(args) in [1,2]: if not checkargs(sender, args, 1, 2):
msg(sender, "&c/damnspam <seconds> &e(Buttons/Levers)")
msg(sender, "&c/damnspam <seconds after off> <seconds after on> &e(Levers only)")
return True
if not is_creative(sender): if not is_creative(sender):
msg(sender, "&cYou can only do this in Creative mode.") msg(sender, "&cYou can only do this in Creative mode.")
@@ -43,8 +46,10 @@ def on_dammnspam_command(sender, args):
try: try:
timeout_on = round(float(timeout_on), 2) timeout_on = round(float(timeout_on), 2)
timeout_off = timeout_on timeout_off = timeout_on
if not 0 <= timeout_on <= 60: if 60 >= timeout_on <= -2 or timeout_on == 0:
msg(sender, "&cThe timeout must be within 0-60.") timeout_on = False
if timeout_on == False:
msg(sender, "&cThe timeout must be within 0-60 or -1.")
return True return True
except ValueError: except ValueError:
msg(sender, "&cThe timeout must be a number") msg(sender, "&cThe timeout must be a number")
@@ -57,8 +62,12 @@ def on_dammnspam_command(sender, args):
try: try:
timeout_on = round(float(timeout_on), 2) timeout_on = round(float(timeout_on), 2)
timeout_off = round(float(timeout_off), 2) timeout_off = round(float(timeout_off), 2)
if not 0 <= timeout_on <= 60 or not 0 <= timeout_off <= 60: if 60 >= timeout_on <= -2 or timeout_on == 0:
msg(sender, "&cThe timeout must be within 0-60.") timeout_on = False
if 60 >= timeout_off <= -2 or timeout_off == 0:
timeout_off = False
if timeout_on == False or timeout_off == False:
msg(sender, "&cThe timeout must be within 0-60 or -1.")
return True return True
except ValueError: except ValueError:
msg(sender, "&cThe timeout must be a number") msg(sender, "&cThe timeout must be a number")
@@ -84,13 +93,9 @@ def on_dammnspam_command(sender, args):
# add block to inputs # add block to inputs
add_input(sender, target, timeout_off, timeout_on) add_input(sender, target, timeout_off, timeout_on)
save_inputs() save_inputs()
msg(sender, "&aSuccessfully set a timeout for this %s." % ttype.lower()) msg(sender, "&aSuccessfully set a timeout for this %s." % ttype.lower().replace("_", " "))
return True return True
else:
msg(sender, "&c/damnspam <seconds> &e(Buttons/Levers)")
msg(sender, "&c/damnspam <seconds after off> <seconds after on> &e(Levers only)")
@hook.event("block.BlockBreakEvent", "normal") @hook.event("block.BlockBreakEvent", "normal")
def on_block_break(event): def on_block_break(event):
@@ -137,7 +142,11 @@ def on_interact(event):
data = inputs.get(pos_str) data = inputs.get(pos_str)
if data: if data:
checktime = data["timeout_on"] if powered else data["timeout_off"] checktime = data["timeout_on"] if powered else data["timeout_off"]
if data["last_time"] + checktime > now(): if checktime == -1:
event.setCancelled(True)
plugin_header(sender, "DamnSpam")
msg(sender, "&cThis %s is locked permanently." % (btype))
elif data["last_time"] + checktime > now():
event.setCancelled(True) event.setCancelled(True)
plugin_header(sender, "DamnSpam") plugin_header(sender, "DamnSpam")
msg(sender, "&cThis %s has a timeout of %ss." % (btype, checktime)) msg(sender, "&cThis %s has a timeout of %ss." % (btype, checktime))
+20 -27
View File
@@ -15,14 +15,23 @@ server = bukkit.Bukkit.getServer()
def info(text): def info(text):
"""
Log info to console
"""
server.getLogger().info("[RedstonerUtils] %s" % text) server.getLogger().info("[RedstonerUtils] %s" % text)
def warn(text): def warn(text):
"""
Log warning to console
"""
server.getLogger().warning("[RedstonerUtils] %s" % text) server.getLogger().warning("[RedstonerUtils] %s" % text)
def error(text): def error(text):
"""
Log error to console
"""
server.getLogger().severe("[RedstonerUtils] %s" % text) server.getLogger().severe("[RedstonerUtils] %s" % text)
@@ -90,6 +99,9 @@ def plugin_header(recipient = None, name="Redstoner Utils"):
def noperm(player): def noperm(player):
"""
Send the default permission failure message to the player
"""
msg(player, "&cno permission") msg(player, "&cno permission")
@@ -129,13 +141,6 @@ def checkargs(sender, args, amin, amax):
return True return True
def warp(player, args, warpname):
if not checkargs(player, args, 0, 1):
return False # You can check if it worked
runas(player, "warp %s" % warpname)
return True
def is_creative(player): def is_creative(player):
""" """
returns True if the player is in Creative mode returns True if the player is in Creative mode
@@ -164,7 +169,7 @@ def known_player(player):
returns True if the player has been on the server returns True if the player has been on the server
this is different to HasPlayedBefore(), which will return False on first join this is different to HasPlayedBefore(), which will return False on first join
""" """
return player.getFirstPlayed() != 0 return player.hasPlayedBefore()
def open_json_file(filename, default): def open_json_file(filename, default):
@@ -193,27 +198,15 @@ def save_json_file(filename, obj):
error("Failed to write to %s: %s" % (filename, e)) error("Failed to write to %s: %s" % (filename, e))
def toggle(player, ls, add = None, on = "&aToggle now on!", off = "&cToggle now off!", already = "&cToggle was already %s"): def toggle(player, ls, name = "Toggle", add = None):
""" """
Toggle presence of a player's UUID in a list (ls) Toggles presence of a player's UUID in a list
'add' controls if a player should be added(True) or removed(False) If add is given, True explicitely adds it whereas False removes it
if 'add' is None, ls will simply be toggled for that player.
when 'add' is given, but won't change anything, %s in 'already' is replaced with "ON" or "OFF"
""" """
pid = uid(player) pid = uid(player)
enabled = pid in ls if pid in ls or add == False:
# Do some checks and remove pid.
if enabled and add == False:
ls.remove(pid) ls.remove(pid)
msg(player, on) msg(player, "&a%s turned off!" % name)
elif add != False:
# Do some checks and append pid.
elif not enabled and add == True:
ls.append(pid) ls.append(pid)
msg(player, off) msg(player, "&a%s turned on!" % name)
# Already on/off (optional)
else:
msg(player, already % (" ON" if add else " OFF"))
+27
View File
@@ -0,0 +1,27 @@
import thread
from helpers import *
from adminchat import *
imout_toggle_list = []
@hook.command("imout")
def on_imout_command(sender, args):
if sender.hasPermission("utils.imout"):
name = sender.getName()
symbol = "&a&l+"
if name in imout_toggle_list:
msg(sender, "&eWelcome back! You are no longer hidden")
msg(sender, "&6We disabled /act for you!")
if name in imout_toggle_list:
imout_toggle_list.remove(name)
if name in ac_toggle_list:
ac_toggle_list.remove(name)
else:
symbol = "&c&l-"
msg(sender, "&eYou just left... Or didn't you?")
imout_toggle_list.append(name)
if name not in ac_toggle_list:
msg(sender, "&6We enabled /act for you!")
ac_toggle_list.append(name)
broadcast(None, "%s &7%s" % (symbol, name))
+25 -1
View File
@@ -9,6 +9,7 @@ from traceback import format_exc as print_traceback
sys.path += ['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/pymodules/python2.7', '/usr/lib/pyshared/python2.7'] sys.path += ['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/pymodules/python2.7', '/usr/lib/pyshared/python2.7']
try: try:
# Library that adds a bunch of re-usable methods which are used in nearly all other modules
from helpers import * from helpers import *
except: except:
print("[RedstonerUtils] ERROR: Failed to import helpers:") print("[RedstonerUtils] ERROR: Failed to import helpers:")
@@ -31,20 +32,43 @@ 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
"misc", "misc",
# Adds chat for staff using /ac <text or ,<text>
"adminchat", "adminchat",
# Adds /badge, allows to give players achievements
"badges",
# 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", "lagchunks",
# Adds /report and /rp, Stores reports with time and location
"reports", "reports",
# Adds group-chat with /chatgroup and /cgt to toggle normal chat into group mode
"chatgroups", "chatgroups",
# Adds /token, reads and writes from the database to generate pronouncable (and thus memorable) registration-tokens for the website
"webtoken", "webtoken",
# Adds /lol, broadcasts random funyy messages. A bit like the splash text in the menu
"saylol", "saylol",
# Shows the owner of a skull when right-clicked
"skullclick", "skullclick",
# Adds /listen, highlights chat and plays a sound when your name was mentioned
"mentio", "mentio",
# Adds /cycler, swaps the hotbar with inventory when player changes slot from right->left or left->right
"cycle", "cycle",
# Adds /getmotd & /setmotd to update the motd on the fly (no reboot)
"motd", "motd",
# AnswerBot. Hides stupid questions from chat and tells the sender about /faq or the like
"abot", "abot",
# Adds '/forcefield', creates forcefield for players who want it.
"forcefield", "forcefield",
"damnspam" # Adds /damnspam, creates timeout for buttons/levers to mitigate button spam.
"damnspam",
# Adds /check, useful to lookup details about a player
"check",
# Adds /imout, displays fake leave/join messages
"imout"
# NOTICE: If you add something here, please add a small descriptive comment above!
] ]
shared["modules"] = {} shared["modules"] = {}
for module in shared["load_modules"]: for module in shared["load_modules"]:
+67 -25
View File
@@ -5,12 +5,12 @@ from sys import exc_info
import thread import thread
import org.bukkit.inventory.ItemStack as ItemStack import org.bukkit.inventory.ItemStack as ItemStack
#
# Welcome new players
#
@hook.event("player.PlayerJoinEvent", "monitor") @hook.event("player.PlayerJoinEvent", "monitor")
def on_join(event): def on_join(event):
"""
Welcome new players
"""
player = event.getPlayer() player = event.getPlayer()
# send welcome broadcast # send welcome broadcast
@@ -23,7 +23,7 @@ def on_join(event):
msg(player, " \n \n \n \n \n \n \n \n \n \n \n \n ") msg(player, " \n \n \n \n \n \n \n \n \n \n \n \n ")
msg(player, " &4Welcome to the Redstoner Server!") msg(player, " &4Welcome to the Redstoner Server!")
msg(player, " &6Before you ask us things, take a quick") msg(player, " &6Before you ask us things, take a quick")
msg(player, " &6look at the &a&l/FAQ &6command.") msg(player, " &6look at &a&nredstoner.com/info")
msg(player, " \n&6thank you and happy playing ;)") msg(player, " \n&6thank you and happy playing ;)")
msg(player, " \n \n") msg(player, " \n \n")
@@ -36,13 +36,12 @@ def on_join(event):
player.teleport(player.getWorld().getSpawnLocation()) player.teleport(player.getWorld().getSpawnLocation())
#
# /sudo - execute command/chat *as* a player/console
#
@hook.command("sudo") @hook.command("sudo")
def on_sudo_command(sender, args): def on_sudo_command(sender, args):
"""
/sudo
execute command/chat *as* a player/console
"""
if sender.hasPermission("utils.sudo"): if sender.hasPermission("utils.sudo"):
plugin_header(sender, "Sudo") plugin_header(sender, "Sudo")
if not checkargs(sender, args, 2, -1): if not checkargs(sender, args, 2, -1):
@@ -71,14 +70,39 @@ def on_sudo_command(sender, args):
return True return True
# #@hook.command("gm")
# Clicking redstone_sheep with shears will drop redstone + wool and makes a moo sound #def on_gm_command(sender, args):
# # """
# /gm - custom gamemode command with extra perms for greater control
# """
# if not is_player(sender):
# msg(sender, "&cDerp! Can't run that from console!")
# return True
# if not checkargs(sender, args, 1, 2):
# return True
# mode = args[0]
# target = args[1]
# if target and not sender.hasPermission("utils.gm.other"):
# msg(sender, "&cYou cannot change the gamemode of another player!")
# else:
# target = sender
# if mode < 0 or mode > 3:
# msg(sender, "&cThat gamemode does not exist!")
# elif sender.hasPermission("utils.gm." % mode):
# runas(server.getConsoleSender(), "gamemode " % mode % " " % target)
# else:
# msg(sender, "&cYou cannot access that gamemode!")
# return True
last_shear = 0.0 last_shear = 0.0
@hook.event("player.PlayerInteractEntityEvent") @hook.event("player.PlayerInteractEntityEvent")
def on_player_entity_interact(event): def on_player_entity_interact(event):
"""
Clicking redstone_sheep with shears will drop redstone + wool
also makes a moo sound for the shearer
"""
global last_shear global last_shear
if not event.isCancelled(): if not event.isCancelled():
shear_time = now() shear_time = now()
@@ -93,12 +117,12 @@ def on_player_entity_interact(event):
sender.playSound(entity.getLocation(), "mob.cow.say", 1, 1) sender.playSound(entity.getLocation(), "mob.cow.say", 1, 1)
#
# /pluginversions - print all plugins + versions; useful when updating plugins
#
@hook.command("pluginversions") @hook.command("pluginversions")
def on_pluginversions_command(sender, args): def on_pluginversions_command(sender, args):
"""
/pluginversions
print all plugins + versions; useful when updating plugins
"""
plugin_header(sender, "Plugin versions") plugin_header(sender, "Plugin versions")
plugins = list(server.getPluginManager().getPlugins()) plugins = list(server.getPluginManager().getPlugins())
plugins.sort(key = lambda pl: pl.getDescription().getName()) plugins.sort(key = lambda pl: pl.getDescription().getName())
@@ -108,21 +132,20 @@ def on_pluginversions_command(sender, args):
return True return True
#
# /echo - essentials echo sucks and prints mail alerts sometimes
#
@hook.command("echo") @hook.command("echo")
def on_echo_command(sender, args): def on_echo_command(sender, args):
"""
/echo
essentials echo sucks and prints mail alerts sometimes
"""
msg(sender, " ".join(args).replace("\\n", "\n")) msg(sender, " ".join(args).replace("\\n", "\n"))
#
# /pyeval - run python ingame
#
# has to be in main.py so we can access the modules
def eval_thread(sender, code): def eval_thread(sender, code):
"""
/pyeval
run python ingame
"""
try: try:
result = eval(code) result = eval(code)
msg(sender, ">>> %s: %s" % (colorify("&3") + type(result).__name__, colorify("&a") + unicode(result) + "\n "), usecolor = False) msg(sender, ">>> %s: %s" % (colorify("&3") + type(result).__name__, colorify("&a") + unicode(result) + "\n "), usecolor = False)
@@ -138,6 +161,10 @@ def eval_thread(sender, code):
@hook.command("pyeval") @hook.command("pyeval")
def on_pyeval_command(sender, args): def on_pyeval_command(sender, args):
"""
/pyeval
run python code ingame
"""
if sender.hasPermission("utils.pyeval"): if sender.hasPermission("utils.pyeval"):
if not checkargs(sender, args, 1, -1): if not checkargs(sender, args, 1, -1):
return True return True
@@ -150,7 +177,22 @@ def on_pyeval_command(sender, args):
@hook.command("modules") @hook.command("modules")
def on_modules_command(sender, args): def on_modules_command(sender, args):
"""
/modules
list all modules, unloaded modules in red
"""
plugin_header(sender, "Modules") plugin_header(sender, "Modules")
for mod in shared["load_modules"]: for mod in shared["load_modules"]:
color = "a" if mod in shared["modules"] else "c" color = "a" if mod in shared["modules"] else "c"
msg(sender, "&" + color + mod) msg(sender, "&" + color + mod)
@hook.event("player.PlayerTeleportEvent")
def on_player_teleport(event):
"""
Disable spectator teleportation
"""
player = event.getPlayer()
if not event.isCancelled() and str(event.getCause()) == "SPECTATE" and not player.hasPermission("utils.tp.spectate"):
event.setCancelled(True)
msg(event.getPlayer(), "&cSpectator teleportation is disabled")
+5
View File
@@ -1,4 +1,9 @@
#pylint: disable = F0401 #pylint: disable = F0401
"""
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 java.lang.reflect.Method import java.lang.reflect.Method
import java.io.File import java.io.File
import java.net.URL import java.net.URL
+4 -2
View File
@@ -1,7 +1,9 @@
#!/usr/bin/python #!/usr/bin/python
# this was going to be a PlotMe-like plugin "plotter" """
# but it seems like PlotMe is still beeing developed, so we don't need our own. *Very basic* start of a custom plot-plugin like PlotMe
on hold because the PlotMe developer continued to develop PlotMe
"""
import sys import sys
+3
View File
@@ -0,0 +1,3 @@
mysql_database = "jdbc:mysql://localhost/database"
mysql_user = "username"
mysql_pass = "secret"
+6
View File
@@ -1,3 +1,9 @@
"""
Code that was used once to create this awesome screenshot
- https://i.imgur.com/v4wg5kl.png
- https://i.imgur.com/tIZ3jmC.png
- https://www.reddit.com/r/Minecraft/comments/28le52/screenshot_of_all_players_that_joined_my_server/
"""
import net.minecraft.server.v1_7_R1.EntityPlayer as EntityPlayer import net.minecraft.server.v1_7_R1.EntityPlayer as EntityPlayer
import net.minecraft.server.v1_7_R1.PacketPlayOutNamedEntitySpawn as PacketPlayOutNamedEntitySpawn import net.minecraft.server.v1_7_R1.PacketPlayOutNamedEntitySpawn as PacketPlayOutNamedEntitySpawn
import net.minecraft.server.v1_7_R1.PlayerInteractManager as PlayerInteractManager import net.minecraft.server.v1_7_R1.PlayerInteractManager as PlayerInteractManager
+3
View File
@@ -1,4 +1,7 @@
#pylint: disable = F0401 #pylint: disable = F0401
"""
A plugin that automatically tiles (stacks) blocks inside a selected region in configurable directions.
"""
import org.bukkit.event.block.BlockPlaceEvent as BlockPlaceEvent import org.bukkit.event.block.BlockPlaceEvent as BlockPlaceEvent
import org.bukkit.event.block.BlockBreakEvent as BlockBreakEvent import org.bukkit.event.block.BlockBreakEvent as BlockBreakEvent
import org.bukkit.event.player.PlayerInteractEvent as PlayerInteractEvent import org.bukkit.event.player.PlayerInteractEvent as PlayerInteractEvent