This commit is contained in:
walterhiggins 2013-12-24 00:16:07 +00:00
parent eb098ff176
commit 4d807373da
2 changed files with 234 additions and 90 deletions

View file

@ -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;
};

View file

@ -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));
})