diff --git a/build.xml b/build.xml index 6b4e694..ad9acd5 100644 --- a/build.xml +++ b/build.xml @@ -1,7 +1,7 @@ Builds the scriptcraft.jar file - a plugin for bukkit - + @@ -24,46 +24,15 @@ - - - - - Retrieving CraftBukkit artifact info - - - - - - Retrieving CraftBukkit jar - - - Creating default ops.txt for your user - - - - - - - Starting Bukkit with ScriptCraft - - - + + classpath="lib/canary.jar" /> @@ -87,14 +56,33 @@ - + - + + + + + + + + + + + + + + + + + + + + @@ -148,7 +136,7 @@ Walter Higgins - + @@ -185,7 +173,7 @@ Walter Higgins - + @@ -206,7 +194,7 @@ Walter Higgins - + diff --git a/docs/YoungPersonsGuideToProgrammingMinecraft.md b/docs/YoungPersonsGuideToProgrammingMinecraft.md index a107155..cb1138e 100644 --- a/docs/YoungPersonsGuideToProgrammingMinecraft.md +++ b/docs/YoungPersonsGuideToProgrammingMinecraft.md @@ -171,7 +171,7 @@ called `location`. We can use that name like this... Blackrock Castle -...You might be wondering where the enclosing `'` single-quotes went. +...You might be wondering why there's no enclosing `'` single quotes. When telling the computer to store some text, you have to put `'` (that's the single-quote character) at the start and end of the text. The computer doesn't store these quote characters, only the diff --git a/lib/canary.jar b/lib/canary.jar new file mode 100644 index 0000000..d11673e Binary files /dev/null and b/lib/canary.jar differ diff --git a/src/generateEventsHelper.js b/src/generateEventsHelper.js index b27792c..feb59fa 100644 --- a/src/generateEventsHelper.js +++ b/src/generateEventsHelper.js @@ -1,3 +1,5 @@ +args = Array.prototype.slice.call(args,1); +// [0] = type, [1] = lib.jar [2] = blockX, [3] = classX var File = java.io.File, FileReader = java.io.FileReader, FileInputStream = java.io.FileInputStream, @@ -6,27 +8,21 @@ var File = java.io.File, Modifier = java.lang.reflect.Modifier, clz, ZipInputStream = java.util.zip.ZipInputStream, - zis = new ZipInputStream(new FileInputStream('./target/minecraft/craftbukkit.jar')), + zis = new ZipInputStream(new FileInputStream(args[1])), entry = null; var content = [ '/*********************', '## Events Helper Module', 'The Events helper module provides a suite of functions - one for each possible event.', - 'For example, the events.blockBreak() function is just a wrapper function which calls events.on(org.bukkit.event.block.BlockBreakEvent, callback, priority)', + 'For example, the events.' + args[2] + '() function is just a wrapper function which calls events.on(' + args[3] + ', callback, priority)', 'This module is a convenience wrapper for easily adding new event handling functions in Javascript. ', 'At the in-game or server-console prompt, players/admins can type `events.` and use TAB completion ', 'to choose from any of the approx. 160 different event types to listen to.', '', '### Usage', '', - ' events.blockBreak( function( event ) { ', - ' event.player.sendMessage(\'You broke a block!\'); ', - ' });', - '', - '... which is just a shorter and less error-prone way of writing ...', - '', - ' events.on(\'block.BlockBreakEvent\',function( event ) { ', - ' event.player.sendMessage(\'You broke a block!\');', + ' events.' + args[2] + '( function( event ) { ', + ' echo( event.player, \'You broke a block!\'); ', ' });', '', 'The crucial difference is that the events module now has functions for each of the built-in events. The functions are accessible via TAB-completion so will help beginning programmers to explore the events at the server console window.', @@ -38,7 +34,11 @@ for (var i = 0; i< content.length; i++){ } while ( ( entry = zis.nextEntry) != null) { var name = '' + entry.name; - if (name.match(/org\/bukkit\/event\/.+Event\.class$/)){ + var re1 = /org\/bukkit\/event\/.+Event\.class$/; + if (args[0] == 'canary'){ + re1 = /net\/canarymod\/hook\/.+Hook\.class$/; + } + if (name.match(re1)){ name = name.replace(/\//g,'.').replace('.class',''); try { clz = java.lang.Class.forName(name); @@ -50,8 +50,21 @@ while ( ( entry = zis.nextEntry) != null) { continue; } var parts = name.split('.'); - var shortName = name.replace('org.bukkit.event.',''); - var fname = parts.reverse().shift().replace(/^(.)/,function(a){ return a.toLowerCase();}).replace(/Event$/,''); + var shortName = null; + if (args[0] == 'canary'){ + shortName = name.replace('net.canarymod.hook.',''); + } + if (args[0] == 'bukkit'){ + shortName = name.replace('org.bukkit.event.',''); + } + var fname = parts.reverse().shift().replace(/^(.)/,function(a){ + return a.toLowerCase();}); + if (args[0] == 'bukkit'){ + fname = fname.replace(/Event$/,''); + } + if (args[0] == 'canary'){ + fname = fname.replace(/Hook$/,''); + } var comment = [ '/*********************', @@ -70,7 +83,12 @@ while ( ( entry = zis.nextEntry) != null) { out.println(comment[i]); } out.println('exports.' + fname + ' = function(callback,priority){ '); - out.println(' return events.on(' + name + ',callback,priority);'); + if (args[0] == 'canary'){ + out.println(' return events.on(Packages.' + name + ',callback,priority);'); + } + if (args[0] == 'bukkit'){ + out.println(' return events.on(' + name + ',callback,priority);'); + } out.println('};'); } } diff --git a/src/main/java/canary/org/scriptcraftjs/canarymod/ScriptCraftPlugin.java b/src/main/java/canary/org/scriptcraftjs/canarymod/ScriptCraftPlugin.java new file mode 100644 index 0000000..3aa1546 --- /dev/null +++ b/src/main/java/canary/org/scriptcraftjs/canarymod/ScriptCraftPlugin.java @@ -0,0 +1,143 @@ +package org.scriptcraftjs.canarymod; + +import java.io.InputStreamReader; +import javax.script.ScriptEngineManager; +import javax.script.ScriptEngine; +import javax.script.Invocable; +import java.util.List; +import java.util.ArrayList; + +import net.canarymod.plugin.Plugin; +import net.canarymod.plugin.PluginListener; +import net.canarymod.tasks.ServerTask; +import net.canarymod.tasks.TaskOwner; +import net.canarymod.commandsys.CommandListener; +import net.canarymod.commandsys.Command; +import net.canarymod.commandsys.TabComplete; +import net.canarymod.chat.MessageReceiver; +import net.canarymod.Canary; + +public class ScriptCraftPlugin extends Plugin implements PluginListener, CommandListener +{ + public boolean canary = true; + public boolean bukkit = false; + private String NO_JAVASCRIPT_MESSAGE = "No JavaScript Engine available. " + + "ScriptCraft will not work without Javascript."; + protected ScriptEngine engine = null; + @Override + public void disable(){ + try { + ((Invocable)this.engine).invokeFunction("__onDisable", this.engine, this); + }catch ( Exception e) { + this.getLogman().error(e.getMessage()); + } + } + @Override + public boolean enable() + { + try{ + ScriptEngineManager factory = new ScriptEngineManager(); + this.engine = factory.getEngineByName("JavaScript"); + if (this.engine == null){ + this.getLogman().error(NO_JAVASCRIPT_MESSAGE); + } else { + Invocable inv = (Invocable)this.engine; + //File f = new File(this.getJarPath()); + InputStreamReader reader = new InputStreamReader(getClass() + .getClassLoader() + .getResourceAsStream("boot.js")); + this.engine.eval(reader); + inv.invokeFunction("__scboot", this, engine, getClass().getClassLoader()); + } + + Canary.commands().registerCommands(this, this, false); + }catch(Exception e){ + e.printStackTrace(); + this.getLogman().error(e.getMessage()); + } + return true; + } + + static class ScriptCraftTask extends ServerTask { + private Runnable runnable = null; + public ScriptCraftTask(Runnable runnable, TaskOwner owner, long delay, boolean continuous){ + super(owner, delay, continuous); + this.runnable = runnable; + } + @Override + public void run(){ + this.runnable.run(); + } + } + + public ServerTask createServerTask(Runnable runnable, long delay, boolean continuous){ + return new ScriptCraftTask(runnable, this, delay, continuous); + } + + private void executeCommand( MessageReceiver sender, String[] args) { + boolean result = false; + String javascriptCode = ""; + Object jsResult = null; + if (this.engine == null){ + this.getLogman().error(NO_JAVASCRIPT_MESSAGE); + return; + } + try { + jsResult = ((Invocable)this.engine).invokeFunction("__onCommand", sender, args); + }catch (Exception se){ + this.getLogman().error(se.toString()); + se.printStackTrace(); + sender.message(se.getMessage()); + } + if (jsResult != null){ + return ; + } + return; + } + @Command( + aliases = { "js" }, + description = "Execute Javascript code", + permissions = { "canary.super.js", "canary.command.super.js" }, + toolTip = "/js javascript expression") + public void jsCommand(MessageReceiver sender, String[] args) { + + executeCommand(sender, args); + } + /* + groupmod permission add visitors canary.jsp + groupmod permission add visitors canary.command.jsp + */ + @Command( + aliases = { "jsp" }, + description = "Run javascript-provided command", + permissions = { "canary.jsp", "canary.command.jsp" }, + toolTip = "/jsp command") + public void jspCommand(MessageReceiver sender, String[] args) { + + executeCommand(sender, args); + } + + private List complete(MessageReceiver sender, String[] args, String cmd){ + List result = new ArrayList(); + if (this.engine == null){ + this.getLogman().error(NO_JAVASCRIPT_MESSAGE); + return null; + } + try { + Invocable inv = (Invocable)this.engine; + inv.invokeFunction("__onTabComplete", result, sender, args, cmd); + }catch (Exception e){ + sender.message(e.getMessage()); + e.printStackTrace(); + } + return result; + } + @TabComplete (commands = { "js" }) + public List jsComplete(MessageReceiver sender, String[] args){ + return complete(sender, args, "js"); + } + @TabComplete (commands = { "jsp" }) + public List jspComplete(MessageReceiver sender, String[] args){ + return complete(sender, args, "jsp"); + } +} diff --git a/src/main/js/lib/console.js b/src/main/js/lib/console.js index 75a2287..2e64c94 100644 --- a/src/main/js/lib/console.js +++ b/src/main/js/lib/console.js @@ -35,39 +35,44 @@ ScriptCraft uses Java's [String.format()][strfmt] so any string substitution ide [webcons]: https://developer.mozilla.org/en-US/docs/Web/API/console ***/ -var logger = __plugin.logger, - logMethodName = 'log(java.util.logging.Level,java.lang.String)'; -var argsToArray = function( args ) { +function argsToArray( args ) { var result = []; for ( var i =0; i < args.length; i++ ) { result.push(args[i]); } return result; } -var log = function( level, restOfArgs ) { - var args = argsToArray( restOfArgs ); +function consMsg(params){ + var args = argsToArray(params); if ( args.length > 1 ) { - var msg = java.lang.String.format( args[0], args.slice(1) ); - logger[logMethodName]( level, msg ); + return java.lang.String.format( args[0], args.slice(1) ); } else { - logger[logMethodName]( level, args[0] ); + return args[0]; + } +} + +module.exports = function(logger){ + + function bukkitLog( level, restOfArgs ) { + logger['log(java.util.logging.Level,java.lang.String)']( + java.util.logging.Level[level], + consMsg(restOfArgs) + ); + } + + if (__plugin.canary){ + return { + log: function( ) { logger.info( consMsg(arguments) ); }, + info: function( ) { logger.info( consMsg(arguments) ); }, + warn: function( ) { logger.warn( consMsg(arguments) ); }, + error: function( ) { logger.error( consMsg(arguments) ); } + }; + } else { + return { + log: function() { bukkitLog('INFO', arguments ); }, + info: function() { bukkitLog('INFO', arguments ); }, + warn: function( ) { bukkitLog('WARNING', arguments ); }, + error: function( ) { bukkitLog('SEVERE', arguments ); } + }; } }; - -var Level = java.util.logging.Level; - -exports.log = function( ) { - log( Level.INFO, arguments ); -}; - -exports.info = function( ) { - log( Level.INFO, arguments ); -}; - -exports.warn = function( ) { - log( Level.WARNING, arguments ); -}; - -exports.error = function( ) { - log( Level.SEVERE, arguments ); -}; diff --git a/src/main/js/lib/events-bukkit.js b/src/main/js/lib/events-bukkit.js new file mode 100644 index 0000000..b90949b --- /dev/null +++ b/src/main/js/lib/events-bukkit.js @@ -0,0 +1,63 @@ +var bkEventPriority = org.bukkit.event.EventPriority, + bkEventExecutor = org.bukkit.plugin.EventExecutor, + bkRegisteredListener = org.bukkit.plugin.RegisteredListener, + bkEventPackage = 'org.bukkit.event.'; + +var nashorn = (typeof Java != 'undefined'); + +function getHandlerListForEventType( eventType ){ + var result = null; + var clazz = null; + if (nashorn) { + + //Nashorn doesn't like when getHandlerList is in a superclass of your event + //so to avoid this problem, call getHandlerList using java.lang.reflect + //methods + clazz = eventType['class']; + result = clazz.getMethod("getHandlerList").invoke(null); + + } else { + result = eventType.getHandlerList(); + } + + return result; +} +exports.on = function( + /* Java Class */ + eventType, + /* function( registeredListener, event) */ + handler, + /* (optional) String (HIGH, HIGHEST, LOW, LOWEST, NORMAL, MONITOR), */ + priority ) { + var handlerList, + regd, + eventExecutor; + + if ( typeof priority == 'undefined' ) { + priority = bkEventPriority.HIGHEST; + } else { + priority = bkEventPriority[priority.toUpperCase().trim()]; + } + handlerList = getHandlerListForEventType (eventType); + + var result = { }; + eventExecutor = new bkEventExecutor( { + execute: function( l, evt ) { + handler.call( result, evt ); + } + } ); + /* + 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. + */ + regd = new bkRegisteredListener( __plugin, eventExecutor, priority, __plugin, true ); + handlerList.register( regd ); + result.unregister = function(){ + handlerList.unregister( regd ); + }; + return result; +}; diff --git a/src/main/js/lib/events-canary.js b/src/main/js/lib/events-canary.js new file mode 100644 index 0000000..07b8943 --- /dev/null +++ b/src/main/js/lib/events-canary.js @@ -0,0 +1,45 @@ +var cmPriority = Packages.net.canarymod.plugin.Priority, + cmCanary = Packages.net.canarymod.Canary, + cmDispatcher = Packages.net.canarymod.hook.Dispatcher, + cmRegisteredPluginListener = Packages.net.canarymod.plugin.RegisteredPluginListener, + cmPluginListener = Packages.net.canarymod.plugin.PluginListener; +var cmHookExecutor = cmCanary.hooks(); + +exports.on = function( + /* Java Class */ + eventType, + /* function( registeredListener, event) */ + handler, + /* (optional) String (CRITICAL, HIGH, NORMAL, LOW, PASSIVE), */ + priority ) { + var handlerList, + regd, + eventExecutor; + + if ( typeof priority == 'undefined' ) { + priority = cmPriority.NORMAL; + } else { + priority = cmPriority[priority.toUpperCase().trim()]; + } + + var result = { }; + eventExecutor = new cmDispatcher( { + execute: function (l, evt) { + handler.call(result, evt ); + } + }); + /* + 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. + */ + regd = new cmPluginListener({}); + cmHookExecutor.registerHook(regd, __plugin, eventType.class, eventExecutor, priority); + result.unregister = function(){ + cmHookExecutor.unregisterPluginListener(regd); + }; + return result; +}; diff --git a/src/main/js/lib/events.js b/src/main/js/lib/events.js index c0c1660..e79a334 100644 --- a/src/main/js/lib/events.js +++ b/src/main/js/lib/events.js @@ -13,9 +13,7 @@ This method is used to register event listeners. #### Parameters - * eventName - A java class. See [Bukkit API][buk] for - details of the many bukkit event types. Provide the full class name (without - enclosing quotes). + * eventName - A Java class. See [Bukkit API][buk] for details of the many bukkit event types. * callback - A function which will be called whenever the event fires. The callback should take a single parameter, event (the event fired). @@ -35,16 +33,16 @@ An object which can be used to unregister the listener. The following code will print a message on screen every time a block is broken in the game ```javascript -events.on( Packages.org.bukkit.event.block.BlockBreakEvent, function( evt ) { - evt.player.sendMessage( evt.player.name + ' broke a block!'); +events.on( org.bukkit.block.BlockBreakEvent, function( evt ) { + echo(evt.player, evt.player.name + ' broke a block!'); } ); ``` To handle an event only once and unregister from further events... ```javascript -events.on( Packages.org.bukkit.event.block.BlockBreakEvent, function( evt ) { - evt.player.sendMessage( evt.player.name + ' broke a block!'); +events.on( org.bukkit.block.BlockBreakEvent, function( evt ) { + echo( evt.player, evt.player.name + ' broke a block!'); this.unregister(); } ); ``` @@ -57,79 +55,22 @@ object which is returned by the `events.on()` function. To unregister a listener *outside* of the listener function... ```javascript -var myBlockBreakListener = events.on( Packages.org.bukkit.event.block.BlockBreakEvent, function( evt ) { ... } ); +var myBlockBreakListener = events.on( org.bukkit.block.BlockBreakEvent, function( evt ) { ... } ); ... myBlockBreakListener.unregister(); ``` + [buk2]: http://wiki.bukkit.org/Event_API_Reference [buk]: http://jd.bukkit.org/dev/apidocs/index.html?org/bukkit/event/Event.html ***/ + +if (__plugin.canary){ + module.exports = require('events-canary'); +} else { + module.exports = require('events-bukkit'); +} var helper = require('events-helper'); for ( var func in helper ) { - exports[func] = helper[func]; -}; - -var bkEventPriority = org.bukkit.event.EventPriority, - bkEventExecutor = org.bukkit.plugin.EventExecutor, - bkRegisteredListener = org.bukkit.plugin.RegisteredListener, - bkEventPackage = 'org.bukkit.event.'; - -var nashorn = (typeof Java != 'undefined'); - -function getHandlerListForEventType( eventType ){ - var result = null; - var clazz = null; - if (nashorn) { - - //Nashorn doesn't like when getHandlerList is in a superclass of your event - //so to avoid this problem, call getHandlerList using java.lang.reflect - //methods - clazz = eventType['class']; - result = clazz.getMethod("getHandlerList").invoke(null); - - } else { - result = eventType.getHandlerList(); - } - - return result; -} -exports.on = function( - /* Java Class */ - eventType, - /* function( registeredListener, event) */ - handler, - /* (optional) String (HIGH, HIGHEST, LOW, LOWEST, NORMAL, MONITOR), */ - priority ) { - var handlerList, - regd, - eventExecutor; - - if ( typeof priority == 'undefined' ) { - priority = bkEventPriority.HIGHEST; - } else { - priority = bkEventPriority[priority.toUpperCase().trim()]; - } - handlerList = getHandlerListForEventType (eventType); - - var result = { }; - eventExecutor = new bkEventExecutor( { - execute: function( l, evt ) { - handler.call( result, evt ); - } - } ); - /* - 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. - */ - regd = new bkRegisteredListener( __plugin, eventExecutor, priority, __plugin, true ); - handlerList.register( regd ); - result.unregister = function(){ - handlerList.unregister( regd ); - }; - return result; + module.exports[func] = helper[func]; }; diff --git a/src/main/js/lib/js-patch.js b/src/main/js/lib/js-patch.js index ea8b7c4..20cd7fa 100644 --- a/src/main/js/lib/js-patch.js +++ b/src/main/js/lib/js-patch.js @@ -1,4 +1,3 @@ - module.exports = function( $ ) { // wph 20140105 trim not availabe in String on Mac OS. @@ -44,29 +43,35 @@ module.exports = function( $ ) { return bind; }(Array.prototype.slice)); } - $.setTimeout = function( callback, delayInMillis ) { + + if (__plugin.canary){ + require('task-canary')($); + } else { + require('task-bukkit')($); + } + + return function unitTest( console ) { /* - javascript programmers familiar with setTimeout know that it expects - a delay in milliseconds. However, bukkit's scheduler expects a delay in ticks - (where 1 tick = 1/20th second) + sanity tests */ - var bukkitTask = server.scheduler.runTaskLater( __plugin, callback, Math.ceil( delayInMillis / 50 ) ); - return bukkitTask; - }; + $.setTimeout(function(){ + console.log('js-patch setTimeout() test complete'); + },100); + var clearMe = $.setTimeout(function(){ + console.error('js-patch clearTimeout() test failed'); + },100); + $.clearTimeout( clearMe ); - $.clearTimeout = function( bukkitTask ) { - bukkitTask.cancel(); + var runs = 3; + var clearAfterRuns = $.setInterval(function(){ + runs --; + if (runs == 0){ + $.clearInterval(clearAfterRuns); + } + if (runs < 0){ + console.error('js-patch clearInterval test failed.'); + } + },100); }; - - $.setInterval = function( callback, intervalInMillis ) { - var delay = Math.ceil( intervalInMillis / 50); - var bukkitTask = server.scheduler.runTaskTimer( __plugin, callback, delay, delay ); - return bukkitTask; - }; - - $.clearInterval = function( bukkitTask ) { - bukkitTask.cancel(); - }; - }; diff --git a/src/main/js/lib/legacy-check.js b/src/main/js/lib/legacy-check.js index 9db7578..b13da08 100644 --- a/src/main/js/lib/legacy-check.js +++ b/src/main/js/lib/legacy-check.js @@ -1,13 +1,19 @@ - - /* - wph 20140102 - warn if legacy 'craftbukkit/js-plugins' or 'craftbukkit/scriptcraft' directories are present - */ +var File = java.io.File; +/* + wph 20140102 - warn if legacy 'mcserver/js-plugins' or + 'mcserver/plugins/scriptcraft' directories are present + */ module.exports = function( jsPluginsRootDir ) { - var cbPluginsDir = jsPluginsRootDir.parentFile, - cbDir = new File(cbPluginsDir.canonicalPath).parentFile, - legacyExists = false, - legacyDirs = [new File( cbDir, 'js-plugins' ), - new File( cbDir, 'scriptcraft' )]; + var mcServerDir = new File(jsPluginsRootDir.canonicalPath).parentFile; + if (mcServerDir == null){ + console.warn('Could not find parent directory for ' + jsPluginsRootDir.canonicalPath); + return; + } + var legacyExists = false, + legacyDirs = [ + new File( mcServerDir, 'js-plugins' ), + new File( mcServerDir, 'plugins/scriptcraft' ) + ]; for ( var i = 0; i < legacyDirs.length; i++ ) { if ( legacyDirs[i].exists() @@ -17,7 +23,7 @@ module.exports = function( jsPluginsRootDir ) { console.warn('Legacy ScriptCraft directory %s was found. This directory is no longer used.', legacyDirs[i].canonicalPath); - console.warn('Please put plugins in the plugins/scriptcraft/plugins directory'); + console.warn('Please put plugins in the ' + jsPluginsRootDir.canonicalPath + '/plugins directory'); } } if ( legacyExists ) { diff --git a/src/main/js/lib/plugin.js b/src/main/js/lib/plugin.js index 5b7bec7..aa5983c 100644 --- a/src/main/js/lib/plugin.js +++ b/src/main/js/lib/plugin.js @@ -1,7 +1,6 @@ 'use strict'; -var console = require('./console'), - File = java.io.File, +var File = java.io.File, FileWriter = java.io.FileWriter, PrintWriter = java.io.PrintWriter; /* @@ -32,7 +31,6 @@ var _plugin = function(/* String */ moduleName, /* Object */ moduleObject, isPer exports.plugin = _plugin; exports.autoload = function( context, pluginDir, logger, options ) { - var _canonize = function( file ) { return '' + file.canonicalPath.replaceAll('\\\\','/'); }; @@ -67,10 +65,12 @@ exports.autoload = function( context, pluginDir, logger, options ) { _listSourceFiles( sourceFiles, pluginDir ); var len = sourceFiles.length; - if ( config.verbose ) { - console.info( len + ' scriptcraft plugins found in ' + pluginDir ); + if ( config && config.verbose ) { + logger.info( len + ' scriptcraft plugins found in ' + pluginDir ); } + for ( var i = 0; i < len; i++ ) { + pluginPath = _canonize( sourceFiles[i] ); module = {}; @@ -84,7 +84,7 @@ exports.autoload = function( context, pluginDir, logger, options ) { } } catch ( e ) { if ( typeof logger != 'undefined' ) { - logger.severe( 'Plugin ' + pluginPath + ' ' + e ); + logger.error( 'Plugin ' + pluginPath + ' ' + e ); } else { java.lang.System.out.println( 'Error: Plugin ' + pluginPath + ' ' + e ); } diff --git a/src/main/js/lib/require.js b/src/main/js/lib/require.js index 4d7398f..2f04042 100644 --- a/src/main/js/lib/require.js +++ b/src/main/js/lib/require.js @@ -209,7 +209,7 @@ When resolving module names to file paths, ScriptCraft uses the following rules. if (! ( (''+path).match( /^\./ ) ) ) { errMsg = errMsg + ' and not found in paths ' + JSON.stringify(modulePaths); } - throw errMsg; + throw new Error(errMsg); } canonizedFilename = _canonize(file); @@ -249,8 +249,8 @@ When resolving module names to file paths, ScriptCraft uses the following rules. This can be fixed by instead using __engine.eval */ throw new Error( "Error evaluating module " + path - + " line #" + e.lineNumber - + " : " + e.message, canonizedFilename, e.lineNumber ); + + " line #" + e.lineNumber + + " : " + e.message, canonizedFilename, e.lineNumber ); } var __dirname = '' + file.parentFile.canonicalPath; var parameters = [ @@ -265,9 +265,20 @@ When resolving module names to file paths, ScriptCraft uses the following rules. .apply(moduleInfo.exports, /* this */ parameters); } catch (e) { + var snippet = ''; + if ((''+e.lineNumber).match(/[0-9]/)){ + var lines = code.split(/\n/); + if (e.lineNumber > 1){ + snippet = ' ' + lines[e.lineNumber-2] + '\n'; + } + snippet += '> ' + lines[e.lineNumber-1] + '\n'; + if (e.lineNumber < lines.length){ + snippet += ' ' + lines[e.lineNumber] + '\n'; + } + } throw new Error( "Error executing module " + path + " line #" + e.lineNumber - + " : " + e.message, canonizedFilename, e.lineNumber ); + + " : " + e.message + (snippet?('\n' + snippet):''), canonizedFilename, e.lineNumber ); } if ( hooks ) { hooks.loaded( canonizedFilename ); diff --git a/src/main/js/lib/scriptcraft.js b/src/main/js/lib/scriptcraft.js index 5e5c781..e2a66ec 100644 --- a/src/main/js/lib/scriptcraft.js +++ b/src/main/js/lib/scriptcraft.js @@ -70,7 +70,7 @@ directory.... ```javascript exports.greet = function(player) { - player.sendMessage('Hello ' + player.name); + echo(player, 'Hello ' + player.name); }; ``` @@ -166,21 +166,15 @@ ScripCraft provides some global functions which can be used by all plugins/modul ### echo function -The `echo()` function displays a message on the in-game screen. The message is displayed to the `self` player (this is usually the player who issued the `/js` or `/jsp` command). +The `echo()` function displays a message on the in-game screen. #### Example - /js echo('Hello World') + /js echo( self, 'Hello World') 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')`. - -#### Notes - -The `echo` and `alert` functions are provided as convenience functions for beginning programmers. The use of these 2 functions is not recommended in event-handling code or multi-threaded code. In such cases, if you want to send a message to a given player then use the Bukkit API's [Player.sendMessage()][plsm] function instead. - -[plsm]: http://jd.bukkit.org/dev/apidocs/org/bukkit/command/CommandSender.html#sendMessage(java.lang.String) +e.g. `alert( self, 'Hello World')`. ### require() function @@ -308,7 +302,7 @@ The `command()` function is used to expose javascript functions for use by non-o // javascript code function boo( params, sender) { - sender.sendMessage( params[0] ); + echo( sender, params[0] ); } command( boo ); @@ -322,7 +316,7 @@ To use a callback for options (TAB-Completion) ... function boo( params, sender ) { var receiver = server.getPlayer( params[0] ); if ( receiver ){ - receiver.sendMessage( sender.name + ' says boo!'); + echo( receiver, sender.name + ' says boo!'); } } command( boo, bukkit.playerNames ); @@ -331,12 +325,10 @@ See chat/colors.js or alias/alias.js or homes/homes.js for more examples of how ### setTimeout() function -This function mimics the setTimeout() function used in browser-based javascript. However, the function will only accept a function reference, not a string of javascript code. Where setTimeout() in the browser returns a numeric value which can be subsequently passed to clearTimeout(), This implementation returns a [BukkitTask][btdoc] object which can be subsequently passed to ScriptCraft's own clearTimeout() implementation. +This function mimics the setTimeout() function used in browser-based javascript. However, the function will only accept a function reference, not a string of javascript code. Where setTimeout() in the browser returns a numeric value which can be subsequently passed to clearTimeout(), This implementation returns an object which can be subsequently passed to ScriptCraft's own clearTimeout() implementation. If Node.js supports setTimeout() then it's probably good for ScriptCraft to support it too. -[btdoc]: http://jd.bukkit.org/beta/apidocs/org/bukkit/scheduler/BukkitTask.html - #### Example ```javascript @@ -355,11 +347,7 @@ A scriptcraft implementation of clearTimeout(). ### setInterval() function -This function mimics the setInterval() function used in browser-based javascript. However, the function will only accept a function reference, not a string of javascript code. Where setInterval() in the browser returns a numeric value which can be subsequently passed to clearInterval(), This implementation returns a [BukkitTask][btdoc] object which can be subsequently passed to ScriptCraft's own clearInterval() implementation. - -If Node.js supports setInterval() then it's probably good for ScriptCraft to support it too. - -[btdoc]: http://jd.bukkit.org/beta/apidocs/org/bukkit/scheduler/BukkitTask.html +This function mimics the setInterval() function used in browser-based javascript. However, the function will only accept a function reference, not a string of javascript code. Where setInterval() in the browser returns a numeric value which can be subsequently passed to clearInterval(), This implementation returns an object which can be subsequently passed to ScriptCraft's own clearInterval() implementation. ### clearInterval() function @@ -384,39 +372,50 @@ The addUnloadHandler() function takes a callback function as a parameter. The ca This function provides a way for ScriptCraft modules to do any required cleanup/housekeeping just prior to the ScriptCraft Plugin unloading. +### isOp() function + +This function takes a single parameter and returns true if it's an operator or has operator-level privileges. + ***/ /* wph 20130124 - make self, plugin and server public - these are far more useful now that tab-complete works. */ var global = this; -var server = org.bukkit.Bukkit.server; +var server; /* private implementation */ -function __onEnable ( __engine, __plugin, __script ) -{ - var File = java.io.File, - FileReader = java.io.FileReader, - BufferedReader = java.io.BufferedReader, - PrintWriter = java.io.PrintWriter, - FileWriter = java.io.FileWriter; - var debug = function(msg){ - java.lang.System.out.println('DEBUG:' + msg); - }; - var _canonize = function( file ) { +var __onDisableImpl; +function __onDisable ( __engine, __plugin ) { + __onDisableImpl( __engine, __plugin); +} +function __onEnable ( __engine, __plugin, __script ) { + function _echo( ) { + var sender, msg; + if (arguments.length == 2){ + sender = arguments[0]; + msg = arguments[1]; + } else { + if ( typeof self == 'undefined' ) { + return; + } + sender = self; + msg = arguments[0]; + } + if (__plugin.canary){ + sender.message( msg ); + } else { + sender.sendMessage( msg ); + } + } // end echo() + function _canonize( file ) { return '' + file.getCanonicalPath().replaceAll( '\\\\', '/' ); - }; - // lib (assumes scriptcraft.js is in craftbukkit/plugins/scriptcraft/lib directory - var libDir = __script.parentFile, - jsPluginsRootDir = libDir.parentFile, // scriptcraft - jsPluginsRootDirName = _canonize(jsPluginsRootDir), - logger = __plugin.logger; - + } /* Save a javascript object to a file (saves using JSON notation) */ - var _save = function( objToSave, filename ) { + function _save( objToSave, filename ) { var objectToStr = null, f, out; @@ -431,17 +430,8 @@ function __onEnable ( __engine, __plugin, __script ) out = new PrintWriter(new FileWriter(f)); out.println( objectToStr ); out.close(); - }; - /* - make sure eval is present: it's present on JRE 6, 7, and 8 on Linux - */ - if ( typeof eval == 'undefined' ) { - global.eval = function( str ) { - return __engine.eval( str ); - }; - } - - var _loadJSON = function ( filename ){ + } + function _loadJSON( filename ){ var result = null, file = filename, r, @@ -464,7 +454,7 @@ function __onEnable ( __engine, __plugin, __script ) } result = JSON.parse(contents); } catch ( e ) { - logger.severe( 'Error evaluating ' + canonizedFilename + ', ' + e ); + logger.error( 'Error evaluating ' + canonizedFilename + ', ' + e ); } finally { try { @@ -475,12 +465,11 @@ function __onEnable ( __engine, __plugin, __script ) } } return result; - - }; + } /* Load the contents of the file and evaluate as javascript */ - var _load = function( filename, warnOnFileNotFound ) + function _load( filename, warnOnFileNotFound ) { var result = null, file = filename, @@ -508,7 +497,7 @@ function __onEnable ( __engine, __plugin, __script ) result = __engine.eval( wrappedCode ); // issue #103 avoid side-effects of || operator on Mac Rhino } catch ( e ) { - logger.severe( 'Error evaluating ' + canonizedFilename + ', ' + e ); + logger.error( 'Error evaluating ' + canonizedFilename + ', ' + e ); } finally { try { @@ -523,7 +512,164 @@ function __onEnable ( __engine, __plugin, __script ) } } return result; - }; + } // end _load() + + function _isOp( sender ){ + if (__plugin.canary){ + return sender.receiverType.name() == 'SERVER' || Canary.ops().isOpped(sender); + } else { + return sender.op; + } + } + function _refresh( ) { + if ( typeof self !== 'undefined' ) { + if ( !_isOp(self) ) { + echo( self, 'Only operators can refresh()'); + return; + } + } + if (__plugin.canary){ + var pluginName = __plugin.name; + Canary.manager().disablePlugin( pluginName ); + Canary.manager().enablePlugin( pluginName ); + } else { + __plugin.pluginLoader.disablePlugin( __plugin ); + __plugin.pluginLoader.enablePlugin( __plugin ); + } + } // end _refresh() + function _onDisable( evt ) { + // save config + _save( global.config, new File( jsPluginsRootDir, 'data/global-config.json' ) ); + _runUnloadHandlers(); + } + function _addUnloadHandler( f ) { + unloadHandlers.push( f ); + } + function _runUnloadHandlers() { + for ( var i = 0; i < unloadHandlers.length; i++ ) { + unloadHandlers[i]( ); + } + } + function __onCommand() { + var jsArgs = [], + i = 0, + jsResult, + result, + cmdName, + sender, + args, + cmd, + label, + fnBody; + + if ( __plugin.canary ) { + sender = arguments[0]; + args = arguments[1]; + cmdName = (''+args[0]).toLowerCase().replace(/^\//,''); + for ( i = 1; i < args.length ; i++ ) { + jsArgs.push( '' + args[i] ); + } + } else { + sender = arguments[0]; + cmd = arguments[1]; + label = arguments[2]; + args = arguments[3]; + cmdName = ( '' + cmd.name ).toLowerCase(); + for ( ; i < args.length ; i++ ) { + jsArgs.push( '' + args[i] ); + } + } + result = false; + + if (cmdName == 'js') + { + result = true; + fnBody = jsArgs.join(' '); + global.self = sender; + global.__engine = __engine; + try { + // cannot rely on native eval in jre7 and jre8 + // because ... + // js var hearts + // js hearts + // ... throws an execption ('hearts' is not defined). vars are not sticky in native eval . + // + jsResult = __engine.eval( fnBody ); + + if ( typeof jsResult != 'undefined' ) { + if ( jsResult == null) { + // engine eval will return null even if the result should be undefined + // this can be confusing so I think it's better to omit output for this case + // sender.sendMessage('(null)'); + } else { + try { + if ( isJavaObject(jsResult) || typeof jsResult === 'function') { + echo(sender, jsResult); + } else { + var replacer = function replacer(key, value){ + return this[key] instanceof java.lang.Object ? '' + this[key] : value; + }; + echo(sender, JSON.stringify( jsResult, replacer, 2) ); + } + } catch ( displayError ) { + logger.error( 'Error while trying to display result: ' + jsResult + ', Error: '+ displayError ); + } + } + } + } catch ( e ) { + logger.error( 'Error while trying to evaluate javascript: ' + fnBody + ', Error: '+ e ); + echo( sender, 'Error while trying to evaluate javascript: ' + fnBody + ', Error: '+ e ); + throw e; + } finally { + /* + wph 20140312 don't delete self on nashorn until https://bugs.openjdk.java.net/browse/JDK-8034055 is fixed + */ + if ( typeof Java === 'undefined' ) { // Java is an object in Nashorn + delete global.self; + delete global.__engine; + } + } + } + if ( cmdName == 'jsp' ) { + cmdModule.exec( jsArgs, sender ); + result = true; + } + return result; + } // end __onCommand() function + + var Bukkit = null; + var Canary = null; + var logger = null; + + if (__plugin.canary){ + Canary = Packages.net.canarymod.Canary; + server = Canary.server; + logger = __plugin.logman; + } else { + Bukkit = Packages.org.bukkit.Bukkit; + server = Bukkit.server; + logger = __plugin.logger; + } + + var File = java.io.File, + FileReader = java.io.FileReader, + BufferedReader = java.io.BufferedReader, + PrintWriter = java.io.PrintWriter, + FileWriter = java.io.FileWriter, + // assumes scriptcraft.js is in mcserver/plugins/scriptcraft/lib directory + jsPluginsRootDir = __script.parentFile.parentFile, + jsPluginsRootDirName = _canonize(jsPluginsRootDir), + unloadHandlers = []; + + /* + make sure eval is present: it's present on JRE 6, 7, and 8 on Linux + */ + if ( typeof eval == 'undefined' ) { + global.eval = function( str ) { + return __engine.eval( str ); + }; + } + /* now that load is defined, use it to load a global config object */ @@ -532,7 +678,7 @@ function __onEnable ( __engine, __plugin, __script ) configFile = new File(configFile,'global-config.json'); var config = _load( configFile ); if ( !config ) { - config = { verbose: false }; + config = { verbose: true }; } global.config = config; global.__plugin = __plugin; @@ -544,45 +690,14 @@ function __onEnable ( __engine, __plugin, __script ) var jsonLoaded = __engine['eval(java.io.Reader)']( jsonFileReader ); }()); - /* - Unload Handlers - */ - var unloadHandlers = []; - var _addUnloadHandler = function( f ) { - unloadHandlers.push( f ); - }; - var _runUnloadHandlers = function() { - for ( var i = 0; i < unloadHandlers.length; i++ ) { - unloadHandlers[i]( ); - } - }; global.addUnloadHandler = _addUnloadHandler; - - - global.refresh = function( ) { - if ( typeof self !== 'undefined' ) { - if ( !self.op ) { - self.sendMessage('Only operators can refresh()'); - return; - } - } - __plugin.pluginLoader.disablePlugin( __plugin ); - __plugin.pluginLoader.enablePlugin( __plugin ); - }; - - var _echo = function ( msg ) { - if ( typeof self == 'undefined' ) { - return; - } - self.sendMessage( msg ); - }; - + global.refresh = _refresh; global.echo = _echo; global.alert = _echo; global.scload = _load; global.scsave = _save; global.scloadJSON = _loadJSON; - + global.isOp = _isOp; var configRequire = _load( jsPluginsRootDirName + '/lib/require.js', true ); /* setup paths to search for modules @@ -615,8 +730,11 @@ function __onEnable ( __engine, __plugin, __script ) } ); - require('js-patch')( global ); - global.console = require('console'); + var testJSPatch = require('js-patch')( global ); + var console = require('console')(logger); + global.console = console; + testJSPatch(console); + /* setup persistence */ @@ -634,86 +752,13 @@ function __onEnable ( __engine, __plugin, __script ) // wph 20131226 - make events global as it is used by many plugins/modules global.events = events; - events.pluginDisable(function( evt ) { - // save config - _save( global.config, new File( jsPluginsRootDir, 'data/global-config.json' ) ); - - _runUnloadHandlers(); - org.bukkit.event.HandlerList['unregisterAll(org.bukkit.plugin.Plugin)'](__plugin); - }); - - require('bukkit')( global ); - - global.__onCommand = function( sender, cmd, label, args) { - var jsArgs = [], - i = 0, - jsResult, - result, - cmdName, - fnBody; - for ( ; i < args.length ; i++ ) { - jsArgs.push( '' + args[i] ); - } - - result = false; - cmdName = ( '' + cmd.name ).toLowerCase(); - if (cmdName == 'js') - { - result = true; - fnBody = jsArgs.join(' '); - global.self = sender; - global.__engine = __engine; - try { - // cannot rely on native eval in jre7 and jre8 - // because ... - // js var hearts - // js hearts - // ... throws an execption ('hearts' is not defined). vars are not sticky in native eval . - // - jsResult = __engine.eval( fnBody ); - - if ( typeof jsResult != 'undefined' ) { - if ( jsResult == null) { - // engine eval will return null even if the result should be undefined - // this can be confusing so I think it's better to omit output for this case - // sender.sendMessage('(null)'); - } else { - try { - if ( isJavaObject(jsResult) || typeof jsResult === 'function') { - sender.sendMessage(jsResult); - } else { - var replacer = function replacer(key, value){ - return this[key] instanceof java.lang.Object ? '' + this[key] : value; - }; - sender.sendMessage( JSON.stringify( jsResult, replacer, 2) ); - } - } catch ( displayError ) { - logger.severe( 'Error while trying to display result: ' + jsResult + ', Error: '+ displayError ); - } - } - } - } catch ( e ) { - logger.severe( 'Error while trying to evaluate javascript: ' + fnBody + ', Error: '+ e ); - sender.sendMessage( 'Error while trying to evaluate javascript: ' + fnBody + ', Error: '+ e ); - throw e; - } finally { - /* - wph 20140312 don't delete self on nashorn until https://bugs.openjdk.java.net/browse/JDK-8034055 is fixed - */ - if ( typeof Java === 'undefined' ) { // Java is an object in Nashorn - delete global.self; - delete global.__engine; - } - } - } - if ( cmdName == 'jsp' ) { - cmdModule.exec( jsArgs, sender ); - result = true; - } - return result; - }; - + if (__plugin.canary) { + // canary plugin doesn't get to handle its own plugin disable event + } else { + events.pluginDisable(_onDisable); + } + __onDisableImpl = _onDisable; + global.__onCommand = __onCommand; plugins.autoload( global, new File(jsPluginsRootDir,'plugins'), logger ); require('legacy-check')(jsPluginsRootDir); - } diff --git a/src/main/js/lib/tabcomplete-jsp.js b/src/main/js/lib/tabcomplete-jsp.js index c73918b..1928b39 100644 --- a/src/main/js/lib/tabcomplete-jsp.js +++ b/src/main/js/lib/tabcomplete-jsp.js @@ -3,7 +3,7 @@ var _commands = require('command').commands; /* Tab completion for the /jsp commmand */ -var __onTabCompleteJSP = function( result, cmdSender, pluginCmd, cmdAlias, cmdArgs ) { +var __onTabCompleteJSP = function( result, cmdArgs ) { var cmdInput = cmdArgs[0], opts, cmd, diff --git a/src/main/js/lib/tabcomplete.js b/src/main/js/lib/tabcomplete.js index 97ac135..fd7a00c 100644 --- a/src/main/js/lib/tabcomplete.js +++ b/src/main/js/lib/tabcomplete.js @@ -93,7 +93,7 @@ var _getProperties = function( o ) { return result.sort(); }; -var onTabCompleteJS = function( result, cmdSender, pluginCmd, cmdAlias, cmdArgs ) { +var onTabCompleteJS = function( ) { var _globalSymbols, lastArg, @@ -111,12 +111,33 @@ var onTabCompleteJS = function( result, cmdSender, pluginCmd, cmdAlias, cmdArgs candidate, re, li, - possibleCompletion; + possibleCompletion, + result, + cmdSender, + pluginCmd, + cmdArgs; + result = arguments[0]; + cmdSender = arguments[1]; + if (__plugin.bukkit){ + pluginCmd = arguments[2].name; + cmdArgs = arguments[4]; + } + if (__plugin.canary){ + cmdArgs = arguments[2]; + pluginCmd = arguments[3]; + } cmdArgs = Array.prototype.slice.call( cmdArgs, 0 ); - if ( pluginCmd.name == 'jsp' ) { - return tabCompleteJSP( result, cmdSender, pluginCmd, cmdAlias, cmdArgs ); + if (__plugin.canary){ + // if 1st element is 'js' then splice + // there's probably a better way to do this + if (cmdArgs[0] == 'js'){ + cmdArgs = cmdArgs.slice(1); + } + } + if ( pluginCmd == 'jsp' ) { + return tabCompleteJSP( result, cmdArgs ); } global.self = cmdSender; // bring in self just for autocomplete diff --git a/src/main/js/lib/task-bukkit.js b/src/main/js/lib/task-bukkit.js new file mode 100644 index 0000000..97ed020 --- /dev/null +++ b/src/main/js/lib/task-bukkit.js @@ -0,0 +1,22 @@ +function bukkitSetTimeout( callback, delayInMillis ){ + var delay = Math.ceil( delayInMillis / 50 ); + var task = server.scheduler.runTaskLater( __plugin, callback, delay ); + return task; +} +function bukkitClearTimeout( task ) { + task.cancel(); +} +function bukkitSetInterval( callback, intervalInMillis ) { + var delay = Math.ceil( intervalInMillis / 50); + var task = server.scheduler.runTaskTimer( __plugin, callback, delay, delay ); + return task; +} +function bukkitClearInterval( bukkitTask ) { + bukkitTask.cancel(); +} +module.exports = function($){ + $.setTimeout = bukkitSetTimeout; + $.clearTimeout = bukkitClearTimeout; + $.setInterval = bukkitSetInterval; + $.clearInterval = bukkitClearInterval; +}; diff --git a/src/main/js/lib/task-canary.js b/src/main/js/lib/task-canary.js new file mode 100644 index 0000000..bbdcb84 --- /dev/null +++ b/src/main/js/lib/task-canary.js @@ -0,0 +1,33 @@ +/* + javascript programmers familiar with setTimeout know that it expects + a delay in milliseconds. However, bukkit's scheduler expects a delay in ticks + (where 1 tick = 1/20th second) + */ +function canarySetTimeout( callback, delayInMillis ){ + var cmTaskManager = Packages.net.canarymod.tasks.ServerTaskManager; + var delay = Math.ceil( delayInMillis / 50 ); + var task = __plugin.createServerTask(callback, delay, false); + cmTaskManager.addTask(task); + return task; +} +function canaryClearTimeout( task ){ + var cmTaskManager = Packages.net.canarymod.tasks.ServerTaskManager; + cmTaskManager.removeTask( task ); +} +function canarySetInterval( callback, intervalInMillis ) { + var cmTaskManager = Packages.net.canarymod.tasks.ServerTaskManager; + var delay = Math.ceil( intervalInMillis / 50 ); + var task = __plugin.createServerTask(callback, delay, true); + cmTaskManager.addTask(task); + return task; +} +function canaryClearInterval( task ){ + var cmTaskManager = Packages.net.canarymod.tasks.ServerTaskManager; + cmTaskManager.removeTask( task ); +} +module.exports = function($){ + $.setTimeout = canarySetTimeout; + $.clearTimeout = canaryClearTimeout; + $.setInterval = canarySetInterval; + $.clearInterval = canaryClearInterval; +}; diff --git a/src/main/js/modules/bukkit.js b/src/main/js/modules/bukkit.js deleted file mode 100644 index 5928af3..0000000 --- a/src/main/js/modules/bukkit.js +++ /dev/null @@ -1,94 +0,0 @@ -/************************************************************************ - -### bukkit - -The bukkit global variable provides short names for commonly used Bukkit -Java classes and Enums. It also provides some helper functions for getting -players, player names and worlds. - -#### bukkit.stat and bukkit.stats - -This is a short name for the [org.bukkit.Statistic](http://jd.bukkit.org/rb/apidocs/org/bukkit/Statistic.html) Enum. - -##### Usage - - var jumpStat = bukkit.stat.JUMP; // var jumpStat = org.bukkit.Statistic.JUMP - -#### bukkit.material - -This is a short name for the [org.bukkit.Material](http://jd.bukkit.org/rb/apidocs/org/bukkit/Material.html) Enum. - -##### Usage - - var apple = bukkit.material.APPLE; - -#### bukkit.art - -This is a short name for the [org.bukkit.Art](http://jd.bukkit.org/rb/apidocs/org/bukkit/Art.html) Enum. - -##### Usage - - var sunsetArt = bukkit.art.SUNSET; - -#### bukkit.mode - -This is a short name for the [org.bukkit.GameMode](http://jd.bukkit.org/rb/apidocs/org/bukkit/GameMode.html) Enum. - -##### Usage - - var creative = bukkit.mode.CREATIVE; - -#### bukkit.sound - -This is a short name for the [org.bukkit.Sound](http://jd.bukkit.org/rb/apidocs/org/bukkit/Sound.html) Enum. - -##### Usage - - var oink = bukkit.sound.PIG_IDLE; - -#### bukkit.players() function - -This function returns a javascript array of all online players on the server. - -#### bukkit.playerNames() function - -This function returns a javascript array of player names (as javascript strings) - -#### bukkit.worlds() function - -This function returns a javascript array of all worlds on the server. - -***/ -var bukkit = { - stat: org.bukkit.Statistic, - stats: org.bukkit.Statistic, - material: org.bukkit.Material, - art: org.bukkit.Art, - mode: org.bukkit.GameMode, - sound: org.bukkit.Sound, - players: function(){ - var result = []; - for (var i = 0; i < server.onlinePlayers.length; i++){ - result.push(server.onlinePlayers[i]); - } - return result; - }, - playerNames: function(){ - var result = []; - for (var i = 0; i < server.onlinePlayers.length; i++){ - result.push(''+ server.onlinePlayers[i].name); - } - return result; - }, - worlds: function(){ - var result = []; - var lWorlds = server.worlds; - for (var i = 0; i < lWorlds.size(); i++){ - result.push(lWorlds.get(i)); - } - return result; - } -}; -module.exports = function( container ){ - container.bukkit = bukkit; -}; diff --git a/src/main/js/modules/fireworks/fireworks.js b/src/main/js/modules/bukkit/fireworks.js similarity index 58% rename from src/main/js/modules/fireworks/fireworks.js rename to src/main/js/modules/bukkit/fireworks.js index 345e96e..bf58840 100644 --- a/src/main/js/modules/fireworks/fireworks.js +++ b/src/main/js/modules/bukkit/fireworks.js @@ -1,42 +1,7 @@ -/************************************************************************ -## Fireworks Module - -The fireworks module makes it easy to create fireworks using -ScriptCraft. The module has a single function `firework` which takes -a `org.bukkit.Location` as its 1 and only parameter. - -### Examples - -The module also extends the `Drone` object adding a `firework` method -so that fireworks can be created as a part of a Drone chain. For -Example.... - - /js firework() - -... creates a single firework, while .... - - /js firework().fwd(3).times(5) - -... creates 5 fireworks in a row. Fireworks have also been added as a -possible option for the `arrow` module. To have a firework launch -where an arrow strikes... - - /js arrows.firework() - -To call the fireworks.firework() function directly, you must provide a -location. For example... - - /js var fireworks = require('fireworks'); - /js fireworks.firework( self.location ); - -![firework example](img/firework.png) - -***/ - /* create a firework at the given location */ -var firework = function( location ) { +function bukkitFirework( location ) { var bkColor = org.bukkit.Color; var bkFireworkEffect = org.bukkit.FireworkEffect; var bkEntityType = org.bukkit.entity.EntityType; @@ -77,7 +42,5 @@ var firework = function( location ) { fwm.addEffect( effect ); fwm.setPower( randInt( 2 ) + 1 ); fw.setFireworkMeta( fwm ); -}; - -exports.firework = firework; - +} +module.exports = bukkitFirework; diff --git a/src/main/js/modules/bukkit/input.js b/src/main/js/modules/bukkit/input.js new file mode 100644 index 0000000..c0db662 --- /dev/null +++ b/src/main/js/modules/bukkit/input.js @@ -0,0 +1,28 @@ +var bkPrompt = org.bukkit.conversations.Prompt, + bkConversationFactory = org.bukkit.conversations.ConversationFactory; + +function bukkitAsyncInput( sender, promptMesg, callback) { + var repeat = function(){ + bukkitAsyncInput( sender, promptMesg, callback); + }; + var prompt = new bkPrompt( { + getPromptText: function( ctx ) { + return promptMesg; + }, + acceptInput: function( ctx, value ) { + callback.apply( { repeat: repeat, sender: sender, message: promptMesg, value: value }, + [value, sender, repeat]); + return null; + }, + blocksForInput: function( ctx ) { + return true; + } + }); + + new bkConversationFactory( __plugin ) + .withModality( false ) + .withFirstPrompt( prompt ) + .buildConversation( sender ) + .begin( ); +} +module.exports = bukkitAsyncInput; diff --git a/src/main/js/modules/bukkit/items.js b/src/main/js/modules/bukkit/items.js new file mode 100644 index 0000000..8631fb3 --- /dev/null +++ b/src/main/js/modules/bukkit/items.js @@ -0,0 +1,28 @@ +var bkItemStack = org.bukkit.inventory.ItemStack; + +var items = function( material, amount ) { + material = material.toUpperCase(); + return new bkItemStack(bukkit.material[material],amount); +}; + +var materials = bukkit.material.values(); + +for (var i = 0;i < materials.length; i++ ){ + var name = (''+materials[i].name()).toLowerCase(); + name = name.replace(/(_.)/g,function(a){ return a.replace(/_/,'').toUpperCase(); }); + + items[name] = (function(material){ + return function(amount){ + if (typeof amount == 'undefined'){ + return material; + } + if (typeof amount == 'number'){ + return new bkItemStack(material, amount); + } else { + return amount == material; + } + }; + })(materials[i]); +} + +module.exports = items; diff --git a/src/main/js/modules/bukkit/sounds.js b/src/main/js/modules/bukkit/sounds.js new file mode 100644 index 0000000..70c08a4 --- /dev/null +++ b/src/main/js/modules/bukkit/sounds.js @@ -0,0 +1,62 @@ +var bkLocation = org.bukkit.Location, + i = 0, + bukkit = require('bukkit'), + foreach = require('utils').foreach, + allSounds = bukkit.sound.values(), + len = allSounds.length, + sound, + soundName; + +for ( ; i < len; i++ ) { + sound = allSounds[i]; + soundName = '' + sound.name(); + var methodName = soundName.toLowerCase().replace(/_(.)/g,function(a,b){ return b.toUpperCase();}); + exports[methodName] = (function(sound){ + return function() + { + switch (arguments.length) { + case 3: + exports.play(sound, arguments[0], arguments[1], arguments[2]); + break; + case 2: + // TODO: possible combinations: + // location, volume, + // volume pitch + exports.play(sound, arguments[0],arguments[1]); + break; + case 1: + exports.play(sound, arguments[0]); + break; + case 0: + // play the sound at full vol, medium pitch for all players + // + foreach(server.onlinePlayers,function(player){ + exports.play(sound, player, 1, 0); + }); + default: + } + }; + })(sound); +} +exports.play = function(sound, locationOrHasLocation, volume, pitch) { + var location = null; + if (!locationOrHasLocation) + return; + if (locationOrHasLocation instanceof bkLocation){ + location = locationOrHasLocation; + } else { + locationOrHasLocation = locationOrHasLocation.location; + if (locationOrHasLocation && locationOrHasLocation instanceof bkLocation ){ + location = locationOrHasLocation; + } + } + if (!location){ + console.warn('sounds.play() needs a location'); + return; + } + if (typeof volume == 'undefined') + volume = 1; + if (typeof pitch == 'undefined') + pitch = 1; + location.world.playSound(location, sound, volume, pitch); +}; diff --git a/src/main/js/modules/canary/fireworks.js b/src/main/js/modules/canary/fireworks.js new file mode 100644 index 0000000..b07034d --- /dev/null +++ b/src/main/js/modules/canary/fireworks.js @@ -0,0 +1,32 @@ +var items = require('items'); +var Canary = Packages.net.canarymod.Canary; +var cmFireworkHelper = Packages.net.canarymod.api.inventory.helper.FireworkHelper; +var cmExplosionType = Packages.net.canarymod.api.inventory.helper.FireworkHelper.ExplosionType; +var explosionTypes = ['STAR','BURST','CREEPER','LARGE','SMALL']; +var entityFactory = Canary.factory().entityFactory; +var cmEntityType = Packages.net.canarymod.api.entity.EntityType; +var colors = [0xff0000, 0xffff00, 0x00ff00, 0x0000ff]; +function canaryFirework( location ) { + var firework = items.fireworkStar(1); + var i1 = Math.floor(Math.random()* colors.length); + var i2 = Math.floor(Math.random()* colors.length); + var colorsToUse = colors.slice(Math.min(i1,i2),Math.max(i1,i2)); + if (colorsToUse.length == 0){ + colorsToUse = colors; + } + cmFireworkHelper.addStarColorsRaw(firework, colorsToUse); + cmFireworkHelper.setDoesFlicker( firework, true); + cmFireworkHelper.setDoesTrail( firework, true ); + // use a random explosion type + var rnd = Math.floor(Math.random() * explosionTypes.length); + var type = explosionTypes[rnd]; + cmFireworkHelper.setStarExplosionType( firework, cmExplosionType[type]); + var rocket = items.fireworkRocket(1); + cmFireworkHelper.setFlightDuration( rocket, 3); + cmFireworkHelper.attachFireworkStars( rocket, [firework] ); + var rocketEntity = entityFactory.newEntity(cmEntityType.FIREWORKROCKET, location); + rocketEntity.item = rocket; + rocketEntity.spawn(); +} + +module.exports = canaryFirework; diff --git a/src/main/js/modules/canary/input.js b/src/main/js/modules/canary/input.js new file mode 100644 index 0000000..de2ef63 --- /dev/null +++ b/src/main/js/modules/canary/input.js @@ -0,0 +1,26 @@ + +function canaryAsyncInput( sender, promptMesg, callback) { + sender.message(promptMesg); + function repeat(){ + setTimeout( function(){ + listener.unregister(); // avoid CME + canaryAsyncInput( sender, promptMesg, callback); + },1); + } + var listener = events.chat(function (event) { + if (event.player == sender) { + var receivers = event.getReceiverList(); + if (receivers.size() == 1 && receivers.contains(sender)){ + var value = event.message; + var that = this; + event.setCanceled(); + callback.apply( { repeat: repeat, sender: sender, message: promptMesg, value: value }, + [value, sender, repeat]); + setTimeout(function(){that.unregister();},10); + } + } + },'CRITICAL'); + // unregister after 30 seconds + setTimeout(function(){ listener.unregister(); }, 30000); +} +module.exports = canaryAsyncInput; diff --git a/src/main/js/modules/canary/items.js b/src/main/js/modules/canary/items.js new file mode 100644 index 0000000..3eebf51 --- /dev/null +++ b/src/main/js/modules/canary/items.js @@ -0,0 +1,45 @@ +var ItemType = Packages.net.canarymod.api.inventory.ItemType; +var Canary = Packages.net.canarymod.Canary; +var itemFactory = Canary.factory().itemFactory; + +function items( material, amount ) { + material = material.toUpperCase(); + var result = itemFactory["newItem(net.canarymod.api.inventory.ItemType)"](material); + result.amount = amount; + return result; +} + +var materials = ItemType.class.getDeclaredFields(); + +for (var i = 0;i < materials.length; i++ ){ + + if (materials[i].type != ItemType.class) { + continue; + } + var materialField = materials[i]; + var name = (''+materialField.name).replace(/^(.)/,function(a){ return a.toLowerCase() }); + + items[name] = (function(material){ + return function(amount){ + if (typeof amount == 'undefined'){ + return material; + } + if (typeof amount == 'number'){ + var itemStack = itemFactory["newItem(net.canarymod.api.inventory.ItemType)"](material); + itemStack.amount = amount; + return itemStack; + } else { + var result = (amount == material); + if (!result){ + if (amount.getId && amount.getData){ + var m2 = ItemType.fromIdAndData(amount.id, amount.data); + result = (m2 == material); + } + } + return result; + } + }; + })(materialField.get(ItemType)); +} + +module.exports = items; diff --git a/src/main/js/modules/canary/sounds.js b/src/main/js/modules/canary/sounds.js new file mode 100644 index 0000000..1d8bcc4 --- /dev/null +++ b/src/main/js/modules/canary/sounds.js @@ -0,0 +1,65 @@ +var allSounds = Packages.net.canarymod.api.world.effects.SoundEffect.Type.values(), + cmSoundEffect = Packages.net.canarymod.api.world.effects.SoundEffect, + foreach = require('utils').foreach, + i = 0, + len = allSounds.length, + sound, + soundName; + +function playSound(sound, locationOrHasLocation, volume, pitch ) { + var location = null; + if (!locationOrHasLocation) + return; + if (locationOrHasLocation.world){ + location = locationOrHasLocation; + } else { + locationOrHasLocation = locationOrHasLocation.location; + if (locationOrHasLocation && locationOrHasLocation.world ){ + location = locationOrHasLocation; + } + } + if (!location){ + console.warn('sounds.play() needs a location'); + return; + } + if (typeof volume == 'undefined') + volume = 1; + if (typeof pitch == 'undefined') + pitch = 1; + var soundEffect = new cmSoundEffect(sound, location.x, location.y, location.z, volume, pitch); + location.world.playSound(soundEffect); +} + +for ( ; i < len; i++ ) { + sound = allSounds[i]; + soundName = '' + sound.name(); + var methodName = soundName.toLowerCase().replace(/_(.)/g,function(a,b){ return b.toUpperCase();}); + exports[methodName] = (function(sound){ + return function() + { + switch (arguments.length) { + case 3: + playSound(sound, arguments[0], arguments[1], arguments[2]); + break; + case 2: + // TODO: possible combinations: + // location, volume, + // volume pitch + playSound(sound, arguments[0],arguments[1]); + break; + case 1: + playSound(sound, arguments[0]); + break; + case 0: + // play the sound at full vol, medium pitch for all players + // + foreach( server.playerList, function(player) { + playSound(sound, player, 1, 0); + }); + default: + } + }; + })(sound); +} + +exports.play = playSound; diff --git a/src/main/js/modules/fireworks.js b/src/main/js/modules/fireworks.js new file mode 100644 index 0000000..396e525 --- /dev/null +++ b/src/main/js/modules/fireworks.js @@ -0,0 +1,42 @@ +/************************************************************************ +## Fireworks Module + +The fireworks module makes it easy to create fireworks using +ScriptCraft. The module has a single function `firework` which takes +a `org.bukkit.Location` as its 1 and only parameter. + +### Examples + +The module also extends the `Drone` object adding a `firework` method +so that fireworks can be created as a part of a Drone chain. For +Example.... + + /js firework() + +... creates a single firework, while .... + + /js firework().fwd(3).times(5) + +... creates 5 fireworks in a row. Fireworks have also been added as a +possible option for the `arrow` module. To have a firework launch +where an arrow strikes... + + /js arrows.firework() + +To call the fireworks.firework() function directly, you must provide a +location. For example... + + /js var fireworks = require('fireworks'); + /js fireworks.firework( self.location ); + +![firework example](img/firework.png) + +***/ + +if ( __plugin.canary ) { + exports.firework = require('./bukkit/fireworks'); +} else { + exports.firework = require('./canary/fireworks'); +} + + diff --git a/src/main/js/modules/fireworks/package.json b/src/main/js/modules/fireworks/package.json deleted file mode 100644 index 99595d8..0000000 --- a/src/main/js/modules/fireworks/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - name: 'fireworks', - main: './fireworks.js' -} diff --git a/src/main/js/modules/input.js b/src/main/js/modules/input.js index c3755af..20d7581 100644 --- a/src/main/js/modules/input.js +++ b/src/main/js/modules/input.js @@ -26,14 +26,14 @@ exports.numberguess = function(player){ } if ( +guess !== randomNumber ) { if (+guess < randomNumber ) { - guesser.sendMessage('Too low - guess again'); + echo( guesser, 'Too low - guess again'); } if (+guess > randomNumber ) { - guesser.sendMessage('Too high - guess again'); + echo( guesser, 'Too high - guess again'); } repeat(); } else { - guesser.sendMessage('You guessed correctly'); + echo( guesser, 'You guessed correctly'); } }); }; @@ -56,32 +56,8 @@ The callback function as well as being bound to an object with the above propert The `value` parameter will be the same as `this.value`, the `repeat` parameter will be the same as `this.repeat` and so on. ***/ - -var bkPrompt = org.bukkit.conversations.Prompt, - bkConversationFactory = org.bukkit.conversations.ConversationFactory; - -function asyncInput( sender, promptMesg, callback) { - var repeat = function(){ - asyncInput( sender, promptMesg, callback); - }; - var prompt = new bkPrompt( { - getPromptText: function( ctx ) { - return promptMesg; - }, - acceptInput: function( ctx, value ) { - callback.apply( { repeat: repeat, sender: sender, message: promptMesg, value: value }, - [value, sender, repeat]); - return null; - }, - blocksForInput: function( ctx ) { - return true; - } - }); - - new bkConversationFactory( __plugin ) - .withModality( false ) - .withFirstPrompt( prompt ) - .buildConversation( sender ) - .begin( ); +if (__plugin.canary) { + module.exports = require('./canary/input'); +} else { + module.exports = require('./bukkit/input'); } -module.exports = asyncInput; diff --git a/src/main/js/modules/items.js b/src/main/js/modules/items.js index 4b87d60..c5ae4cc 100644 --- a/src/main/js/modules/items.js +++ b/src/main/js/modules/items.js @@ -1,27 +1,5 @@ -var bkItemStack = org.bukkit.inventory.ItemStack; - -var items = function( material, amount ) { - material = material.toUpperCase(); - return new bkItemStack(bukkit.material[material],amount); -}; -module.exports = items; - -var materials = bukkit.material.values(); - -for (var i = 0;i < materials.length; i++ ){ - var name = (''+materials[i].name()).toLowerCase(); - name = name.replace(/(_.)/g,function(a){ return a.replace(/_/,'').toUpperCase(); }); - - items[name] = (function(material){ - return function(amount){ - if (typeof amount == 'undefined'){ - return material; - } - if (typeof amount == 'number'){ - return new bkItemStack(material, amount); - } else { - return amount == material; - } - }; - })(materials[i]); +if (__plugin.canary) { + module.exports = require('./canary/items'); +} else { + module.exports = require('./bukkit/items'); } diff --git a/src/main/js/modules/signs/menu.js b/src/main/js/modules/signs/menu.js index a792a76..d4aa5e7 100644 --- a/src/main/js/modules/signs/menu.js +++ b/src/main/js/modules/signs/menu.js @@ -181,6 +181,10 @@ signs.menu = function( /* String */ label, /* Array */ options, /* Function */ c return convertToMenuSign; }; +if (__plugin.canary){ + console.warn('signs/menu is not yet supported in CanaryMod'); + return; +} // // update it every time player interacts with it. // diff --git a/src/main/js/modules/signs/signs.js b/src/main/js/modules/signs/signs.js index 8851d83..57ae39a 100644 --- a/src/main/js/modules/signs/signs.js +++ b/src/main/js/modules/signs/signs.js @@ -85,7 +85,7 @@ var signs = require('signs'), var player = utils.player('tom1234'); var sign = signs.getTargetedBy( player ); if ( !sign ) { - player.sendMessage('Not looking at a sign'); + echo( player, 'Not looking at a sign'); } ``` diff --git a/src/main/js/modules/sounds.js b/src/main/js/modules/sounds.js index e580092..4065cc3 100644 --- a/src/main/js/modules/sounds.js +++ b/src/main/js/modules/sounds.js @@ -1,49 +1,10 @@ -var bkLocation = org.bukkit.Location, - i = 0, - foreach = require('utils').foreach, - allSounds = bukkit.sound.values(), - len = allSounds.length, - sound, - soundName; - -for ( ; i < len; i++ ) { - sound = allSounds[i]; - soundName = '' + sound.name(); - var methodName = soundName.toLowerCase().replace(/_(.)/g,function(a,b){ return b.toUpperCase();}); - exports[methodName] = (function(sound){ - return function() - { - switch (arguments.length) { - case 3: - exports.play(sound, arguments[0], arguments[1], arguments[2]); - break; - case 2: - // TODO: possible combinations: - // location, volume, - // volume pitch - exports.play(sound, arguments[0],arguments[1]); - break; - case 1: - exports.play(sound, arguments[0]); - break; - case 0: - // play the sound at full vol, medium pitch for all players - // - foreach(server.onlinePlayers,function(player){ - exports.play(sound, player, 1, 0); - }); - default: - } - }; - })(sound); -} /************************************************************************* ## Sounds Module This module is a simple wrapper around the Bukkit Sound class and provides a simpler way to play sounds. All of the org.bukkit.Sound Enum values are attached. -### Usage: +### Usage (Bukkit) : var sounds = require('sounds'); sounds.play( bukkit.sound.VILLAGER_NO , self, 1, 0); // plays VILLAGER_NO sound at full volume and medium pitch @@ -64,25 +25,8 @@ In addition, a play function is provided for each possible sound using the follo These methods are provided for convenience to help beginners explore sounds using TAB completion. ***/ -exports.play = function(sound, locationOrHasLocation, volume, pitch) { - var location = null; - if (!locationOrHasLocation) - return; - if (locationOrHasLocation instanceof bkLocation){ - location = locationOrHasLocation; - } else { - locationOrHasLocation = locationOrHasLocation.location; - if (locationOrHasLocation && locationOrHasLocation instanceof bkLocation ){ - location = locationOrHasLocation; - } - } - if (!location){ - console.warn('sounds.play() needs a location'); - return; - } - if (typeof volume == 'undefined') - volume = 1; - if (typeof pitch == 'undefined') - pitch = 1; - location.world.playSound(location, sound, volume, pitch); -}; +if (__plugin.canary) { + module.exports = require('./canary/sounds'); +} else { + module.exports = require('./bukkit/sounds'); +} diff --git a/src/main/js/modules/utils/string-exts.js b/src/main/js/modules/utils/string-exts.js index 8167636..1cf1dda 100644 --- a/src/main/js/modules/utils/string-exts.js +++ b/src/main/js/modules/utils/string-exts.js @@ -37,7 +37,7 @@ Example ------- /js var boldGoldText = "Hello World".bold().gold(); - /js self.sendMessage( boldGoldText ); + /js echo(self, boldGoldText );

