diff --git a/pom.xml b/pom.xml index d62903e..602717c 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 org.masteroftime PyPluginLoader - 0.3.5 + 0.3.6 PyPluginLoader UTF-8 @@ -16,7 +16,7 @@ bukkit-repo - http://repo.bukkit.org/content/groups/public + https://hub.spigotmc.org/nexus/content/repositories/snapshots @@ -99,12 +99,12 @@ org.python jython-standalone - 2.5.3 + 2.7.0 org.bukkit bukkit - 1.3.2-R3.0 + LATEST diff --git a/readme.md b/readme.md index d88eb64..849c624 100644 --- a/readme.md +++ b/readme.md @@ -23,7 +23,7 @@ Running 0. Ensure you are using a bukkit build that uses https://github.com/Bukkit/Bukkit/pull/335 - otherwise, only some of your plugins will work. -1. Put PyPluginLoader-0.2.jar in your bukkit/plugins/ dir +1. Put PyPluginLoader-0.3.6.jar in your bukkit/plugins/ dir 2. Put jython.jar in your bukkit/lib/ dir 3. [Re-]Start bukkit @@ -70,6 +70,9 @@ your plugin.py: print "enabled!" def onDisable(): print "disabled!" + def onLoaded(): + print "load complete!" + Decorator API ------------- @@ -94,7 +97,11 @@ your main.py: @hook.disable def ondisable(): print "main.py disabled" - + + @hook.load_complete + def onloadcomplete(): + print "main.py loading complete" + @hook.event("player.PlayerJoinEvent", "normal") def playerjoin(event): event.getPlayer().sendMessage("Hello from python") @@ -202,6 +209,30 @@ Summary of fields: - "website" - mainly for people reading the code +Plugin resources +---------------- + +Some plugins may contain resource files. Unlike the code these files maybe text, images +or other binary files. When this is the case you need some way to access resources packed +within a plugin. Plugin object accessible from python interpreter globals has a special +method to obtain resource files data from within the plugin. + + def init_plugin(): + resource_data = pyplugin.getPyResource(resource_filename) + with resource_data: + for record in resource_data: + ... + +getPyResource() method of the pyplugin exposed object take a resource file path local to +plugin container (zip archive or folder) and returns python file object available for +reading. That file object needs to be closed after. Context manager may be used for this +purpose. +Resource files may only be accessed before plugin loaded will close the plugin file +(in case of zip for example); best place for this is a load_complete hook handler +which is called right after pyplugin object instantiated and before plugin file will be +closed by plugin loader. + + Decorator api ------------- @@ -346,6 +377,21 @@ examples: def onDisable(): print "disabled!" +Initialization +************** + +Function decorated with hook.load_complete is called when your +plugin is first loaded and immediately after plugin object is instantiated. +this functionality is intended to provide you a point when a once per server run +plugin initialization routine should be called. + +examples: + + @hook.load_complete + def onLoadComplete(): + doInit(pyplugin) + print "initialization complete!" + Accessing the plugin object *************************** @@ -386,13 +432,17 @@ main.py @hook.disable def onDisable(): print "sample plugin disabled" + + @hook.load_complete + def onLoadComplete(): + print "sample plugin loading complete" @hook.event("player_join", "normal") def onPlayerJoin(event): msg = "welcome from the sample plugin, %s" % event.getPlayer().getName() print msg event.getPlayer().sendMessage(msg) - + @hook.command("samplecommand", usage="/", desc="send a sample message") def onSampleCommand(sender, command, label, args): @@ -437,7 +487,10 @@ plugin.py def onDisable(self): print "sample plugin disabled" - + + def onLoaded(self): + print "sample plugin load complete" + def onCommand(self, sender, command, label, args): msg = "sample plugin command" print msg diff --git a/src/main/java/net/lahwran/bukkit/jython/PluginImporter.java b/src/main/java/net/lahwran/bukkit/jython/PluginImporter.java index 2ce173e..9d739b6 100644 --- a/src/main/java/net/lahwran/bukkit/jython/PluginImporter.java +++ b/src/main/java/net/lahwran/bukkit/jython/PluginImporter.java @@ -10,7 +10,7 @@ import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyTuple; -import org.python.modules.imp; +import org.python.modules._imp; /** * Unfinished importer to separate plugins into their own namespaces, possibly also import @@ -61,7 +61,7 @@ private PyObject retrieveModule(String name) { PyString pypath = new PyString(pluginpath.getAbsolutePath()); PyObject[] elements = new PyObject[] {pypath}; PyList paths = new PyList(elements); - PyObject result = imp.find_module(subname, paths); + PyObject result = _imp.find_module(subname, paths); if (result != null) { PyTuple info = (PyTuple) result; diff --git a/src/main/java/net/lahwran/bukkit/jython/PythonHooks.java b/src/main/java/net/lahwran/bukkit/jython/PythonHooks.java index 9324b98..87c492e 100644 --- a/src/main/java/net/lahwran/bukkit/jython/PythonHooks.java +++ b/src/main/java/net/lahwran/bukkit/jython/PythonHooks.java @@ -52,6 +52,11 @@ public class PythonHooks { */ PyFunction onDisable; + /** + * Function to call when plugin is initialized + */ + PyFunction onLoaded; + /** * List of handlers to register */ @@ -247,6 +252,21 @@ public PyFunction disable(PyFunction func) { return func; } + /** + * Python decorator. functions decorated with this are called on load complete + *
+     * @hook.load_complete
+     * def loaded():
+     *     print "load complete!"
+     * 
+ * @param func function to decorate + * @return decorated function + */ + public PyFunction load_complete(PyFunction func) { + onLoaded = func; + return func; + } + /** * Python decorator. functions decorated with this are called as event handlers * @param type event type diff --git a/src/main/java/net/lahwran/bukkit/jython/PythonPlugin.java b/src/main/java/net/lahwran/bukkit/jython/PythonPlugin.java index 5d80ef1..da6b4fe 100644 --- a/src/main/java/net/lahwran/bukkit/jython/PythonPlugin.java +++ b/src/main/java/net/lahwran/bukkit/jython/PythonPlugin.java @@ -27,6 +27,9 @@ import org.bukkit.plugin.PluginLogger; import org.bukkit.plugin.java.JavaPlugin; import org.python.util.PythonInterpreter; +import org.python.core.util.FileUtil; +import org.python.core.PyFile; +import org.python.core.PyString; import com.avaje.ebean.EbeanServer; import com.avaje.ebeaninternal.api.SpiEbeanServer; @@ -274,6 +277,11 @@ public PluginCommand getCommand(String name) { */ public void onLoad() {} + public void onLoaded() { + if (hooks.onLoaded != null) + hooks.onLoaded.__call__(); + } + public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { getServer().getLogger().severe("Plugin " + getDescription().getFullName() + " does not contain any generators that may be used in the default world!"); return null; @@ -335,6 +343,19 @@ public InputStream getResource(String filename) { } } + public PyFile getPyResource(PyString filename) { + if(filename == null) { + throw new IllegalArgumentException("Filename cannot be null"); + } + + try { + return FileUtil.wrap(dataFile.getStream(filename.asString())); + } catch (IOException e) { + //just return null and do not print stack trace as JavaPlugin's getResource does not print it either + return null; + } + } + @Override public void saveResource(String resourcePath, boolean replace) { if (resourcePath == null || resourcePath.equals("")) { diff --git a/src/main/java/net/lahwran/bukkit/jython/PythonPluginLoader.java b/src/main/java/net/lahwran/bukkit/jython/PythonPluginLoader.java index e78a837..a8461da 100644 --- a/src/main/java/net/lahwran/bukkit/jython/PythonPluginLoader.java +++ b/src/main/java/net/lahwran/bukkit/jython/PythonPluginLoader.java @@ -171,10 +171,7 @@ private Plugin loadPlugin(File file, boolean ignoreSoftDependencies, PluginDataF ArrayList depend; try { - depend = (ArrayList) description.getDepend(); - if (depend == null) { - depend = new ArrayList(); - } + depend = new ArrayList(description.getDepend()); } catch (ClassCastException ex) { throw new InvalidPluginException(ex); } @@ -288,6 +285,8 @@ private Plugin loadPlugin(File file, boolean ignoreSoftDependencies, PluginDataF result.initialize(this, server, description, dataFolder, file); result.setDataFile(data); + + result.onLoaded(); } catch (Throwable t) { if (data.shouldAddPathEntry() && pythonpath.__contains__(filepath)) { diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 4b476db..670c173 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,3 +1,3 @@ name: PythonLoader main: com.master.bukkit.python.PythonLoader -version: 0.3.4 +version: 0.3.6