Futurism › extend

From Botdom Documentation

Jump to: navigation, search

This article will explain how to code extensions for Futurism, so it can do all sorts of exciting things. Extending Futurism is usually done by creating a module. A module is basically a set of bot commands or event handlers (see the terms section below) that are somehow related.

Futurism is coded in the programming language Python, and so Python knowledge is required to code modules, and you are expected to have at least basic Python knowledge to complete this guide. If you want to get started with Python, Wikibooks has a great Python guide. Also, have a look at the Futurism objects and Futurism classes if you see names or methods in the code that you haven't seen before. Generally, this guide is targeted at people unfamiliar to coding modules for Futurism. If you are an old Futurism PHP developer, also have a look at the For old Futurism developers guide.

Futurism modules subfolder (Click to see larger)

So how do modules work? If you navigate to the folder you installed Futurism in, you will see that there is a subfolder called modules (see screenshot to the right). Futurism automatically looks for modules in this folder, and then attempts to activate all it can find, unless you explicitly tell it not to activate these certain modules. If you navigate to the modules folder, you will see some files. All modules are present in the Python (.py) files you find in this folder. If you want to turn some off really quick, you can just drag them to the OFF subfolder. (The best way to turn off modules is to use the modules reload command though.) If you have just installed Futurism, you will see that the only modules in this folder are two called dAmn and internal. These two modules (especially the latter) are core parts of the bot, and removing these are not recommended.

How are modules built? Before we get into the details further down on this page, here's the short summary on how modules are built: Modules, like most other parts of Futurism, are objects. So you build your module by building a class for it, defining some properties and setting some special methods that the bot then triggers on certain commands and events. Other than that, you can add whatever you want to have an internal structure in the class you like.

Contents

Terms

Before we start building our modules, it's good to have the core terms in place. Because of the way Futurism is built up, there's a chance you'll see terms that you haven't seen before, and they are introduced here (sorted alphabetically).

