'Buddha' Release : The annihilation of 'self' variable.

use of 'self' should be limited only to in-game or console commands. It should not be used in the context of a module.
This commit is contained in:
walterhiggins 2013-12-30 21:33:12 +00:00
parent fc440654b8
commit f88d1f0428
17 changed files with 239 additions and 220 deletions

View file

@ -18,7 +18,7 @@ loads the module circle.js in the same directory.
The contents of foo.js: The contents of foo.js:
var circle = require('./circle.js'); var circle = require('./circle.js');
echo( 'The area of a circle of radius 4 is ' console.log( 'The area of a circle of radius 4 is '
+ circle.area(4)); + circle.area(4));
The contents of circle.js: The contents of circle.js:
@ -71,14 +71,14 @@ module in the `plugins` directory exports becomes a global
variable. For example, if you have a module greeting.js in the plugins variable. For example, if you have a module greeting.js in the plugins
directory.... directory....
exports.greet = function() { exports.greet = function(player) {
echo('Hello ' + self.name); player.sendMessage('Hello ' + player.name);
}; };
... then `greet` becomes a global function and can be used at the ... then `greet` becomes a global function and can be used at the
in-game (or server) command prompt like so... in-game (or server) command prompt like so...
/js greet() /js greet(self)
... This differs from how modules (in NodeJS and commonJS ... This differs from how modules (in NodeJS and commonJS
environments) normally work. If you want your module to be exported environments) normally work. If you want your module to be exported
@ -138,7 +138,16 @@ The ScriptCraft JavaPlugin object.
The Minecraft Server object The Minecraft Server object
### self variable ### self variable
The current player. (Note - this value should not be used in multi-threaded scripts or event-handling code - it's not thread-safe) The current player. (Note - this value should not be used in
multi-threaded scripts or event-handling code - it's not
thread-safe). This variable is only safe to use at the in-game prompt
and should *never* be used in modules. For example you can use it here...
/js console.log(self.name)
... but not in any javascript module you create yourself or in any
event handling code. `self` is a temporary short-lived variable which
only exists in the context of the in-game or server command prompts.
### config variable ### config variable
ScriptCraft configuration - this object is loaded and saved at startup/shutdown. ScriptCraft configuration - this object is loaded and saved at startup/shutdown.
@ -239,7 +248,7 @@ load() will return the result of the last statement evaluated in the file.
#### Example #### Example
load(__folder + "myFile.js"); // loads a javascript file and evaluates it. load("myFile.js"); // loads a javascript file and evaluates it.
var myData = load("myData.json"); // loads a javascript file and evaluates it - eval'd contents are returned. var myData = load("myData.json"); // loads a javascript file and evaluates it - eval'd contents are returned.
@ -939,7 +948,7 @@ Drones can be created in any of the following ways...
var d = new Drone().box( blocks.oak ) var d = new Drone().box( blocks.oak )
... All of the Drone's methods return `this` (self) so you can chain operations together like this... ... All of the Drone's methods return `this` so you can chain operations together like this...
var d = box( blocks.oak ) var d = box( blocks.oak )
.up() .up()
@ -1742,13 +1751,13 @@ The arrows mod adds fancy arrows to the game. Arrows which...
### Usage: ### Usage:
* `/js arrows.firework()` - A firework launches where the the arrow lands. * `/js arrows.firework(self)` - A firework launches where the the arrow lands.
* `/js arrows.lightning()` - lightning strikes where the arrow lands. * `/js arrows.lightning(self)` - lightning strikes where the arrow lands.
* `/js arrows.teleport()` - makes player teleport to where arrow has landed. * `/js arrows.teleport(self)` - makes player teleport to where arrow has landed.
* `/js arrows.flourish()` - makes a tree grow where the arrow lands. * `/js arrows.flourish(self)` - makes a tree grow where the arrow lands.
* `/js arrows.explosive()` - makes arrows explode. * `/js arrows.explosive(self)` - makes arrows explode.
* `/js arrows.normal()` sets arrow type to normal. * `/js arrows.normal(self)` sets arrow type to normal.
* `/js arrows.sign()` turns a targeted sign into a Arrows menu * `/js arrows.sign(self)` turns a targeted sign into a Arrows menu
All of the above functions can take an optional player object or name All of the above functions can take an optional player object or name
as a parameter. For example: `/js arrows.explosive('player23')` makes as a parameter. For example: `/js arrows.explosive('player23')` makes
@ -1835,11 +1844,11 @@ to every student in a Minecraft classroom environment.
To allow all players (and any players who connect to the server) to To allow all players (and any players who connect to the server) to
use the `js` and `jsp` commands... use the `js` and `jsp` commands...
/js classroom.allowScripting(true) /js classroom.allowScripting(true,self)
To disallow scripting (and prevent players who join the server from using the commands)... To disallow scripting (and prevent players who join the server from using the commands)...
/js classroom.allowScripting(false) /js classroom.allowScripting(false,self)
Only ops users can run the classroom.allowScripting() function - this is so that students Only ops users can run the classroom.allowScripting() function - this is so that students
don't try to bar themselves and each other from scripting. don't try to bar themselves and each other from scripting.
@ -1853,7 +1862,7 @@ to Minecraft. Normally ScriptCraft only allows for provision of new
commands as extensions to the jsp command. For example, to create a commands as extensions to the jsp command. For example, to create a
new simple command for use by all players... new simple command for use by all players...
/js command('hi', function(){ echo('Hi ' + self.name); }); /js command('hi', function(args,player){ player.sendMessage('Hi ' + player.name); });
... then players can use this command by typing... ... then players can use this command by typing...
@ -1890,8 +1899,8 @@ of the ScriptCraft core.
### Example hi-command.js ### Example hi-command.js
var commando = require('../commando'); var commando = require('../commando');
commando('hi', function(){ commando('hi', function(args,player){
echo('Hi ' + self.name); player.sendMessage('Hi ' + player.name);
}); });
...Displays a greeting to any player who issues the `/hi` command. ...Displays a greeting to any player who issues the `/hi` command.
@ -1899,8 +1908,8 @@ of the ScriptCraft core.
### Example - timeofday-command.js ### Example - timeofday-command.js
var times = {Dawn: 0, Midday: 6000, Dusk: 12000, Midnight:18000}; var times = {Dawn: 0, Midday: 6000, Dusk: 12000, Midnight:18000};
commando('timeofday', function(params){ commando('timeofday', function(params,player){
self.location.world.setTime(times[params[0]]); player.location.world.setTime(times[params[0]]);
}, },
['Dawn','Midday','Dusk','Midnight']); ['Dawn','Midday','Dusk','Midnight']);
@ -2030,7 +2039,7 @@ code is to demonstrate use of Bukkit's Conversation API.
### Example ### Example
/js Game_NumberGuess.start() /js Game_NumberGuess.start(self)
Once the game begins, guess a number by typing the `/` character Once the game begins, guess a number by typing the `/` character
followed by a number between 1 and 10. followed by a number between 1 and 10.