Hello World

diff --git a/src/main/js/modules/utils/utils.js b/src/main/js/modules/utils/utils.js index 4308032..f92eb07 100644 --- a/src/main/js/modules/utils/utils.js +++ b/src/main/js/modules/utils/utils.js @@ -1,8 +1,14 @@ 'use strict'; -var File = java.io.File, - bkBukkit = org.bukkit.Bukkit, - bkLocation = org.bukkit.Location, - bkBlockCommandSender = org.bukkit.command.BlockCommandSender; +var File = java.io.File; + +if (__plugin.bukkit){ + var bkBukkit = org.bukkit.Bukkit, + bkLocation = org.bukkit.Location, + bkBlockCommandSender = org.bukkit.command.BlockCommandSender; +} +if (__plugin.canary){ + var Canary = Packages.net.canarymod.Canary; +} /************************************************************************ ## Utilities Module @@ -31,7 +37,7 @@ var utils = require('utils'); var name = 'walterh'; var player = utils.player(name); if ( player ) { - player.sendMessage('Got ' + name); + echo(player, 'Got ' + name); } else { console.log('No player named ' + name); } @@ -50,7 +56,11 @@ var _player = function ( playerName ) { } } else { if ( typeof playerName == 'string' ) - return bkBukkit.getPlayer( playerName ); + if (__plugin.canary) { + return Canary.server.getPlayer( playerName ); + } else { + return bkBukkit.getPlayer( playerName ); + } else return playerName; // assumes it's a player object } @@ -132,8 +142,14 @@ exports.locationFromJSON = function( json ) { world = bkBukkit.getWorld( json[0] ); return new bkLocation( world, json[1], json[2] , json[3] ); } else { - world = bkBukkit.getWorld( json.world ); - return new bkLocation( world, json.x, json.y , json.z, json.yaw, json.pitch ); + if (__plugin.canary){ + world = Canary.server.getWorld( json.world ); + var cmLocation = Packages.net.canarymod.api.world.position.Location; + return new cmLocation(world, json.x, json.y, json.z, json.pitch, json.yaw); + } else { + world = bkBukkit.getWorld( json.world ); + return new bkLocation( world, json.x, json.y , json.z, json.yaw, json.pitch ); + } } }; @@ -203,13 +219,23 @@ exports.getMousePos = function( player ) { if ( !player ) { return null; } - // player might be CONSOLE or a CommandBlock - if ( !player.getTargetBlock ) { - return null; - } - var targetedBlock = player.getTargetBlock( null, 5 ); - if ( targetedBlock == null || targetedBlock.isEmpty() ) { - return null; + var targetedBlock ; + if ( __plugin.canary ) { + var cmLineTracer = Packages.net.canarymod.LineTracer; + var lineTracer = new cmLineTracer(player); + targetedBlock = lineTracer.getTargetBlock(); + if (targetedBlock == null){ + return null; + } + } else { + // player might be CONSOLE or a CommandBlock + if ( !player.getTargetBlock ) { + return null; + } + targetedBlock = player.getTargetBlock( null, 5 ); + if ( targetedBlock == null || targetedBlock.isEmpty() ) { + return null; + } } return targetedBlock.location; }; @@ -265,7 +291,7 @@ The following example illustrates how to use foreach for immediate processing of var utils = require('utils'); var players = ['moe', 'larry', 'curly']; utils.foreach (players, function(item){ - server.getPlayer(item).sendMessage('Hi ' + item); + echo( server.getPlayer(item), 'Hi ' + item); }); ``` @@ -299,7 +325,7 @@ var processItem = function(item, index, object, array){ // assume this code is within a function/closure var player = self; var onDone = function(){ - player.sendMessage('Job Done!'); + echo( player, 'Job Done!'); }; utils.foreach (a, processItem, null, 10, onDone); ``` @@ -720,3 +746,70 @@ exports.array = function( ){ } return result; }; +function getPlayersBukkit(){ + var result = []; + for (var i = 0; i < server.onlinePlayers.length; i++){ + result.push(server.onlinePlayers[i]); + } + return result; +} +function getPlayersCanary(){ + var result = []; + var players = server.playerList; + for (var i = 0; i < players.size(); i++){ + result.push(players.get(i)); + } + return result; +} +function getStatBukkit(player, stat){ + return player.getStatistic(org.bukkit.Statistic[stat.toUpperCase()]); +} +function getStatCanary(player, stat){ + var cmStatistics = Packages.net.canarymod.api.statistics.Statistics; + return player.getStat(cmStatistics[stat.toUpperCase()].instance); +} +exports.players = __plugin.canary ? getPlayersCanary: getPlayersBukkit; +/************************************************************************* +### utils.stat() function + +This function returns a numeric value for a given player statistic. + +#### Parameters + + * Player - The player object + * Statistic - A string whose value should be one of the following (CanaryMod) + * ANIMALSBRED + * BOATONECM + * CLIMBONECM + * CROUCHONECM + * DAMAGEDEALT + * DAMAGETAKEN + * DEATHS + * DRIVEONECM + * DROP + * FALLONECM + * FISHCAUGHT + * FLYONECM + * HORSEONECM + * JUMP + * JUNKFISHED + * LEAVEGAME + * MINECARTONECM + * MOBKILLS + * PIGONECM + * PLAYERKILLS + * PLAYONEMINUTE + * SPRINTONECM + * SWIMONECM + * TALKEDTOVILLAGER + * TIMESINCEDEATH + * TRADEDWITHVILLAGER + * TREASUREFISHED + * WALKONECM + +See [CanaryMod's Statistic][cmstat] class for a list of possible stat values + +[cmstat]: https://ci.visualillusionsent.net/job/CanaryLib/javadoc/net/canarymod/api/statistics/Statistics.html + +***/ +exports.stat = __plugin.canary ? getStatCanary: getStatBukkit; diff --git a/src/main/js/plugins/alias/alias.js b/src/main/js/plugins/alias/alias.js index 6ffe4af..8daada3 100644 --- a/src/main/js/plugins/alias/alias.js +++ b/src/main/js/plugins/alias/alias.js @@ -93,16 +93,16 @@ var _set = function( params, player ) { var o = _processParams( params ); playerAliases[o.cmd] = o.aliases; _store.players[player.name] = playerAliases; - player.sendMessage( 'Alias ' + o.cmd + ' created.' ); + echo( player, 'Alias ' + o.cmd + ' created.' ); }; var _remove = function( params, player ) { if ( _store.players[player.name] && _store.players[player.name][ params[0] ] ) { delete _store.players[player.name][params[0]]; - player.sendMessage( 'Alias ' + params[0] + ' removed.' ); + echo( player, 'Alias ' + params[0] + ' removed.' ); } else{ - player.sendMessage( 'Alias ' + params[0] + ' does not exist.' ); + echo( player, 'Alias ' + params[0] + ' does not exist.' ); } if ( player.op ) { if ( _store.global[params[0]] ) { @@ -113,30 +113,30 @@ var _remove = function( params, player ) { var _global = function( params, player ) { if ( !player.op ) { - player.sendMessage( 'Only operators can set global aliases. ' + - 'You need to be an operator to perform this command.' ); + echo( player, 'Only operators can set global aliases. ' + + 'You need to be an operator to perform this command.' ); return; } var o = _processParams( params ); _store.global[o.cmd] = o.aliases; - player.sendMessage( 'Global alias ' + o.cmd + ' created.' ); + echo( player, 'Global alias ' + o.cmd + ' created.' ); }; var _list = function( params, player ) { var alias = 0; try { if ( _store.players[player.name] ) { - player.sendMessage('Your aliases:'); + echo( player, 'Your aliases:'); for ( alias in _store.players[player.name] ) { - player.sendMessage( alias + ' = ' + - JSON.stringify( _store.players[player.name][alias] ) ); + echo( player, alias + ' = ' + + JSON.stringify( _store.players[player.name][alias] ) ); } } else { - player.sendMessage( 'You have no player-specific aliases.' ); + echo( player, 'You have no player-specific aliases.' ); } - player.sendMessage( 'Global aliases:' ); + echo( player, 'Global aliases:' ); for ( alias in _store.global ) { - player.sendMessage( alias + ' = ' + JSON.stringify( _store.global[alias] ) ); + echo( player, alias + ' = ' + JSON.stringify( _store.global[alias] ) ); } } catch( e ) { console.error( 'Error in list function: ' + e.message ); @@ -144,7 +144,7 @@ var _list = function( params, player ) { } }; var _help = function( params, player ) { - player.sendMessage( 'Usage:\n' + _usage ); + echo( player, 'Usage:\n' + _usage ); }; var alias = plugin( 'alias', { @@ -160,7 +160,7 @@ var aliasCmd = command( 'alias', function( params, invoker ) { var operation = params[0], fn; if ( !operation ) { - invoker.sendMessage( 'Usage:\n' + _usage ); + echo( invoker, 'Usage:\n' + _usage ); return; } /* @@ -175,7 +175,7 @@ var aliasCmd = command( 'alias', function( params, invoker ) { return; } } - invoker.sendMessage( 'Usage:\n' + _usage ); + echo( invoker, 'Usage:\n' + _usage ); }); var _intercept = function( msg, invoker, exec ) { @@ -223,6 +223,10 @@ var _intercept = function( msg, invoker, exec ) { Intercept all command processing and replace with aliased commands if the command about to be issued matches an alias. */ +if (__plugin.canary){ + console.warn('alias plugin is not yet supported in CanaryMod'); + return; +} events.playerCommandPreprocess( function( evt ) { var invoker = evt.player; var exec = function( cmd ) { diff --git a/src/main/js/plugins/arrows.js b/src/main/js/plugins/arrows.js index 2aa54e0..0aa08e5 100644 --- a/src/main/js/plugins/arrows.js +++ b/src/main/js/plugins/arrows.js @@ -24,7 +24,10 @@ as a parameter. For example: `/js arrows.explosive('player23')` makes player23's arrows explosive. ***/ - +if (__plugin.canary){ + console.warn('arrows plugin not yet supported in CanaryMod'); + return; +} var signs = require('signs'), fireworks = require('fireworks'), utils = require('utils'), diff --git a/src/main/js/plugins/classroom/classroom.js b/src/main/js/plugins/classroom/classroom.js index dd22cc8..d4f3f0e 100644 --- a/src/main/js/plugins/classroom/classroom.js +++ b/src/main/js/plugins/classroom/classroom.js @@ -35,7 +35,7 @@ directory... ```javascript exports.hi = function( player ){ - player.sendMessage('Hi ' + player.name); + echo( player, 'Hi ' + player.name); }; ``` @@ -129,10 +129,10 @@ function grantScripting( player ) { }); /* - player.sendMessage('Create your own minecraft mods by adding javascript (.js) files'); - player.sendMessage(' Windows: Open Explorer, go to \\\\' + serverAddress + '\\players\\' + player.name); - player.sendMessage(' Macintosh: Open Finder, Go to smb://' + serverAddress + '/players/' + player.name); - player.sendMessage(' Linux: Open Nautilus, Go to smb://' + serverAddress + '/players/' + player.name); + echo( player, 'Create your own minecraft mods by adding javascript (.js) files'); + echo( player, ' Windows: Open Explorer, go to \\\\' + serverAddress + '\\players\\' + player.name); + echo( player, ' Macintosh: Open Finder, Go to smb://' + serverAddress + '/players/' + player.name); + echo( player, ' Linux: Open Nautilus, Go to smb://' + serverAddress + '/players/' + player.name); */ } @@ -150,13 +150,13 @@ var classroom = plugin('classroom', { */ if ( !sender.op ) { console.log( 'Attempt to set classroom scripting without credentials: ' + sender.name ); - sender.sendMessage('Only operators can use this function'); + echo( sender, 'Only operators can use this function'); return; } foreach( server.onlinePlayers, canScript ? grantScripting : revokeScripting); _store.enableScripting = canScript; - sender.sendMessage('Scripting turned ' + ( canScript ? 'on' : 'off' ) + + echo( sender, 'Scripting turned ' + ( canScript ? 'on' : 'off' ) + ' for all players on server ' + serverAddress); }, store: _store @@ -164,9 +164,16 @@ var classroom = plugin('classroom', { exports.classroom = classroom; -events.playerJoin( function( event ) { - if ( _store.enableScripting ) { - grantScripting(event.player); - } -}, 'HIGHEST'); - +if (__plugin.canary){ + events.connection( function( event ) { + if ( _store.enableScripting ) { + grantScripting(event.player); + } + }, 'CRITICAL'); +} else { + events.playerJoin( function( event ) { + if ( _store.enableScripting ) { + grantScripting(event.player); + } + }, 'HIGHEST'); +} diff --git a/src/main/js/plugins/commando/commando-test.js b/src/main/js/plugins/commando/commando-test.js index 5457e11..3e535cb 100644 --- a/src/main/js/plugins/commando/commando-test.js +++ b/src/main/js/plugins/commando/commando-test.js @@ -2,6 +2,10 @@ A test of the commando plugin. Adds a new `/js-time` command with 4 possible options: Dawn, Midday, Dusk, Midnight */ +if (__plugin.canary){ + console.warn('commando-test not yet supported in CanaryMod'); + return; +} var commando = require('./commando').commando, times = ['Dawn','Midday','Dusk','Midnight']; @@ -16,7 +20,7 @@ commando( 'js-time' , function( params, sender ) { } } } else { - sender.sendMessage('This command only works in-world'); + echo( sender, 'This command only works in-world'); } },times); diff --git a/src/main/js/plugins/commando/commando.js b/src/main/js/plugins/commando/commando.js index 30f2707..331c99c 100644 --- a/src/main/js/plugins/commando/commando.js +++ b/src/main/js/plugins/commando/commando.js @@ -8,7 +8,7 @@ to Minecraft. Normally ScriptCraft only allows for provision of new commands as extensions to the jsp command. For example, to create a new simple command for use by all players... - /js command('hi', function(args,player){ player.sendMessage('Hi ' + player.name); }); + /js command('hi', function(args,player){ echo( player, 'Hi ' + player.name); }); ... then players can use this command by typing... @@ -46,7 +46,7 @@ of the ScriptCraft core. var commando = require('../commando'); commando('hi', function(args,player){ - player.sendMessage('Hi ' + player.name); + echo( player, 'Hi ' + player.name); }); ...Displays a greeting to any player who issues the `/hi` command. @@ -76,6 +76,10 @@ global commands for a plugin, please let me know. [pcppevt]: http://jd.bukkit.org/dev/apidocs/org/bukkit/event/player/PlayerCommandPreprocessEvent.html ***/ +if (__plugin.canary){ + console.warn('commando plugin is not yet supported in CanaryMod'); + return; +} var commands = {}; exports.commando = function( name, func, options, intercepts ) { diff --git a/src/main/js/plugins/drone/contrib/dancefloor.js b/src/main/js/plugins/drone/contrib/dancefloor.js index 67333e0..885e69c 100644 --- a/src/main/js/plugins/drone/contrib/dancefloor.js +++ b/src/main/js/plugins/drone/contrib/dancefloor.js @@ -1,5 +1,5 @@ var Drone = require('../drone').Drone; - +var blocks = require('blocks'); // // Create a floor of colored tiles some of which emit light. // The tiles change color every second creating a strobe-lit dance-floor. @@ -27,13 +27,14 @@ function dancefloor(width,length) var discoTicks = 30; var task = null; var strobe = function() { - disco.rand(floorTiles,width,1,length); + disco.rand(blocks.rainbow ,width,1,length); if (!discoTicks--) - task.cancel(); + clearInterval(task); }; var now = 0; var everySecond = 20; - task = server.scheduler.runTaskTimer(__plugin,strobe,now,everySecond); + task = setInterval( strobe, 1000); + return this; } Drone.extend(dancefloor); diff --git a/src/main/js/plugins/drone/drone.js b/src/main/js/plugins/drone/drone.js index fdf1df7..afe07ed 100644 --- a/src/main/js/plugins/drone/drone.js +++ b/src/main/js/plugins/drone/drone.js @@ -576,8 +576,15 @@ var putBlock = function( x, y, z, blockId, metadata, world ) { } var block = world.getBlockAt( x, y, z ); if ( block.typeId != blockId || block.data != metadata ) { - block.setTypeIdAndData( blockId, metadata, false ); - block.data = metadata; + if (__plugin.canary) { + block.typeId = blockId; + block.data = metadata; + block.update(); + } + if (__plugin.bukkit) { + block.setTypeIdAndData( blockId, metadata, false ); + block.data = metadata; + } } }; @@ -595,12 +602,30 @@ var putSign = function( drone, x, y, z, world, texts, blockId, meta, immediate ) } putBlock( x, y, z, blockId, meta, world ); block = world.getBlockAt( x, y, z ); - state = block.state; - if ( state instanceof bkSign ) { + var getState, isSign, setLine; + if (__plugin.canary){ + isSign = function(block){ + var sign = block.getTileEntity(); + return sign.setTextOnLine; + }; + setLine = function( block, i, text) { + var sign = block.getTileEntity(); + sign.setTextOnLine( text, i ); + sign.upate(true); + }; + } + if (__plugin.bukkit){ + isSign = function(block){ return block.state && block.state.setLine; }; + setLine = function( block, i, text) { + var sign = block.state; + sign.setLine( i, text ); + sign.upate(true); + }; + } + if ( isSign(block) ) { for ( i = 0; i < texts.length; i++ ) { - state.setLine( i % 4, texts[ i ] ); + setLine(block, i % 4, texts[ i ] ); } - state.update( true ); } }; @@ -608,24 +633,26 @@ var Drone = function( x, y, z, dir, world ) { this.record = false; var usePlayerCoords = false; var player = (typeof self !== 'undefined' ? self : null); - if ( x instanceof bkPlayer ) { + var playerPos; + if ( x.location && x.name) { player = x; - } - var playerPos = utils.getPlayerPos( player ); + } + playerPos = x.location; + var that = this; var populateFromLocation = function( loc ) { that.x = loc.x; that.y = loc.y; that.z = loc.z; - that.dir = _getDirFromRotation(loc.yaw); + that.dir = _getDirFromRotation(loc); that.world = loc.world; }; var mp = utils.getMousePos( player ); - if ( typeof x == 'undefined' || x instanceof bkPlayer ) { + if ( typeof x == 'undefined' || x.location ) { if ( mp ) { populateFromLocation( mp ); if ( playerPos ) { - this.dir = _getDirFromRotation(playerPos.yaw); + this.dir = _getDirFromRotation(playerPos); } } else { // base it on the player's current location @@ -640,14 +667,14 @@ var Drone = function( x, y, z, dir, world ) { populateFromLocation( playerPos ); } } else { - if ( arguments[0] instanceof bkLocation ) { + if ( arguments[0].x && arguments[0].y && arguments[0].z ) { populateFromLocation( arguments[ 0 ] ); } else { this.x = x; this.y = y; this.z = z; if ( typeof dir == 'undefined' ) { - this.dir = _getDirFromRotation( playerPos.yaw ); + this.dir = _getDirFromRotation( playerPos); } else { this.dir = dir%4; } @@ -818,12 +845,13 @@ Drone.prototype._checkpoints = {}; Drone.extend(function chkpt( name ) { this._checkpoints[ name ] = { x:this.x, y:this.y, z:this.z, dir:this.dir }; }); + Drone.extend(function move( ) { - if ( arguments[0] instanceof bkLocation ) { + if ( arguments[0].x && arguments[0].y && arguments[0].z) { this.x = arguments[0].x; this.y = arguments[0].y; this.z = arguments[0].z; - this.dir = _getDirFromRotation(arguments[0].yaw ); + this.dir = _getDirFromRotation(arguments[0] ); this.world = arguments[0].world; } else if ( typeof arguments[0] === 'string' ) { var coords = this._checkpoints[arguments[0]]; @@ -901,7 +929,13 @@ Drone.extend( function down( n ) { // position // Drone.prototype.getLocation = function( ) { - return new bkLocation( this.world, this.x, this.y, this.z ); + if (__plugin.canary) { + var cmLocation = Packages.net.canarymod.api.world.position.Location; + return new cmLocation( this.world, this.x, this.y, this.z, 0, 0); + } + if (__plugin.bukkit) { + return new bkLocation( this.world, this.x, this.y, this.z ); + } }; // // building @@ -916,7 +950,7 @@ Drone.extend( function sign( message, block ) { if ( block != 63 && block != 68 ) { var usage = 'Usage: sign("message", "63:1") or sign("message","68:1")'; if ( this.player ) { - this.player.sendMessage(usage); + echo( this.player, usage); } console.error(usage); return; @@ -994,11 +1028,8 @@ Drone.prototype.cuboida = function(/* Array */ blocks, w, h, d, overwrite, immed _traverse[dir].depth( that, d, function traverseDepthCallback( ) { traverseHeight( that, h, function traverseHeightCallback( ) { _traverse[dir].width( that, w, function traverseWidthCallback( ) { - var block = that.world.getBlockAt( that.x, that.y, that.z ); - var properBlock = blocksForBuild[ bi % len ]; - if (overwrite || block.type.equals(bkMaterial.AIR) ) { - block.setTypeIdAndData( properBlock[0], properBlock[1], false ); - } + var properBlock = blocksForBuild[ bi % len ]; + putBlock( that.x, that.y, that.z, properBlock[0], properBlock[1], that.world); bi++; }); }); @@ -1050,13 +1081,7 @@ Drone.prototype.cuboidX = function( blockType, meta, w, h, d, immediate ) { return this; } var depthFunc = function( ) { - - var block = that.world.getBlockAt( that.x, that.y, that.z ); - block.setTypeIdAndData( blockType, meta, false ); - // wph 20130210 - dont' know if this is a bug in bukkit but for chests, - // the metadata is ignored (defaults to 2 - south facing) - // only way to change data is to set it using property/bean. - block.data = meta; + putBlock( that.x, that.y, that.z, blockType, meta, that.world ); }; var heightFunc = function( ) { _traverse[dir].depth( that, d, depthFunc ); @@ -1578,13 +1603,25 @@ var _paste = function( name, immediate ) } ); } ); }; -var _getDirFromRotation = function( r ) { +var _getDirFromRotation = function( location ) { // 0 = east, 1 = south, 2 = west, 3 = north // 46 to 135 = west // 136 to 225 = north // 226 to 315 = east // 316 to 45 = south - + var r; + if (__plugin.canary ) { + r = location.rotation; + } + if (__plugin.bukkit) { + r = location.yaw; + } + + // west = -270 + // north = -180 + // east = -90 + // south = 0 + r = (r + 360 ) % 360; // east could be 270 or -90 if ( r > 45 && r <= 135 ) diff --git a/src/main/js/plugins/examples/example-1-hello-module.js b/src/main/js/plugins/examples/example-1-hello-module.js index cb13ed6..3306704 100644 --- a/src/main/js/plugins/examples/example-1-hello-module.js +++ b/src/main/js/plugins/examples/example-1-hello-module.js @@ -21,10 +21,10 @@ The `hello` function below is only usable by players with the scriptcraft.evalua permission since it relies on the `/js` command to execute. exports.hello = function(player){ - player.sendMessage('Hello ' + player.name); + echo( player, 'Hello ' + player.name); }; ***/ exports.hello = function( player ) { - player.sendMessage( 'Hello ' + player.name ); + echo( player, 'Hello ' + player.name ); }; diff --git a/src/main/js/plugins/examples/example-2-hello-command.js b/src/main/js/plugins/examples/example-2-hello-command.js index 4470003..1ef6b20 100644 --- a/src/main/js/plugins/examples/example-2-hello-command.js +++ b/src/main/js/plugins/examples/example-2-hello-command.js @@ -22,11 +22,11 @@ can use the new extension. Unlike the previous example, the `jsp hello` command does not evaluate javascript code so this command is much more secure. command('hello', function (parameters, player) { - player.sendMessage('Hello ' + player.name); + echo( player, 'Hello ' + player.name); }); ***/ command( 'hello', function( parameters, player ) { - player.sendMessage( 'Hello ' + player.name ); + echo( player, 'Hello ' + player.name ); }); diff --git a/src/main/js/plugins/examples/example-3-hello-ops-only.js b/src/main/js/plugins/examples/example-3-hello-ops-only.js index 84b2a14..c310272 100644 --- a/src/main/js/plugins/examples/example-3-hello-ops-only.js +++ b/src/main/js/plugins/examples/example-3-hello-ops-only.js @@ -23,10 +23,10 @@ message for operators. command('op-hello', function (parameters, player) { if (!player.op){ - player.sendMessage('Only operators can do this.'); - return; + echo( player, 'Only operators can do this.'); + return; } - player.sendMessage('Hello ' + player.name); + echo( player, 'Hello ' + player.name); }); ***/ @@ -35,8 +35,8 @@ command( 'op-hello', function( parameters, player ) { this is how you limit based on player privileges */ if ( !player.op ) { - player.sendMessage( 'Only operators can do this.' ); + echo( player, 'Only operators can do this.' ); return; } - player.sendMessage( 'Hello ' + player.name ); + echo( player, 'Hello ' + player.name ); }); diff --git a/src/main/js/plugins/examples/example-4-hello-parameters.js b/src/main/js/plugins/examples/example-4-hello-parameters.js index 76def9f..ba01adc 100644 --- a/src/main/js/plugins/examples/example-4-hello-parameters.js +++ b/src/main/js/plugins/examples/example-4-hello-parameters.js @@ -21,7 +21,7 @@ a fixed 'Hello ' to anything you like by passing a parameter. command( 'hello-params', function ( parameters, player ) { var salutation = parameters[0] ; - player.sendMessage( salutation + ' ' + player.name ); + echo( player, salutation + ' ' + player.name ); }); ***/ @@ -36,5 +36,5 @@ command('hello-params', function( parameters, player ) { which appears after `jsp hello-params `. */ var salutation = parameters[0] ; - player.sendMessage( salutation + ' ' + player.name ); + echo( player, salutation + ' ' + player.name ); }); diff --git a/src/main/js/plugins/examples/example-6-hello-player.js b/src/main/js/plugins/examples/example-6-hello-player.js index b53e0bd..fd92854 100644 --- a/src/main/js/plugins/examples/example-6-hello-player.js +++ b/src/main/js/plugins/examples/example-6-hello-player.js @@ -38,7 +38,7 @@ Source Code ... if ( recipient ) { greetings.hello( recipient ); } else { - sender.sendMessage( 'Player ' + playerName + ' not found.' ); + echo( sender, 'Player ' + playerName + ' not found.' ); } }); @@ -53,6 +53,6 @@ command( 'hello-byname', function( parameters, sender ) { if ( recipient ) { greetings.hello( recipient ); } else { - sender.sendMessage( 'Player ' + playerName + ' not found.' ); + echo( sender, 'Player ' + playerName + ' not found.' ); } }); diff --git a/src/main/js/plugins/examples/example-7-hello-events.js b/src/main/js/plugins/examples/example-7-hello-events.js index 6c32f8f..2cb96f6 100644 --- a/src/main/js/plugins/examples/example-7-hello-events.js +++ b/src/main/js/plugins/examples/example-7-hello-events.js @@ -80,7 +80,7 @@ cleaner and more readable. Similarly where you see a method like events.on( 'player.PlayerJoinEvent', function( event ) { if ( event.player.op ) { - event.player.sendMessage('Welcome to ' + __plugin); + echo( event.player, 'Welcome to ' + __plugin); } }); @@ -88,13 +88,16 @@ Update: Since version 2.0.8 the above code can be replaced by the more succinct: events.playerJoin( function( event ) { if ( event.player.op ) { - event.player.sendMessage('Welcome to ' + __plugin); + echo( event.player, 'Welcome to ' + __plugin); } }); ***/ -events.playerJoin( function( event ) { - if ( event.player.op ) { - event.player.sendMessage( 'Welcome to ' + __plugin ); +// wph 20140927 - event handler differs depending on framework. + +var onJoin = __plugin.canary ? events.connection : events.playerJoin; +onJoin( function( event ) { + if ( isOp(event.player) ) { + echo( event.player, 'Welcome to ' + __plugin ); } }); diff --git a/src/main/js/plugins/homes/homes.js b/src/main/js/plugins/homes/homes.js index a4b0af7..f6af3ec 100644 --- a/src/main/js/plugins/homes/homes.js +++ b/src/main/js/plugins/homes/homes.js @@ -106,11 +106,11 @@ var homes = plugin( 'homes', { host = utils.player( host ); loc = _store.houses[ host.name ]; if ( !loc ) { - guest.sendMessage( host.name + ' has no home' ); + echo( guest, host.name + ' has no home' ); return; } if ( !this._canVisit( guest, host ) ) { - guest.sendMessage( 'You can not visit ' + host.name + "'s home yet" ); + echo( guest, 'You can not visit ' + host.name + "'s home yet" ); return; } homeLoc = utils.locationFromJSON( loc ); @@ -213,8 +213,8 @@ var homes = plugin( 'homes', { } invitations.push( guest.name ); _store.invites[host.name] = invitations; - guest.sendMessage( host.name + ' has invited you to their home.' ); - guest.sendMessage( 'type "/jsp home ' + host.name + '" to accept' ); + echo( guest, host.name + ' has invited you to their home.' ); + echo( guest, 'type "/jsp home ' + host.name + '" to accept' ); }, /* Uninvite someone to the home @@ -290,16 +290,16 @@ var options = { }, 'help': function( params, sender ) { - sender.sendMessage( homes.help() ); + echo( sender, homes.help() ); }, 'list': function( params, sender ) { var visitable = homes.list(); if ( visitable.length == 0 ) { - sender.sendMessage( 'There are no homes to visit' ); + echo( sender, 'There are no homes to visit' ); return; } else { - sender.sendMessage([ + echo( sender, [ 'You can visit any of these ' + visitable.length + ' homes' ,visitable.join(', ') ]); @@ -309,9 +309,9 @@ var options = { 'ilist': function( params, sender ) { var potentialVisitors = homes.ilist(); if ( potentialVisitors.length == 0 ) { - sender.sendMessage('No one can visit your home'); + echo( sender, 'No one can visit your home'); } else { - sender.sendMessage([ + echo( sender, [ 'These ' + potentialVisitors.length + 'players can visit your home', potentialVisitors.join(', ')]); } @@ -319,13 +319,13 @@ var options = { 'invite': function( params, sender ) { if ( params.length == 1 ) { - sender.sendMessage( 'You must provide a player name' ); + echo( sender, 'You must provide a player name' ); return; } var playerName = params[1]; var guest = utils.player( playerName ); if ( !guest ) { - sender.sendMessage( playerName + ' is not here' ); + echo( sender, playerName + ' is not here' ); } else { homes.invite( sender, guest ); } @@ -333,13 +333,13 @@ var options = { 'uninvite': function( params, sender ) { if ( params.length == 1 ) { - sender.sendMessage( 'You must provide a player name' ); + echo( sender, 'You must provide a player name' ); return; } var playerName = params[1]; var guest = utils.player( playerName ); if ( !guest ) { - sender.sendMessage( playerName + ' is not here' ); + echo( sender, playerName + ' is not here' ); } else { homes.uninvite( sender, guest ); } @@ -347,25 +347,25 @@ var options = { 'public': function( params, sender ) { homes.open( sender, params.slice( 1 ).join(' ') ); - sender.sendMessage( 'Your home is open to the public' ); + echo( sender, 'Your home is open to the public' ); }, 'private': function( params, sender ) { homes.close( sender ); - sender.sendMessage( 'Your home is closed to the public' ); + echo( sender, 'Your home is closed to the public' ); }, 'listall': function( params, sender ) { if ( !sender.isOp() ) { - sender.sendMessage( 'Only operators can do this' ); + echo( sender, 'Only operators can do this' ); } else { - sender.sendMessage( homes.listall().join(', ') ); + echo( sender, homes.listall().join(', ') ); } }, 'clear': function( params, sender ) { if ( !sender.isOp() ) { - sender.sendMessage( 'Only operators can do this' ); + echo( sender, 'Only operators can do this' ); } else { homes.clear( params[1], sender ); } @@ -393,7 +393,7 @@ command( 'home', function ( params , sender) { } else { host = utils.player( params[0] ); if ( !host ) { - sender.sendMessage( params[0] + ' is not here' ); + echo( sender, params[0] + ' is not here' ); } else { homes.go( sender, host ); } diff --git a/src/main/js/plugins/minigames/cow-clicker.js b/src/main/js/plugins/minigames/cow-clicker.js index cde048b..2b690a2 100644 --- a/src/main/js/plugins/minigames/cow-clicker.js +++ b/src/main/js/plugins/minigames/cow-clicker.js @@ -41,6 +41,10 @@ your own mini-game... ***/ +if (__plugin.canary){ + console.warn('cow-clicker minigame is not yet supported in CanaryMod'); + return; +} var store = {}, bkBukkit = org.bukkit.Bukkit, bkCow = org.bukkit.entity.Cow, @@ -122,7 +126,7 @@ var _addPlayer = function( player, score ) { store[ player.name ] = { score: score }; scoreboard.update( 'cowclicker', player, store[ player.name ].score); - player.sendMessage( 'Go forth and click some cows!' ); + echo( player, 'Go forth and click some cows!' ); }; var _removePlayer = function( player, notify ) { @@ -144,8 +148,8 @@ var _removePlayer = function( player, notify ) { delete store[ player.name ]; if ( notify && player ) { - player.sendMessage( 'You clicked ' + playerScore + ' cows! ' + - 'You must be tired after all that clicking.' ); + echo( player, 'You clicked ' + playerScore + ' cows! ' + + 'You must be tired after all that clicking.' ); } }; diff --git a/src/main/js/plugins/signs/examples.js b/src/main/js/plugins/signs/examples.js index 179ee3f..4bb39ba 100644 --- a/src/main/js/plugins/signs/examples.js +++ b/src/main/js/plugins/signs/examples.js @@ -12,38 +12,40 @@ var signs = require('signs'); // var onDinnerChoice = function(event){ - event.player.sendMessage("You chose " + event.text); + echo( event.player, 'You chose ' + event.text); }; -var convertToDinnerMenu = signs.menu("Dinner", ["Lamb","Pork","Chicken","Duck","Beef"], onDinnerChoice); +var convertToDinnerMenu = signs.menu('Dinner', + ['Lamb','Pork','Chicken','Duck','Beef'], + onDinnerChoice); var onTimeChoice = function(event){ - event.player.location.world.setTime( event.number * 6000 ); + event.player.location.world.setTime( event.number * 6000 ); }; -var convertToTimeMenu = signs.menu("Time", ["Dawn","Midday","Dusk","Midnight"], onTimeChoice); +var convertToTimeMenu = signs.menu('Time', ['Dawn','Midday','Dusk','Midnight'], onTimeChoice); exports.signs = { - menu_food: function(cmdSender){ - var sign = signs.getTargetedBy(cmdSender); - if (!sign){ - throw new Error('You must look at an existing sign'); - } - convertToDinnerMenu(sign); - }, -// -// This is an example sign that displays a menu of times of day -// interacting with the sign will change the time of day accordingly. -// -// In game, create a sign , target it and type ... -// -// /js var signExamples = require('./signs/examples'); -// /js signExamples.timeOfDay() -// - menu_time: function(cmdSender){ - var sign = signs.getTargetedBy(cmdSender); - if (!sign){ - throw new Error('You must look at an existing sign'); - } - convertToTimeMenu(sign); + menu_food: function(cmdSender){ + var sign = signs.getTargetedBy(cmdSender); + if (!sign){ + throw new Error('You must look at an existing sign'); } -} + convertToDinnerMenu(sign); + }, + // + // This is an example sign that displays a menu of times of day + // interacting with the sign will change the time of day accordingly. + // + // In game, create a sign , target it and type ... + // + // /js var signExamples = require('./signs/examples'); + // /js signExamples.timeOfDay() + // + menu_time: function(cmdSender){ + var sign = signs.getTargetedBy(cmdSender); + if (!sign){ + throw new Error('You must look at an existing sign'); + } + convertToTimeMenu(sign); + } +}; diff --git a/src/main/js/plugins/spawn.js b/src/main/js/plugins/spawn.js index 1cfd566..17ed2fe 100644 --- a/src/main/js/plugins/spawn.js +++ b/src/main/js/plugins/spawn.js @@ -16,26 +16,37 @@ press TAB. Visit for a list of possible entities (creatures) which can be spawned. ***/ -var entities = [], - bkEntityType = org.bukkit.entity.EntityType; - -var entitytypes = bkEntityType.values(); +var entities = []; +var entityType = null; +if (__plugin.canary){ + entityType = Packages.net.canarymod.api.entity.EntityType; +}else { + entityType = org.bukkit.entity.EntityType; +} +var entitytypes = entityType.values(); for ( var t in entitytypes ) { if ( entitytypes[t] && entitytypes[t].ordinal ) { entities.push(entitytypes[t].name()); } } + command( 'spawn', function( parameters, sender ) { - if ( !sender.op ) { - sender.sendMessage( 'Only operators can perform this command' ); + if ( !isOp(sender) ) { + echo( sender, 'Only operators can perform this command' ); return; } var location = sender.location; if ( !location ) { - sender.sendMessage( 'You have no location. This command only works in-game.' ); + echo( sender, 'You have no location. This command only works in-game.' ); return; } - var world = location.world; + var world = location.world || sender.world; var type = ('' + parameters[0]).toUpperCase(); - world.spawnEntity( location, bkEntityType[type] ); + if (__plugin.bukkit){ + world.spawnEntity( location, entityType[type] ); + } else { + var Canary = Packages.net.canarymod.Canary; + var entity = Canary.factory().entityFactory.newEntity(entityType[type], location); + entity.spawn(); + } }, entities ); diff --git a/src/main/resources/Canary.inf b/src/main/resources/Canary.inf new file mode 100644 index 0000000..56c784c --- /dev/null +++ b/src/main/resources/Canary.inf @@ -0,0 +1,4 @@ +main-class = org.scriptcraftjs.canarymod.ScriptCraftPlugin +isLibrary = false +author = walter higgins +version = 2.1.10 \ No newline at end of file diff --git a/src/main/resources/boot.js b/src/main/resources/boot.js index aed8412..3816c2b 100644 --- a/src/main/resources/boot.js +++ b/src/main/resources/boot.js @@ -7,12 +7,12 @@ var __scboot = null; FileReader = java.io.FileReader, FileOutputStream = java.io.FileOutputStream, ZipInputStream = java.util.zip.ZipInputStream, - jsPlugins = new File('plugins/scriptcraft'), + //jsPlugins = new File('plugins/scriptcraft'), + jsPlugins = new File('scriptcraft'), initScript = 'lib/scriptcraft.js'; - var unzip = function(path, logger, plugin) { - var zis = new ZipInputStream(plugin.getResource(path)), - entry, + var unzip = function(zis, logger) { + var entry, reason = null, unzipFile = false, zTime = 0, @@ -57,14 +57,13 @@ var __scboot = null; /* Called from Java plugin */ - __scboot = function ( plugin, engine ) + __scboot = function ( plugin, engine, classLoader ) { - var logger = plugin.logger, - cfg = plugin.config, - cfgName, + var logger = plugin.logman, initScriptFile = new File(jsPlugins,initScript), zips = ['lib','plugins','modules'], i = 0, + zis, len = zips.length; if (!jsPlugins.exists()){ @@ -74,14 +73,25 @@ var __scboot = null; } for (i = 0; i < len;i++){ - cfgName = 'extract-js.' + zips[i]; - if (cfg.getBoolean(cfgName)){ - unzip( zips[i] + '.zip',logger,plugin); + if ( plugin.canary ) { + zis = new ZipInputStream(classLoader.getResourceAsStream(zips[i] + '.zip')); + unzip( zis, logger ); + } else { + if ( plugin.config.getBoolean('extract-js.' + zips[i]) ) { + zis = new ZipInputStream(plugin.getResource(zips[i] + '.zip')); + unzip( zis, logger ); + } } } - plugin.saveDefaultConfig(); - - engine.eval(new FileReader(initScriptFile)); - __onEnable(engine, plugin, initScriptFile); + if (plugin.bukkit) { + plugin.saveDefaultConfig(); + } + try { + engine.eval(new FileReader(initScriptFile)); + __onEnable(engine, plugin, initScriptFile); + }catch ( e ){ + logger.error('Error evaluating ' + initScriptFile + ': ' + e); + throw e; + } }; })();