Reshuffling the Evennia package into the new template paradigm.
This commit is contained in:
parent
2846e64833
commit
2b3a32e447
371 changed files with 17250 additions and 304 deletions
|
|
@ -1,334 +0,0 @@
|
|||
"""
|
||||
Bots are a special child typeclasses of
|
||||
Player that are controlled by the server.
|
||||
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
from src.players.player import DefaultPlayer
|
||||
from src.scripts.scripts import Script
|
||||
from src.commands.command import Command
|
||||
from src.commands.cmdset import CmdSet
|
||||
from src.utils import search
|
||||
|
||||
_IDLE_TIMEOUT = settings.IDLE_TIMEOUT
|
||||
|
||||
_SESSIONS = None
|
||||
|
||||
|
||||
# Bot helper utilities
|
||||
|
||||
class BotStarter(Script):
|
||||
"""
|
||||
This non-repeating script has the
|
||||
sole purpose of kicking its bot
|
||||
into gear when it is initialized.
|
||||
"""
|
||||
def at_script_creation(self):
|
||||
self.key = "botstarter"
|
||||
self.desc = "bot start/keepalive"
|
||||
self.persistent = True
|
||||
self.db.started = False
|
||||
if _IDLE_TIMEOUT > 0:
|
||||
# call before idle_timeout triggers
|
||||
self.interval = int(max(60, _IDLE_TIMEOUT * 0.90))
|
||||
self.start_delay = True
|
||||
|
||||
def at_start(self):
|
||||
"Kick bot into gear"
|
||||
if not self.db.started:
|
||||
self.player.start()
|
||||
self.db.started = True
|
||||
|
||||
def at_repeat(self):
|
||||
"""
|
||||
Called self.interval seconds to keep connection. We cannot use
|
||||
the IDLE command from inside the game since the system will
|
||||
not catch it (commands executed from the server side usually
|
||||
has no sessions). So we update the idle counter manually here
|
||||
instead. This keeps the bot getting hit by IDLE_TIMEOUT.
|
||||
"""
|
||||
global _SESSIONS
|
||||
if not _SESSIONS:
|
||||
from src.server.sessionhandler import SESSIONS as _SESSIONS
|
||||
for session in _SESSIONS.sessions_from_player(self.player):
|
||||
session.update_session_counters(idle=True)
|
||||
|
||||
def at_server_reload(self):
|
||||
"""
|
||||
If server reloads we don't need to reconnect the protocol
|
||||
again, this is handled by the portal reconnect mechanism.
|
||||
"""
|
||||
self.db.started = True
|
||||
|
||||
def at_server_shutdown(self):
|
||||
"Make sure we are shutdown"
|
||||
self.db.started = False
|
||||
|
||||
|
||||
class CmdBotListen(Command):
|
||||
"""
|
||||
This is a command that absorbs input
|
||||
aimed specifically at the bot. The session
|
||||
must prepend its data with bot_data_in for
|
||||
this to trigger.
|
||||
"""
|
||||
key = "bot_data_in"
|
||||
def func(self):
|
||||
"Relay to typeclass"
|
||||
self.obj.execute_cmd(self.args.strip(), sessid=self.sessid)
|
||||
|
||||
class BotCmdSet(CmdSet):
|
||||
"Holds the BotListen command"
|
||||
key = "botcmdset"
|
||||
def at_cmdset_creation(self):
|
||||
self.add(CmdBotListen())
|
||||
|
||||
|
||||
# Bot base class
|
||||
|
||||
class Bot(DefaultPlayer):
|
||||
"""
|
||||
A Bot will start itself when the server
|
||||
starts (it will generally not do so
|
||||
on a reload - that will be handled by the
|
||||
normal Portal session resync)
|
||||
"""
|
||||
|
||||
def basetype_setup(self):
|
||||
"""
|
||||
This sets up the basic properties for the bot.
|
||||
"""
|
||||
# the text encoding to use.
|
||||
self.db.encoding = "utf-8"
|
||||
# A basic security setup
|
||||
lockstring = "examine:perm(Wizards);edit:perm(Wizards);delete:perm(Wizards);boot:perm(Wizards);msg:false()"
|
||||
self.locks.add(lockstring)
|
||||
# set the basics of being a bot
|
||||
self.cmdset.add_default(BotCmdSet)
|
||||
script_key = "%s" % self.key
|
||||
self.scripts.add(BotStarter, key=script_key)
|
||||
self.is_bot = True
|
||||
|
||||
def start(self, **kwargs):
|
||||
"""
|
||||
This starts the bot, whatever that may mean.
|
||||
"""
|
||||
pass
|
||||
|
||||
def msg(self, text=None, from_obj=None, sessid=None, **kwargs):
|
||||
"""
|
||||
Evennia -> outgoing protocol
|
||||
"""
|
||||
pass
|
||||
|
||||
def execute_cmd(self, raw_string, sessid=None):
|
||||
"""
|
||||
Incoming protocol -> Evennia
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_server_shutdown(self):
|
||||
"We need to handle this case manually since the shutdown may be a reset"
|
||||
print "bots at_server_shutdown called"
|
||||
for session in self.get_all_sessions():
|
||||
session.sessionhandler.disconnect(session)
|
||||
|
||||
|
||||
# Bot implementations
|
||||
|
||||
# IRC
|
||||
|
||||
class IRCBot(Bot):
|
||||
"""
|
||||
Bot for handling IRC connections.
|
||||
"""
|
||||
def start(self, ev_channel=None, irc_botname=None, irc_channel=None, irc_network=None, irc_port=None):
|
||||
"""
|
||||
Start by telling the portal to start a new session.
|
||||
|
||||
ev_channel - key of the Evennia channel to connect to
|
||||
irc_botname - name of bot to connect to irc channel. If not set, use self.key
|
||||
irc_channel - name of channel on the form #channelname
|
||||
irc_network - url of network, like irc.freenode.net
|
||||
irc_port - port number of irc network, like 6667
|
||||
"""
|
||||
global _SESSIONS
|
||||
if not _SESSIONS:
|
||||
from src.server.sessionhandler import SESSIONS as _SESSIONS
|
||||
|
||||
# if keywords are given, store (the BotStarter script
|
||||
# will not give any keywords, so this should normally only
|
||||
# happen at initialization)
|
||||
if irc_botname:
|
||||
self.db.irc_botname = irc_botname
|
||||
elif not self.db.irc_botname:
|
||||
self.db.irc_botname = self.key
|
||||
if ev_channel:
|
||||
# connect to Evennia channel
|
||||
channel = search.channel_search(ev_channel)
|
||||
if not channel:
|
||||
raise RuntimeError("Evennia Channel '%s' not found." % ev_channel)
|
||||
channel = channel[0]
|
||||
channel.connect(self)
|
||||
self.db.ev_channel = channel
|
||||
if irc_channel:
|
||||
self.db.irc_channel = irc_channel
|
||||
if irc_network:
|
||||
self.db.irc_network = irc_network
|
||||
if irc_port:
|
||||
self.db.irc_port = irc_port
|
||||
|
||||
# instruct the server and portal to create a new session with
|
||||
# the stored configuration
|
||||
configdict = {"uid":self.dbid,
|
||||
"botname": self.db.irc_botname,
|
||||
"channel": self.db.irc_channel ,
|
||||
"network": self.db.irc_network,
|
||||
"port": self.db.irc_port}
|
||||
_SESSIONS.start_bot_session("src.server.portal.irc.IRCBotFactory", configdict)
|
||||
|
||||
def msg(self, text=None, **kwargs):
|
||||
"""
|
||||
Takes text from connected channel (only)
|
||||
"""
|
||||
if not self.ndb.ev_channel and self.db.ev_channel:
|
||||
# cache channel lookup
|
||||
self.ndb.ev_channel = self.db.ev_channel
|
||||
if "from_channel" in kwargs and text and self.ndb.ev_channel.dbid == kwargs["from_channel"]:
|
||||
if "from_obj" not in kwargs or kwargs["from_obj"] != [self.id]:
|
||||
text = "bot_data_out %s" % text
|
||||
self.msg(text=text)
|
||||
|
||||
def execute_cmd(self, text=None, sessid=None):
|
||||
"""
|
||||
Take incoming data and send it to connected channel. This is triggered
|
||||
by the CmdListen command in the BotCmdSet.
|
||||
"""
|
||||
if not self.ndb.ev_channel and self.db.ev_channel:
|
||||
# cache channel lookup
|
||||
self.ndb.ev_channel = self.db.ev_channel
|
||||
if self.ndb.ev_channel:
|
||||
self.ndb.ev_channel.msg(text, senders=self.id)
|
||||
|
||||
|
||||
# RSS
|
||||
|
||||
class RSSBot(Bot):
|
||||
"""
|
||||
An RSS relayer. The RSS protocol itself runs a ticker to update its feed at regular
|
||||
intervals.
|
||||
"""
|
||||
def start(self, ev_channel=None, rss_url=None, rss_rate=None):
|
||||
"""
|
||||
Start by telling the portal to start a new RSS session
|
||||
|
||||
ev_channel - key of the Evennia channel to connect to
|
||||
rss_url - full URL to the RSS feed to subscribe to
|
||||
rss_update_rate - how often for the feedreader to update
|
||||
"""
|
||||
global _SESSIONS
|
||||
if not _SESSIONS:
|
||||
from src.server.sessionhandler import SESSIONS as _SESSIONS
|
||||
|
||||
if ev_channel:
|
||||
# connect to Evennia channel
|
||||
channel = search.channel_search(ev_channel)
|
||||
if not channel:
|
||||
raise RuntimeError("Evennia Channel '%s' not found." % ev_channel)
|
||||
channel = channel[0]
|
||||
self.db.ev_channel = channel
|
||||
if rss_url:
|
||||
self.db.rss_url = rss_url
|
||||
if rss_rate:
|
||||
self.db.rss_rate = rss_rate
|
||||
# instruct the server and portal to create a new session with
|
||||
# the stored configuration
|
||||
configdict = {"uid": self.dbid,
|
||||
"url": self.db.rss_url,
|
||||
"rate": self.db.rss_rate}
|
||||
_SESSIONS.start_bot_session("src.server.portal.rss.RSSBotFactory", configdict)
|
||||
|
||||
def execute_cmd(self, text=None, sessid=None):
|
||||
"""
|
||||
Echo RSS input to connected channel
|
||||
"""
|
||||
print "execute_cmd rss:", text
|
||||
if not self.ndb.ev_channel and self.db.ev_channel:
|
||||
# cache channel lookup
|
||||
self.ndb.ev_channel = self.db.ev_channel
|
||||
if self.ndb.ev_channel:
|
||||
self.ndb.ev_channel.msg(text, senders=self.id)
|
||||
|
||||
class IMC2Bot(Bot):
|
||||
"""
|
||||
IMC2 Bot
|
||||
"""
|
||||
def start(self, ev_channel=None, imc2_network=None, imc2_mudname=None,
|
||||
imc2_port=None, imc2_client_pwd=None, imc2_server_pwd=None):
|
||||
"""
|
||||
Start by telling the portal to start a new session
|
||||
ev_channel - key of the Evennia channel to connect to
|
||||
imc2_network - IMC2 network name
|
||||
imc2_mudname - registered mudname (if not given, use settings.SERVERNAME)
|
||||
imc2_port - port number of IMC2 network
|
||||
imc2_client_pwd - client password registered with IMC2 network
|
||||
imc2_server_pwd - server password registered with IMC2 network
|
||||
"""
|
||||
global _SESSIONS
|
||||
if not _SESSIONS:
|
||||
from src.server.sessionhandler import SESSIONS as _SESSIONS
|
||||
if ev_channel:
|
||||
# connect to Evennia channel
|
||||
channel = search.channel_search(ev_channel)
|
||||
if not channel:
|
||||
raise RuntimeError("Evennia Channel '%s' not found." % ev_channel)
|
||||
channel = channel[0]
|
||||
channel.connect(self)
|
||||
self.db.ev_channel = channel
|
||||
if imc2_network:
|
||||
self.db.imc2_network = imc2_network
|
||||
if imc2_port:
|
||||
self.db.imc2_port = imc2_port
|
||||
if imc2_mudname:
|
||||
self.db.imc2_mudname = imc2_mudname
|
||||
elif not self.db.imc2_mudname:
|
||||
self.db.imc2_mudname = settings.SERVERNAME
|
||||
# storing imc2 passwords in attributes - a possible
|
||||
# security issue?
|
||||
if imc2_server_pwd:
|
||||
self.db.imc2_server_pwd = imc2_server_pwd
|
||||
if imc2_client_pwd:
|
||||
self.db.imc2_client_pwd = imc2_client_pwd
|
||||
|
||||
configdict = {"uid": self.dbid,
|
||||
"mudname": self.db.imc2_mudname,
|
||||
"network": self.db.imc2_network,
|
||||
"port": self.db.imc2_port,
|
||||
"client_pwd": self.db.client_pwd,
|
||||
"server_pwd": self.db.server_pwd}
|
||||
|
||||
_SESSIONS.start_bot_session("src.server.portal.imc2.IMC2BotFactory", configdict)
|
||||
|
||||
def msg(self, text=None, **kwargs):
|
||||
"""
|
||||
Takes text from connected channel (only)
|
||||
"""
|
||||
if not self.ndb.ev_channel and self.db.ev_channel:
|
||||
# cache channel lookup
|
||||
self.ndb.ev_channel = self.db.ev_channel
|
||||
if "from_channel" in kwargs and text and self.ndb.ev_channel.dbid == kwargs["from_channel"]:
|
||||
if "from_obj" not in kwargs or kwargs["from_obj"] != [self.id]:
|
||||
text = "bot_data_out %s" % text
|
||||
self.msg(text=text)
|
||||
|
||||
def execute_cmd(self, text=None, sessid=None):
|
||||
"""
|
||||
Relay incoming data to connected channel.
|
||||
"""
|
||||
if not self.ndb.ev_channel and self.db.ev_channel:
|
||||
# cache channel lookup
|
||||
self.ndb.ev_channel = self.db.ev_channel
|
||||
if self.ndb.ev_channel:
|
||||
self.ndb.ev_channel.msg(text, senders=self.id)
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue