Python Plugin Loader

PythonLoader 0.3.2

This plugin allows developers to code bukkit plugins in the python programming language. The plugins in python can either use a thin wrapper to the standard Bukkit API, or the newer decorator API. For more detailed instructions for installing this plugin and how to code plugins, take a look into the Readme on Github.

Features:

  • Load bukkit plugins written in python.

Installation: Put PythonLoader.jar into plugins directory and jython.jar into lib directory (within bukkit folder not plugins folder).

Downloads:

Documentation
The Readme on github contains an introduction to creating plugins in python
Also make sure to check out @zaph34r's tutorial series

I have to give special credits to lahwran who created the whole decorator API and corrected many of my mistakes. :)

You must login to post a comment. Don't have an account? Register to get one!

  • Avatar of zaph34r zaph34r May 09, 2012 at 20:34 UTC - 1 like

    @Cwbh10: Go

    Just create a .zip archive containing the .py and the .yml at root level (using 7zip or winzip or winrar, or whatever else),and rename it from .zip to .pyp or .py.zip :)

  • Avatar of Cwbh10 Cwbh10 May 09, 2012 at 20:23 UTC - 0 likes

    @zaph34r: Go

    Thanks a lot Zaph34r! That really help clear things up now, and I should be able to generate more accurate results xD!

    So, will there be a place where we can post out plugins for others to see?

    P.S. How do I create a zip the contains the yml and py that pyplugin loader will see, I've tried but it doesn't seem to see it. (Sorry for all the questions :P )

    My Server: Mc.Cmonkeycraft.info :3

  • Avatar of zaph34r zaph34r May 09, 2012 at 19:47 UTC - 1 like

    @Cwbh10: Go Ok so heres how the global keyword works (according to my knowledge, which might be wrong :D ):

    • whenever you use a variable name in python, it looks it up scope by scope, starting with local scope, then stepping outward trying again until it hits global scope. So inside a nested function, or loop, it would look stepwise in each outer function/loop, one after another.
    • To just access variables in any outer scope (say print a or a.foo()), you need to do nothing special, apart from not having a local variable of the same name shadowing it.
    • To assign something to a variable in global scope (say you defined a=0 in global scope, and want to change that variable with a = 1, you need to explicitely declare the variable as a global variable with global a, because otherwise python would create a local variable a and assign the value 1 to it (which is the default). This local variable would shadow the global a until you leave the scope (the local variable a would cease to exist after that, and the global one would be unchanged) So basically,global a tells python "do not create a new local variable a when i assign to that name later on in the current scope". So if you don't plan to assign anything new to the variable, you don't need global, that is why it works in your event handler if you just check if immediate:
    a = 0
    
    def foo():
        a = 2 # creates and assigns to local variable
    def bar():
        global a # declare that you intend to modify a global variable
        a = 2 # does NOT create a new local variable, instead assigns to the global one
    
    for i in range(3):
        a = i # creates a local variable 'a' with value 1
        print a # prints i
    
    print a # prints 0
    foo()
    print a # prints 0
    bar()
    print a # prints 2
    

    You should also generally do all global declarations at the beginning of the scope in which you want to use them, and not somewhere in the middle, and not use any local variables of the same name before using global, otherwise you get a syntax warning from the interpreter.


    There is also not a lot of stuff pre-imported, off the top of my hat, you can access:

    • PythonPlugin (from which you have to inherit if you want to use a plugin main class)
    • Listener (if you use my mod, inherit from that to use the additional decorators with class/instance/static methods)
    • hook (for the decorators amongst other things)
    • CustomEvent (to inherit from if you want to create custom events, although i haven't quite wrapped my head around how to make those work with other non-python plugins)
    • pyplugin (the instance of your plugin)
    • info (the plugin description)
    • sys (the builtin python module)

    Everything else you have to import, which is why the first few lines of any plugin i do are

    from java.io import File
    import org.bukkit as bukkit
    server = bukkit.Bukkit.getServer()
    log = server.getLogger()
    

    since i use those all the time :)

    There may be more pre-imported things in the future, i just today changed how the modification i did works, and that would allow for pre-loading certain boilerplate code automatically without lots of effort. I will look into that :)

    Last edited May 09, 2012 by zaph34r
  • Avatar of Cwbh10 Cwbh10 May 09, 2012 at 19:12 UTC - 0 likes

    @zaph34r: Go

    Oh, So I have to immediately define it as a global before each use? But wouldn't that break my function in the Event handler wouldn't it? Though it did work once I added the global in the command handler.

    I've been able to get it to declare outside the onEnable but I still have to call it as a global in the command handler but not the event handler.... (Confused face)

    I'm just slightly confused how globals are being handled throughout the program. No you're not bragging I just think your pretty boss xD

    Thnxs for the help btw

    P.S. Is there a list of pre-imported globals that Python does for me; I saw I had to import org.bukkit to access the colors which I thought was already done for me...

    Last edited May 09, 2012 by Cwbh10: Another ps
  • Avatar of zaph34r zaph34r May 09, 2012 at 18:52 UTC - 0 likes

    @Cwbh10: Go

    I certainly do hope i didn't come across as boasting :D The modified loader (that should be pulled into the main repository soon i think) does add a few things for convenience. There's a writeup of what it does here. The rationale behind the changes/additions was to make decorators work with instance methods, and the use of additional decorators was to change as little about the original python loader as possible, to avoid incompatibilities.


    Regarding your problem with the globals:

    __plugin_name__ = "globaltest"
    __plugin_version__ = "0.1"
    
    immediate = False
    
    @hook.enable
    def onEnable():
        global immediate
        immediate = True
        print "global test enabled"
        
    @hook.command
    def immediates(sender, args):
        print immediate
        global immediate
        immediate = not immediate
        print immediate
    

    This works for me, and is probably how you need to do it. I think global immediate is used to access a global variable, not to define it. You just use immediate = something, the keyword global is used to distinguish between accessing the global variable in the local scope and creation of a new local variable (and possibly shadowing a global one). You only need it when assigning to the global variable, since assignment would create a new local variable otherwise. When just accessing it (as i do here with print immediate before global immediate) it just looks for the name scope by scope until it either finds it,or doesn't find anything even in global scope, in which case it would throw a NameError.


    Regarding chat colors: use the bukkit.ChatColor enumeration, but remember that you cannot concatenate it with strings (since the ChatColor type doesn't have concatenation with strings defined), you need to format it in, like

    red_string = "%s"%bukkit.ChatColor.RED + "some other string"
    blue_text = "%sblablabla"%bukkit.ChatColor.BLUE
    
    Last edited May 09, 2012 by zaph34r
  • Avatar of Cwbh10 Cwbh10 May 09, 2012 at 18:03 UTC - 0 likes

    @masteroftime: Go I deleted the old code from the other plugin, but just ran into the same issue again. I've tried the global declaration in and out of the onEnable... It just limits what I can do ya know? Anyways, please try to attack me about my code's neatness xD

    I get the error: " File "<iostream>", line 74, in immediates UnboundLocalError: local variable 'immediate' referenced before assignment"

    But I don't see what it says it's local... I've also tried calling the global inside the same function, but in the previous function the global worked in a few functions before ceasing to work in later ones..

    P.S. How do I get color in the chat for my plugin? I've looked around (e.g. http://jd.bukkit.org/doxygen/df/d1d/ChatColorTest_8java_source.html) but I still can't find a way to get it into my plugins...

    '''
    Created on May 7, 2012
    '''
    
    
    __plugin_name__ = "ShortURL"
    __plugin_version__ = "0.1"
    
    import urllib, thread
    global immediate
    
    def log(text):
        prefix = "[%s] " % __plugin_name__
        print(prefix+text)
        
    def tinyurl(url):
        
        openurl = urllib.urlopen("http://tinyurl.com/api-create.php?url=" + url)
        tinyurl = openurl.read()
        openurl.close()
        
        return tinyurl
    
    def sendtinylink(sender,text,linkbool):
        if linkbool:
            text = "[Tiny]: " + tinyurl(text)
            sender.sendMessage(text)
    
    @hook.enable
    def onEnable():
        global immediate
        immediate = True
        log("Enabled!")
    
    @hook.disable
    def onDisable():
        log("Disabled!")
        
    @hook.event("player.PlayerChatEvent", "normal")
    def chatevent(event):
        try:
            http_prefix = "http://"
            original = str(event.getMessage())
            check = 0
        
            if http_prefix in original:
                for char in http_prefix: ## Make sure the http:// is the first 7 characters in the text
                    if http_prefix[check] == original[check]: ## If the letters match
                        check += 1
                    else:
                        break
                
                if check == len(http_prefix):
                
                    sender = event.getPlayer()
                    if immediate == True:
                        event.setMessage(tinyurl(original))
                    elif immediate == False:
                        event.setMessage(original)
                        
                        thread.start_new_thread(sendtinylink,(sender,original,True)) ## Prevent the annoying chat-lag otherwised have been caused
                else:
                    pass 
                   
            else:
                pass
        except:
            log("A CRITICAL ERROR HAS OCCORED! :O")
    
    @hook.command
    def immediates(sender, args):
        if immediate == True:
            immediate = False
            
        elif immediate == False:
            immediate = True
    
    Last edited May 09, 2012 by Cwbh10: a ps
  • Avatar of masteroftime masteroftime May 08, 2012 at 16:34 UTC - 0 likes

    @Cwbh10: Go

    Could you maybe post code which produces the error here or as a ticket?

    Last edited May 08, 2012 by masteroftime
  • Avatar of Cwbh10 Cwbh10 May 07, 2012 at 15:21 UTC - 0 likes

    Okay, while I've been loving the PythonPlugin Loader, it hasn't been without it's faults.

    I'm having a rather major issue in that the fact that I want to have global variables across my script, and for some reason after I declare the variable outside any function and set the variable in the onEnable() it isn't recognized in later functions. I also have tried putting the "global var" inside the onEnable() and it only seems to recognize the global for another 3 functions out of the 3+. I've spent many hours on this so if anyone could help that would be great! Besides that, PythonPlugin Loader as been a great tool!

    Ps. @zaph34r what is this modified pythonplugin loader you boast about in your tutorial? What are the changes in using it. I've notice you write differently than I do in your examples... any reason for the choice?

  • Avatar of zaph34r zaph34r May 03, 2012 at 14:04 UTC - 2 likes

    I have started a collection of Tutorials for Python Plugin Development, that might help some people getting started. They contain practical example plugins and a step-by-step walkthrough on how to create them and what each part does.

    Feel free to direct any requests for additional tutorial topics or specific things that you would like to have explained in more detail to me and i will see what i can do :)

  • Avatar of Sithdown Sithdown Apr 30, 2012 at 03:12 UTC - 0 likes

    THANKS.

    <3 Python.

Table of contents

  1. 1 PythonLoader 0.3.2

Facts

Date created
Aug 27, 2011
Category
Last update
Apr 05, 2012
Development stage
Release
License
GNU General Public License version 3 (GPLv3)
Curse link
Python Plugin Loader
Downloads
435
Recent files

Authors