Created
May 1, 2013 20:59
-
-
Save kierdavis/5498334 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from mc3p.plugins import MC3Plugin, msghdlr | |
import urllib | |
import urllib2 | |
import StringIO | |
import sys | |
import os | |
import re | |
import time | |
import random | |
import threading | |
import pickle | |
import gzip | |
import nbt | |
import struct | |
WE_LIMIT = 1000 | |
WORLD_SIGNAL_ITEM = 322 # Golden Apple | |
DATA_FILE = os.path.expanduser("~/.grabproxy.pkl") | |
LOG_FILE = os.path.expanduser("~/.grabproxy.log") | |
CHAT_COLOUR = u"c" # c is the colour I'm supposed to have | |
ANNOUNCE_INTERVAL = 15 * 60 | |
BOOST_FORMAT = u"&4&o".replace(u"&", u"\xa7") | |
PREFIX = "&a[&cH@&a]&a" | |
ENTITIES = [ | |
"arrows", | |
"items", | |
#"paintings", | |
"boats", | |
"minecarts", | |
"tnt", | |
"xp", | |
] | |
ADMINS = [ | |
"Niklon9141", # CEO | |
"durrant", # CEO | |
"theF41_1_3N", # vCEO | |
"kierdavis", # H@ | |
"HiddenSentinels", # H@ | |
"mathonftw2", # H@ | |
"sjonsson", # H@ | |
"nate214", # H@ | |
"Stef534", # A | |
"JokerDayz", # A | |
"chloesthename", # A | |
] | |
UNSTEALTHY_COMMANDS = [ | |
"/broadcast", | |
"/bcast", | |
"/me", | |
] | |
CSEQS = { | |
"plotpath": [ | |
"/b d cm", | |
"/b 3", | |
"/vr 35", | |
"/v 5", | |
"/vi 2", | |
], | |
"grass": [ | |
"/b d mm", | |
"/b 3", | |
"/vr 3", | |
"/v 2", | |
], | |
"regenchunk": [ | |
"//chunk", | |
"//regen", | |
], | |
"regenvert2": [ | |
"//hpos2", | |
#"//expand vert", | |
"//expand 10 u", | |
"//expand 100 d", | |
"//regen", | |
"//regen", | |
], | |
} | |
ANNOUNCEMENTS = [ | |
#u"House for sale in S! See the House For Sale post in General Server Discussion!", | |
#u"Last chance to buy my house! Ask kierdavis for info!", | |
#u"If you see entity spam anywhere, let an admin know ASAP!", | |
#u"Merry Christmas All! ~kier" | |
#u"Talented Foreman+ sci-fi builders needed for Project Icarus!", | |
#u"Want to know how to rank up? Read http://www.grabmc.com/ranks", | |
] | |
AUTOCOMPLETES = [ | |
("/prox warp ", lambda self: self.warps.keys()), | |
("/prox delwarp ", lambda self: self.warps.keys()), | |
("/prox plot ", lambda self: self.plots.keys()), | |
("/prox plot del ", lambda self: self.plots.keys()), | |
("/prox note ", lambda self: self.notes.keys()), | |
("/prox delnote ", lambda self: self.notes.keys()), | |
("/prox boost ", lambda self: self.players), | |
("/prox where ", lambda self: self.players), | |
("/prox fall ", lambda self: self.players), | |
("/prox as ", lambda self: self.players), | |
("/prox cseq ", lambda self: CSEQS.keys()), | |
] | |
def remove_formatting(s): | |
return re.sub(u"\xa7.", "", s) | |
class Task(object): | |
def __init__(self, delay, f, *args, **kwds): | |
self.delay = delay | |
self.f = f | |
self.args = args | |
self.kwds = kwds | |
def decrement(self): | |
self.delay -= 1 | |
if self.delay <= 0: | |
return True | |
return False | |
def __call__(self): | |
return self.f(*self.args, **self.kwds) | |
class TaskManager(object): | |
def __init__(self): | |
self.lock = threading.Lock() | |
self.tasks = {} | |
self.next_id = 1 | |
def add(self, task): | |
self.lock.acquire() | |
key = self.next_id | |
self.next_id += 1 | |
self.tasks[key] = task | |
self.lock.release() | |
return key | |
def get(self, key): | |
self.lock.acquire() | |
task = self.tasks[key] | |
self.lock.release() | |
return task | |
def remove(self, key): | |
self.lock.acquire() | |
del self.tasks[key] | |
self.lock.release() | |
def getall(self): | |
self.lock.acquire() | |
tasks = dict(self.tasks) | |
self.lock.release() | |
return tasks | |
class Plugin(MC3Plugin): | |
def init(self, args): | |
self.ready = False | |
self.tasks = TaskManager() | |
self.data = {} | |
self.stop_repeating = False | |
self.plot_id = None | |
self.selection = None | |
self.players = [] | |
self.display_names = {} | |
self.player_worlds = {} | |
self.awaiting_response = None | |
self.ss_client = None | |
self.timelock = "day" | |
self.player_prefixes = {} | |
self.pos = (0, 0, 0) | |
self.held_item = 0 | |
self.tpall = [] | |
self.tpall_num = 0 | |
self.replies = {} | |
self.stealth = False | |
self.reload_time = None | |
self.keepalive_time = time.time() | |
self.keepalive_intervals = [] | |
self.keepalive_request = time.time() | |
self.keepalive_responses = [] | |
self.join_hooks = {} | |
self.quit_hooks = {} | |
self.ping_time = None | |
self.boosted = [] | |
self.vanished = False | |
self.tpa = False | |
self.bindings = {} | |
self.ofilters = [] | |
self.ifilters = [] | |
for name in dir(self): | |
if name.startswith("outgoing_"): | |
self.ofilters.append(getattr(self, name)) | |
elif name.startswith("incoming_"): | |
self.ifilters.append(getattr(self, name)) | |
if os.path.exists(DATA_FILE): | |
f = open(DATA_FILE, "rb") | |
self.data = pickle.load(f) | |
f.close() | |
self.logfile = open(LOG_FILE, "a") | |
self.log("----", "--------Login--------") | |
if len(ANNOUNCEMENTS) > 0: | |
self.tasks.add(Task(2 * ANNOUNCE_INTERVAL, self.announce, 0)) | |
def announce(self, i): | |
self.send_to_server(u"/bcast " + ANNOUNCEMENTS[i]) | |
i = (i + 1) % len(ANNOUNCEMENTS) | |
self.tasks.add(Task(2 * ANNOUNCE_INTERVAL, self.announce, i)) | |
def destroy(self): | |
self.save_data() | |
self.logfile.close() | |
def save_data(self): | |
f = open(DATA_FILE, "wb") | |
pickle.dump(self.data, f) | |
f.close() | |
@property | |
def selections(self): | |
return self.data.setdefault("selections", {}) | |
@property | |
def books(self): | |
return self.data.setdefault("books", []) | |
@property | |
def plots(self): | |
return self.data.setdefault("plots", {}) | |
@property | |
def warps(self): | |
return self.data.setdefault("warps", {}) | |
@property | |
def mls(self): | |
return self.data.setdefault("mls", {}) | |
@property | |
def mail_queue(self): | |
return self.data.setdefault("mail_queue", []) | |
@property | |
def ml_cache(self): | |
return self.data.setdefault("ml_cache", []) | |
@property | |
def notes(self): | |
return self.data.setdefault("notes", {}) | |
@property | |
def autoevac(self): | |
return self.data.setdefault("autoevac", True) | |
@autoevac.setter | |
def autoevac(self, v): | |
self.data["autoevac"] = v | |
def page(self, items, args, title): | |
items = list(items) | |
if len(items) == 0: | |
self.send_notification(u"%s: No data" % title) | |
return [] | |
items = list(items) | |
page_num = 1 | |
items_per_page = 10 | |
if len(args) > 0: | |
try: | |
page_num = int(args[0]) | |
except ValueError: | |
pass | |
start = (page_num - 1) * items_per_page | |
end = start + items_per_page | |
if start < 0 or start >= len(items): | |
self.send_notification(u"Error: page number out of range") | |
return [] | |
total_pages = (len(items) + items_per_page - 1) / items_per_page | |
self.send_notification("%s (page %d/%d):" % (title, page_num, total_pages)) | |
return items[start:end] | |
@msghdlr(0x00) | |
def handle00(self, msg, source): | |
if source == "client": | |
tasks = self.tasks.getall() | |
if len(tasks): | |
for key, task in tasks.iteritems(): | |
if task.decrement(): | |
self.tasks.remove(key) | |
task() | |
if len(self.mail_queue): | |
player, message = self.mail_queue.pop(0) | |
prefix = u"/mail send %s " % player | |
maxlen = 100 - len(prefix) | |
while len(message): | |
part, message = message[:maxlen], message[maxlen:] | |
self.send_to_server(prefix + part) | |
if len(self.mail_queue) == 0: | |
self.send_to_server("/ GCPROXY: Mail queue empty!") | |
t = time.time() | |
self.keepalive_intervals.append(t - self.keepalive_time) | |
self.keepalive_responses.append(t - self.keepalive_request) | |
self.keepalive_intervals = self.keepalive_intervals[-20:] | |
self.keepalive_responses = self.keepalive_responses[-20:] | |
self.keepalive_time = t | |
else: | |
self.keepalive_request = time.time() | |
return True | |
@msghdlr(0x03) | |
def handle03(self, msg, source): | |
s = msg["chat_msg"] | |
if source == "client": | |
if self.awaiting_response is not None: | |
f = self.awaiting_response | |
self.awaiting_response = None | |
f(s) | |
return False | |
else: | |
s = self.process_outgoing(s) | |
if s is None: | |
return False | |
else: | |
formatted = s | |
unformatted = remove_formatting(s) | |
for f in self.ifilters: | |
s = f(s, unformatted) | |
if s is None: | |
return False | |
elif s != formatted: | |
formatted = s | |
unformatted = remove_formatting(s) | |
msg["chat_msg"] = s | |
return True | |
def process_outgoing(self, s): | |
for f in self.ofilters: | |
s = f(s) | |
if s is None: | |
return None | |
return s | |
@msghdlr(0x04) | |
def handle04(self, msg, source): | |
t = msg["day_time"] % 24000 | |
if self.timelock == "day" and t >= 12000: | |
self.send_notification(u"Time is %d, setting to day" % t) | |
self.send_to_server(u"/time day") | |
if self.timelock == "night" and t < 12000: | |
self.send_notification(u"Time is %d, setting to night" % t) | |
self.send_to_server(u"/time night") | |
return True | |
@msghdlr(0x0B) | |
def handle0B(self, msg, source): | |
self.pos = int(msg["x"]), int(msg["y"]), int(msg["z"]) | |
return True | |
@msghdlr(0x0D) | |
def handle0D(self, msg, source): | |
self.pos = int(msg["x"]), int(msg["y"]), int(msg["z"]) | |
if source == "server" and not self.ready: | |
self.ready = True | |
self.tasks.add(Task(3, self.on_ready)) | |
return True | |
@msghdlr(0x0F) | |
def handle0F(self, msg, source): | |
if msg["dir"] == -1: | |
item = msg["details"]["item_id"] | |
if item in self.bindings: | |
self.send_to_server(self.process_outgoing(self.bindings[item])) | |
return False | |
return True | |
@msghdlr(0x10) | |
def handle10(self, msg, source): | |
self.held_item = msg["slot_id"] | |
return True | |
@msghdlr(0x46) | |
def handle46(self, msg, source): | |
if self.timelock is not None and msg["reason"] == 1: | |
self.send_notification(u"Rain started, setting to sun") | |
self.send_to_server(u"/weather sun") | |
return True | |
@msghdlr(0x67) | |
def handle67(self, msg, source): | |
if msg["slot_update"] is not None: | |
if msg["slot_update"]["item_id"] == 387: | |
data = msg["slot_update"]["nbt_data"] | |
f = gzip.GzipFile(fileobj=StringIO.StringIO(data)) | |
tag = nbt.Tag.read(f) | |
f.close() | |
if "title" in tag.value and "author" in tag.value and "pages" in tag.value: | |
title = tag["title"].value | |
author = tag["author"].value | |
pages = [page.value for page in tag["pages"].value[1]] | |
key = author + ":" + re.sub(r"[^a-zA-Z0-9]+", "-", title) | |
for (k, _, _, p) in self.books: | |
if k == key and p == pages: | |
break | |
else: | |
self.send_notification("Book %s by %s added to index (id %d)" % (title, author, len(self.books))) | |
self.books.append((key, title, author, pages)) | |
return True | |
@msghdlr(0xC9) | |
def handleC9(self, msg, source): | |
name = re.sub(r"\[.+?\]", "", remove_formatting(msg["name"])) | |
for n in ADMINS: | |
if n.lower().startswith(name.lower()): | |
name = n | |
break | |
if msg["online"] and name not in self.players: | |
self.players.append(name) | |
elif not msg["online"] and name in self.players: | |
self.players.remove(name) | |
self.display_names[name] = msg["name"] | |
#print msg, name | |
#print self.players | |
#print "-----" | |
return True | |
@msghdlr(0xCB) | |
def handleCB(self, msg, source): | |
if source == "client": | |
text = msg["text"] | |
matches = [] | |
for prefix, lister in AUTOCOMPLETES: | |
if text.startswith(prefix): | |
l = lister(self) | |
word = text[len(prefix):] | |
for x in l: | |
if x.startswith(word): | |
matches.append(x) | |
break | |
else: | |
return True | |
response = u"\x00".join(map(unicode, matches)) | |
self.to_client({"msgtype": 0xCB, "text": response}) | |
return False | |
return True | |
#@msghdlr(0xFE) | |
#def handleFE(self, msg, source): | |
# self.server_list_ping = True | |
# return True | |
# | |
#@msghdlr(0xFF) | |
#def handleFF(self, msg, source): | |
# if source == "server" and self.server_list_ping: | |
# self.server_list_ping = False | |
# | |
# fields = msg["reason"].split("\x00") | |
# fields[2] = u"\xa71GrabCraft via GCProxy" | |
# msg["reason"] = "\x00".join(fields) | |
# | |
# return True | |
def incoming_socialspy(self, msg, unformatted): | |
m = re.match(r"([a-zA-Z0-9_]+)( ?): (/(?:r|reply) .*|/(?:msg|tell|m|whisper) [a-zA-Z0-9_]+ .*)", unformatted) | |
if m is not None: | |
src = m.group(1) | |
space = m.group(2) | |
words = m.group(3).split() | |
if not space: | |
return None | |
if words[0] in (u"/r", u"/reply"): | |
dest = "(replying)" | |
s = u" ".join(words[1:]) | |
else: | |
dest = words[1] | |
s = u" ".join(words[2:]) | |
if src == "kierdavis" or (dest.lower() in "kierdavis" and not self.vanished): | |
return None | |
else: | |
msg = u"\xa78[\xa77%s\xa78 -> \xa77%s\xa78]\xa7r %s" % (src, dest, s) | |
return msg | |
def incoming_filter_time_commands(self, msg, unformatted): | |
return None if msg.startswith(u"\xa75[Server]") else msg | |
def incoming_selection_info(self, msg, unformatted): | |
m = re.match(u"\xa7dPosition ([12]): \\(([-.0-9]+), ([-.0-9]+), ([-.0-9]+)\\)", msg) | |
if m is not None: | |
point, x, y, z = tuple(map(int, map(float, m.groups()))) | |
if self.selection is None: | |
a = b = (0, 0, 0) | |
else: | |
a, b = self.selection | |
if point == 1: | |
a = (x, y, z) | |
else: | |
b = (x, y, z) | |
self.selection = (a, b) | |
return msg | |
def incoming_plot_id(self, msg, unformatted): | |
if unformatted.startswith("Plot id: "): | |
self.plot_id = unformatted[len("Plot id: "):] | |
return msg | |
def incoming_norandom(self, msg, unformatted): | |
return msg.replace(u"\xa7k", u"") | |
def incoming_chat(self, msg, unformatted): | |
m = re.match(r"\[([a-zA-Z0-9_]+?)\](.+?)([a-zA-Z0-9_]+?) : (.*?)\.", unformatted) | |
if m is not None: | |
world, tags, player, chat = m.groups() | |
tags = tags.strip() | |
self.player_worlds[player.lower()] = world | |
if self.autoevac: | |
if tags in ("[New]", "[Member]") and world in ("C2", "C3", "C4"): | |
self.send_notification("Automatically evacuating %s from %s" % (player, world)) | |
self.send_to_server(u"/mv tp %s H" % player) | |
if player.lower() in self.boosted: | |
p = msg.index(chat) | |
msg = msg[:p] + BOOST_FORMAT + msg[p:] | |
#print >> sys.stderr, `msg` | |
p = msg.index(u"\xa76 : ") | |
msg = msg[:p] + u"\xa76" + remove_formatting(msg[p:]) | |
#self.player_prefixes[player.lower()] = msg[:p].replace(u"\xa7", u"&") | |
self.log("CHAT", "%s: %s", player, chat) | |
return msg | |
def incoming_welcome(self, msg, unformatted): | |
if unformatted.startswith(u"Welcome to Grabcraft, "): | |
name = unformatted[len(u"Welcome to Grabcraft, "):-1] | |
self.tasks.add(Task(2, self.send_to_server, self.rainbow(u"Welcome, %s!" % name))) | |
#if "theF41_1_3N" in self.players: | |
#self.tasks.add(Task(4, self.send_to_server, u"/fsay theF41_1_3N Welcome %s!" % name)) | |
#if "sjonsson" in self.players: | |
#self.tasks.add(Task(7, self.send_to_server, u"/fsay sjonsson welcome %s" % name)) | |
return msg | |
def trigger_hooks(self, hooks, player): | |
player = player.lower() | |
if player in hooks: | |
for hook in hooks[player]: | |
self.send_to_server(hook) | |
del hooks[player] | |
def incoming_hooks(self, msg, unformatted): | |
m = re.match(r"\*\* ([a-zA-Z0-9_]+) (joined|left) the Game!", unformatted) | |
if m is not None: | |
player = m.group(1) | |
if m.group(2) == "joined": | |
self.log("JOIN", player) | |
self.trigger_hooks(self.join_hooks, player) | |
elif m.group(2) == "left": | |
self.log("QUIT", player) | |
self.trigger_hooks(self.quit_hooks, player) | |
return msg | |
m = re.match(r"([a-zA-Z0-9_]+) left the game.", unformatted) | |
if m is not None: | |
self.log("QUIT", m.group(1)) | |
self.trigger_hooks(self.quit_hooks, m.group(1)) | |
return msg | |
#def is_fc_duration(self, s): | |
# return s == "perma" or re.match(r"(\d+[smhdw])+", s) | |
# | |
#def outgoing_fc_bans(self, msg): | |
# if msg.startswith((u"/ban ", u"/mute ", u"/freeze ")): | |
# words = msg.split() | |
# if words[1] in (u"remove", u"check"): | |
# return msg | |
# | |
# index = words[1] == u"ip" and 3 or 2 | |
# | |
# if not self.is_fc_duration(words[index]): | |
# words.insert(index, u"perma") | |
# msg = u" ".join(words) | |
# | |
# return msg | |
def outgoing_vanish(self, msg): | |
if msg == u"/vanish": | |
self.vanished = not self.vanished | |
return msg | |
def obfuscate_player(self, s): | |
for player in self.players: | |
if s.lower() in player.lower(): | |
s = player | |
break | |
if len(s) > 4: | |
p = random.randrange(len(s) - 3) | |
s = s[p:p+4] | |
return s.lower() | |
def outgoing_plotme_rewrite(self, msg): | |
if msg.startswith(u"/p ") or msg == u"/p": | |
msg = u"/plotme" + msg[2:] | |
elif msg.startswith(u"/vsp ") or msg == u"/vsp": | |
msg = u"/p" + msg[4:] | |
if msg in ["/plotme auto", "/plot auto", "/plotme claim", "/plot claim"]: | |
self.send_notification(u"\xa74Don't forget to /prox plot add!") | |
return msg | |
def incoming_pong(self, msg, unformatted): | |
if msg == "_gcproxy_reload_": | |
t = time.time() - self.reload_time | |
self.send_to_server(u"/bcast Reload complete in approx. %.1f seconds" % t) | |
self.send_notification(u"Reload complete") | |
self.tasks.add(Task(3, self.on_ready)) | |
elif msg == "_gcproxy_stat_": | |
t = time.time() - self.ping_time | |
self.send_notification(u"Ping (network): %.3fs" % t) | |
else: | |
return msg | |
#def outgoing_sudo(self, msg): | |
# if msg.startswith(u"/sudo "): | |
# words = msg.split() | |
# msg = u"/fsay %s /%s" % (words[1], u" ".join(words[2:])) | |
# | |
# return msg | |
def outgoing_tp(self, msg): | |
if msg.startswith((u"/tp ")) and not self.vanished: | |
self.send_to_server(u"/vanish") | |
self.tasks.add(Task(2, self.send_to_server, msg)) | |
self.tasks.add(Task(5, self.send_to_server, u"/vanish")) | |
return None | |
return msg | |
def outgoing_cso(self, msg): | |
if msg.startswith(u"/cso "): | |
player = msg[5:] | |
msg = u"/sudo %s commandspy on" % player | |
#msg = u"/fsay %s /commandspy on" % player | |
return msg | |
def outgoing_evac(self, msg): | |
if msg.startswith(u"/evac "): | |
msg = u"/mv tp " + msg[6:] + " H" | |
return msg | |
#def incoming_reload(self, msg, unformatted): | |
# if re.match(r"[a-zA-Z0-9_]+: /reload", unformatted): | |
# self.send_to_server(u"/ping _gcproxy_reload_") | |
# self.reload_time = time.time() | |
# self.send_notification(u"Reload started") | |
# | |
# return msg | |
def incoming_commandspy(self, msg, unformatted): | |
m = re.match("(?:\\[WorldEdit\\]\\[(\d+) blocks\\])?([a-zA-Z0-9_]+): (.+)$", unformatted) | |
if m is not None: | |
num_blocks, player, command = m.groups() | |
self.log("CMD", "%s: %s", player, command) | |
return msg | |
def outgoing_proxy_control(self, msg): | |
words = msg.split(" ") | |
if words[0] == u"/fs": | |
self.send_to_server(u"/f c f") | |
self.tasks.add(Task(1, self.send_to_server, msg[4:])) | |
self.tasks.add(Task(2, self.send_to_server, u"/f c p")) | |
return None | |
elif words[0] == u"/as": | |
self.send_to_server(u"/f c a") | |
self.tasks.add(Task(1, self.send_to_server, msg[4:])) | |
self.tasks.add(Task(2, self.send_to_server, u"/f c p")) | |
return None | |
elif words[0] == u"/prox": | |
if len(words) < 2: | |
self.send_notification(u"Usage:") | |
self.send_notification(u" /prox save - Save config") | |
self.send_notification(u" /prox bcast <name> <message> - Broadcast") | |
self.send_notification(u" /prox name <name>|off - Disguise as a n00b") | |
self.send_notification(u" /prox fakejoin [<player>] - Fake join a player (defaulting to yourself)") | |
self.send_notification(u" /prox fakequit [<player>] - Fake quit a player (defaulting to yourself)") | |
self.send_notification(u" /prox fakeafkon [<player>] - Fake start AFK a player (defaulting to yourself)") | |
self.send_notification(u" /prox fakeafkoff [<player>] - Fake end AFK a player (defaulting to yourself)") | |
self.send_notification(u" /prox autoevac - Toggle autoevac") | |
self.send_notification(u" /prox stat - Stats") | |
self.send_notification(u" /prox bind <itemID> <command> - Binds an item to a command") | |
self.send_notification(u" /prox unbind <itemID> - Unbinds an item") | |
self.send_notification(u" /prox bindings [<page>] - Lists bindings") | |
self.send_notification(u" /prox tpa - Toggle auto-tpaccept (default: on)") | |
self.send_notification(u" /prox stealth - Toggle stealth mode") | |
self.send_notification(u" /prox boost <nickname> - Toggle a player's chat being boosted") | |
self.send_notification(u" /prox cseq <name> - Run a cseq") | |
self.send_notification(u" /prox repeat <command> - Repeats a command") | |
self.send_notification(u" /prox repeati <interval> <command> - Repeats a command with a specified interval") | |
self.send_notification(u" /prox norepeat - Stops repeating commands") | |
self.send_notification(u" /prox admins - Broadcasts list of online admins") | |
self.send_notification(u" /prox say - Fakes a /say command") | |
self.send_notification(u" /prox where <player> - Reports which world a player was last seen in") | |
self.send_notification(u" /prox cleanlag - Cleans up entities") | |
self.send_notification(u" /prox timelock [<day|night|off>] - Change timelock") | |
self.send_notification(u" /prox setwarp <name> - Set a warp") | |
self.send_notification(u" /prox delwarp <name> - Delete a warp") | |
self.send_notification(u" /prox warp <name> - Go to a warp") | |
self.send_notification(u" /prox warps [<page>] - List warps") | |
self.send_notification(u" /prox tpall [reset] - Teleport through all players") | |
self.send_notification(u" /prox fall <player> - Make a flying player fall") | |
self.send_notification(u" /prox addhook <j|q> <player> <command> - Add a hook") | |
self.send_notification(u" /prox hooks <j|q> <player> [<page>] - List hooks") | |
self.send_notification(u" /prox marry <player1> <player2> - Make 2 players marry") | |
self.send_notification(u" /prox note [<name>] [<message>] - Record a note") | |
self.send_notification(u" /prox delnote <name> - Delete a note") | |
self.send_notification(u" /prox book - Book stuff") | |
self.send_notification(u" /prox sel - Selection stuff") | |
self.send_notification(u" /prox plot - Plot stuff") | |
self.send_notification(u" /prox ml - Mailing list stuff") | |
elif words[1] == u"save": | |
self.save_data() | |
self.send_notification(u"Data saved.") | |
elif words[1] == u"bcast": | |
name = words[2] | |
message = u" ".join(words[3:]) | |
return u"/af announce &6[&4%s&6] &a%s" % (name, message) | |
elif words[1] == u"name": | |
if words[2] == u"off": | |
self.send_to_server(u"/pex user kierdavis prefix %s" % PREFIX) | |
self.send_to_server(u"/pex user kierdavis suffix &c") | |
self.send_to_server(u"/nick off") | |
else: | |
self.send_to_server(u"/pex user kierdavis prefix &7") | |
self.send_to_server(u"/pex user kierdavis suffix &6") | |
self.send_to_server(u"/nick %s" % words[2]) | |
elif words[1] == u"fakejoin": | |
player = u"kierdavis" | |
if len(words) > 2: | |
player = words[2] | |
self.send_to_server(u"/af announce &b[STAB]&e [%s&e] has joined." % player) | |
elif words[1] == u"fakequit": | |
player = u"kierdavis" | |
if len(words) > 2: | |
player = words[2] | |
self.send_to_server(u"/af announce &b[STAB]&e [%s&e] has quit." % player) | |
elif words[1] == u"fakeafkon": | |
player = u"kierdavis" | |
if len(words) > 2: | |
player = words[2] | |
self.send_to_server(u"/af announce &5%s&5 is now AFK" % player) | |
elif words[1] == u"fakeafkoff": | |
player = u"kierdavis" | |
if len(words) > 2: | |
player = words[2] | |
self.send_to_server(u"/af announce &5%s&5 is no longer AFK" % player) | |
elif words[1] == u"autoevac": | |
self.autoevac = not self.autoevac | |
if self.autoevac: | |
self.send_notification(u"Autoevac enabled") | |
else: | |
self.send_notification(u"Autoevac disabled") | |
elif words[1] == u"tpa": | |
self.tpa = not self.tpa | |
if self.tpa: | |
self.send_notification(u"Auto-tpaccept enabled") | |
else: | |
self.send_notification(u"Auto-tpaccept disabled") | |
elif words[1] == u"stat": | |
if len(self.keepalive_intervals) > 0: | |
kai = sum(self.keepalive_intervals) / len(self.keepalive_intervals) | |
self.send_notification(u"KAI (server): %.3fs (%d samples)" % (kai, len(self.keepalive_intervals))) | |
else: | |
self.send_notification(u"KAI (server): No data") | |
if len(self.keepalive_responses) > 0: | |
resptime = sum(self.keepalive_responses) / len(self.keepalive_responses) | |
self.send_notification(u"Response time (client): %.1fms (%d samples)" % (resptime * 1000.0, len(self.keepalive_intervals))) | |
else: | |
self.send_notification(u"Response time (client): No data") | |
self.ping_time = time.time() | |
self.send_to_server(u"/ping _gcproxy_stat_") | |
elif words[1] == u"bind": | |
if len(words) < 4: | |
self.send_notification(u"Usage: /prox bind <itemID> [<page>]") | |
else: | |
if words[2] == "hand": | |
self.send_notification(u"Binding hand item is not implemented yet!") | |
else: | |
id = int(words[2]) | |
command = " ".join(words[3:]) | |
self.bindings[id] = command | |
self.send_notification(u"Command bound!") | |
elif words[1] == u"unbind": | |
if len(words) < 3: | |
self.send_notification(u"Usage: /prox unbind <itemID>") | |
else: | |
id = int(words[2]) | |
if id in self.bindings: | |
del self.bindings[id] | |
self.send_notification(u"Command unbound!") | |
else: | |
self.send_notification("That item ID is not bound!") | |
elif words[1] == u"bindings": | |
for id, command in self.page(self.bindings.items(), words[2:], "Bindings"): | |
self.send_notification(" %d: %s" % (id, command)) | |
elif words[1] == u"stealth": | |
self.stealth = not self.stealth | |
if self.stealth: | |
self.send_notification(u"Stealth on") | |
else: | |
self.send_notification(u"Stealth off") | |
elif words[1] == u"boost": | |
if len(words) < 3: | |
self.send_notification(u"Usage: /prox boost <nickname>") | |
else: | |
player = words[2].lower() | |
if player in self.boosted: | |
self.boosted.remove(player) | |
self.send_notification(u"%s's chat is no longer boosted" % player) | |
else: | |
self.boosted.append(player) | |
self.send_notification(u"%s's chat is now boosted" % player) | |
elif words[1] == u"cseq": | |
if len(words) < 3: | |
self.send_notification(u"Usage: /prox cseq <name>") | |
else: | |
name = words[2] | |
if name in CSEQS: | |
for cmd in CSEQS[name]: | |
self.send_to_server(cmd) | |
else: | |
self.send_notification(u"Invalid cseq") | |
elif words[1] == u"repeat": | |
command = " ".join(words[2:]) | |
self.tasks.add(Task(3, self.repeat, 1, command)) | |
elif words[1] == u"repeati": | |
interval = int(words[2]) | |
command = " ".join(words[3:]) | |
self.tasks.add(Task(interval + 2, self.repeat, interval, command)) | |
elif words[1] == u"norepeat": | |
self.stop_repeating = True | |
elif words[1] == u"admins": | |
admins = [x for x in self.players if x in ADMINS] | |
if len(admins): | |
self.send_to_server(u"/bcast Admins online: %s" % ", ".join(admins)) | |
else: | |
self.send_to_server(u"/bcast Admins online: none") | |
elif words[1] == u"say": | |
self.send_to_server(u"&d [Server] " + " ".join(words[2:])) | |
#elif words[1] == u"as": | |
# player = words[2].lower() | |
# prefix = u"&b. " + self.player_prefixes[player] | |
# textlen = 98 - len(prefix) | |
# | |
# msg = " ".join(words[3:]) | |
# while len(msg) > 0: | |
# s = msg[:textlen] | |
# msg = msg[textlen:] | |
# | |
# self.send_to_server(prefix + s) | |
elif words[1] == u"where": | |
player = words[2].lower() | |
if player in self.player_worlds: | |
self.send_notification(u"%s was last seen in %s" % (player, self.player_worlds[player])) | |
else: | |
self.send_notification(u"No data for %s" % player) | |
elif words[1] == u"cleanlag": | |
for entity in ENTITIES: | |
self.send_to_server(u"/remove %s 100000" % entity) | |
elif words[1] == u"timelock": | |
if len(words) < 3: | |
if self.timelock is None: | |
words.append("day") | |
else: | |
words.append("off") | |
if words[2] == "day": | |
self.timelock = "day" | |
self.send_notification(u"Time locked to day") | |
elif words[2] == "night": | |
self.timelock = "night" | |
self.send_notification(u"Time locked to night") | |
elif words[2] == "off": | |
self.timelock = None | |
self.send_notification(u"Timelock disabled") | |
else: | |
self.send_notification(u"Usage: /prox timelock [<day|night|off>]") | |
elif words[1] == u"setwarp": | |
if len(words) < 3: | |
self.send_notification(u"Usage: /prox setwarp <name>") | |
else: | |
name = words[2] | |
self.warps[name] = self.pos | |
self.send_notification(u"Warp '%s' set at (%d, %d, %d)" % ((name,) + self.pos)) | |
elif words[1] == u"delwarp": | |
if len(words) < 3: | |
self.send_notification(u"Usage: /prox delwarp <name>") | |
else: | |
name = words[2] | |
if name in self.warps: | |
del self.warps[name] | |
self.send_notification(u"Warp '%s' deleted" % name) | |
else: | |
self.send_notification(u"Warp '%s' not found" % name) | |
elif words[1] == u"warp": | |
if len(words) < 3: | |
self.send_notification(u"Usage: /prox warp <name>") | |
else: | |
name = words[2] | |
if name in self.warps: | |
pos = self.warps[name] | |
self.send_to_server(u"/tppos %d %d %d" % pos) | |
else: | |
self.send_notification(u"Warp '%s' not found" % name) | |
elif words[1] == u"warps": | |
warps = self.warps.items() | |
warps.sort() | |
for name, pos in self.page(warps, words[2:], "Warps"): | |
self.send_notification(u" %s (%d, %d, %d)" % ((name,) + pos)) | |
elif words[1] == u"tpall": | |
if len(self.tpall) == 0 or words[2:] == ["reset"]: | |
self.tpall = list(self.players) | |
self.tpall_num = len(self.tpall) | |
self.send_notification(u"Reset tpall with %d players" % self.tpall_num) | |
player = self.tpall.pop(0) | |
num = self.tpall_num - len(self.tpall) | |
self.send_notification(u"Player %d of %d: %s" % (num, self.tpall_num, player)) | |
self.send_to_server(u"/tpo %s" % player) | |
elif words[1] == u"fall": | |
player = words[2] | |
self.send_to_server(u"/gamemode 0 %s" % player) | |
self.send_to_server(u"/gamemode 1 %s" % player) | |
elif words[1] == u"addhook": | |
if len(words) < 5: | |
self.send_notification(u"Usage: /prox addhook <j|q> <player> <command>") | |
return None | |
if words[2] == u"j": | |
hooks = self.join_hooks | |
elif words[2] == u"q": | |
hooks = self.quit_hooks | |
else: | |
self.send_notification(u"Usage: /prox addhook <j|q> <player> <command>") | |
return None | |
player = words[3].lower() | |
command = u" ".join(words[4:]) | |
hooks.setdefault(player, []).append(command) | |
self.send_notification(u"Hook added to player %s" % player) | |
elif words[1] == u"hooks": | |
if len(words) < 4: | |
self.send_notification(u"Usage: /prox hooks <j|q> <player> [<page>]") | |
return None | |
if words[2] == u"j": | |
hooks = self.join_hooks | |
s = "Join" | |
elif words[2] == u"q": | |
hooks = self.quit_hooks | |
s = "Quit" | |
else: | |
self.send_notification(u"Usage: /prox hooks <j|q> <player> [<page>]") | |
return None | |
player = words[3].lower() | |
hooks = hooks.get(player, []) | |
for i, hook in self.page(enumerate(hooks), words[3:], u"%s hooks for %s" % (s, player)): | |
self.send_notification("%d) %s" % (i, hook)) | |
elif words[1] == u"marry": | |
if len(words) < 4: | |
self.send_notification(u"Usage: /prox marry <player1> <player2>") | |
else: | |
player1 = words[2] | |
player2 = words[3] | |
self.send_to_server(u"/fsay %s /marry %s" % (player1, player2)) | |
self.send_to_server(u"/fsay %s /marry accept" % (player2)) | |
elif words[1] == u"note": | |
if len(words) < 3: | |
for name, message in self.page(sorted(self.notes.items()), words[2:], "Notes"): | |
self.send_notification(u" %s" % name) | |
elif len(words) < 4: | |
name = words[2] | |
if name in self.notes: | |
self.send_notification(u"%s: %s" % (name, self.notes[name])) | |
else: | |
self.send_notification(u"No note named '%s'!" % name) | |
else: | |
name = words[2] | |
message = u" ".join(words[3:]) | |
self.notes[name] = message | |
self.send_notification(u"Note '%s' saved!" % name) | |
elif words[1] == u"delnote": | |
if len(words) < 3: | |
self.send_notification(u"Usage: /prox delnote <name>") | |
else: | |
name = words[2] | |
if name in self.notes: | |
del self.notes[name] | |
self.send_notification(u"Note '%s' deleted!" % name) | |
else: | |
self.send_notification(u"No note named '%s'!" % name) | |
elif words[1] == u"book": | |
if len(words) < 3: | |
self.send_notification(u"Usage:") | |
self.send_notification(u" /prox book list [<page>] - List books") | |
self.send_notification(u" /prox book read <book> [<page>] - Read a book") | |
elif words[2] == u"list": | |
for i, (_, title, author, pages) in self.page(enumerate(self.books), words[3:], "Books"): | |
self.send_notification(u" %d: %s by %s (%d pages)" % (i, title, author, len(pages))) | |
elif words[2] == u"read": | |
try: | |
booknum = int(words[3]) | |
except (IndexError, ValueError): | |
self.send_notification(u"Invalid book number.") | |
return None | |
pagenum = 1 | |
if len(words) > 4: | |
try: | |
pagenum = int(words[4]) | |
except (IndexError, ValueError): | |
self.send_notification(u"Invalid page number.") | |
return None | |
(key, title, author, pages) = self.books[booknum] | |
if pagenum < 1 or pagenum > len(pages): | |
self.send_notification(u"Page number out of range.") | |
return None | |
page = pages[pagenum - 1] | |
self.send_notification(u"Page %d of %d" % (pagenum, len(pages))) | |
self.send_notification(page) | |
elif words[2] == u"gen": | |
try: | |
booknum = int(words[3]) | |
except (IndexError, ValueError): | |
self.send_notification(u"Invalid page number.") | |
return None | |
(key, title, author, pages) = self.books[booknum] | |
page_tags = [] | |
for page in pages: | |
page_tag = nbt.StringTag("") | |
page_tag.value = page | |
page_tags.append(page_tag) | |
if len(pages) == 0 or not pages[-1].startswith("Generated by GCProxy"): | |
note_tag = nbt.StringTag("") | |
note_tag.value = "Generated by GCProxy\nOriginally by %s\n" % author | |
page_tags.append(note_tag) | |
pages_tag = nbt.ListTag("pages") | |
pages_tag.value = (nbt.StringTag, page_tags) | |
tag = nbt.CompoundTag("") | |
tag.value = {} | |
tag.value["pages"] = pages_tag | |
buf = StringIO.StringIO() | |
g = gzip.GzipFile(mode="wb", fileobj=buf) | |
tag.write(g) | |
g.close() | |
data = buf.getvalue() | |
self.to_server({ | |
"msgtype": 0xFA, | |
"channel": u"MC|BEdit", | |
"data": struct.pack(">HBHH", 386, 1, 0, len(data)) + data, | |
}) | |
#self.to_client({ | |
# "msgtype": 0x67, | |
# "window_id": 0, | |
# "slot": self.held_item + 36, | |
# "slot_update": { | |
# "item_id": 386, | |
# "count": 1, | |
# "uses": 0, | |
# "nbt_size": len(data), | |
# "nbt_data": data, | |
# }, | |
#}) | |
tag.value["title"] = nbt.StringTag("title") | |
tag.value["title"].value = title | |
tag.value["author"] = nbt.StringTag("author") | |
tag.value["author"].value = "kierdavis" | |
buf = StringIO.StringIO() | |
g = gzip.GzipFile(mode="wb", fileobj=buf) | |
tag.write(g) | |
g.close() | |
data = buf.getvalue() | |
self.to_server({ | |
"msgtype": 0xFA, | |
"channel": u"MC|BSign", | |
"data": struct.pack(">HBHH", 387, 1, 0, len(data)) + data, | |
}) | |
#self.to_client({ | |
# "msgtype": 0x67, | |
# "window_id": 0, | |
# "slot": self.held_item + 36, | |
# "slot_update": { | |
# "item_id": 387, | |
# "count": 1, | |
# "uses": 0, | |
# "nbt_size": len(data), | |
# "nbt_data": data, | |
# }, | |
#}) | |
elif words[1] == u"sel": | |
if len(words) < 3: | |
self.send_notification(u"List of selections:") | |
selections = self.selections | |
for name, (a, b) in selections.iteritems(): | |
self.send_notification(u" %s: (%d, %d, %d) (%d, %d, %d)" % (name, a[0], a[1], a[2], b[0], b[1], b[2])) | |
elif words[2] == u"save": | |
if len(words) < 4: | |
self.send_notification(u"Usage: /prox sel save <name>") | |
else: | |
name = words[3] | |
if self.selection is None: | |
self.send_to_server(u"//size") | |
self.tasks.add(Task(2, self.save_selection, name)) | |
else: | |
self.save_selection(name) | |
elif words[2] == u"load": | |
if len(words) < 4: | |
self.send_notification(u"Usage: /prox sel load <name>") | |
else: | |
name = words[3] | |
self.selection = self.selections[name] | |
a, b = self.selection | |
self.send_notification(u"Loaded selection %s: (%d, %d, %d) (%d, %d, %d)" % (name, a[0], a[1], a[2], b[0], b[1], b[2])) | |
elif words[1] == u"plot": | |
if len(words) < 3: | |
self.send_notification(u"Plot commands:") | |
self.send_notification(u" /prox plot add <name> [<id>] - Add a plot") | |
self.send_notification(u" /prox plot del <name> - Delete a plot") | |
self.send_notification(u" /prox plot delall - Delete all plots") | |
self.send_notification(u" /prox plot list [<page>] - List plots") | |
self.send_notification(u" /prox plot <name> - Go to a plot") | |
elif words[2] == u"add": | |
if len(words) < 4: | |
self.send_notification(u"Usage: /prox plot add <id> <name>") | |
elif len(words) < 5: | |
name = words[3] | |
self.tasks.add(Task(2, self.add_plot, name)) | |
return u"/plotme id" | |
else: | |
name = words[3] | |
id = words[4] | |
self.plots[name] = id | |
self.send_notification(u"Plot '%s' added with ID '%s'" % (name, id)) | |
elif words[2] == u"del": | |
if len(words) < 4: | |
self.send_notification(u"Usage: /prox plot del <name>") | |
else: | |
name = words[3] | |
if name in self.plots: | |
del self.plots[name] | |
self.send_notification(u"Deleted plot '%s'" % name) | |
else: | |
self.send_notification(u"Plot '%s' not found" % name) | |
elif words[2] == u"delall": | |
self.send_notification("Are you sure you want to delete all plots? Say 'yes' if you want to continue or anything else to cancel.") | |
self.awaiting_response = self.delall | |
elif words[2] == u"list": | |
plots = self.plots.items() | |
plots.sort() | |
if len(plots) == 0: | |
self.send_notification(u"No plots") | |
else: | |
for name, id in self.page(plots, words[3:], "Plots"): | |
self.send_notification(u" %s (plot %s)" % (name, id)) | |
else: | |
name = words[2] | |
if name in self.plots: | |
id = self.plots[name] | |
return u"/plotme tp %s" % id | |
else: | |
self.send_notification(u"Plot '%s' not found" % name) | |
elif words[1] == u"ml": | |
if len(words) < 3: | |
self.send_notification(u"Mailing list commands:") | |
self.send_notification(u" /prox ml new <name> - Create a mailing list") | |
self.send_notification(u" /prox ml del <name> - Delete a mailing list") | |
self.send_notification(u" /prox ml add <name> <players...> - Add players to a mailing list") | |
self.send_notification(u" /prox ml rm <name> <players...> - Remove players from a mailing list") | |
self.send_notification(u" /prox ml list [<page>] - List mailing lists") | |
self.send_notification(u" /prox ml show <name> [<page>] - Show info about a mailing list") | |
self.send_notification(u" /prox ml send <name> <message> - Send a message to a mailing list") | |
elif words[2] == u"new": | |
if len(words) < 4: | |
self.send_notification(u"Usage: /prox ml new <name>") | |
else: | |
name = words[3] | |
self.mls[name] = set() | |
self.send_notification(u"Mailing list '%s' created" % name) | |
elif words[2] == u"del": | |
if len(words) < 4: | |
self.send_notification(u"Usage: /prox ml del <name>") | |
else: | |
name = words[3] | |
if name in self.mls: | |
del self.mls[name] | |
self.send_notification(u"Mailing list '%s' deleted" % name) | |
else: | |
self.send_notification(u"Mailing list '%s' does not exist" % name) | |
elif words[2] == u"add": | |
if len(words) < 5: | |
self.send_notification(u"Usage: /prox ml add <name> <players...>") | |
else: | |
name = words[3] | |
if name in self.mls: | |
players = words[4:] | |
self.mls[name].update(players) | |
self.send_notification(u"%d players added to mailing list '%s' (now has %d members)" % (len(players), name, len(self.mls[name]))) | |
else: | |
self.send_notification(u"Mailing list '%s' does not exist" % name) | |
elif words[2] == u"rm": | |
if len(words) < 5: | |
self.send_notification(u"Usage: /prox ml rm <name> <players...>") | |
else: | |
name = words[3] | |
if name in self.mls: | |
players = words[4:] | |
self.mls[name].difference_update(players) | |
self.send_notification(u"%d players removed from mailing list '%s' (now has %d members)" % (len(players), name, len(self.mls[name]))) | |
else: | |
self.send_notification(u"Mailing list '%s' does not exist" % name) | |
elif words[2] == u"list": | |
for name in self.page(self.mls.keys(), words[3:], u"Mailing lists"): | |
self.send_notification(u" %s" % name) | |
elif words[2] == u"show": | |
if len(words) < 4: | |
self.send_notification(u"Usage: /prox ml show <name> [<page>]") | |
else: | |
name = words[3] | |
if name in self.mls: | |
for player in self.page(self.mls[name], words[4:], u"Mailing list '%s'" % name): | |
self.send_notification(u" %s" % player) | |
else: | |
self.send_notification(u"Mailing list '%s' does not exist" % name) | |
elif words[2] == u"send": | |
if len(words) < 5: | |
self.send_notification(u"Usage: /prox ml send <name> <message>") | |
else: | |
name = words[3] | |
if name in self.mls: | |
message = " ".join(words[4:]) | |
self.mlsend(name, message) | |
else: | |
self.send_notification(u"Mailing list '%s' does not exist" % name) | |
else: | |
self.send_notification(u"Invalid subcommand.") | |
return None | |
return msg | |
def mlsend(self, name, message): | |
for player in self.mls[name]: | |
self.mail_queue.append((player, message)) | |
n = len(self.mls[name]) | |
self.send_to_server(u"/ GCPROXY: Mass-mailing of %d messages queued" % n) | |
def incoming_mlsend(self, msg, unformatted): | |
m = re.match(r"([a-zA-Z0-9_]+): ML:([a-zA-Z0-9_]+) (.+)", msg) | |
if m is not None and msg not in self.ml_cache: | |
self.ml_cache.append(msg) | |
sender = m.group(1) | |
name = m.group(2) | |
message = m.group(3) | |
self.mlsend(name, message) | |
return msg | |
def outgoing_mailclear(self, msg): | |
if msg == u"/mail clear": | |
for i in xrange(len(self.ml_cache)): | |
self.ml_cache.pop(0) | |
self.send_notification(u"Cleared ML cache") | |
return msg | |
def incoming_tpa(self, msg, unformatted): | |
if unformatted == "To deny this request, type /tpdeny." and self.tpa: | |
self.tasks.add(Task(3, self.send_to_server, u"/tpaccept")) | |
return msg | |
def replace_rainbow(self, m): | |
return self.rainbow(m.group(1)) | |
def rainbow(self, text): | |
out = "" | |
for c in text: | |
out += "&%s%s" % (random.choice("1234569abcde"), c) | |
return out + "&r"#&" + CHAT_COLOUR | |
#def outgoing_commands(self, msg): | |
# words = msg.split() | |
# if words[0] in OBFUSCATED_COMMANDS: | |
# words[1] = self.obfuscate_player(words[1]) | |
# msg = " ".join(words) | |
# | |
# return msg | |
def outgoing_formatting(self, msg): | |
msg = re.sub(r"@@(.+?)@@", self.replace_rainbow, msg) | |
if msg[0] in "!/": | |
return msg | |
out = u"" | |
props = [] | |
i = 0 | |
while i < len(msg): | |
prop = None | |
if msg[i:i+2] == u"##": prop = u"k" | |
elif msg[i:i+2] == u"**": prop = u"l" | |
elif msg[i:i+2] == u"~~": prop = u"m" | |
elif msg[i:i+2] == u"__": prop = u"n" | |
elif msg[i:i+2] == u"\\\\": prop = u"o" | |
elif msg[i:i+2] == u"<<" and msg[i+3] == u":": | |
prop = msg[i+2] | |
i += 2 | |
elif msg[i:i+2] == u">>": | |
for p in reversed(props): | |
if p in u"0123456789abcdefABCEF": | |
prop = p | |
break | |
if prop is not None: | |
i += 1 | |
if prop in props: | |
props.remove(prop) | |
out += u"&r&" + CHAT_COLOUR | |
for prop in props: | |
out += u"&" + prop | |
else: | |
props.append(prop) | |
out += u"&" + prop | |
else: | |
out += msg[i] | |
i += 1 | |
return out | |
def save_selection(self, name): | |
self.selections[name] = self.selection | |
a, b = self.selection | |
self.send_notification(u"Saved selection %s: (%d, %d, %d) (%d, %d, %d)" % (name, a[0], a[1], a[2], b[0], b[1], b[2])) | |
def repeat(self, interval, command): | |
if self.stop_repeating: | |
self.stop_repeating = False | |
self.send_notification(u"Stopped repeating: %s" % command) | |
return | |
processed_command = self.process_outgoing(command) | |
if processed_command is not None: | |
self.send_to_server(processed_command) | |
self.tasks.add(Task(interval, self.repeat, interval, command)) | |
def add_plot(self, name): | |
if self.plot_id is None: | |
self.send_notification(u"No plot ID received!") | |
else: | |
(id, self.plot_id) = (self.plot_id, None) | |
self.plots[name] = id | |
self.send_notification(u"Plot '%s' added with ID '%s'" % (name, id)) | |
def on_ready(self): | |
print "Initialisation commands" | |
self.send_to_server(u"//limit %d" % WE_LIMIT) | |
self.send_to_server(u"/commandspy on") | |
self.send_to_server(u"/f chatspy on") | |
self.send_to_server(u"/mail read") | |
def send_to_client(self, msg): | |
print "To client: %s" % msg.encode("utf-8") | |
self.to_client({"msgtype": 0x03, "chat_msg": msg}) | |
def is_unstealthy(self, msg): | |
return self.stealth and (msg[0] != "/" or msg.split()[0] in UNSTEALTHY_COMMANDS) | |
def send_to_server(self, msg): | |
if self.is_unstealthy(msg): | |
self.send_notification(u"'%s' rejected due to stealth mode" % msg) | |
return | |
while len(msg) > 0: | |
part, msg = msg[:99], msg[99:] | |
print "To server: %s" % part.encode("utf-8") | |
self.to_server({"msgtype": 0x03, "chat_msg": part}) | |
def outgoing_stealth(self, msg): | |
if self.is_unstealthy(msg): | |
self.send_notification(u"Message rejected due to stealth mode") | |
return None | |
return msg | |
def send_notification(self, msg): | |
self.send_to_client(u"\xa77[GCProxy] %s\xa7r" % msg) | |
def delall(self, msg): | |
if msg == "yes": | |
self.plots.clear() | |
self.send_notification("All plots deleted") | |
else: | |
self.send_notification("Operation aborted") | |
def log(self, type, format, *args): | |
line = "[%s] %-4s %s" % (time.asctime(), type, format % args) | |
self.logfile.write(line + "\n") | |
self.logfile.flush() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment