This commit is contained in:
walterhiggins 2013-12-24 00:17:07 +00:00
parent 4d807373da
commit aa93491a6c

View file

@ -49,7 +49,12 @@ As of February 10 2013, the js-plugins directory has the following sub-directori
## Core Module ## Core Module
This module defines commonly used functions by all plugins... This module defines commonly used functions by all plugins...
* echo (message) - Displays a message on the screen.
For example: `/js echo('Hello World')` will print Hello World on the in-game chat window.
For programmers familiar with Javascript web programming, an `alert` function is also provided.
`alert` works exactly the same as `echo` e.g. `alert('Hello World')`
* load (filename,warnOnFileNotFound) - loads and evaluates a javascript file, returning the evaluated object. * load (filename,warnOnFileNotFound) - loads and evaluates a javascript file, returning the evaluated object.
* save (object, filename) - saves an object to a file. * save (object, filename) - saves an object to a file.
@ -140,7 +145,7 @@ whose state you want to have managed by ScriptCraft - that is - a
Module whose state will be loaded at start up and saved at shut down. Module whose state will be loaded at start up and saved at shut down.
A plugin is just a regular javascript object whose state is managed by A plugin is just a regular javascript object whose state is managed by
ScriptCraft. The only member of the plugin which whose persistence is ScriptCraft. The only member of the plugin which whose persistence is
managed by Scriptcraft is `state` - this special member will be managed by Scriptcraft is `store` - this special member will be
automatically saved at shutdown and loaded at startup by automatically saved at shutdown and loaded at startup by
ScriptCraft. This makes it easier to write plugins which need to ScriptCraft. This makes it easier to write plugins which need to
persist data. persist data.
@ -225,7 +230,6 @@ There are a couple of special javascript variables available in ScriptCraft...
* self - the current player. (Note - this value should not be used in multi-threaded scripts - it's not thread-safe) * self - the current player. (Note - this value should not be used in multi-threaded scripts - it's not thread-safe)
***/ ***/
var verbose = verbose || false;
/* /*
wph 20130124 - make self, plugin and server public - these are far more useful now that tab-complete works. wph 20130124 - make self, plugin and server public - these are far more useful now that tab-complete works.
*/ */
@ -239,13 +243,14 @@ var server = org.bukkit.Bukkit.server;
// //
if (typeof load == "function") if (typeof load == "function")
return ; return ;
var File = java.io.File;
var _canonize = function(file){ var _canonize = function(file){
return "" + file.getCanonicalPath().replaceAll("\\\\","/"); return "" + file.getCanonicalPath().replaceAll("\\\\","/");
}; };
var _originalScript = __script; var _originalScript = __script;
var parentFileObj = new java.io.File(__script).getParentFile(); var parentFileObj = new File(__script).getParentFile();
var jsPluginsRootDir = parentFileObj.getParentFile(); var jsPluginsRootDir = parentFileObj.getParentFile();
var jsPluginsRootDirName = _canonize(jsPluginsRootDir); var jsPluginsRootDirName = _canonize(jsPluginsRootDir);
@ -257,9 +262,15 @@ var server = org.bukkit.Bukkit.server;
*/ */
var _load = function(filename,warnOnFileNotFound) var _load = function(filename,warnOnFileNotFound)
{ {
var result = null; var FileReader = java.io.FileReader
,BufferedReader = java.io.BufferedReader
,result = null
,file = filename
,r = undefined;
var file = new java.io.File(filename); if (!(filename instanceof File))
file = new File(filename);
var canonizedFilename = _canonize(file); var canonizedFilename = _canonize(file);
// //
// wph 20130123 don't load the same file more than once. // wph 20130123 don't load the same file more than once.
@ -267,27 +278,24 @@ var server = org.bukkit.Bukkit.server;
if (_loaded[canonizedFilename]) if (_loaded[canonizedFilename])
return _loaded[canonizedFilename]; return _loaded[canonizedFilename];
if (verbose)
print("loading " + canonizedFilename);
if (file.exists()) { if (file.exists()) {
var parent = file.getParentFile(); var parent = file.getParentFile();
var reader = new java.io.FileReader(file); var reader = new FileReader(file);
var br = new java.io.BufferedReader(reader); var br = new BufferedReader(reader);
__engine.put("__script",canonizedFilename); __engine.put("__script",canonizedFilename);
__engine.put("__folder",(parent?_canonize(parent):"")+"/"); __engine.put("__folder",(parent?_canonize(parent):"")+"/");
var code = ""; var code = "";
try{ try{
if (file.getCanonicalPath().endsWith(".coffee")) { if (file.getCanonicalPath().endsWith(".coffee")) {
var r = undefined;
while ((r = br.readLine()) !== null) code += "\"" + r + "\" +\n"; while ((r = br.readLine()) !== null) code += "\"" + r + "\" +\n";
code += "\"\""; code += "\"\"";
var code = "load(__folder + \"../core/_coffeescript.js\"); var ___code = "+code+"; eval(CoffeeScript.compile(___code, {bare: true}))"; var code = "load(__folder + \"../core/_coffeescript.js\"); var ___code = "+code+"; eval(CoffeeScript.compile(___code, {bare: true}))";
} else { } else {
while ((r = br.readLine()) !== null) code += r + "\n"; while ((r = br.readLine()) !== null)
code += r + "\n";
} }
result = __engine.eval(code); result = __engine.eval("(" + code + ")");
_loaded[canonizedFilename] = result || true; _loaded[canonizedFilename] = result || true;
}catch (e){ }catch (e){
__plugin.logger.severe("Error evaluating " + canonizedFilename + ", " + e ); __plugin.logger.severe("Error evaluating " + canonizedFilename + ", " + e );
@ -306,168 +314,12 @@ var server = org.bukkit.Bukkit.server;
return result; return result;
}; };
/* /*
recursively walk the given directory and return a list of all .js files now that load is defined, use it to load a global config object
*/ */
var _listSourceFiles = function(store,dir) var config = _load(new File(jsPluginsRootDir, "data/global-config.json" ));
{ if (!config)
if (typeof dir == "undefined"){ config = {verbose: false};
dir = new java.io.File(_originalScript).getParentFile().getParentFile(); global.config = config;
}
var files = dir.listFiles();
for (var i = 0;i < files.length; i++){
var file = files[i];
if (file.isDirectory()){
_listSourceFiles(store,file);
}else{
if ((file.getCanonicalPath().endsWith(".js") || file.getCanonicalPath().endsWith(".coffee")) &&
!(file.getName().startsWith("_")) &&
file.exists())
{
store.push(file);
}
}
}
};
/*
sort so that .js files with same name as parent directory appear before
other files in the same directory
*/
var sortByModule = function(a,b){
a = _canonize(a);
b = _canonize(b);
var aparts = (""+a).split(/\//);
var bparts = (""+b).split(/\//);
//var adir = aparts[aparts.length-2];
var adir = aparts.slice(0,aparts.length-1).join("/");
var afile = aparts[aparts.length-1];
//var bdir = bparts[bparts.length-2];
var bdir = bparts.slice(0,bparts.length-1).join("/");
var bfile = bparts[bparts.length-1];
if(adir<bdir) return -1;
if(adir>bdir) return 1;
afile = afile.match(/[a-zA-Z0-9\-_]+/)[0];
if (adir.match(new RegExp(afile + "$")))
return -1;
else
return 1;
};
/*
Reload all of the .js files in the given directory
*/
var _reload = function(pluginDir)
{
_loaded = [];
var sourceFiles = [];
_listSourceFiles(sourceFiles,pluginDir);
sourceFiles.sort(sortByModule);
//
// script files whose name begins with _ (underscore)
// will not be loaded automatically at startup.
// These files are assumed to be dependencies/private to plugins
//
// E.g. If you have a plugin called myMiniGame.js in the myMiniGame directory
// and which in addition to myMiniGame.js also includes _myMiniGame_currency.js _myMiniGame_events.js etc.
// then it's assumed that _myMiniGame_currency.js and _myMiniGame_events.js will be loaded
// as dependencies by myMiniGame.js and do not need to be loaded via js reload
//
var len = sourceFiles.length;
for (var i = 0;i < len; i++){
load(_canonize(sourceFiles[i]),true);
}
};
/*
Save a javascript object to a file (saves using JSON notation)
*/
var _save = function(object, filename){
var objectToStr = null;
try{
objectToStr = JSON.stringify(object);
}catch(e){
print("ERROR: " + e.getMessage() + " while saving " + filename);
return;
}
var f = new java.io.File(filename);
var out = new java.io.PrintWriter(new java.io.FileWriter(f));
out.println("__data = " + objectToStr);
out.close();
};
/*
plugin management
*/
var _plugins = {};
var _plugin = function(/* String */ moduleName, /* Object */ moduleObject, isPersistent)
{
//
// don't load plugin more than once
//
if (typeof _plugins[moduleName] != "undefined")
return _plugins[moduleName].module;
var pluginData = {persistent: isPersistent, module: moduleObject};
moduleObject.store = moduleObject.store || {};
_plugins[moduleName] = pluginData;
if (isPersistent)
moduleObject.store = load(jsPluginsRootDirName + "/" + moduleName + "-store.txt") || {};
global[moduleName] = moduleObject;
return moduleObject;
};
/*
allow for deferred execution (once all modules have loaded)
*/
var _deferred = [];
var _ready = function( func ){
_deferred.push(func);
};
var _cmdInterceptors = [];
/*
command management - allow for non-ops to execute approved javascript code.
*/
var _commands = {};
var _command = function(name,func,options,intercepts)
{
if (typeof name == "undefined"){
// it's an invocation from the Java Plugin!
if (__cmdArgs.length === 0)
throw new Error("Usage: jsp command-name command-parameters");
var name = __cmdArgs[0];
var cmd = _commands[name];
if (typeof cmd === "undefined"){
// it's not a global command - pass it on to interceptors
var intercepted = false;
for (var i = 0;i < _cmdInterceptors.length;i++){
if (_cmdInterceptors[i](__cmdArgs))
intercepted = true;
}
if (!intercepted)
self.sendMessage("Command '" + name + "' is not recognised");
}else{
func = cmd.callback;
var params = [];
for (var i =1; i < __cmdArgs.length;i++){
params.push("" + __cmdArgs[i]);
}
return func(params);
}
}else{
if (typeof options == "undefined")
options = [];
_commands[name] = {callback: func, options: options};
if (intercepts)
_cmdInterceptors.push(func);
return func;
}
};
var _rmCommand = function(name){
delete _commands[name];
};
/* /*
Tab Completion of the /js and /jsp commands Tab Completion of the /js and /jsp commands
*/ */
@ -568,6 +420,7 @@ var server = org.bukkit.Bukkit.server;
} }
return result; return result;
}; };
var _commands;
/* /*
Tab completion for the /js command Tab completion for the /js command
*/ */
@ -775,41 +628,41 @@ See [issue #69][issue69] for more information.
__plugin.pluginLoader.enablePlugin(__plugin); __plugin.pluginLoader.enablePlugin(__plugin);
}; };
var _echo = function (msg) {
__plugin.logger.info( msg );
if (typeof self == "undefined"){
return;
}
self.sendMessage(msg);
};
global.echo = _echo;
global.alert = _echo;
global.load = _load; global.load = _load;
global.save = _save; global.logger = __plugin.logger;
global.plugin = _plugin;
global.ready = _ready;
global.command = _command;
global._onTabComplete = __onTabCompleteJS; global._onTabComplete = __onTabCompleteJS;
global.addUnloadHandler = _addUnloadHandler; global.addUnloadHandler = _addUnloadHandler;
var fnRequire = load(jsPluginsRootDirName + '/core/_require.js',true); var fnRequire = load(jsPluginsRootDirName + '/lib/require.js',true);
global.require = fnRequire(__plugin, __engine, verbose); global.require = fnRequire(__plugin.logger, __engine, config.verbose, jsPluginsRootDirName);
//
// assumes this was loaded from js-plugins/core/
// load all of the plugins.
//
_reload(jsPluginsRootDir);
//
// all modules have loaded var plugins = require('plugin');
// _commands = plugins.commands;
for (var i =0;i < _deferred.length;i++) global.plugin = plugins.plugin;
_deferred[i](); global.command = plugins.command;
global.save = plugins.save;
events.on("server.PluginDisableEvent",function(l,e){ plugins.autoload(jsPluginsRootDir);
//
// save all plugins which have persistent data var events = require('events');
// events.on('server.PluginDisableEvent',function(l,e){
for (var moduleName in _plugins){ // save config
var pluginData = _plugins[moduleName]; plugins.save(global.config, new File(jsPluginsRootDir, "data/global-config.json" ));
if (pluginData.persistent)
save(pluginData.module.store, jsPluginsRootDirName + "/" + moduleName + "-store.txt"); _runUnloadHandlers();
}
_runUnloadHandlers();
org.bukkit.event.HandlerList["unregisterAll(org.bukkit.plugin.Plugin)"](__plugin); org.bukkit.event.HandlerList["unregisterAll(org.bukkit.plugin.Plugin)"](__plugin);
}); });
}()); }());