diff --git a/src/main/javascript/lib/events.js b/src/main/javascript/lib/events.js index 7ead348..ea292e3 100644 --- a/src/main/javascript/lib/events.js +++ b/src/main/javascript/lib/events.js @@ -45,12 +45,16 @@ Example: ------ The following code will print a message on screen every time a block is broken in the game + var events = require('./events/events'); + events.on("block.BlockBreakEvent", function(listener, evt){ echo (evt.player.name + " broke a block!"); }); To handle an event only once and unregister from further events... + var events = require('./events/events'); + events.on("block.BlockBreakEvent", function(listener, evt){ print (evt.player.name + " broke a block!"); evt.handlers.unregister(listener); @@ -58,6 +62,8 @@ To handle an event only once and unregister from further events... To unregister a listener *outside* of the listener function... + var events = require('./events/events'); + var myBlockBreakListener = events.on("block.BlockBreakEvent",function(l,e){ ... }); ... var handlers = org.bukkit.event.block.BlockBreakEvent.getHandlerList(); @@ -67,67 +73,56 @@ To unregister a listener *outside* of the listener function... [buk]: http://jd.bukkit.org/dev/apidocs/index.html?org/bukkit/event/Event.html ***/ - -var events = events || { - // - // handle events in Minecraft - // -------------------------- - // eventType can be a string (assumed to be a sub package of org.bukkit.event - e.g. - // if the string "block.BlockBreakEvent" is supplied then it's converted to the - // org.bukkit.event.block.BlockBreakEvent class . For custom event classes, just - // supply the custom event class e.g. - // events.on(net.yourdomain.events.YourCustomEvent,function(l,e){ ... }); - // - on: function( - /* String or java Class */ eventType, - /* function( registeredListener, event) */ handler, - /* (optional) String (HIGH, HIGHEST, LOW, LOWEST, NORMAL, MONITOR), */ priority - ){} -}; -// -// private implementation from here on in... -// -(function(events){ - if (events._eventsLoaded){ - return; - } - var bkEvent = org.bukkit.event; - var bkEvtExecutor = org.bukkit.plugin.EventExecutor; - var bkRegListener = org.bukkit.plugin.RegisteredListener; - var _on = function(eventType, handler, priority) - { - if (typeof priority == "undefined"){ - priority = bkEvent.EventPriority.HIGHEST; - }else{ - priority = bkEvent.EventPriority[priority]; +// +// handle events in Minecraft +// -------------------------- +// eventType can be a string (assumed to be a sub package of org.bukkit.event - e.g. +// if the string "block.BlockBreakEvent" is supplied then it's converted to the +// org.bukkit.event.block.BlockBreakEvent class . For custom event classes, just +// supply the custom event class e.g. +// events.on(net.yourdomain.events.YourCustomEvent,function(l,e){ ... }); +// +var bkEvent = org.bukkit.event; +var bkEvtExecutor = org.bukkit.plugin.EventExecutor; +var bkRegListener = org.bukkit.plugin.RegisteredListener; + +exports.on = function( + /* String or java Class */ + eventType, + /* function( registeredListener, event) */ + handler, + /* (optional) String (HIGH, HIGHEST, LOW, LOWEST, NORMAL, MONITOR), */ + priority ) { + + if (typeof priority == "undefined"){ + priority = bkEvent.EventPriority.HIGHEST; + }else{ + priority = bkEvent.EventPriority[priority]; + } + if (typeof eventType == "string"){ + var subPkgs = eventType.split('.'); + eventType = bkEvent[subPkgs[0]]; + for (var i = 1;i < subPkgs.length; i++){ + eventType = eventType[subPkgs[i]]; } - if (typeof eventType == "string"){ - var subPkgs = eventType.split('.'); - eventType = bkEvent[subPkgs[0]]; - for (var i = 1;i < subPkgs.length; i++){ - eventType = eventType[subPkgs[i]]; - } - } - var handlerList = eventType.getHandlerList(); - var listener = {}; - var eventExecutor = new bkEvtExecutor(){ - execute: function(l,e){ - handler(listener.reg,e); - } - }; - /* - wph 20130222 issue #64 bad interaction with Essentials plugin - if another plugin tries to unregister a Listener (not a Plugin or a RegisteredListener) - then BOOM! the other plugin will throw an error because Rhino can't coerce an - equals() method from an Interface. - The workaround is to make the ScriptCraftPlugin java class a Listener. - Should only unregister() registered plugins in ScriptCraft js code. - */ - listener.reg = new bkRegListener( __plugin, eventExecutor, priority, __plugin, true); - handlerList.register(listener.reg); - return listener.reg; + } + var handlerList = eventType.getHandlerList(); + var listener = {}; + var eventExecutor = new bkEvtExecutor(){ + execute: function(l,e){ + handler(listener.reg,e); + } }; - events.on = _on; - events._eventsLoaded = true; -}(events)); + /* + wph 20130222 issue #64 bad interaction with Essentials plugin + if another plugin tries to unregister a Listener (not a Plugin or a RegisteredListener) + then BOOM! the other plugin will throw an error because Rhino can't coerce an + equals() method from an Interface. + The workaround is to make the ScriptCraftPlugin java class a Listener. + Should only unregister() registered plugins in ScriptCraft js code. + */ + listener.reg = new bkRegListener( __plugin, eventExecutor, priority, __plugin, true); + handlerList.register(listener.reg); + return listener.reg; +}; diff --git a/src/main/javascript/lib/require.js b/src/main/javascript/lib/require.js index a96beb8..ef95233 100644 --- a/src/main/javascript/lib/require.js +++ b/src/main/javascript/lib/require.js @@ -55,7 +55,153 @@ module specification, the '.js' suffix is optional. [cjsmodules]: http://wiki.commonjs.org/wiki/Modules/1.1.1. ***/ -(function(__plugin, __engine, verbose){ +( function (logger, evaluator, verbose, rootDir) { + + if (verbose) + logger.info("Setting up 'require' module system. Root Directory: " + rootDir); + + var File = java.io.File; + + var readModuleFromDirectory = function(dir){ + + // look for a package.json file + var pkgJsonFile = new File(dir, './package.json'); + if (pkgJsonFile.exists()){ + var pkg = load(pkgJsonFile); + var mainFile = new File(dir, pkg.main); + if (mainFile.exists()){ + return mainFile; + } else { + return null; + } + }else{ + // look for an index.js file + var indexJsFile = new File(dir + './index.js'); + if (indexJsFile.exists()){ + return indexJsFile; + } else { + return null; + } + } + }; + + var LIB_DIR = rootDir + '/lib/'; + var MODULE_DIR = rootDir + '/modules/'; + + var resolveModuleToFile = function(moduleName, parentDir) { +/********************************************************************** +## When resolving module names to file paths, ScriptCraft uses the following rules... + + 1. if the module does not begin with './' or '/' then ... + + 1.1 Look in the 'scriptcraft/lib' directory. If it's not there then... + 1.2 Look in the 'scriptcraft/modules' directory. If it's not there then + Throw an Error. + + 2. If the module begins with './' or '/' then ... + + 2.1 if the module begins with './' then it's treated as a file path. File paths are + always relative to the module from which the require() call is being made. + + 2.2 If the module begins with '/' then it's treated as an absolute path. + + If the module does not have a '.js' suffix, and a file with the same name and a .js sufix exists, + then the file will be loaded. + + 3. If the module name resolves to a directory then... + + 3.1 look for a package.json file in the directory and load the `main` property e.g. + + // package.json located in './some-library/' + { + "main": './some-lib.js', + "name": 'some-library' + } + + 3.2 if no package.json file exists then look for an index.js file in the directory + +***/ + var file = new File(moduleName); + + var fileExists = function(file) { + + if (file.isDirectory()){ + return readModuleFromDirectory(file); + }else { + return file; + } + }; + + if (file.exists()){ + return fileExists(file); + } + if (moduleName.match(/^[^\.\/]/)){ + // it's a module named like so ... 'events' , 'net/http' + // + + var resolvedFile = new File(LIB_DIR + moduleName); + if (resolvedFile.exists()){ + + return fileExists(resolvedFile); + } else{ + + // try appending a .js to the end + resolvedFile = new File(LIB_DIR + moduleName + '.js'); + if (resolvedFile.exists()){ + + return resolvedFile; + }else{ + + if (verbose){ + logger.info("File not found in " + LIB_DIR + ': ' + resolvedFile.canonicalPath); + } + + resolvedFile = new File(MODULE_DIR + moduleName); + if (resolvedFile.exists()){ + return fileExists(resolvedFile); + }else { + if (verbose){ + logger.info("File not found in " + MODULE_DIR + ': ' + resolvedFile.canonicalPath); + } + resolvedFile = new File(MODULE_DIR + moduleName + '.js'); + if (resolvedFile.exists()) + return resolvedFile; + else{ + + if (verbose){ + logger.info("File not found in " + MODULE_DIR + ': ' + resolvedFile.canonicalPath); + } + } + } + } + } + } else { + // it's of the form ./path + file = new File(parentDir, moduleName); + if (file.exists()){ + if (file.isDirectory()){ + return readModuleFromDirectory(file); + }else { + return file; + } + }else { + + // try appending a .js to the end + var pathWithJSExt = file.canonicalPath + '.js'; + file = new File( parentDir, pathWithJSExt); + if (file.exists()) + return file; + else{ + + file = new File(pathWithJSExt); + if (file.exists()) + return file; + } + + } + } + return null; + }; /* wph 20131215 Experimental */ @@ -66,25 +212,10 @@ module specification, the '.js' suffix is optional. var _canonize = function(file){ return "" + file.canonicalPath.replaceAll("\\\\","/"); }; - - var file = new java.io.File(parentFile, path); - if (!file.exists()) - { - if (path.match(/\.js$/i)){ - __plugin.logger.warning('require("' + path + '") failed. File [' + file.canonicalPath + '] not found'); - return; - }else{ - path = path + '.js'; - file = new java.io.File(parentFile, path); - if (!file.exists()){ - __plugin.logger.warning('require("' + path + '") failed. File [' + file.canonicalPath + '] not found'); - return; - } - } - } - if (file.isDirectory()){ - __plugin.logger.warning('require("' + path + '") directories not yet supported. ' + file.canonicalPath); - return; + + var file = resolveModuleToFile(path, parentFile); + if (!file){ + throw new Error("require('" + path + "'," + parentFile.canonicalPath + ") failed"); } var canonizedFilename = _canonize(file); @@ -93,12 +224,14 @@ module specification, the '.js' suffix is optional. return moduleInfo; } if (verbose){ - print("loading module " + canonizedFilename); + logger.info("loading module " + canonizedFilename); } var reader = new java.io.FileReader(file); var br = new java.io.BufferedReader(reader); var code = ""; - while ((r = br.readLine()) !== null) code += r + "\n"; + var r = null; + while ((r = br.readLine()) !== null) + code += r + "\n"; var head = "(function(exports,module,require,__filename,__dirname){ "; @@ -111,12 +244,28 @@ module specification, the '.js' suffix is optional. code = head + code + tail; _loadedModules[canonizedFilename] = moduleInfo; - moduleInfo.main = __engine.eval(code); - moduleInfo.main(moduleInfo.exports, - moduleInfo, - _requireClosure(file.parentFile), - canonizedFilename, - "" + parentFile?parentFile.canonicalPath:""); + var compiledWrapper = null; + try { + compiledWrapper = evaluator.eval(code); + }catch (e){ + logger.severe("Error:" + e + " while evaluating module " + canonizedFilename); + throw e; + } + var __dirname = file.parentFile.canonicalPath; + try { + compiledWrapper.apply(moduleInfo.exports, + [moduleInfo.exports, + moduleInfo, + _requireClosure(file.parentFile), + canonizedFilename, + "" + __dirname]); + } catch (e){ + logger.severe("Error:" + e + " while executing module " + canonizedFilename); + throw e; + } + if (verbose) + logger.info("loaded module " + canonizedFilename); + moduleInfo.loaded = true; return moduleInfo; }; @@ -127,5 +276,5 @@ module specification, the '.js' suffix is optional. return module.exports; }; }; - return _requireClosure(new java.io.File("./")); + return _requireClosure(new java.io.File(rootDir)); })