Browse Source

fixed bugs and cleaned stuff here

master
jcao219 14 years ago
parent
commit
816d922b85
  1. 4
      decorators.py
  2. 49
      oyoyo/client.py
  3. 32
      oyoyo/cmdhandler.py
  4. 16
      oyoyo/parse.py
  5. 16
      wolfbot.py
  6. 41
      wolfgame.py

4
decorators.py

@ -7,9 +7,9 @@ def generate(fdict):
def dec(f): def dec(f):
def innerf(*args): def innerf(*args):
largs = list(args) largs = list(args)
if not raw_nick: largs[1] = parse_nick(largs[1])[0] if not raw_nick and largs[1]: largs[1] = parse_nick(largs[1])[0]
if admin_only: if admin_only:
if largs[1] in botconfig.ADMINS: if largs[1] and largs[1] in botconfig.ADMINS:
return f(*largs) return f(*largs)
else: else:
largs[0].notice(largs[1], "You are not an admin.") largs[0].notice(largs[1], "You are not an admin.")

49
oyoyo/client.py

@ -60,25 +60,8 @@ class IRCClient(object):
Warning: By default this class will not block on socket operations, this Warning: By default this class will not block on socket operations, this
means if you use a plain while loop your app will consume 100% cpu. means if you use a plain while loop your app will consume 100% cpu.
To enable blocking pass blocking=True. To enable blocking pass blocking=True.
>>> class My_Handler(DefaultCommandHandler):
... def privmsg(self, prefix, command, args):
... print "%s said %s" % (prefix, args[1])
...
>>> def connect_callback(c):
... c.join('#myroom')
...
>>> cli = IRCClient(My_Handler,
... host="irc.freenode.net",
... port=6667,
... nick="myname",
... connect_cb=connect_callback)
...
>>> cli_con = cli.connect()
>>> while 1:
... cli_con.next()
...
""" """
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.nickname = "" self.nickname = ""
self.real_name = "" self.real_name = ""
@ -96,7 +79,7 @@ class IRCClient(object):
""" send a message to the connected server. all arguments are joined """ send a message to the connected server. all arguments are joined
with a space for convenience, for example the following are identical with a space for convenience, for example the following are identical
>>> cli.send("JOIN %s" % some_room) >>> cli.send("JOIN " + some_room)
>>> cli.send("JOIN", some_room) >>> cli.send("JOIN", some_room)
In python 2, all args must be of type str or unicode, *BUT* if they are In python 2, all args must be of type str or unicode, *BUT* if they are
@ -109,7 +92,7 @@ class IRCClient(object):
# Convert all args to bytes if not already # Convert all args to bytes if not already
encoding = kwargs.get('encoding') or 'utf_8' encoding = kwargs.get('encoding') or 'utf_8'
bargs = [] bargs = []
for arg in args: for i,arg in enumerate(args):
if isinstance(arg, str): if isinstance(arg, str):
bargs.append(bytes(arg, encoding)) bargs.append(bytes(arg, encoding))
elif isinstance(arg, bytes): elif isinstance(arg, bytes):
@ -117,11 +100,12 @@ class IRCClient(object):
elif arg is None: elif arg is None:
continue continue
else: else:
raise IRCClientError('Refusing to send one of the args from provided: %s' raise Exception(('Refusing to send arg at index {1} of the args from '+
% repr([(type(arg), arg) for arg in args])) 'provided: {0}').format(repr([(type(arg), arg)
for arg in args]), i))
msg = bytes(" ", "utf_8").join(bargs) msg = bytes(" ", "utf_8").join(bargs)
logging.info('---> send "%s"' % msg) logging.info('---> send "{0}"'.format(msg))
self.socket.send(msg + bytes("\r\n", "utf_8")) self.socket.send(msg + bytes("\r\n", "utf_8"))
@ -132,12 +116,12 @@ class IRCClient(object):
>>> cli = IRCClient(my_handler, host="irc.freenode.net", port=6667) >>> cli = IRCClient(my_handler, host="irc.freenode.net", port=6667)
>>> g = cli.connect() >>> g = cli.connect()
>>> while 1: >>> while 1:
... g.next() ... next(g)
""" """
try: try:
logging.info('connecting to %s:%s' % (self.host, self.port)) logging.info('connecting to {0}:{1}'.format(self.host, self.port))
self.socket.connect(("%s" % self.host, self.port)) self.socket.connect(("{0}".format(self.host), self.port))
if not self.blocking: if not self.blocking:
self.socket.setblocking(0) self.socket.setblocking(0)
@ -152,16 +136,12 @@ class IRCClient(object):
try: try:
buffer += self.socket.recv(1024) buffer += self.socket.recv(1024)
except socket.error as e: except socket.error as e:
try: # a little dance of compatibility to get the errno if not self.blocking and e.errno == 11:
errno = e.errno
except AttributeError:
errno = e[0]
if not self.blocking and errno == 11:
pass pass
else: else:
raise e raise e
else: else:
data = buffer.split(bytes("\n", "ascii")) data = buffer.split(bytes("\n", "utf_8"))
buffer = data.pop() buffer = data.pop()
for el in data: for el in data:
@ -181,6 +161,7 @@ class IRCClient(object):
def msg(self, user, msg): def msg(self, user, msg):
for line in msg.split('\n'): for line in msg.split('\n'):
self.send("PRIVMSG", user, ":{0}".format(line)) self.send("PRIVMSG", user, ":{0}".format(line))
privmsg = msg # Same thing
def notice(self, user, msg): def notice(self, user, msg):
for line in msg.split('\n'): for line in msg.split('\n'):
self.send("NOTICE", user, ":{0}".format(line)) self.send("NOTICE", user, ":{0}".format(line))
@ -191,3 +172,7 @@ class IRCClient(object):
def user(self, uname, rname): def user(self, uname, rname):
self.send("USER", uname, self.host, self.host, self.send("USER", uname, self.host, self.host,
rname or uname) rname or uname)
def mainLoop(self):
conn = self.connect()
while True:
next(conn)

