Archived
Merge branch 'dev'
This commit is contained in:
@@ -0,0 +1 @@
|
||||
If you want to contribute, please [read through the pages on the wiki](https://github.com/RedstonerServer/redstoner-utils/wiki).
|
||||
+21
@@ -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
|
||||
@@ -2,245 +2,8 @@
|
||||
|
||||
Redstoner's custom plugins, written in python.
|
||||
|
||||
------
|
||||
|
||||
# Installation / Set-up
|
||||
## Contributing
|
||||
|
||||
1-line-install-script for bash:
|
||||
`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())
|
||||
```
|
||||
If you want to contribute, please [read through the pages on the wiki](https://github.com/RedstonerServer/redstoner-utils/wiki).
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -31,7 +31,10 @@ def on_dammnspam_command(sender, args):
|
||||
global changing_input
|
||||
|
||||
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):
|
||||
msg(sender, "&cYou can only do this in Creative mode.")
|
||||
@@ -43,8 +46,10 @@ def on_dammnspam_command(sender, args):
|
||||
try:
|
||||
timeout_on = round(float(timeout_on), 2)
|
||||
timeout_off = timeout_on
|
||||
if not 0 <= timeout_on <= 60:
|
||||
msg(sender, "&cThe timeout must be within 0-60.")
|
||||
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.")
|
||||
return True
|
||||
except ValueError:
|
||||
msg(sender, "&cThe timeout must be a number")
|
||||
@@ -57,8 +62,12 @@ def on_dammnspam_command(sender, args):
|
||||
try:
|
||||
timeout_on = round(float(timeout_on), 2)
|
||||
timeout_off = round(float(timeout_off), 2)
|
||||
if not 0 <= timeout_on <= 60 or not 0 <= timeout_off <= 60:
|
||||
msg(sender, "&cThe timeout must be within 0-60.")
|
||||
if 60 >= timeout_on <= -2 or timeout_on == 0:
|
||||
timeout_on = False
|
||||
if 60 >= timeout_off <= -2 or timeout_off == 0:
|
||||
timeout_off = False
|
||||
if timeout_on == False or timeout_off == False:
|
||||
msg(sender, "&cThe timeout must be within 0-60 or -1.")
|
||||
return True
|
||||
except ValueError:
|
||||
msg(sender, "&cThe timeout must be a number")
|
||||
@@ -84,13 +93,9 @@ def on_dammnspam_command(sender, args):
|
||||
# add block to inputs
|
||||
add_input(sender, target, timeout_off, timeout_on)
|
||||
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
|
||||
|
||||
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")
|
||||
def on_block_break(event):
|
||||
@@ -137,7 +142,11 @@ def on_interact(event):
|
||||
data = inputs.get(pos_str)
|
||||
if data:
|
||||
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)
|
||||
plugin_header(sender, "DamnSpam")
|
||||
msg(sender, "&cThis %s has a timeout of %ss." % (btype, checktime))
|
||||
|
||||
+20
-27
@@ -15,14 +15,23 @@ server = bukkit.Bukkit.getServer()
|
||||
|
||||
|
||||
def info(text):
|
||||
"""
|
||||
Log info to console
|
||||
"""
|
||||
server.getLogger().info("[RedstonerUtils] %s" % text)
|
||||
|
||||
|
||||
def warn(text):
|
||||
"""
|
||||
Log warning to console
|
||||
"""
|
||||
server.getLogger().warning("[RedstonerUtils] %s" % text)
|
||||
|
||||
|
||||
def error(text):
|
||||
"""
|
||||
Log error to console
|
||||
"""
|
||||
server.getLogger().severe("[RedstonerUtils] %s" % text)
|
||||
|
||||
|
||||
@@ -90,6 +99,9 @@ def plugin_header(recipient = None, name="Redstoner Utils"):
|
||||
|
||||
|
||||
def noperm(player):
|
||||
"""
|
||||
Send the default permission failure message to the player
|
||||
"""
|
||||
msg(player, "&cno permission")
|
||||
|
||||
|
||||
@@ -129,13 +141,6 @@ def checkargs(sender, args, amin, amax):
|
||||
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):
|
||||
"""
|
||||
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
|
||||
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):
|
||||
@@ -193,27 +198,15 @@ def save_json_file(filename, obj):
|
||||
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)
|
||||
'add' controls if a player should be added(True) or removed(False)
|
||||
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"
|
||||
Toggles presence of a player's UUID in a list
|
||||
If add is given, True explicitely adds it whereas False removes it
|
||||
"""
|
||||
|
||||
pid = uid(player)
|
||||
enabled = pid in ls
|
||||
|
||||
# Do some checks and remove pid.
|
||||
if enabled and add == False:
|
||||
if pid in ls or add == False:
|
||||
ls.remove(pid)
|
||||
msg(player, on)
|
||||
|
||||
# Do some checks and append pid.
|
||||
elif not enabled and add == True:
|
||||
msg(player, "&a%s turned off!" % name)
|
||||
elif add != False:
|
||||
ls.append(pid)
|
||||
msg(player, off)
|
||||
|
||||
# Already on/off (optional)
|
||||
else:
|
||||
msg(player, already % (" ON" if add else " OFF"))
|
||||
msg(player, "&a%s turned on!" % name)
|
||||
@@ -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))
|
||||
@@ -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']
|
||||
|
||||
try:
|
||||
# Library that adds a bunch of re-usable methods which are used in nearly all other modules
|
||||
from helpers import *
|
||||
except:
|
||||
print("[RedstonerUtils] ERROR: Failed to import helpers:")
|
||||
@@ -31,20 +32,43 @@ info("Loading RedstonerUtils...")
|
||||
|
||||
# Import all modules, in this order
|
||||
shared["load_modules"] = [
|
||||
# Collection of tiny utilities
|
||||
"misc",
|
||||
# Adds chat for staff using /ac <text or ,<text>
|
||||
"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",
|
||||
# Adds /report and /rp, Stores reports with time and location
|
||||
"reports",
|
||||
# Adds group-chat with /chatgroup and /cgt to toggle normal chat into group mode
|
||||
"chatgroups",
|
||||
# Adds /token, reads and writes from the database to generate pronouncable (and thus memorable) registration-tokens for the website
|
||||
"webtoken",
|
||||
# Adds /lol, broadcasts random funyy messages. A bit like the splash text in the menu
|
||||
"saylol",
|
||||
# Shows the owner of a skull when right-clicked
|
||||
"skullclick",
|
||||
# Adds /listen, highlights chat and plays a sound when your name was mentioned
|
||||
"mentio",
|
||||
# Adds /cycler, swaps the hotbar with inventory when player changes slot from right->left or left->right
|
||||
"cycle",
|
||||
# Adds /getmotd & /setmotd to update the motd on the fly (no reboot)
|
||||
"motd",
|
||||
# AnswerBot. Hides stupid questions from chat and tells the sender about /faq or the like
|
||||
"abot",
|
||||
# Adds '/forcefield', creates forcefield for players who want it.
|
||||
"forcefield",
|
||||
"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"] = {}
|
||||
for module in shared["load_modules"]:
|
||||
|
||||
@@ -5,12 +5,12 @@ from sys import exc_info
|
||||
import thread
|
||||
import org.bukkit.inventory.ItemStack as ItemStack
|
||||
|
||||
#
|
||||
# Welcome new players
|
||||
#
|
||||
|
||||
@hook.event("player.PlayerJoinEvent", "monitor")
|
||||
def on_join(event):
|
||||
"""
|
||||
Welcome new players
|
||||
"""
|
||||
player = event.getPlayer()
|
||||
|
||||
# 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, " &4Welcome to the Redstoner Server!")
|
||||
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 \n")
|
||||
|
||||
@@ -36,13 +36,12 @@ def on_join(event):
|
||||
player.teleport(player.getWorld().getSpawnLocation())
|
||||
|
||||
|
||||
#
|
||||
# /sudo - execute command/chat *as* a player/console
|
||||
#
|
||||
|
||||
|
||||
@hook.command("sudo")
|
||||
def on_sudo_command(sender, args):
|
||||
"""
|
||||
/sudo
|
||||
execute command/chat *as* a player/console
|
||||
"""
|
||||
if sender.hasPermission("utils.sudo"):
|
||||
plugin_header(sender, "Sudo")
|
||||
if not checkargs(sender, args, 2, -1):
|
||||
@@ -71,14 +70,39 @@ def on_sudo_command(sender, args):
|
||||
return True
|
||||
|
||||
|
||||
#
|
||||
# Clicking redstone_sheep with shears will drop redstone + wool and makes a moo sound
|
||||
#
|
||||
#@hook.command("gm")
|
||||
#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
|
||||
|
||||
@hook.event("player.PlayerInteractEntityEvent")
|
||||
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
|
||||
if not event.isCancelled():
|
||||
shear_time = now()
|
||||
@@ -93,12 +117,12 @@ def on_player_entity_interact(event):
|
||||
sender.playSound(entity.getLocation(), "mob.cow.say", 1, 1)
|
||||
|
||||
|
||||
#
|
||||
# /pluginversions - print all plugins + versions; useful when updating plugins
|
||||
#
|
||||
|
||||
@hook.command("pluginversions")
|
||||
def on_pluginversions_command(sender, args):
|
||||
"""
|
||||
/pluginversions
|
||||
print all plugins + versions; useful when updating plugins
|
||||
"""
|
||||
plugin_header(sender, "Plugin versions")
|
||||
plugins = list(server.getPluginManager().getPlugins())
|
||||
plugins.sort(key = lambda pl: pl.getDescription().getName())
|
||||
@@ -108,21 +132,20 @@ def on_pluginversions_command(sender, args):
|
||||
return True
|
||||
|
||||
|
||||
#
|
||||
# /echo - essentials echo sucks and prints mail alerts sometimes
|
||||
#
|
||||
|
||||
@hook.command("echo")
|
||||
def on_echo_command(sender, args):
|
||||
"""
|
||||
/echo
|
||||
essentials echo sucks and prints mail alerts sometimes
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
/pyeval
|
||||
run python ingame
|
||||
"""
|
||||
try:
|
||||
result = eval(code)
|
||||
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")
|
||||
def on_pyeval_command(sender, args):
|
||||
"""
|
||||
/pyeval
|
||||
run python code ingame
|
||||
"""
|
||||
if sender.hasPermission("utils.pyeval"):
|
||||
if not checkargs(sender, args, 1, -1):
|
||||
return True
|
||||
@@ -150,7 +177,22 @@ def on_pyeval_command(sender, args):
|
||||
|
||||
@hook.command("modules")
|
||||
def on_modules_command(sender, args):
|
||||
"""
|
||||
/modules
|
||||
list all modules, unloaded modules in red
|
||||
"""
|
||||
plugin_header(sender, "Modules")
|
||||
for mod in shared["load_modules"]:
|
||||
color = "a" if mod in shared["modules"] else "c"
|
||||
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")
|
||||
@@ -1,4 +1,9 @@
|
||||
#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.io.File
|
||||
import java.net.URL
|
||||
|
||||
+4
-2
@@ -1,7 +1,9 @@
|
||||
#!/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
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
mysql_database = "jdbc:mysql://localhost/database"
|
||||
mysql_user = "username"
|
||||
mysql_pass = "secret"
|
||||
@@ -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.PacketPlayOutNamedEntitySpawn as PacketPlayOutNamedEntitySpawn
|
||||
import net.minecraft.server.v1_7_R1.PlayerInteractManager as PlayerInteractManager
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
#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.BlockBreakEvent as BlockBreakEvent
|
||||
import org.bukkit.event.player.PlayerInteractEvent as PlayerInteractEvent
|
||||
|
||||
Reference in New Issue
Block a user