I'm actually working with Sleekxmpp but it was only a couple of hours ago that I dug up the developer docs on Github that talked about how to create custom stanzas. Now I'm feeling more confident that it actually can do the sort of processing required to deal with the special Paragon Chat <pc:> and <u:> stanzas and whatever else there is or might potentially be.
It most definitely can. Its a little frustrating figuring out the language, but the capabilities are all there. Just don't ask me send/send_X semantics questions yet.
Speaking of stanzas, I've been wondering - Are there dtd's for the namespaces of those custom stanzas or is it enough to simply define the name spaces and leave the structure of them ambiguous? If Paragon Chat has DTD's defined for <pc:> and <u:> and what not, do bots that define the same name spaces require those DTD's?
Codewalker described all of them above. However, since I already worked out sleekxmpp's kinks:
from sleekxmpp import ClientXMPP
from sleekxmpp.xmlstream.stanzabase import ElementBase
class pcCharacterStanza(ElementBase):
namespace = 'pc:character'
name = 'character'
plugin_attrib = 'character'
interfaces = set(('origin','map','class','name','costume'))
class pcPresenceStanza(ElementBase):
namespace = 'pc:presence'
name = 'pc'
plugin_attrib = 'pc'
interfaces = set(('jid','protocol'))
class pcuStanza(ElementBase):
namespace = 'pc:u'
name = 'u'
plugin_attrib = "u"
interfaces = set(('p','m','v','o'))
class pcChannelStanza(ElementBase):
namespace = 'pc:message'
name = 'channel'
plugin_attrib = 'channel'
interfaces = set(('id'))
class pcDescriptionStanza(ElementBase):
namespace = 'pc:description'
name = 'description'
plugin_attr = 'description'
(warning: do not list subinterfaces like a lot of sleekxmpp demo code does. That will convert stanza attributes into substanzas, i.e. it will turn <u xmlns="pc:u" o="0 0 0" /> into <u xmlns="pc:u"><o>"0 0 0"</ o></ u>. Demo writers like to teach highly normalized XML/XMPP.)
You have to register those as plugins to the appropriate parent stanza:
registerStanzaPlugin(Presence,pcPresenceStanza)
registerStanzaPlugin(Presence,pcCharacterStanza)
registerStanzaPlugin(Iq,pcDescriptionStanza)
registerStanzaPlugin(Message,pcuStanza)
registerStanzaPlugin(Message,pcChannelStanza)
You then make handlers that access the contents of a stanza like so:
def handle_pcPresenceStanza(self,msg):
print "Debug: pcPresence jid:" + str(msg.values['pc']['jid'])
print "Debug: pcPresence character costume: " + str(msg.values['character']['costume'])
and register them as a callback in the appropriate xmpp object, with the appropriate XPath matching pattern:
self.registerHandler(Callback('pcPresenceStanza Handler', MatchXPath('{%s}presence/{%s}pc' % (self.default_ns, pcPresenceStanza.namespace)), self.handle_pcPresenceStanza))
Technically speaking, you don't need to implement stanza plugins because you can just register handlers to process all Iq, Presence, and Message stanzas and write your own parser to parse the raw stanza information (ala str(stanza_msg)), but that's crazy.
I haven't written the costume code yet, so those stanza definitions aren't above yet. But you should be able to figure out how to do that by following the examples.
I think what I'm really going to be interested in whether a bot can induce a change in the state of a player. For instance, I've edited my character record in the SQLite database to put my character next to the flagpole atop city hall. It would be very interesting to be able to send a message to a player that says, "Change to these x,y,z coordinates". You could make a taxibot that offers a series of destinations and a player could say, "Taxibot, flagpole" to be "teleported" to the flagpole.
At the moment I do not believe that is possible, because I don't think Paragon Chat itself supports that. Which is why I'm investigating bots. Paragon Chat doesn't "react" to events, but nothing stops a bot from doing so. To put it another way, at the moment a bot cannot knock a player over. But hypothetically speaking, a player can knock a bot over, because bots can take dives.
Just a note: your bot won't have any idea where flagpoles and buildings are, and for that matter where the ground is, unless you write special code that can read City of Heroes mapfiles. In the absence of such an ability, you will be forced to "hardcode" where the bot goes so it doesn't pass through walls or move downward through the ground. Your bot doesn't have the game client's collision detection logic, so you have to write your own or figure out another way for the bot to go where you want it to go with the right movement path that "looks right" to everyone else in the game.
That's what the whole LUA-thing exchange was between Codewalker and myself just now. Theoretically speaking, Paragon Chat (the software) itself knows what players can and cannot do in large part, including knowing how to read maps and detect collisions. Its hypothetically possible for Codewalker to add features to Paragon Chat that allow bot writers and other scripters like machinima authors to tell Paragon Chat what they want the bot to do, and have Paragon Chat tell the bot if those actions are legal, or alternatively calculate their result and push that back to the bot. That would basically put me out of the bot-writing business (and put me in the LUA scripting business).