32
oyoyo/cmdhandler.py

@ -33,11 +33,11 @@ class CommandError(Exception):
class NoSuchCommandError(CommandError): class NoSuchCommandError(CommandError):
def __str__(self): def __str__(self):
return 'No such command "%s"' % ".".join(self.cmd) return 'No such command "{0}"'.format(".".join(self.cmd))
class ProtectedCommandError(CommandError): class ProtectedCommandError(CommandError):
def __str__(self): def __str__(self):
return 'Command "%s" is protected' % ".".join(self.cmd) return 'Command "{0}" is protected'.format(".".join(self.cmd))
class CommandHandler(object): class CommandHandler(object):
@ -65,7 +65,7 @@ class CommandHandler(object):
command_parts = [] command_parts = []
for cmdpart in in_command_parts: for cmdpart in in_command_parts:
if isinstance(cmdpart, bytes): if isinstance(cmdpart, bytes):
cmdpart = cmdpart.decode('ascii') cmdpart = cmdpart.decode('utf_8')
command_parts.append(cmdpart) command_parts.append(cmdpart)
p = self p = self
@ -91,7 +91,10 @@ class CommandHandler(object):
@protected @protected
def run(self, command, *args): def run(self, command, *args):
""" finds and runs a command """ """ finds and runs a command """
logging.debug("processCommand %s(%s)" % (command, args)) logging.debug("processCommand {0}({1})".format(command,
[arg.decode('utf_8')
for arg in args
if isinstance(arg, bytes)]))
try: try:
f = self.get(command) f = self.get(command)
@ -99,15 +102,15 @@ class CommandHandler(object):
self.__unhandled__(command, *args) self.__unhandled__(command, *args)
return return
logging.debug('f %s' % f) logging.debug('f {0}'.format(f))
try: try:
largs = list(args) largs = list(args)
for i,arg in enumerate(largs): for i,arg in enumerate(largs):
if arg: largs[i] = arg.decode('ascii') if arg: largs[i] = arg.decode('utf_8')
f(*largs) f(*largs)
self.__unhandled__(command, *args)
except Exception as e: except Exception as e:
logging.error('command raised %s' % e) logging.error('command raised {0}'.format(e))
logging.error(traceback.format_exc()) logging.error(traceback.format_exc())
raise CommandError(command) raise CommandError(command)
@ -116,13 +119,6 @@ class CommandHandler(object):
"""The default handler for commands. Override this method to """The default handler for commands. Override this method to
apply custom behavior (example, printing) unhandled commands. apply custom behavior (example, printing) unhandled commands.
""" """
logging.debug('unhandled command %s(%s)' % (cmd, args)) logging.debug('Unhandled command {0}({1})'.format(cmd, [arg.decode('utf_8')
for arg in args
if isinstance(arg, bytes)]))
class DefaultCommandHandler(CommandHandler):
""" CommandHandler that provides methods for the normal operation of IRC.
If you want your bot to properly respond to pings, etc, you should subclass this.
"""
def ping(self, prefix, server):
self.client.send('PONG', server)