Deferred
Futurism is built on the Twisted networking framework, which brings in some revolutionary new technologies, which of course in turn introduces new terms. A Deferred (or defer.Deferred) is one of these. But what does it mean? Well, when you work with networking, it is fact that in theory, when you send a packet to any server (the dAmn server in this case), and you expect a responding packet to tell if your query was successful, you will not receive this instantly, even though it may feel like that for most humans. Therefore, instead of blocking the whole bot for continuing while waiting for that one packet to arrive, a Deferred is returned. A Deferred is in simple term a reference to data which isn't present yet. You can then add callbacks or errbacks to a Deferred to handle the content coming back (and define what happens on success or error, respectively), when it comes back. That way the bot can continue doing other things, and the callbacks or errbacks are automatically run by Twisted to handle the data, whenever it arrives. Deferreds are not directly worked with in modules, but it's good to know what they are.
events
Have you ever wanted your bot to do something everytime something specific happens in a chatroom or the bot? Like posting a message every time the topic is changed? There is support for this! These things are in the bot called events, and are triggered in your bot everytime things like these happen in a namespace (see below) the bot is in. The bot's modules can then have event handlers that do something every time these events occur. See the events list for a full list of the different events.
namespace (or ns)
Namespaces (or ns'es for short) is a new term used in Futurism. A namespace is simply a place on dAmn where people can talk. This is called a chatroom or channel in many other bots, but since private chats (pchats for short) are existant in dAmn too, we needed a term that covered both things. And that is what a namespace (or ns) is. And that's a term used nearly everywhere in Futurism's code. (However, it is still recommended to use the term chatrooms when talking to mere mortals, as pchats are yet to be available in the official client.)

First module

Alright, it's time to code our first module! And let's do it the classic way, and simply make a module that says "Hello, world!" when responding to a hello command activated by a user. Put the following code inside a hello.py file in the modules folder:

class helloModule:
	"""This module is an example of a very simple module."""
	def __init__(self):
		self.version = 0.8
		self.author  = "electricnet"
	def cmd_hello(self, cmd):
		dAmn.say("%s: Hello, world!" % (cmd.user), cmd.targetns)

(If you are already running your bot: When you have moved this into the modules folder, reload the bot modules, either by using the modules reload command or simply restarting the bot.)

What does this do?

When someone sends a hello command to the bot, the module above sends a message to dAmn saying "Hello, world!", directed to the one who sent the command.

How does it work?

As mentioned earlier, like many other things in Futurism, a module is an object. And so, you have to create a main class declaration for the module you want to make. If you create a file called hello.py in the modules folder, the module you are creating is then called hello. The module class name must then be helloModule, as seen above (i.e. the module name with Module at the end). The only way to change module name is to change these. Most modules only have this class in it, but as long as you have a class called this, you can generally do whatever you want with your module, and organize it as you want to.

The docstring (the string with three quote marks on both sides) of this class is read as the module description, so in there, you can write a little description for what the module does. The init method of this class declaration then defines the class properties version (float or str) and author (str, tuple or list), which tells the bot what version of this module this is, and the deviantART username of who created it. These will both be showed in the module info command about your module. You can have more than one author in the author variable, simply make it a tuple (or a list) of different dA usernames.

The next method seen in the module then registers a command with the name hello. This is very easy. To register a command under any name, simply create a method in your module class named what you want the command name to be, but prefixed with cmd_, and a single argument called cmd. The bot will then call this method whenever this command is sent to the bot, and the command is displayed in the commands list, too. When this command hello is run, it sends a message to the chatroom using the say method of the dAmn object. This message sends the text "Hello, world!" to the user who executed this command (found in cmd.user) by prefixing that user's name (like tabbing in dAmn), in the namespace which this user intended to send this command to (found in cmd.targetns). If the user prefixed a chatroom as the first argument, this is considered to be the target ns. This happens only rarely though, and when the user doesn't prefix any chatroom, the target ns is usually just the ns the command came from. If you want to target the namespace where the command came from no matter what, you can use the cmd.ns variable to get the namespace where the command came from.

And that's it! Not only was it explained how this little module works, but also in general explained how the code found in modules work.

A more advanced module

To explain what more can be done, the next module is a handy example that posts an announcement X seconds after the command requesting it was sent. Put the following code inside an announce.py file in the modules folder:

class announceModule:
	"""A module that controls the command that makes announcements X seconds after plan."""
	def __init__(self):
		self.version = 0.8
		self.author  = "electricnet"
	def cmd_announce(self, cmd):
		if not bot.user.has(cmd.user, 75): return False
		if len(cmd.arguments) >= 2:
			if len(cmd.arguments) >= 3 and cmd.arguments[1].isdigit(): # First argument is a number
				time    = int(cmd.arguments[1])
				message = " ".join(cmd.arguments[2:])
			else:
				time    = 0
				message = cmd.argumentsF
			reactor.callLater(time, dAmn.say, "<b>%s</b>" % (message), cmd.targetns) # Use callLater to call the dAmn.say method, instead of directly
		else:
			dAmn.say("%s: This command is used to make an announcement in the supplied chatroom X seconds after this command.\n<sup>Syntax: %sannouncement <i>[targetroom]</i> [seconds] [message]\nExamples: %sannouncement 5 Hello! %sannouncement #Botdom 10 Trivia in 5 minutes!" % (cmd.user, config.tr, config.tr, config.tr), cmd.ns)

(If you are already running your bot: When you have moved this into the modules folder, reload the bot modules, either by using the modules reload command or simply restarting the bot.)

What does this do?

This module holds a command that when called takes a number of seconds, a message and optionally an ns as first argument, and then sends a message to the target ns with an "announcement" being the message provided written in bold, but delayed the number of seconds supplied after the command was originally sent. If no arguments are present, it instead presents a guide on how to use the command. Also, the command can only be called by bot operators (users in a bot privclass of order 75) or higher. For users in a lower privclass, the command does not work.

How does it work?

This module is a bit more complicated, but there are things that look just like the previous module. There are still information about the modules being added in the docstring and in the init method, and there is still only one command as the only content in the module (which is not recommended for production release if there are more commands; all related commands should be grouped under a single module). The command in this module is again called the same as the module, announce. This is where this module is different, as the command is much more advanced. First the bot checks if the user sending the command is in a bot privclass of order 75 or higher (using bot.user.has), and then quits the method by returning False if they do not.

Next, the method sees if the length of the command arguments (found in cmd.arguments) is more than or equal to two, that is, if the command was sent with at least one argument. If it wasn't, it jumps to the final dAmn.say which presents a guide on how to use the command. But if it was, it continues. It then checks if the command was sent with at least 2 arguments (if length of cmd.arguments is more than or equal to three) and if the first argument then is a number. If both of these are true, it interprets the first argument as being the amount of seconds to wait before posting the message. Then, it joins the rest of the arguments together with a space starting from index 2, and sets that to be the message to be announced. If both of values in the previous if weren't true (that is, there is either only one argument or the first argument is not a number), the amount of seconds is just 0, and the message to announce is all arguments seperated by space (found in cmd.argumentsF).

Then, it uses the Twisted method reactor.callLater, part of Twisted's scheduling interface, to call the dAmn.say method those seconds later which were specified. The say method is then run with all the neccessary parameters, just as in the previous example, only passed through reactor.callLater. The timing is all handled by the Twisted framework, and so you can use this method to have modules depending on time scheduling various things.

Working with events

In the Terms section, events were mentioned. In these two past examples, we have only used commands to execute our code. We can also use events, and the module below showcases this. Put the following code inside a welcometest.py file in the modules folder:

class welcometestModule:
	"""This modules showcases a basic event handling."""
	def __init__(self):
		self.version = 0.8
		self.author  = "electricnet"
	def evt_recv_join(self, ns, user, properties):
		dAmn.say("<b>Hello :dev%s:! :D</b>" % (user), ns)

(If you are already running your bot: When you have moved this into the modules folder, reload the bot modules, either by using the modules reload command or simply restarting the bot.)

What does this do?

This module makes it so that whenever any user joins any namespace, the bot says the message "Hello :devusername:! :D" in bold.

How does it work?

The setting of this module's properties in the docstring and the init method is the same as the two modules above, but in this module there is a method that handles the event called recv_join (when someone joins a namespace), instead of one that handles a command. This event requires the following parameters: ns, user and properties. (Go to the events list for a list of events and what parameters each event needs (and what these parameters are).) The bot then greets it with a hello message with the username in it and in the namespace the user joined in. The handling part here is really simple, but it is very extensible. You can easily combine event handlers with commands, and e.g. use commands to modify what the bot does in these events. Events are really powerful, and you can do a lot of things with them, and it doesn't always have to be the bot saying anything when it happens. For example, every time the topic in a certain chat changes, you could use the bot to post the topic of the chat to a website owned by you, and thus always have a public log of the topics in the chatroom, available for everyone in the room. The limits are practically endless.

Distributing your modules

I hope you are now inspired to create modules of your own. When you have made your awesome module, you can upload it using the Botdom Upload System and add it to the Modules section of the Futurism page over at the Botdom Wiki.

And this is the end of the guide, so far. In the future, more content may be added. I hope you learned from this guide, and I can't wait to see the great modules that result from it! Have fun!

See also

Personal tools