View file

@ -439,8 +439,8 @@ object can do, let's use that knowledge to create a Minecraft Mod!
Once you've installed Notepad++, Launch it, create a new file and type the following... Once you've installed Notepad++, Launch it, create a new file and type the following...
exports.greet = function(){ exports.greet = function(player){
echo("Hi " + self.name); player.sendMessage("Hi " + player.name);
} }
... then save the file in a new directory ... then save the file in a new directory
@ -479,16 +479,16 @@ one or more functions, objects or variables. For example...
#### thrower.js #### thrower.js
exports.egg = function(){ exports.egg = function(player){
self.throwEgg(); player.throwEgg();
} }
exports.snowball = function(){ exports.snowball = function(player){
self.throwSnowball(); player.throwSnowball();
} }
... is a plugin which provides 2 javascript functions called `egg()` ... is a plugin which provides 2 javascript functions called `egg()`
and `snowball()` which can be invoked from the in-game prompt like and `snowball()` which can be invoked from the in-game prompt like
this `/js egg()` or `/js snowball()`. this `/js egg(self)` or `/js snowball(self)`.
### Parameters ### Parameters
If you want to change the `greet()` function so that it displays a If you want to change the `greet()` function so that it displays a
@ -501,18 +501,18 @@ differently each time it is called.
Change the `greet()` function so that it looks like this... Change the `greet()` function so that it looks like this...
exports.greet = function ( greeting ) { exports.greet = function ( greeting , player) {
echo( greeting + self.name ); player.sendMessage( greeting + player.name );
} }
... Save your greet.js file and issue the `/js refresh()` command in ... Save your greet.js file and issue the `/js refresh()` command in
minecraft. Now enter the following command in Minecraft... minecraft. Now enter the following command in Minecraft...
greet("Hello "); greet("Hello ",self);
... Now try ... ... Now try ...
greet("Dia Dhuit "); greet("Dia Dhuit ",self);
... you should see the following messages in your chat window... ... you should see the following messages in your chat window...
@ -716,7 +716,7 @@ loop. The following `while` loop counts to 100...
var i = 1; var i = 1;
while (i <= 100){ while (i <= 100){
echo( i ); console.log( i );
i = i + 1; i = i + 1;
} }
@ -743,7 +743,7 @@ the server...
var players = server.onlinePlayers; var players = server.onlinePlayers;
var i = 0; var i = 0;
while ( i < players.length ) { while ( i < players.length ) {
echo( players[i] ); console.log( players[i] );
i = i + 1; i = i + 1;
} }
@ -765,17 +765,17 @@ loops. utils.foreach() takes two parameters...
2. A function which will be called for each item in the array. 2. A function which will be called for each item in the array.
...that's right, you can pass functions as parameters in javascript! ...that's right, you can pass functions as parameters in javascript!
Let's see it in action, the following code will `echo()` (print) the Let's see it in action, the following code will `console.log()` (print) the
name of each online player... name of each online player in the server console window...
utils.foreach( server.onlinePlayers, echo ); utils.foreach( server.onlinePlayers, console.log );
... in the above example, the list of online players is processed one ... in the above example, the list of online players is processed one
at a time and each item (player) is passed to the `echo` at a time and each item (player) is passed to the `console.log`
function. Note here that I used `echo` not `echo()`. The round braces function. Note here that I used `console.log` not `console.log()`. The round braces
() are used to call the function. If I want to pass the function as a () are used to call the function. If I want to pass the function as a
parameter, I just use the function name without the round braces. The parameter, I just use the function name without the round braces. The
above example uses a named function which already exists ( `echo` ), above example uses a named function which already exists ( `console.log` ),
you can also create new functions on-the-fly and pass them to the you can also create new functions on-the-fly and pass them to the
utils.foreach() function... utils.foreach() function...
@ -930,20 +930,20 @@ flying or not? This is where the `if - else` construct comes in handy.
Open your favorite editor and type the following code into a new file Open your favorite editor and type the following code into a new file
in your scriptcraft/plugins directory... in your scriptcraft/plugins directory...
function flightStatus() function flightStatus(player)
{ {
if ( self.flying ) if ( player.flying )
{ {
echo( "Hey, You are flying!" ); player.sendMessage( 'Hey, You are flying!' );
} }
else else
{ {
echo( "You are not flying." ); player.sendMessage( 'You are not flying.' );
} }
} }
... now type `/reload` at the in-game prompt then type `/js ... now type `/reload` at the in-game prompt then type `/js
flightStatus()` and an appropriate message will appear based on flightStatus(self)` and an appropriate message will appear based on
whether or not you're currently flying. Type the `/js flightStatus()` whether or not you're currently flying. Type the `/js flightStatus()`
command while on the ground and while flying. The message displayed in command while on the ground and while flying. The message displayed in
each case should be different. each case should be different.

