User Tools

Site Tools


Sidebar

B3 Homepage


Main Links


Support Subjects


Related Links


This wiki was updated recently and all user accounts were reset. If you want to contribute to this documentation wiki drop me an email at xlr8or[at]bigbrotherbot[dot]net.

customize:plugin_sdk:tutorial1

Plugin tutorial 1 : defining new commands

In this tutorial we will make a plugin that will define 3 new B3 commands : !hello, !hi and !foo

As it is the first tutorial, a few other aspects of B3 plugin programming will be also detailed :

  • writing to B3 log file
  • sending a message to all connected players
  • sending a private message to a player
  • writing and running automated tests on the plugin

If you have any question or comment regarding this tutorial, please use this topic from our forums.

the plugin code

tutorial1.py
#
# HelloWorld Plugin for BigBrotherBot(B3) (www.bigbrotherbot.net)
# Copyright (C) 2011 Courgette
# 
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#
 
__version__ = '1.0'
__author__  = 'Courgette'
 
import b3
import b3.events
import b3.plugin
 
 
class Tutorial1Plugin(b3.plugin.Plugin):
 
    def onStartup(self):
        # get the admin plugin so we can register commands
        self._adminPlugin = self.console.getPlugin('admin')
 
        if not self._adminPlugin:
            # something is wrong, can't start without admin plugin
            self.error('Could not find admin plugin')
            return
 
        # Register commands
        self._adminPlugin.registerCommand(self, 'helloworld', 1, self.helloWorld, 'hw')
        self._adminPlugin.registerCommand(self, 'hi', 2, self.hi)
        self._adminPlugin.registerCommand(self, 'foo', 2, self.the_foo)
 
 
    def helloWorld(self,  data, client, cmd):
        """Say 'Hello World!' to everyone"""
        self.console.say('Hello World!')
 
    def hi(self,  data, client, cmd):
        """Say 'Hi!' to everyone in a very visible manner"""
        self.console.saybig('Hi!')
 
    def the_foo(self, data, client, cmd):
        """Send a private message to the player who typed the command"""
        client.message('bar')
 
if __name__ == '__main__':
    """The code below is meant for tests.
    It will never be executed from B3.
 
    To run the tests on Windows, open a new DOS console and type :
    set PYTHONPATH=c:\where\b3\is\installed && c:\python27\python.exe tutorial1.py
 
    To run the tests on Linux, open a new console and type :
    PYTHONPATH=/where/b3/is/installed python tutorial1.py
 
    """
 
    # create a fake console which emulates B3
    from b3.fake import fakeConsole, joe, superadmin
 
    myplugin = Tutorial1Plugin(fakeConsole)
    print("\n\n * * * * * * * * * * * *  Tests starting below * * * * * * * * * * * * \n\n")
 
    # we call onStartup() as the real B3 would do
    myplugin.onStartup()
 
    # make superadmin connect to the fake game server on slot 0
    superadmin.connects(cid=0)
 
    # make joe connect to the fake game server on slot 1
    joe.connects(cid=1)
 
    # superadmin put joe in group user
    superadmin.says('!putgroup joe user')
    superadmin.says('!leveltest joe')
 
    # make joe try our commands
    joe.says('!helloworld')
    joe.says('!hi')
 
    # make superadmin try the !hi command
    superadmin.says('!putgroup joe reg')
    joe.says('!hi')
 
    # make joe try the !foo command
    joe.says('!foo')

Writting to B3 log file

Within the plugin code, we can use a set of method to write to the B3 log file :

Method usage
debug self.debug('test')
info self.info('test')
warning self.warning('test')
error self.error('test')

Registering a new command

The admin plugin is in charge of all B3 commands. For our plugin to add new commands, we need to register them to the admin plugin.

getting the admin plugin

Firstly, we need to get the admin plugin :

    # get the admin plugin so we can register commands
    self._adminPlugin = self.console.getPlugin('admin')

Now we can use self._adminPlugin to register our commands.

registering commands

The registerCommand method takes 4 mandatory parameters :

  • the plugin registering the commands (as it is our current plugin, we use the python keyword self)
  • a string representing the command we want to register (without the command prefix '!')
  • a integer representing the minimum level required to use the command (see group levels)
  • a method to call when the command is typed by a player

