Skip to content

Commit

Permalink
Improvements to classroom.js module (added players/ directory into wh…
Browse files Browse the repository at this point in the history
…ich players can drop their custom scripts when classroom.allowScripting(true) is called.
  • Loading branch information
walterhiggins committed Feb 10, 2014
1 parent 39b459a commit 8453525
Show file tree
Hide file tree
Showing 6 changed files with 327 additions and 87 deletions.
75 changes: 73 additions & 2 deletions docs/API-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ Walter Higgins
* [utils.nicely() function](#utilsnicely-function)
* [utils.at() function](#utilsat-function)
* [utils.find() function](#utilsfind-function)
* [utils.serverAddress() function](#utilsserveraddress-function)
* [utils.watchFile() function](#utilswatchfile-function)
* [Drone Plugin](#drone-plugin)
* [TLDNR; (Just read this if you're impatient)](#tldnr-just-read-this-if-youre-impatient)
* [Constructing a Drone Object](#constructing-a-drone-object)
Expand Down Expand Up @@ -1338,6 +1340,34 @@ var jsFiles = utils.find('./', function(dir,name){
});
```
### utils.serverAddress() function
The utils.serverAddress() function returns the IP(v4) address of the server.
```javascript
var utils = require('utils');
var serverAddress = utils.serverAddress();
console.log(serverAddress);
```
### utils.watchFile() function
Watches for changes to the given file or directory and calls the function provided
when the file changes.
#### Parameters
* File - the file to watch (can be a file or directory)
* Callback - The callback to invoke when the file has changed. The callback takes the
changed file as a parameter.
#### Example
```javascript
var utils = require('utils');
utils.watchFile( 'test.txt', function( file ) {
console.log( file + ' has changed');
});
```
## Drone Plugin
The Drone is a convenience class for building. It can be used for...
Expand Down Expand Up @@ -2560,15 +2590,56 @@ quickly realise how to grant themselves and others operator privileges
once they have access to ScriptCraft).
The goal of this module is not so much to enforce restrictions
(security or otherwise) but to make it easier for tutors to setup a shared server
so students can learn Javascript.
(security or otherwise) but to make it easier for tutors to setup a
shared server so students can learn Javascript. When scripting is
turned on, every player who joins the server will have a dedicated
directory into which they can save scripts. All scripts in such
directories are automatically watched and loaded into a global
variable named after the player.
So for example, if player 'walterh' joins the server, a `walterh`
global variable is created. If a file `greet.js` with the following
content is dropped into the `plugins/scriptcraft/players/walterh`
directory...
```javascript
exports.hi = function( player ){
player.sendMessage('Hi ' + player.name);
};
```
... then it can be invoked like this: `/js walterh.hi( self )` . This
lets every player/student create their own functions without having
naming collisions.
It's strongly recommended that the
`craftbukkit/plugins/scriptcraft/players/` directory is shared so that
others can connect to it and drop .js files into their student
directories. On Ubuntu, select the folder in Nautilus (the default
file browser) then right-click and choose *Sharing Options*, check the
*Share this folder* checkbox and the *Allow others to create and
delete files* and *Guest access* checkboxes. Click *Create Share*
button to close the sharing options dialog. Students can then access
the shared folder as follows...
* Windows: Open Explorer, Go to \\{serverAddress}\players\
* Macintosh: Open Finder, Go to smb://{serverAddress}/players/
* Linux: Open Nautilus, Go to smb://{serverAddress}/players/
... where {serverAddress} is the ip address of the server (this is
displayed to whoever invokes the classroom.allowScripting() function.)
### classroom.allowScripting() function
Allow or disallow anyone who connects to the server (or is already
connected) to use ScriptCraft. This function is preferable to granting 'ops' privileges
to every student in a Minecraft classroom environment.
Whenever any file is added/edited or removed from any of the players/
directories the contents are automatically reloaded. This is to
facilitate quick turnaround time for students getting to grips with
Javascript.
#### Parameters
* canScript : true or false
Expand Down
24 changes: 10 additions & 14 deletions src/main/js/lib/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,7 @@ var _plugin = function(/* String */ moduleName, /* Object */ moduleObject, isPer

exports.plugin = _plugin;

var scriptCraftDir = null;
var pluginDir = null;
var dataDir = null;

exports.autoload = function( dir, logger ) {

scriptCraftDir = dir;
pluginDir = new File( dir, 'plugins' );
dataDir = new File( dir, 'data' );
exports.autoload = function( context, pluginDir, logger, options ) {

var _canonize = function( file ) {
return '' + file.canonicalPath.replaceAll('\\\\','/');
Expand Down Expand Up @@ -76,22 +68,26 @@ exports.autoload = function( dir, logger ) {

var len = sourceFiles.length;
if ( config.verbose ) {
console.info( len + ' scriptcraft plugins found.' );
console.info( len + ' scriptcraft plugins found in ' + pluginDir );
}
for ( var i = 0; i < len; i++ ) {
pluginPath = _canonize( sourceFiles[i] );
module = {};

try {
module = require( pluginPath );
module = require( pluginPath , options);
for ( property in module ) {
/*
all exports in plugins become global
all exports in plugins become members of context object
*/
global[property] = module[property];
context[property] = module[property];
}
} catch ( e ) {
logger.severe( 'Plugin ' + pluginPath + ' ' + e );
if ( typeof logger != 'undefined' ) {
logger.severe( 'Plugin ' + pluginPath + ' ' + e );
} else {
java.lang.System.out.println( 'Error: Plugin ' + pluginPath + ' ' + e );
}
}
}
}(pluginDir));
Expand Down
61 changes: 36 additions & 25 deletions src/main/js/lib/require.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,65 +136,72 @@ When resolving module names to file paths, ScriptCraft uses the following rules.
***/
var resolveModuleToFile = function ( moduleName, parentDir ) {
var file = new File(moduleName);

var file = new File(moduleName),
i = 0,
pathWithJSExt,
resolvedFile;
if ( file.exists() ) {
return fileExists(file);
}
if ( moduleName.match( /^[^\.\/]/ ) ) {
// it's a module named like so ... 'events' , 'net/http'
//
var resolvedFile;
for (var i = 0;i < modulePaths.length; i++){
for ( ; i < modulePaths.length; i++ ) {
resolvedFile = new File(modulePaths[i] + moduleName);
if (resolvedFile.exists()){
if ( resolvedFile.exists() ) {
return fileExists(resolvedFile);
}else{
} else {
// try appending a .js to the end
resolvedFile = new File(modulePaths[i] + moduleName + '.js');
if (resolvedFile.exists())
if ( resolvedFile.exists() ) {
return resolvedFile;
}
}
}
} else {
// it's of the form ./path
file = new File(parentDir, moduleName);
if (file.exists()){
if ( file.exists() ) {
return fileExists(file);
}else {

} else {
// try appending a .js to the end
var pathWithJSExt = file.canonicalPath + '.js';
file = new File( parentDir, pathWithJSExt);
if (file.exists())
pathWithJSExt = file.canonicalPath + '.js';
file = new File( parentDir, pathWithJSExt );
if (file.exists()) {
return file;
else{
} else {
file = new File(pathWithJSExt);
if (file.exists())
if ( file.exists() ) {
return file;
}
}

}
}
return null;
};
/*
wph 20131215 Experimental
*/
var _loadedModules = {};
var _format = java.lang.String.format;
/*
require() function implementation
*/
var _require = function( parentFile, path ) {
var _require = function( parentFile, path, options ) {
var file,
canonizedFilename,
moduleInfo,
buffered,
head = '(function(exports,module,require,__filename,__dirname){ ',
code = '',
line = null;


if ( typeof options == 'undefined' ) {
options = { cache: true };
} else {
if ( typeof options.cache == 'undefined' ) {
options.cache = true;
}
}

file = resolveModuleToFile(path, parentFile);
if ( !file ) {
var errMsg = '' + _format("require() failed to find matching file for module '%s' " +
Expand All @@ -205,10 +212,12 @@ When resolving module names to file paths, ScriptCraft uses the following rules.
throw errMsg;
}
canonizedFilename = _canonize(file);

moduleInfo = _loadedModules[canonizedFilename];
if ( moduleInfo ) {
return moduleInfo;
if ( options.cache ) {
return moduleInfo;
}
}
if ( hooks ) {
hooks.loading( canonizedFilename );
Expand All @@ -228,7 +237,9 @@ When resolving module names to file paths, ScriptCraft uses the following rules.
var tail = '})';
code = head + code + tail;

_loadedModules[canonizedFilename] = moduleInfo;
if ( options.cache ) {
_loadedModules[canonizedFilename] = moduleInfo;
}
var compiledWrapper = null;
try {
compiledWrapper = eval(code);
Expand Down Expand Up @@ -258,8 +269,8 @@ When resolving module names to file paths, ScriptCraft uses the following rules.
};

var _requireClosure = function( parent ) {
return function( path ) {
var module = _require( parent, path );
return function( path, options ) {
var module = _require( parent, path , options);
return module.exports;
};
};
Expand Down
51 changes: 34 additions & 17 deletions src/main/js/lib/scriptcraft.js
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ function __onEnable ( __engine, __plugin, __script )
try {
while ( (r = br.readLine()) !== null ) {
code += r + '\n';
}
}
wrappedCode = '(' + code + ')';
result = __engine.eval( wrappedCode );
// issue #103 avoid side-effects of || operator on Mac Rhino
Expand Down Expand Up @@ -566,7 +566,7 @@ function __onEnable ( __engine, __plugin, __script )
setup paths to search for modules
*/
var modulePaths = [ jsPluginsRootDirName + '/lib/',
jsPluginsRootDirName + '/modules/' ];
jsPluginsRootDirName + '/modules/' ];

if ( config.verbose ) {
logger.info( 'Setting up CommonJS-style module system. Root Directory: ' + jsPluginsRootDirName );
Expand Down Expand Up @@ -612,27 +612,44 @@ function __onEnable ( __engine, __plugin, __script )


global.__onCommand = function( sender, cmd, label, args) {
var jsArgs = [];
var i = 0;
var jsArgs = [],
i = 0,
jsResult,
result,
cmdName,
fnBody;
for ( ; i < args.length ; i++ ) {
jsArgs.push( '' + args[i] );
}

var result = false;
var cmdName = ( '' + cmd.name ).toLowerCase();
result = false;
cmdName = ( '' + cmd.name ).toLowerCase();
if (cmdName == 'js')
{
result = true;
var fnBody = jsArgs.join(' ');
fnBody = jsArgs.join(' ');
global.self = sender;
global.__engine = __engine;
try {
var jsResult = __engine.eval(fnBody);
if ( jsResult ) {
sender.sendMessage(jsResult);
}
if ( typeof eval == 'undefined' ) {
jsResult = __engine.eval(fnBody);
} else {
/*
nashorn
https://bugs.openjdk.java.net/browse/JDK-8034055
*/
jsResult = eval( fnBody );
}
if ( typeof jsResult != 'undefined' ) {
if ( jsResult == null) {
sender.sendMessage('(null)');
} else {
sender.sendMessage(jsResult);
}
}
} 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 {
delete global.self;
Expand All @@ -646,7 +663,7 @@ function __onEnable ( __engine, __plugin, __script )
return result;
};

plugins.autoload( jsPluginsRootDir, logger );
plugins.autoload( global, new File(jsPluginsRootDir,'plugins'), logger );
/*
wph 20140102 - warn if legacy 'craftbukkit/js-plugins' or 'craftbukkit/scriptcraft' directories are present
*/
Expand All @@ -655,21 +672,21 @@ function __onEnable ( __engine, __plugin, __script )
cbDir = new File(cbPluginsDir.canonicalPath).parentFile,
legacyExists = false,
legacyDirs = [new File( cbDir, 'js-plugins' ),
new File( cbDir, 'scriptcraft' )];
new File( cbDir, 'scriptcraft' )];

for ( var i = 0; i < legacyDirs.length; i++ ) {
if ( legacyDirs[i].exists()
&& legacyDirs[i].isDirectory() ) {
&& legacyDirs[i].isDirectory() ) {

legacyExists = true;
legacyExists = true;

console.warn('Legacy ScriptCraft directory %s was found. This directory is no longer used.',
console.warn('Legacy ScriptCraft directory %s was found. This directory is no longer used.',
legacyDirs[i].canonicalPath);
}
}
if ( legacyExists ) {
console.info( 'Please note that the working directory for %s is %s',
__plugin, jsPluginsRootDir.canonicalPath );
__plugin, jsPluginsRootDir.canonicalPath );
}
})();

Expand Down
Loading

0 comments on commit 8453525

Please sign in to comment.