View file

@ -92,20 +92,12 @@ public class ScriptCraftPlugin extends JavaPlugin implements Listener
FileReader reader = null; FileReader reader = null;
try{ try{
ScriptEngineManager factory = new ScriptEngineManager(); ScriptEngineManager factory = new ScriptEngineManager();
File boot = new File(JS_PLUGINS_DIR + "/lib/scriptcraft.js"); File bootScript = new File(JS_PLUGINS_DIR + "/lib/scriptcraft.js");
this.engine = factory.getEngineByName("JavaScript"); this.engine = factory.getEngineByName("JavaScript");
this.engine.put("__engine",engine); reader = new FileReader(bootScript);
this.engine.put("__plugin",this);
this.engine.put("__script",boot.getCanonicalPath().replaceAll("\\\\","/"));
reader = new FileReader(boot);
this.engine.eval(reader); this.engine.eval(reader);
/* Invocable inv = (Invocable)this.engine;
wph 20130811 Need to disable coffeescript support until issues loading and evaluating it are resolved. inv.invokeFunction("__onEnable", engine, this, bootScript);
See issue #92
// Load the CoffeeScript compiler
File coffeescript = new File(JS_PLUGINS_DIR + "/lib/coffeescript.js");
this.engine.eval(new FileReader(coffeescript));
*/
}catch(Exception e){ }catch(Exception e){
e.printStackTrace(); e.printStackTrace();
@ -128,12 +120,8 @@ public class ScriptCraftPlugin extends JavaPlugin implements Listener
// //
List<String> result = new ArrayList<String>(); List<String> result = new ArrayList<String>();
try { try {
this.engine.put("__onTC_result",result); Invocable inv = (Invocable)this.engine;
this.engine.put("__onTC_sender",sender); inv.invokeFunction("__onTabComplete", result, sender, cmd, alias, args);
this.engine.put("__onTC_cmd",cmd);
this.engine.put("__onTC_alias",alias);
this.engine.put("__onTC_args",args);
this.engine.eval("_onTabComplete()");
}catch (Exception e){ }catch (Exception e){
sender.sendMessage(e.getMessage()); sender.sendMessage(e.getMessage());
e.printStackTrace(); e.printStackTrace();
@ -145,40 +133,17 @@ public class ScriptCraftPlugin extends JavaPlugin implements Listener
{ {
boolean result = false; boolean result = false;
String javascriptCode = ""; String javascriptCode = "";
Object jsResult = null;
if(cmd.getName().equalsIgnoreCase("js")){ try {
for (int i = 0;i < args.length; i++){ jsResult = ((Invocable)this.engine).invokeFunction("__onCommand", sender, cmd, label, args);
javascriptCode = javascriptCode + args[i] + " "; }catch (Exception se){
} this.getLogger().severe(se.toString());
result = true; se.printStackTrace();
} else if (cmd.getName().equalsIgnoreCase("jsp")){ sender.sendMessage(se.getMessage());
javascriptCode = "command()";
this.engine.put("__cmdArgs",args);
result = true;
} else if (cmd.getName().equalsIgnoreCase("coffee")) {
for (int i = 0;i < args.length; i++)
javascriptCode += args[i] + " ";
javascriptCode = "eval(CoffeeScript.compile(\""+javascriptCode+"\", {bare: true}))";
result = true;
} }
if (jsResult != null){
if (result){ return ((Boolean)jsResult).booleanValue();
this.engine.put("self",sender);
try{
Object resultObj = this.engine.eval(javascriptCode);
if (resultObj != null){
if (resultObj instanceof java.util.Collection){
java.util.Collection collection = (java.util.Collection)resultObj;
sender.sendMessage(Arrays.toString(collection.toArray()));
}else{
sender.sendMessage(resultObj.toString());
}
}
}catch (Exception e){
sender.sendMessage(e.getMessage());
e.printStackTrace();
}
} }
return result; return result;
} }
} }

View file

@ -22,15 +22,11 @@ var executeCmd = function(args, player){
console.warn('Command %s is not recognised',name); console.warn('Command %s is not recognised',name);
}else{ }else{
func = cmd.callback; func = cmd.callback;
var params = [];
for (var i =1; i < args.length;i++){
params.push("" + args[i]);
}
var result = null; var result = null;
try { try {
result = func(params,player); result = func(args.slice(1),player);
}catch (e){ }catch (e){
console.error("Error while trying to execute command: " + JSON.stringify(params)); console.error("Error while trying to execute command: " + JSON.stringify(args));
throw e; throw e;
} }
return result; return result;
@ -48,12 +44,8 @@ var defineCmd = function(name, func, options, intercepts) {
return func; return func;
}; };
var _command = function(name, func, options, intercepts) { var _command = function(name, func, options, intercepts) {
if (typeof name == "undefined"){ return defineCmd(name, func, options, intercepts);
// it's an invocation from the Java Plugin!
return executeCmd(__cmdArgs, self);
}else{
return defineCmd(name, func, options, intercepts);
}
}; };
_command.exec = executeCmd;
exports.command = _command; exports.command = _command;
exports.commands = _commands; exports.commands = _commands;

View file

@ -19,7 +19,7 @@ loads the module circle.js in the same directory.
The contents of foo.js: The contents of foo.js:
var circle = require('./circle.js'); var circle = require('./circle.js');
echo( 'The area of a circle of radius 4 is ' console.log( 'The area of a circle of radius 4 is '
+ circle.area(4)); + circle.area(4));
The contents of circle.js: The contents of circle.js:
@ -72,14 +72,14 @@ module in the `plugins` directory exports becomes a global
variable. For example, if you have a module greeting.js in the plugins variable. For example, if you have a module greeting.js in the plugins
directory.... directory....
exports.greet = function() { exports.greet = function(player) {
echo('Hello ' + self.name); player.sendMessage('Hello ' + player.name);
}; };
... then `greet` becomes a global function and can be used at the ... then `greet` becomes a global function and can be used at the
in-game (or server) command prompt like so... in-game (or server) command prompt like so...
/js greet() /js greet(self)
... This differs from how modules (in NodeJS and commonJS ... This differs from how modules (in NodeJS and commonJS
environments) normally work. If you want your module to be exported environments) normally work. If you want your module to be exported
@ -139,7 +139,16 @@ The ScriptCraft JavaPlugin object.
The Minecraft Server object The Minecraft Server object
### self variable ### self variable
The current player. (Note - this value should not be used in multi-threaded scripts or event-handling code - it's not thread-safe) The current player. (Note - this value should not be used in
multi-threaded scripts or event-handling code - it's not
thread-safe). This variable is only safe to use at the in-game prompt
and should *never* be used in modules. For example you can use it here...
/js console.log(self.name)
... but not in any javascript module you create yourself or in any
event handling code. `self` is a temporary short-lived variable which
only exists in the context of the in-game or server command prompts.
### config variable ### config variable
ScriptCraft configuration - this object is loaded and saved at startup/shutdown. ScriptCraft configuration - this object is loaded and saved at startup/shutdown.
@ -240,7 +249,7 @@ load() will return the result of the last statement evaluated in the file.
#### Example #### Example
load(__folder + "myFile.js"); // loads a javascript file and evaluates it. load("myFile.js"); // loads a javascript file and evaluates it.
var myData = load("myData.json"); // loads a javascript file and evaluates it - eval'd contents are returned. var myData = load("myData.json"); // loads a javascript file and evaluates it - eval'd contents are returned.
@ -413,8 +422,8 @@ var server = org.bukkit.Bukkit.server;
/* /*
private implementation private implementation
*/ */
(function(){ function __onEnable (__engine, __plugin, __script)
{
/* /*
don't execute this more than once don't execute this more than once
*/ */
@ -428,9 +437,8 @@ var server = org.bukkit.Bukkit.server;
return "" + file.getCanonicalPath().replaceAll("\\\\","/"); return "" + file.getCanonicalPath().replaceAll("\\\\","/");
}; };
var _originalScript = __script; var parentFileObj = __script.parentFile;
var parentFileObj = new File(__script).getParentFile(); var jsPluginsRootDir = parentFileObj.parentFile;
var jsPluginsRootDir = parentFileObj.getParentFile();
var jsPluginsRootDirName = _canonize(jsPluginsRootDir); var jsPluginsRootDirName = _canonize(jsPluginsRootDir);
var _loaded = {}; var _loaded = {};
@ -457,19 +465,11 @@ var server = org.bukkit.Bukkit.server;
var parent = file.getParentFile(); var parent = file.getParentFile();
var reader = new FileReader(file); var reader = new FileReader(file);
var br = new BufferedReader(reader); var br = new BufferedReader(reader);
__engine.put("__script",canonizedFilename);
__engine.put("__folder",(parent?_canonize(parent):"")+"/");
var code = ""; var code = "";
try{ try{
if (file.getCanonicalPath().endsWith(".coffee")) { while ((r = br.readLine()) !== null)
while ((r = br.readLine()) !== null) code += "\"" + r + "\" +\n"; code += r + "\n";
code += "\"\"";
var code = "load(__folder + \"../core/_coffeescript.js\"); var ___code = "+code+"; eval(CoffeeScript.compile(___code, {bare: true}))";
} else {
while ((r = br.readLine()) !== null)
code += r + "\n";
}
result = __engine.eval("(" + code + ")"); result = __engine.eval("(" + code + ")");
// issue #103 avoid side-effects of || operator on Mac Rhino // issue #103 avoid side-effects of || operator on Mac Rhino
_loaded[canonizedFilename] = result ; _loaded[canonizedFilename] = result ;
@ -498,6 +498,7 @@ var server = org.bukkit.Bukkit.server;
if (!config) if (!config)
config = {verbose: false}; config = {verbose: false};
global.config = config; global.config = config;
global.__plugin = __plugin;
/* /*
wph 20131229 Issue #103 JSON is not bundled with javax.scripting / Rhino on Mac. wph 20131229 Issue #103 JSON is not bundled with javax.scripting / Rhino on Mac.
*/ */
@ -567,7 +568,8 @@ var server = org.bukkit.Bukkit.server;
global.console = require('console'); global.console = require('console');
global.command = require('command').command; global.command = require('command').command;
var plugins = require('plugin'); var plugins = require('plugin');
global._onTabComplete = require('tabcomplete');
global.__onTabComplete = require('tabcomplete');
global.plugin = plugins.plugin; global.plugin = plugins.plugin;
global.save = plugins.save; global.save = plugins.save;
@ -584,4 +586,37 @@ var server = org.bukkit.Bukkit.server;
global.events = events; global.events = events;
plugins.autoload(jsPluginsRootDir); plugins.autoload(jsPluginsRootDir);
}());
global.__onCommand = function( sender, cmd, label, args) {
var jsArgs = [];
var i = 0;
for (;i < args.length; i++) jsArgs.push('' + args[i]);
var result = false;
var cmdName = ('' + cmd.name).toLowerCase();
if (cmdName == 'js')
{
result = true;
var fnBody = jsArgs.join(' ');
global.self = sender;
global.__engine = __engine;
try {
//var jsResult = __engine["eval(java.lang.String,javax.script.Bindings)"]( fnBody, bindings );
var jsResult = __engine.eval(fnBody);
if (jsResult)
sender.sendMessage(jsResult);
}catch (e){
__plugin.logger.severe("Error while trying to evaluate javascript: " + fnBody + ", Error: "+ e);
throw e;
}finally{
delete global.self;
delete global.__engine;
}
}
if (cmdName == 'jsp'){
command.exec(jsArgs, sender);
result = true;
}
return result;
};
}

View file

@ -2,9 +2,9 @@ var _commands = require('command').commands;
/* /*
Tab completion for the /jsp commmand Tab completion for the /jsp commmand
*/ */
var __onTabCompleteJSP = function() { var __onTabCompleteJSP = function( __onTC_result, __onTC_sender, __onTC_cmd, __onTC_alias, __onTC_args) {
var result = global.__onTC_result; var result = __onTC_result;
var args = global.__onTC_args; var args = __onTC_args;
var cmdInput = args[0]; var cmdInput = args[0];
var cmd = _commands[cmdInput]; var cmd = _commands[cmdInput];
if (cmd){ if (cmd){

View file

@ -73,12 +73,13 @@ var _getProperties = function(o)
return result.sort(); return result.sort();
}; };
var onTabCompleteJS = function() { var onTabCompleteJS = function( __onTC_result, __onTC_sender, __onTC_cmd, __onTC_alias, __onTC_args) {
if (__onTC_cmd.name == 'jsp') if (__onTC_cmd.name == 'jsp')
return tabCompleteJSP() return tabCompleteJSP( __onTC_result, __onTC_sender, __onTC_cmd, __onTC_alias, __onTC_args );
var _globalSymbols = _getProperties(global) var _globalSymbols = _getProperties(global)
var result = global.__onTC_result; var result = __onTC_result;
var args = global.__onTC_args; var args = __onTC_args;
var lastArg = args.length?args[args.length-1]+'':null; var lastArg = args.length?args[args.length-1]+'':null;
var propsOfLastArg = []; var propsOfLastArg = [];
var statement = args.join(' '); var statement = args.join(' ');

View file

@ -175,7 +175,9 @@ var _intercept = function( msg, invoker, exec)
isAlias = true; isAlias = true;
}else{ }else{
if (config.verbose){ if (config.verbose){
console.info("No global alias found for command: " + command); var commandObj = server.commandMap.getCommand(command);
if (!commandObj)
console.info("No global alias found for command: " + command);
} }
} }
/* /*
@ -188,7 +190,9 @@ var _intercept = function( msg, invoker, exec)
isAlias = true; isAlias = true;
}else{ }else{
if (config.verbose){ if (config.verbose){
console.info("No player alias found for command: " + command); var commandObj = server.commandMap.getCommand(command);
if (!commandObj)
console.info("No player alias found for command: " + command);
} }
} }
for (var i = 0;i < template.length; i++) for (var i = 0;i < template.length; i++)

View file

@ -11,13 +11,13 @@ The arrows mod adds fancy arrows to the game. Arrows which...
### Usage: ### Usage:
* `/js arrows.firework()` - A firework launches where the the arrow lands. * `/js arrows.firework(self)` - A firework launches where the the arrow lands.
* `/js arrows.lightning()` - lightning strikes where the arrow lands. * `/js arrows.lightning(self)` - lightning strikes where the arrow lands.
* `/js arrows.teleport()` - makes player teleport to where arrow has landed. * `/js arrows.teleport(self)` - makes player teleport to where arrow has landed.
* `/js arrows.flourish()` - makes a tree grow where the arrow lands. * `/js arrows.flourish(self)` - makes a tree grow where the arrow lands.
* `/js arrows.explosive()` - makes arrows explode. * `/js arrows.explosive(self)` - makes arrows explode.
* `/js arrows.normal()` sets arrow type to normal. * `/js arrows.normal(self)` sets arrow type to normal.
* `/js arrows.sign()` turns a targeted sign into a Arrows menu * `/js arrows.sign(self)` turns a targeted sign into a Arrows menu
All of the above functions can take an optional player object or name All of the above functions can take an optional player object or name
as a parameter. For example: `/js arrows.explosive('player23')` makes as a parameter. For example: `/js arrows.explosive('player23')` makes
@ -27,6 +27,7 @@ player23's arrows explosive.
var signs = require('signs'); var signs = require('signs');
var fireworks = require('fireworks'); var fireworks = require('fireworks');
var utils = require('utils');
var _store = {players: {}}; var _store = {players: {}};
@ -75,14 +76,8 @@ for (var type in _types)
{ {
arrows[type] = (function(n){ arrows[type] = (function(n){
return function(player){ return function(player){
if (typeof player == "undefined") player = utils.getPlayerObject(player);
player = self; arrows.store.players[player.name] = n;
var playerName = null;
if (typeof player == "string")
playerName = player;
else
playerName = player.name;
arrows.store.players[playerName] = n;
}; };
})(_types[type]); })(_types[type]);
} }

View file

@ -35,19 +35,19 @@ events.on("player.AsyncPlayerChatEvent",function(l,e){
e.message = "§" + colorCodes[playerChatColor] + e.message; e.message = "§" + colorCodes[playerChatColor] + e.message;
} }
}); });
var listColors = function(params){ var listColors = function(params,sender){
var colorNamesInColor = []; var colorNamesInColor = [];
for (var i = 0;i < colors.length;i++) for (var i = 0;i < colors.length;i++)
colorNamesInColor[i] = "§"+colorCodes[colors[i]] + colors[i]; colorNamesInColor[i] = "§"+colorCodes[colors[i]] + colors[i];
self.sendMessage("valid chat colors are " + colorNamesInColor.join(", ")); sender.sendMessage("valid chat colors are " + colorNamesInColor.join(", "));
}; };
command("list_colors", listColors); command("list_colors", listColors);
command("chat_color",function(params){ command("chat_color",function(params,sender){
var color = params[0]; var color = params[0];
if (colorCodes[color]){ if (colorCodes[color]){
chat.setColor(self,color); chat.setColor(sender,color);
}else{ }else{
self.sendMessage(color + " is not a valid color"); sender.sendMessage(color + " is not a valid color");
listColors(); listColors();
} }
},colors); },colors);

View file

@ -32,11 +32,11 @@ to every student in a Minecraft classroom environment.
To allow all players (and any players who connect to the server) to To allow all players (and any players who connect to the server) to
use the `js` and `jsp` commands... use the `js` and `jsp` commands...
/js classroom.allowScripting(true) /js classroom.allowScripting(true,self)
To disallow scripting (and prevent players who join the server from using the commands)... To disallow scripting (and prevent players who join the server from using the commands)...
/js classroom.allowScripting(false) /js classroom.allowScripting(false,self)
Only ops users can run the classroom.allowScripting() function - this is so that students Only ops users can run the classroom.allowScripting() function - this is so that students
don't try to bar themselves and each other from scripting. don't try to bar themselves and each other from scripting.
@ -44,16 +44,25 @@ don't try to bar themselves and each other from scripting.
***/ ***/
var _store = {enableScripting: false}; var _store = {enableScripting: false};
var classroom = plugin("classroom", { var classroom = plugin("classroom", {
allowScripting: function (/* boolean: true or false */ canScript) { allowScripting: function (/* boolean: true or false */ canScript, sender) {
if (typeof sender == 'undefined'){
console.log("Attempt to set classroom scripting without credentials");
return;
}
if (!sender.op){
console.log("Attempt to set classroom scripting without credentials: " + sender.name);
return;
}
/* /*
only operators should be allowed run this function only operators should be allowed run this function
*/ */
if (!self.isOp()) if (!sender.isOp())
return; return;
if (canScript){ if (canScript){
utils.foreach( server.onlinePlayers, function (player) { utils.foreach( server.onlinePlayers, function (player) {
player.addAttachment(__plugin, "scriptcraft.*", true); player.addAttachment(__plugin, "scriptcraft.*", true);
}); });
}else{ }else{
utils.foreach( server.onlinePlayers, function(player) { utils.foreach( server.onlinePlayers, function(player) {
utils.foreach(player.getEffectivePermissions(), function(perm) { utils.foreach(player.getEffectivePermissions(), function(perm) {

View file

@ -9,6 +9,13 @@ var times = {
Dusk: 12000, Dusk: 12000,
Midnight: 18000 Midnight: 18000
}; };
commando('scriptcrafttimeofday',function(params){ commando('scriptcrafttimeofday',function(params,sender){
self.location.world.setTime(times[params[0]]); if (config.verbose){
console.log('scriptcrafttimeofday.params=%s',JSON.stringify(params));
}
if (sender.location)
sender.location.world.setTime(times[params[0]]);
else
sender.sendMessage('This command only works in-world');
},['Dawn','Midday','Dusk','Midnight']); },['Dawn','Midday','Dusk','Midnight']);

View file

@ -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 commands as extensions to the jsp command. For example, to create a
new simple command for use by all players... new simple command for use by all players...
/js command('hi', function(){ echo('Hi ' + self.name); }); /js command('hi', function(args,player){ player.sendMessage('Hi ' + player.name); });
... then players can use this command by typing... ... then players can use this command by typing...
@ -45,8 +45,8 @@ of the ScriptCraft core.
### Example hi-command.js ### Example hi-command.js
var commando = require('../commando'); var commando = require('../commando');
commando('hi', function(){ commando('hi', function(args,player){
echo('Hi ' + self.name); player.sendMessage('Hi ' + player.name);
}); });
...Displays a greeting to any player who issues the `/hi` command. ...Displays a greeting to any player who issues the `/hi` command.
@ -54,8 +54,8 @@ of the ScriptCraft core.
### Example - timeofday-command.js ### Example - timeofday-command.js
var times = {Dawn: 0, Midday: 6000, Dusk: 12000, Midnight:18000}; var times = {Dawn: 0, Midday: 6000, Dusk: 12000, Midnight:18000};
commando('timeofday', function(params){ commando('timeofday', function(params,player){
self.location.world.setTime(times[params[0]]); player.location.world.setTime(times[params[0]]);
}, },
['Dawn','Midday','Dusk','Midnight']); ['Dawn','Midday','Dusk','Midnight']);
@ -85,7 +85,7 @@ exports.commando = function(name, func, options, intercepts){
}; };
events.on('player.PlayerCommandPreprocessEvent', function(l,e){ events.on('player.PlayerCommandPreprocessEvent', function(l,e){
var msg = "" + e.message; var msg = '' + e.message;
var parts = msg.match(/^\/([^\s]+)/); var parts = msg.match(/^\/([^\s]+)/);
if (!parts) if (!parts)
return; return;
@ -97,7 +97,7 @@ events.on('player.PlayerCommandPreprocessEvent', function(l,e){
} }
}); });
events.on('server.ServerCommandEvent', function(l,e){ events.on('server.ServerCommandEvent', function(l,e){
var msg = "" + e.command; var msg = '' + e.command;
var parts = msg.match(/^\/*([^\s]+)/); var parts = msg.match(/^\/*([^\s]+)/);
if (!parts) if (!parts)
return; return;
@ -105,6 +105,10 @@ events.on('server.ServerCommandEvent', function(l,e){
return; return;
var command = parts[1]; var command = parts[1];
if (commands[command]){ if (commands[command]){
e.command = "jsp " + msg.replace(/^\//,""); var newCmd = "jsp " + msg.replace(/^\//,"");
if (config.verbose){
console.log('Redirecting to : %s',newCmd);
}
e.command = newCmd;
} }
}); });

View file

@ -33,7 +33,7 @@ Drone.extend('fort', function(side, height)
try{ try{
this.boxa(turret,1,1,side-2).fwd(side-2).turn(); this.boxa(turret,1,1,side-2).fwd(side-2).turn();
}catch(e){ }catch(e){
self.sendMessage("ERROR: " + e.toString()); console.log("ERROR: " + e.toString());
} }
} }
// //

View file

@ -46,7 +46,7 @@ Drones can be created in any of the following ways...
var d = new Drone().box( blocks.oak ) var d = new Drone().box( blocks.oak )
... All of the Drone's methods return `this` (self) so you can chain operations together like this... ... All of the Drone's methods return `this` so you can chain operations together like this...
var d = box( blocks.oak ) var d = box( blocks.oak )
.up() .up()
@ -727,8 +727,6 @@ Drone = function(x,y,z,dir,world)
this.chkpt('start'); this.chkpt('start');
this.record = true; this.record = true;
this.history = []; this.history = [];
// for debugging
// self.sendMessage("New Drone " + this.toString());
return this; return this;
}; };

View file

@ -251,71 +251,71 @@ exports.homes = homes;
var options = { var options = {
'set': function(){homes.set();}, 'set': function(){homes.set();},
'delete': function(){ homes.remove();}, 'delete': function(){ homes.remove();},
'help': function(){ self.sendMessage(homes.help());}, 'help': function(params, sender){ sender.sendMessage(homes.help());},
'list': function(){ 'list': function(params, sender){
var visitable = homes.list(); var visitable = homes.list();
if (visitable.length == 0){ if (visitable.length == 0){
self.sendMessage("There are no homes to visit"); sender.sendMessage("There are no homes to visit");
return; return;
}else{ }else{
self.sendMessage([ sender.sendMessage([
"You can visit any of these " + visitable.length + " homes" "You can visit any of these " + visitable.length + " homes"
,visitable.join(", ") ,visitable.join(", ")
]); ]);
} }
}, },
'ilist': function(){ 'ilist': function(params, sender){
var potentialVisitors = homes.ilist(); var potentialVisitors = homes.ilist();
if (potentialVisitors.length == 0) if (potentialVisitors.length == 0)
self.sendMessage("No one can visit your home"); sender.sendMessage("No one can visit your home");
else else
self.sendMessage([ sender.sendMessage([
"These " + potentialVisitors.length + "players can visit your home", "These " + potentialVisitors.length + "players can visit your home",
potentialVisitors.join(", ")]); potentialVisitors.join(", ")]);
}, },
'invite': function(params){ 'invite': function(params,sender){
if (params.length == 1){ if (params.length == 1){
self.sendMessage("You must provide a player's name"); sender.sendMessage("You must provide a player's name");
return; return;
} }
var playerName = params[1]; var playerName = params[1];
var guest = utils.getPlayerObject(playerName); var guest = utils.getPlayerObject(playerName);
if (!guest) if (!guest)
self.sendMessage(playerName + " is not here"); sender.sendMessage(playerName + " is not here");
else else
homes.invite(self,guest); homes.invite(sender,guest);
}, },
'uninvite': function(params){ 'uninvite': function(params,sender){
if (params.length == 1){ if (params.length == 1){
self.sendMessage("You must provide a player's name"); sender.sendMessage("You must provide a player's name");
return; return;
} }
var playerName = params[1]; var playerName = params[1];
var guest = utils.getPlayerObject(playerName); var guest = utils.getPlayerObject(playerName);
if (!guest) if (!guest)
self.sendMessage(playerName + " is not here"); sender.sendMessage(playerName + " is not here");
else else
homes.uninvite(self,guest); homes.uninvite(sender,guest);
}, },
'public': function(params){ 'public': function(params,sender){
homes.open(self,params.slice(1).join(' ')); homes.open(sender,params.slice(1).join(' '));
self.sendMessage("Your home is open to the public"); sender.sendMessage("Your home is open to the public");
}, },
'private': function(){ 'private': function(params, sender){
homes.close(); homes.close(sender);
self.sendMessage("Your home is closed to the public"); sender.sendMessage("Your home is closed to the public");
}, },
'listall': function(){ 'listall': function(params, sender){
if (!self.isOp()) if (!sender.isOp())
self.sendMessage("Only operators can do this"); sender.sendMessage("Only operators can do this");
else else
self.sendMessage(homes.listall().join(", ")); sender.sendMessage(homes.listall().join(", "));
}, },
'clear': function(params){ 'clear': function(params,sender){
if (!self.isOp()) if (!sender.isOp())
self.sendMessage("Only operators can do this"); sender.sendMessage("Only operators can do this");
else else
homes.clear(params[1]); homes.clear(params[1], sender);
} }
}; };
var optionList = []; var optionList = [];
@ -324,20 +324,20 @@ for (var o in options)
/* /*
Expose a set of commands that players can use at the in-game command prompt Expose a set of commands that players can use at the in-game command prompt
*/ */
command("home", function ( params ) { command("home", function ( params , sender) {
if (params.length == 0){ if (params.length == 0){
homes.go(); homes.go(sender,sender);
return; return;
} }
var option = options[params[0]]; var option = options[params[0]];
if (option) if (option)
option(params); option(params,sender);
else{ else{
var host = utils.getPlayerObject(params[0]); var host = utils.getPlayerObject(params[0]);
if (!host) if (!host)
self.sendMessage(params[0] + " is not here"); sender.sendMessage(params[0] + " is not here");
else else
homes.go(self,host); homes.go(sender,host);
} }
},optionList); },optionList);

View file

@ -9,14 +9,14 @@ code is to demonstrate use of Bukkit's Conversation API.
### Example ### Example
/js Game_NumberGuess.start() /js Game_NumberGuess.start(self)
Once the game begins, guess a number by typing the `/` character Once the game begins, guess a number by typing the `/` character
followed by a number between 1 and 10. followed by a number between 1 and 10.
***/ ***/
exports.Game_NumberGuess = { exports.Game_NumberGuess = {
start: function() { start: function(sender) {
importPackage(org.bukkit.conversations); importPackage(org.bukkit.conversations);
var number = Math.ceil(Math.random() * 10); var number = Math.ceil(Math.random() * 10);
@ -54,7 +54,7 @@ exports.Game_NumberGuess = {
var conv = cf.withModality(true) var conv = cf.withModality(true)
.withFirstPrompt(prompt) .withFirstPrompt(prompt)
.withPrefix(new ConversationPrefix(){ getPrefix: function(ctx){ return "[1-10] ";} }) .withPrefix(new ConversationPrefix(){ getPrefix: function(ctx){ return "[1-10] ";} })
.buildConversation(self); .buildConversation(sender);
conv.begin(); conv.begin();
} }
}; };