and an optional parameters :

  • alias : a string representing an additional name for that command
self._adminPlugin.registerCommand(self, 'helloworld', 1, self.helloWorld, 'hw')

tells the admin plugin to register the command 'helloworld' that will be available to registered users (1) and will execute the code defined in our self.helloWorld method. Also tells the admin plugin to register an alias 'hw' for that command

self._adminPlugin.registerCommand(self, 'hi', 2, self.hi)

tells the admin plugin to register the command 'hi' that will be available to regular users (2) and will execute the code defined in our self.hi method.

Interacting with players

Sending messages to all players

Our plugin has now registered two commands that will execute the helloWorld and hi methods. These methods need to broadcast a message to all connected players. To do so, our plugin will use methods available in self.console

Method usage description
say self.console.say('test1') will write “test1” on the game server console zone for all players to see
saybig self.console.saybig('test2') will write “test2” on the game server console zone for all players to see in a more visible way (depending on the game)

Sending a private message

Our plugin also registered the !foo command that executes our plugin method the_foo and which is supposed to send a private message to the player who typed the command. To do so, our the_foo method needs to know who typed the command. This is done through the client parameter of the_foo method.

When the admin plugin recognizes a command, it will then execute the associated plugin method with 3 parameters :

  • data : the optional parameters the player put after the command
  • client : a client object which represents the player who typed the command
  • command : a command object which represents the registered command in the admin plugin
    def the_foo(self, data, client, cmd):
        """Send a private message to the player who typed the command"""
        client.message('bar')

Here, we use the message method of the Client class to send a private message to the player represented by the client object that was passed on to our method.

Other types of interaction with players

Other Client methods you can use in your plugins are :

Method Usage Description
message joe.message('a private message') send a private message to the player represented by the joe client object
kick client.kick(reason='do not call me noob') kicks the player represented by the client Client object with the reason message “do not call me noob”. Depending on the game the kicked player will see the reason.
ban joe.ban(reason='aimbot') ban permanently the player joe with “aimbot” as a reason message
tempban joe.tempban(duration='3m', reason='tk') ban joe for 3 minutes with reason “tk”
unban joe.unban() disable currently active ban for joe
warn joe.warn(duration='1h', warning=“watch your mouth”) give a warning to joe that will expire in 1 hour with reason “watch your mouth”
notice joe.notice('might be cheating') save a notification message for player joe that will be viewable in Echelon only

Plugin automated testing

In the plugin code you probably noticed a strange line :

if __name__ == '__main__':

The test in this line is only verified when you call directly the plugin file. When B3 loads your plugin, the code under this line will never be run. This is convenient to place our automated plugin tests.

The fake module

The B3 framework comes with a ''fake'' module which is able to emulate B3 and your game server. In the test section, we will start by importing from the fake module a fakeconsole which will emulate B3 and a game server and also two fake users : joe and superadmin.

The fake module provides you 4 users ready to use in your tests :

  • simon : a unregistered user (no group)
  • joe : a registered user (group User)
  • moderator : a user from the Moderator group
  • superadmin : a user from the Super admin group

You can make these users write commands as if they were in the game. The available methods for the fake users are :

Method usage description
connects joe.connects(cid=<some slot id>) make B3 think joe just connected on the fake game server
disconnects joe.disconnects() make B3 think joe disconnected on the fake game server
says joe.says(“something”) make B3 think joe said “something” on the fake game server
say2team joe.says2team(“bla”) make B3 think joe said “bla” to its team on the fake game server
damages joe.damages(simon) make B3 think joe did some damage to simon on the fake game server
kills joe.kills(simon) make B3 think joe killed simon on the fake game server
suicides joe.suicides() make B3 think joe committed suicide on the fake game server

Running the tests

On my computer, I have extracted the B3 source code in c:\b3_1.5, the plugin file is in c:\b3-plugins\tutorials\ and I've got Python 2.6 installed in c:\python26\. The command line I use to run the plugin tests is then :

set PYTHONPATH=c:\b3_1.5\ && c:\python26\python.exe c:\b3-plugins\tutorials\tutorial1.py

And below is the result of the tests :

