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.
|
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())
|
|
||||||
```
|
|
||||||
@@ -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
|
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
@@ -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"))
|
|
||||||
@@ -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']
|
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"]:
|
||||||
|
|||||||
@@ -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")
|
||||||
@@ -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
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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.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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user