16
oyoyo/parse.py

@ -40,8 +40,8 @@ def parse_raw_irc_command(element):
<crlf> ::= CR LF <crlf> ::= CR LF
""" """
parts = element.strip().split(bytes(" ", "ascii")) parts = element.strip().split(bytes(" ", "utf_8"))
if parts[0].startswith(bytes(':', 'ascii')): if parts[0].startswith(bytes(':', 'utf_8')):
prefix = parts[0][1:] prefix = parts[0][1:]
command = parts[1] command = parts[1]
args = parts[2:] args = parts[2:]
@ -54,16 +54,16 @@ def parse_raw_irc_command(element):
try: try:
command = numeric_events[command] command = numeric_events[command]
except KeyError: except KeyError:
logging.warn('unknown numeric event %s' % command) logging.warn('unknown numeric event {0}'.format(command))
command = command.lower() command = command.lower()
if isinstance(command, bytes): command = command.decode("ascii") if isinstance(command, bytes): command = command.decode("utf_8")
if args[0].startswith(bytes(':', 'ascii')): if args[0].startswith(bytes(':', 'utf_8')):
args = [bytes(" ", "ascii").join(args)[1:]] args = [bytes(" ", "utf_8").join(args)[1:]]
else: else:
for idx, arg in enumerate(args): for idx, arg in enumerate(args):
if arg.startswith(bytes(':', 'ascii')): if arg.startswith(bytes(':', 'utf_8')):
args = args[:idx] + [bytes(" ", 'ascii').join(args[idx:])[1:]] args = args[:idx] + [bytes(" ", 'utf_8').join(args[idx:])[1:]]
break break
return (prefix, command, args) return (prefix, command, args)

16
wolfbot.py

@ -1,11 +1,11 @@
from oyoyo.client import IRCClient from oyoyo.client import IRCClient
from oyoyo.cmdhandler import DefaultCommandHandler, protected from oyoyo.cmdhandler import CommandHandler, protected
from oyoyo.parse import parse_nick from oyoyo.parse import parse_nick
import logging import logging
import botconfig import botconfig
import wolfgame import wolfgame
class WolfBotHandler(DefaultCommandHandler): class WolfBotHandler(CommandHandler):
def __init__(self, client): def __init__(self, client):
super().__init__(client) super().__init__(client)
@ -28,19 +28,19 @@ class WolfBotHandler(DefaultCommandHandler):
if cmd in wolfgame.HOOKS.keys(): if cmd in wolfgame.HOOKS.keys():
largs = list(args) largs = list(args)
for i,arg in enumerate(largs): for i,arg in enumerate(largs):
if arg: largs[i] = arg.decode('ascii') if isinstance(arg, bytes): largs[i] = arg.decode('ascii')
wolfgame.HOOKS[cmd](self.client, *largs) wolfgame.HOOKS[cmd](self.client, *largs)
else: else:
logging.debug('unhandled command %s(%s)' % (cmd, args)) logging.debug('Unhandled command {0}({1})'.format(cmd, [arg.decode('utf_8')
for arg in args
if isinstance(arg, bytes)]))
def main(): def main():
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.DEBUG)
cli = IRCClient(WolfBotHandler, host=botconfig.HOST, port=botconfig.PORT, nickname=botconfig.NICK, cli = IRCClient(WolfBotHandler, host=botconfig.HOST, port=botconfig.PORT, nickname=botconfig.NICK,
connect_cb=wolfgame.connect_callback) connect_cb=wolfgame.connect_callback)
conn = cli.connect() cli.mainLoop()
while True:
next(conn)
if __name__ == "__main__": if __name__ == "__main__":