creating fakeConsole with @b3/conf/b3.distribution.xml
creating fakeAdminPlugin with @b3/conf/plugin_admin.xml
BOT      : AdminPlugin: Loading config @b3/conf/plugin_admin.xml for AdminPlugin
DEBUG    : Register Event: Stop Process: AdminPlugin
...
ERROR    : Tutorial1Plugin: Could not load config for Tutorial1Plugin
DEBUG    : Register Event: Stop Process: Tutorial1Plugin
DEBUG    : Register Event: Program Exit: Tutorial1Plugin


 * * * * * * * * * * * *  Tests starting below * * * * * * * * * * * * 


DEBUG    : AdminPlugin: Command "helloworld (hw)" registered with helloWorld for level (1, 100)
DEBUG    : AdminPlugin: Command "hi (None)" registered with hi for level (2, 100)
DEBUG    : AdminPlugin: Command "foo (None)" registered with the_foo for level (2, 100)

God connects to the game on slot #0
VERBOSE  : 0 cid changed from None to 0
DEBUG    : Client Connected: [0] God - f4qfer654r ({})
DEBUG    : User not found f4qfer654r: 'No client found in fakestorage for {id: 0, guid: f4qfer654r}'
BOT      : Client not found in the storage f4qfer654r, create new
VERBOSE2 : Aborted Making Alias for cid: 0, name is the same
DEBUG    : Client Authorized: [0] God - f4qfer654r

Joe connects to the game on slot #1
VERBOSE  : 0 cid changed from None to 1
DEBUG    : Client Connected: [1] Joe - zaerezarezar ({})
DEBUG    : User not found zaerezarezar: 'No client found in fakestorage for {id: 0, guid: zaerezarezar}'
BOT      : Client not found in the storage zaerezarezar, create new
VERBOSE2 : Aborted Making Alias for cid: 1, name is the same
DEBUG    : Client Authorized: [1] Joe - zaerezarezar

God says "!putgroup joe user"
VERBOSE  : Queueing event Say !putgroup joe user
VERBOSE  : Parsing Event: Say: AdminPlugin
DEBUG    : AdminPlugin: OnSay handle 5:"!putgroup joe user"
DEBUG    : AdminPlugin: Handle command !putgroup joe user
sending msg to God: Joe is already in group User

God says "!leveltest joe"
VERBOSE  : Queueing event Say !leveltest joe
VERBOSE  : Parsing Event: Say: AdminPlugin
DEBUG    : AdminPlugin: OnSay handle 5:"!leveltest joe"
DEBUG    : AdminPlugin: Handle command !leveltest joe
DEBUG    : formatting time with timezone [CST], tzOffset : -21600
sending msg to God: Joe [@2] is a User [1] since 10:45AM CST 03/27/11

Joe says "!helloworld"
VERBOSE  : Queueing event Say !helloworld
VERBOSE  : Parsing Event: Say: AdminPlugin
DEBUG    : AdminPlugin: OnSay handle 5:"!helloworld"
DEBUG    : AdminPlugin: Handle command !helloworld
>>> Hello World!

Joe says "!hi"
VERBOSE  : Queueing event Say !hi
VERBOSE  : Parsing Event: Say: AdminPlugin
DEBUG    : AdminPlugin: OnSay handle 5:"!hi"
DEBUG    : AdminPlugin: Handle command !hi
sending msg to Joe: You do not have sufficient access to use !hi

God says "!putgroup joe reg"
VERBOSE  : Queueing event Say !putgroup joe reg
VERBOSE  : Parsing Event: Say: AdminPlugin
DEBUG    : AdminPlugin: OnSay handle 5:"!putgroup joe reg"
DEBUG    : AdminPlugin: Handle command !putgroup joe reg
sending msg to God: Joe put in group Regular

Joe says "!hi"
VERBOSE  : Queueing event Say !hi
VERBOSE  : Parsing Event: Say: AdminPlugin
DEBUG    : AdminPlugin: OnSay handle 5:"!hi"
DEBUG    : AdminPlugin: Handle command !hi
+++ Hi!

Joe says "!foo"
VERBOSE  : Queueing event Say !foo
VERBOSE  : Parsing Event: Say: AdminPlugin
DEBUG    : AdminPlugin: OnSay handle 5:"!foo"
DEBUG    : AdminPlugin: Handle command !foo
sending msg to Joe: bar
customize/plugin_sdk/tutorial1.txt · Last modified: 2011/07/25 00:00 (external edit)

Page Tools