41
wolfgame.py

@ -259,7 +259,7 @@ def chk_decision(cli):
cli.msg(botconfig.CHANNEL, cli.msg(botconfig.CHANNEL,
random.choice(vars.LYNCH_MESSAGES).format( random.choice(vars.LYNCH_MESSAGES).format(
votee, vars.get_role(votee))) votee, vars.get_role(votee)))
if del_player(cli, votee, True): if del_player_lynch(cli, vote):
transition_night(cli) transition_night(cli)
@ -368,10 +368,10 @@ def chk_win(cli):
def del_player(cli, nick, forced_death): def del_player(cli, nick):
""" """
forced_death = True if death is from a natural game process Returns: False if one side won.
Returns False if one side won. forced_death = True when lynched or killed arg: forced_death = True when lynched.
""" """
cmode = [] cmode = []
@ -379,14 +379,17 @@ def del_player(cli, nick, forced_death):
vars.del_player(nick) vars.del_player(nick)
ret = True ret = True
if vars.PHASE == "join": if vars.PHASE == "join":
# Died during the joining process as a person
mass_mode(cli, cmode) mass_mode(cli, cmode)
return not chk_win(cli) return not chk_win(cli)
if vars.PHASE != "join" and ret: # Died during the game if vars.PHASE != "join" and ret:
# Died during the game, so quiet!
cmode.append(("+q", nick)) cmode.append(("+q", nick))
mass_mode(cli, cmode) mass_mode(cli, cmode)
vars.DEAD.append(nick) vars.DEAD.append(nick)
ret = not chk_win(cli) ret = not chk_win(cli)
if vars.PHASE in ("night", "day") and ret: if vars.PHASE in ("night", "day") and ret:
# remove him from variables if he is in there
if vars.VICTIM == nick: if vars.VICTIM == nick:
vars.VICTIM = "" vars.VICTIM = ""
for x in (vars.OBSERVED, vars.HVISITED): for x in (vars.OBSERVED, vars.HVISITED):
@ -396,15 +399,26 @@ def del_player(cli, nick, forced_death):
del x[k] del x[k]
elif x[k] == nick: elif x[k] == nick:
del x[k] del x[k]
if vars.PHASE == "day" and not forced_death and ret: # didn't die from lynching return ret
def del_player_lynch(cli, nick):
if not del_player(cli, nick):
return
if vars.PHASE == "day" and not lynched_death and ret:
# didn't die from lynching, therefore a vote is still going on
if nick in vars.VOTES.keys(): if nick in vars.VOTES.keys():
del vars.VOTES[nick] # Delete his votes del vars.VOTES[nick] # Delete his votes
for k in vars.VOTES.keys(): for k in vars.VOTES.keys():
if nick in vars.VOTES[k]: if nick in vars.VOTES[k]:
vars.VOTES[k].remove(nick) vars.VOTES[k].remove(nick)
chk_decision(cli) chk_decision(cli)
return ret return not chk_win(cli)
@hook("ping")
def on_ping(cli, prefix, server):
cli.send('PONG', server)
def leave(cli, what, nick): def leave(cli, what, nick):
@ -429,7 +443,7 @@ def leave(cli, what, nick):
"Appears (s)he was a \u0002{1}\u0002.") "Appears (s)he was a \u0002{1}\u0002.")
msg = msg.format(nick, vars.get_role(nick)) msg = msg.format(nick, vars.get_role(nick))
cli.msg(botconfig.CHANNEL, msg) cli.msg(botconfig.CHANNEL, msg)
del_player(cli, nick, False) del_player(cli, nick)
cmd("!leave")(lambda cli, nick, *rest: leave(cli, "!leave", nick)) cmd("!leave")(lambda cli, nick, *rest: leave(cli, "!leave", nick))
cmd("!quit")(lambda cli, nick, *rest: leave(cli, "!quit", nick)) cmd("!quit")(lambda cli, nick, *rest: leave(cli, "!quit", nick))
@ -502,7 +516,7 @@ def transition_day(cli):
"The drunk's pet tiger probably ate him.").format(crow)) "The drunk's pet tiger probably ate him.").format(crow))
dead.append(crow) dead.append(crow)
for deadperson in dead: for deadperson in dead:
if not del_player(cli, deadperson, True): if not del_player(cli, deadperson):
return return
cli.msg(chan, "\n".join(message)) cli.msg(chan, "\n".join(message))
cli.msg(chan, ("The villagers must now vote for whom to lynch. "+ cli.msg(chan, ("The villagers must now vote for whom to lynch. "+
@ -540,6 +554,9 @@ def vote(cli, nick, chan, rest):
pl_l = [x.strip().lower() for x in pl] pl_l = [x.strip().lower() for x in pl]
rest = re.split("\s+",rest)[0].strip().lower() rest = re.split("\s+",rest)[0].strip().lower()
if rest in pl_l: if rest in pl_l:
if nick in vars.WOUNDED:
cli.msg(chan, ("{0}: You are wounded and resting, "+
"thus you are unable to vote for the day."))
voted = pl[pl_l.index(rest)] voted = pl[pl_l.index(rest)]
lcandidates = list(vars.VOTES.keys()) lcandidates = list(vars.VOTES.keys())
for voters in lcandidates: # remove previous vote for voters in lcandidates: # remove previous vote
@ -618,13 +635,13 @@ def shoot(cli, nick, chan, rest):
if victimrole in ("wolf", "werecrow"): if victimrole in ("wolf", "werecrow"):
cli.msg(chan, ("\u0002{0}\u0002 is a wolf, and is dying from "+ cli.msg(chan, ("\u0002{0}\u0002 is a wolf, and is dying from "+
"the silver bullet.").format(victim)) "the silver bullet.").format(victim))
if not del_player(cli, victim, True): if not del_player(cli, victim):
return return
elif random.random() <= vars.MANSLAUGHTER_CHANCE: elif random.random() <= vars.MANSLAUGHTER_CHANCE:
cli.msg(chan, ("\u0002{0}\u0002 is a not a wolf "+ cli.msg(chan, ("\u0002{0}\u0002 is a not a wolf "+
"but was accidentally fatally injured.").format(victim)) "but was accidentally fatally injured.").format(victim))
cli.msg(chan, "Appears (s)he was a \u0002{0}\u0002.".format(victimrole)) cli.msg(chan, "Appears (s)he was a \u0002{0}\u0002.".format(victimrole))
if not del_player(cli, victim, True): if not del_player(cli, victim):
return return
else: else:
cli.msg(chan, ("\u0002{0}\u0002 is a villager and is injured but "+ cli.msg(chan, ("\u0002{0}\u0002 is a villager and is injured but "+
@ -639,7 +656,7 @@ def shoot(cli, nick, chan, rest):
cli.msg(chan, ("\u0002{0}\u0002 should clean his/her weapons more often. "+ cli.msg(chan, ("\u0002{0}\u0002 should clean his/her weapons more often. "+
"The gun exploded and killed him/her!").format(nick)) "The gun exploded and killed him/her!").format(nick))
cli.msg(chan, "Appears that (s)he was a \u0002{0}\u0002.".format(vars.get_role(nick))) cli.msg(chan, "Appears that (s)he was a \u0002{0}\u0002.".format(vars.get_role(nick)))
if not del_player(cli, nick, True): if not del_player(cli, nick):
return # Someone won. return # Someone won.
@checks @checks

Loading…
Cancel
Save