Added experimental LCDGameClock

This commit is contained in:
walterhiggins 2014-01-24 23:38:56 +00:00
parent f71d1a4e78
commit 8c690452e7
6 changed files with 390 additions and 309 deletions

View file

@ -8,40 +8,40 @@ var _cmdInterceptors = [];
execute a JSP command. execute a JSP command.
*/ */
var executeCmd = function(args, player){ var executeCmd = function(args, player){
if (args.length === 0) if (args.length === 0)
throw new Error('Usage: jsp command-name command-parameters'); throw new Error('Usage: jsp command-name command-parameters');
var name = args[0]; var name = args[0];
var cmd = _commands[name]; var cmd = _commands[name];
if (typeof cmd === 'undefined'){ if (typeof cmd === 'undefined'){
// it's not a global command - pass it on to interceptors // it's not a global command - pass it on to interceptors
var intercepted = false; var intercepted = false;
for (var i = 0;i < _cmdInterceptors.length;i++){ for (var i = 0;i < _cmdInterceptors.length;i++){
if (_cmdInterceptors[i](args,player)) if (_cmdInterceptors[i](args,player))
intercepted = true; intercepted = true;
}
if (!intercepted)
console.warn('Command %s is not recognised',name);
}else{
var result = null;
try {
result = cmd.callback(args.slice(1),player);
}catch (e){
console.error('Error while trying to execute command: ' + JSON.stringify(args));
throw e;
}
return result;
} }
if (!intercepted)
console.warn('Command %s is not recognised',name);
}else{
var result = null;
try {
result = cmd.callback(args.slice(1),player);
}catch (e){
console.error('Error while trying to execute command: ' + JSON.stringify(args));
throw e;
}
return result;
}
}; };
/* /*
define a new JSP command. define a new JSP command.
*/ */
var defineCmd = function(name, func, options, intercepts) { var defineCmd = function(name, func, options, intercepts) {
if (typeof options == 'undefined') if (typeof options == 'undefined')
options = []; options = [];
_commands[name] = {callback: func, options: options}; _commands[name] = {callback: func, options: options};
if (intercepts) if (intercepts)
_cmdInterceptors.push(func); _cmdInterceptors.push(func);
return func; return func;
}; };
exports.command = defineCmd; exports.command = defineCmd;
exports.commands = _commands; exports.commands = _commands;

View file

@ -1,8 +1,8 @@
'use strict'; 'use strict';
var console = require('./console'); var console = require('./console'),
var File = java.io.File; File = java.io.File,
var FileWriter = java.io.FileWriter; FileWriter = java.io.FileWriter,
var PrintWriter = java.io.PrintWriter; PrintWriter = java.io.PrintWriter;
/* /*
plugin management plugin management
*/ */
@ -10,22 +10,22 @@ var _plugins = {};
var _plugin = function(/* String */ moduleName, /* Object */ moduleObject, isPersistent) var _plugin = function(/* String */ moduleName, /* Object */ moduleObject, isPersistent)
{ {
// //
// don't load plugin more than once // don't load plugin more than once
// //
if (typeof _plugins[moduleName] != "undefined") if (typeof _plugins[moduleName] != "undefined")
return _plugins[moduleName].module; return _plugins[moduleName].module;
var pluginData = {persistent: isPersistent, module: moduleObject}; var pluginData = {persistent: isPersistent, module: moduleObject};
if (typeof moduleObject.store == 'undefined') if (typeof moduleObject.store == 'undefined')
moduleObject.store = {}; moduleObject.store = {};
_plugins[moduleName] = pluginData; _plugins[moduleName] = pluginData;
if (isPersistent){ if (isPersistent){
moduleObject.store = persist(moduleName, moduleObject.store); moduleObject.store = persist(moduleName, moduleObject.store);
} }
return moduleObject; return moduleObject;
}; };
exports.plugin = _plugin; exports.plugin = _plugin;
@ -36,59 +36,59 @@ var dataDir = null;
exports.autoload = function(dir) { exports.autoload = function(dir) {
scriptCraftDir = dir; scriptCraftDir = dir;
pluginDir = new File(dir, "plugins"); pluginDir = new File(dir, "plugins");
dataDir = new File(dir, "data"); dataDir = new File(dir, "data");
var _canonize = function(file){ var _canonize = function(file){
return '' + file.canonicalPath.replaceAll("\\\\","/"); return '' + file.canonicalPath.replaceAll("\\\\","/");
}; };
/* /*
recursively walk the given directory and return a list of all .js files recursively walk the given directory and return a list of all .js files
*/ */
var _listSourceFiles = function(store,dir) var _listSourceFiles = function(store,dir)
{ {
var files = dir.listFiles(); var files = dir.listFiles();
if (!files) if (!files)
return; return;
for (var i = 0;i < files.length; i++) { for (var i = 0;i < files.length; i++) {
var file = files[i]; var file = files[i];
if (file.isDirectory()){ if (file.isDirectory()){
_listSourceFiles(store,file); _listSourceFiles(store,file);
}else{ }else{
if ( file.canonicalPath.endsWith('.js') ){ if ( file.canonicalPath.endsWith('.js') ){
store.push(file); store.push(file);
}
}
} }
}; }
/* }
Reload all of the .js files in the given directory };
*/ /*
var _reload = function(pluginDir) Reload all of the .js files in the given directory
{ */
var sourceFiles = []; var _reload = function(pluginDir)
_listSourceFiles(sourceFiles,pluginDir); {
var sourceFiles = [];
_listSourceFiles(sourceFiles,pluginDir);
var len = sourceFiles.length; var len = sourceFiles.length;
if (config.verbose) if (config.verbose)
console.info(len + ' scriptcraft plugins found.'); console.info(len + ' scriptcraft plugins found.');
for (var i = 0;i < len; i++){ for (var i = 0;i < len; i++){
var pluginPath = _canonize(sourceFiles[i]); var pluginPath = _canonize(sourceFiles[i]);
var module = {}; var module = {};
try { try {
module = require(pluginPath); module = require(pluginPath);
for (var property in module){ for (var property in module){
/* /*
all exports in plugins become global all exports in plugins become global
*/ */
global[property] = module[property]; global[property] = module[property];
}
}catch (e){
}
} }
}; }catch (e){
_reload(pluginDir);
}
}
};
_reload(pluginDir);
}; };

View file

@ -174,13 +174,13 @@ When resolving module names to file paths, ScriptCraft uses the following rules.
wph 20131215 Experimental wph 20131215 Experimental
*/ */
var _loadedModules = {}; var _loadedModules = {};
var _format = java.lang.String.format;
var _require = function(parentFile, path) var _require = function(parentFile, path)
{ {
var file = resolveModuleToFile(path, parentFile); var file = resolveModuleToFile(path, parentFile);
if (!file){ if (!file){
var errMsg = '' + java.lang.String.format("require() failed to find matching file for module '%s' " + var errMsg = '' + _format("require() failed to find matching file for module '%s' " +
"in working directory '%s' ", [path, parentFile.canonicalPath]); "in working directory '%s' ", [path, parentFile.canonicalPath]);
if (! ( (''+path).match(/^\./) )){ if (! ( (''+path).match(/^\./) )){
errMsg = errMsg + ' and not found in paths ' + JSON.stringify(modulePaths); errMsg = errMsg + ' and not found in paths ' + JSON.stringify(modulePaths);
} }

View file

@ -1,3 +1,4 @@
'use strict';
/************************************************************************* /*************************************************************************
## sc-mqtt module ## sc-mqtt module
@ -62,83 +63,98 @@ library.
***/ ***/
var MISSING_MQTT = '\nMissing class org.walterhiggins.scriptcraft.ScriptCraftMqttCallback.\n' + var MISSING_MQTT = '\nMissing class org.walterhiggins.scriptcraft.ScriptCraftMqttCallback.\n' +
'Make sure sc-mqtt.jar is in the classpath.\n' + 'Make sure sc-mqtt.jar is in the classpath.\n' +
'See http://github.com/walterhiggins/scriptcraft-extras-mqtt for details.\n'; 'See http://github.com/walterhiggins/scriptcraft-extras-mqtt for details.\n';
function Client(brokerUrl, clientId){ function Client(brokerUrl, clientId){
var Callback = org.walterhiggins.scriptcraft.ScriptCraftMqttCallback; var Callback = org.walterhiggins.scriptcraft.ScriptCraftMqttCallback;
var MqttClient = org.eclipse.paho.client.mqttv3.MqttClient; var MqttClient = org.eclipse.paho.client.mqttv3.MqttClient;
var callback = new Callback( var callback = new Callback(
function(err){ function(err){
console.log('connectionLost: ' + err); console.log('connectionLost: ' + err);
}, },
function(topic, message){ function(topic, message){
console.log('messageArrived ' + topic + '> ' + message); console.log('messageArrived ' + topic + '> ' + message);
}, },
function(token){ function(token){
console.log('deliveryComplete:' + token); console.log('deliveryComplete:' + token);
}
);
if (!brokerUrl){
brokerUrl = 'tcp://localhost:1883';
} }
if (!clientId){ );
clientId = 'scriptcraft';
if (!brokerUrl){
brokerUrl = 'tcp://localhost:1883';
}
if (!clientId){
clientId = 'scriptcraft' + new Date().getTime();
}
var client = new MqttClient(brokerUrl, clientId, null);
client.setCallback(callback);
return {
connect: function(options){
if (typeof options === 'undefined'){
client.connect();
}else{
client.connect(options);
}
return client;
},
disconnect: function(quiesceTimeout){
if (typeof quiesceTimeout == 'undefined')
client.disconnect();
else
client.disconnect(quiesceTimeout);
return client;
},
publish: function(topic, message, qos, retained){
if (typeof message == 'string'){
message = new java.lang.String(message).bytes;
}
if (typeof qos == 'undefined'){
qos = 1;
}
if (typeof retained == 'undefined'){
retained = false;
}
client.publish(topic, message,qos, retained);
return client;
},
subscribe: function(topic){
client.subscribe(topic);
return client;
},
unsubscribe: function(topic){
client.unsubscribe(topic);
return client;
},
onMessageArrived: function(fn){
callback.setMesgArrived(fn);
return client;
},
onDeliveryComplete: function(fn){
callback.setDeliveryComplete(fn);
return client;
},
onConnectionLost: function(fn){
callback.setConnLost(fn);
return client;
} }
var client = new MqttClient(brokerUrl, clientId, null); };
client.setCallback(callback); }
return {
connect: function(options){
if (typeof options === 'undefined'){
client.connect();
}else{
client.connect(options);
}
return client;
},
publish: function(topic, message, qos, retained){
if (typeof message == 'string'){
message = new java.lang.String(message).bytes;
}
if (typeof qos == 'undefined'){
qos = 1;
}
if (typeof retained == 'undefined'){
retained = false;
}
client.publish(topic, message,qos, retained);
return client;
},
subscribe: function(topic){
client.subscribe(topic);
return client;
},
unsubscribe: function(topic){
client.unsubscribe(topic);
return client;
},
onMessageArrived: function(fn){
callback.setMesgArrived(fn);
return client;
},
onDeliveryComplete: function(fn){
callback.setDeliveryComplete(fn);
return client;
},
onConnectionLost: function(fn){
callback.setConnLost(fn);
return client;
}
};
};
exports.client = function(brokerUrl, clientId, options){ exports.client = function(brokerUrl, clientId, options){
if (typeof org.walterhiggins.scriptcraft.ScriptCraftMqttCallback != 'function'){ if (typeof org.walterhiggins.scriptcraft.ScriptCraftMqttCallback != 'function'){
throw MISSING_MQTT; throw MISSING_MQTT;
} }
return new Client(brokerUrl, clientId, options); return new Client(brokerUrl, clientId, options);
}; };

View file

@ -1,3 +1,4 @@
'use strict';
/************************************************************************* /*************************************************************************
## alias Plugin ## alias Plugin
@ -65,8 +66,8 @@ Execute the alias : \n \
persist aliases persist aliases
*/ */
var _store = { var _store = {
players: {}, players: {},
global: {} global: {}
}; };
/* /*
turns 'cw = time set {1} ; weather {2}' into {cmd: 'cw', aliases: ['time set {1}', 'weather {2}']} turns 'cw = time set {1} ; weather {2}' into {cmd: 'cw', aliases: ['time set {1}', 'weather {2}']}
@ -74,159 +75,148 @@ var _store = {
used for the 'set' and 'global' options. used for the 'set' and 'global' options.
*/ */
var _processParams = function(params){ var _processParams = function(params){
var paramStr = params.join(' '); var paramStr = params.join(' '),
var eqPos = paramStr.indexOf('='); eqPos = paramStr.indexOf('='),
var aliasCmd = paramStr.substring(0,eqPos).trim(); aliasCmd = paramStr.substring(0,eqPos).trim(),
var aliasValue = paramStr.substring(eqPos+1).trim(); aliasValue = paramStr.substring(eqPos+1).trim();
return { cmd: aliasCmd, aliases: aliasValue.split(/\s*;\s*/) }; return {
cmd: aliasCmd,
aliases: aliasValue.split(/\s*;\s*/)
};
}; };
var _set = function(params, player){ var _set = function(params, player){
var playerAliases = _store.players[player.name]; var playerAliases = _store.players[player.name];
if (!playerAliases){ if (!playerAliases){
playerAliases = {}; playerAliases = {};
} }
var o = _processParams(params); var o = _processParams(params);
playerAliases[o.cmd] = o.aliases; playerAliases[o.cmd] = o.aliases;
_store.players[player.name] = playerAliases; _store.players[player.name] = playerAliases;
player.sendMessage("Alias '" + o.cmd + "' created."); player.sendMessage("Alias '" + o.cmd + "' created.");
}; };
var _remove = function(params, player){ var _remove = function(params, player){
if (_store.players[player.name] && if (_store.players[player.name] &&
_store.players[player.name][params[0]]){ _store.players[player.name][params[0]]){
delete _store.players[player.name][params[0]]; delete _store.players[player.name][params[0]];
player.sendMessage("Alias '" + params[0] + "' removed."); player.sendMessage("Alias '" + params[0] + "' removed.");
} }
else{ else{
player.sendMessage("Alias '" + params[0] + "' does not exist."); player.sendMessage("Alias '" + params[0] + "' does not exist.");
} }
if (player.op){ if (player.op){
if (_store.global[params[0]]) if (_store.global[params[0]])
delete _store.global[params[0]]; delete _store.global[params[0]];
} }
}; };
var _global = function(params, player){ var _global = function(params, player){
if (!player.op){ if (!player.op){
player.sendMessage("Only operators can set global aliases. " + player.sendMessage("Only operators can set global aliases. " +
"You need to be an operator to perform this command."); "You need to be an operator to perform this command.");
return; return;
} }
var o = _processParams(params); var o = _processParams(params);
_store.global[o.cmd] = o.aliases; _store.global[o.cmd] = o.aliases;
player.sendMessage("Global alias '" + o.cmd + "' created."); player.sendMessage("Global alias '" + o.cmd + "' created.");
}; };
var _list = function(params, player){ var _list = function(params, player){
try { var alias = 0;
var alias = 0; try {
if (_store.players[player.name]){ if (_store.players[player.name]){
player.sendMessage("Your aliases:"); player.sendMessage("Your aliases:");
for (alias in _store.players[player.name]){ for (alias in _store.players[player.name]){
player.sendMessage(alias + " = " + player.sendMessage(alias + " = " +
JSON.stringify(_store.players[player.name][alias])); JSON.stringify(_store.players[player.name][alias]));
} }
}else{ }else{
player.sendMessage("You have no player-specific aliases."); player.sendMessage("You have no player-specific aliases.");
}
player.sendMessage("Global aliases:");
for (alias in _store.global){
player.sendMessage(alias + " = " + JSON.stringify(_store.global[alias]) );
}
}catch(e){
console.error("Error in list function: " + e.message);
throw e;
} }
player.sendMessage("Global aliases:");
for (alias in _store.global){
player.sendMessage(alias + " = " + JSON.stringify(_store.global[alias]) );
}
}catch(e){
console.error("Error in list function: " + e.message);
throw e;
}
}; };
var _help = function(params, player){ var _help = function(params, player){
player.sendMessage('Usage:\n' + _usage); player.sendMessage('Usage:\n' + _usage);
}; };
var alias = plugin('alias', { var alias = plugin('alias', {
store: _store, store: _store,
set: _set, set: _set,
global: _global, global: _global,
remove: _remove, remove: _remove,
list: _list, list: _list,
help: _help help: _help
}, true ); }, true );
var aliasCmd = command('alias', function( params, invoker ) { var aliasCmd = command('alias', function( params, invoker ) {
var operation = params[0], fn; var operation = params[0],
if (!operation){ fn;
invoker.sendMessage('Usage:\n' + _usage); if (!operation){
return; invoker.sendMessage('Usage:\n' + _usage);
} return;
/* }
wph 20140122 this is kind of dumb but Nashorn has some serious problems /*
accessing object properties by array index notation wph 20140122 this is kind of dumb but Nashorn has some serious problems
in JRE8 alias[operation] returns null - definitely a bug in Nashorn. accessing object properties by array index notation
*/ in JRE8 alias[operation] returns null - definitely a bug in Nashorn.
if (operation == 'set'){ */
alias.set(params.slice(1), invoker); for (var key in alias){
}else if (operation == 'global'){ if (key == operation){
alias.global(params.slice(1), invoker); fn = alias[key];
}else if (operation == 'remove'){ fn(params.slice(1),invoker);
alias.remove(params.slice(1), invoker); return;
}else if (operation == 'list'){
alias.list(params.slice(1), invoker);
}else if (operation == 'help'){
alias.help(params.slice(1), invoker);
}else {
invoker.sendMessage('Usage:\n' + _usage);
} }
}
invoker.sendMessage('Usage:\n' + _usage);
}); });
var _intercept = function( msg, invoker, exec) var _intercept = function( msg, invoker, exec)
{ {
if (msg.trim().length == 0) if (msg.trim().length == 0)
return false; return false;
var msgParts = msg.split(' '); var msgParts = msg.split(' '),
var command = msg.match(/^\/*([^\s]+)/)[1]; command = msg.match(/^\/*([^\s]+)/)[1],
template = [], isAlias = false, cmds = [],
var template = [], isAlias = false, cmds = []; commandObj,
filledinCommand;
if (_store.global[command]){
template = _store.global[command]; if (_store.global[command]){
isAlias = true; template = _store.global[command];
}else{ isAlias = true;
if (config.verbose){ }
var commandObj = server.commandMap.getCommand(command); /*
if (!commandObj) allows player-specific aliases to override global aliases
console.info('No global alias found for command: ' + command); */
} if (_store.players[invoker] &&
} _store.players[invoker][command])
/* {
allows player-specific aliases to override global aliases template = _store.players[invoker][command];
*/ isAlias = true;
if (_store.players[invoker] && }
_store.players[invoker][command]) for (var i = 0;i < template.length; i++)
{ {
template = _store.players[invoker][command]; filledinCommand = template[i].replace(/{([0-9]+)}/g, function (match,index){
isAlias = true; index = parseInt(index,10);
}else{ if (msgParts[index])
if (config.verbose){ return msgParts[index];
var commandObj = server.commandMap.getCommand(command); else
if (!commandObj) return match;
console.info('No player alias found for command: ' + command); });
} cmds.push(filledinCommand);
} }
for (var i = 0;i < template.length; i++)
{ for (var i = 0; i< cmds.length; i++){
var filledinCommand = template[i].replace(/{([0-9]+)}/g, function (match,index){ exec(cmds[i]);
index = parseInt(index,10); }
if (msgParts[index]) return isAlias;
return msgParts[index]
else
return match;
});
cmds.push(filledinCommand);
}
for (var i = 0; i< cmds.length; i++){
exec(cmds[i]);
}
return isAlias;
}; };
/* /*
@ -234,19 +224,19 @@ var _intercept = function( msg, invoker, exec)
command about to be issued matches an alias. command about to be issued matches an alias.
*/ */
events.on('player.PlayerCommandPreprocessEvent', function(listener,evt){ events.on('player.PlayerCommandPreprocessEvent', function(listener,evt){
var invoker = evt.player; var invoker = evt.player;
var exec = function(cmd){ invoker.performCommand(cmd);}; var exec = function(cmd){ invoker.performCommand(cmd);};
var isAlias = _intercept(''+evt.message, ''+invoker.name, exec); var isAlias = _intercept(''+evt.message, ''+invoker.name, exec);
if (isAlias) if (isAlias)
evt.cancelled = true; evt.cancelled = true;
}); });
/* define a 'void' command because ServerCommandEvent can't be canceled */ /* define a 'void' command because ServerCommandEvent can't be canceled */
command('void',function(){}); command('void',function(){});
events.on('server.ServerCommandEvent', function(listener,evt){ events.on('server.ServerCommandEvent', function(listener,evt){
var invoker = evt.sender; var invoker = evt.sender;
var exec = function(cmd){ invoker.server.dispatchCommand(invoker, cmd); }; var exec = function(cmd){ invoker.server.dispatchCommand(invoker, cmd); };
var isAlias = _intercept(''+evt.command, ''+ invoker.name, exec); var isAlias = _intercept(''+evt.command, ''+ invoker.name, exec);
if (isAlias) if (isAlias)
evt.command = 'jsp void'; evt.command = 'jsp void';
}); });

View file

@ -0,0 +1,75 @@
/*
Experimental:
Point at a block and issue the following ...
/js var d = new Drone();
/js var clock = new LCDClock(d);
/js clock.start24();
... start the clock...
/js clock.stop24();
... stops the clock...
*/
var Drone = require('../drone').Drone;
var blocktype = require('../blocktype');
exports.LCDClock = function(drone, fgColor,bgColor,border) {
var lastSecs = [0,0,0,0],
world = drone.world,
intervalId = -1;
if (typeof bgColor == 'undefined')
bgColor = '35:15'; // black wool
if (typeof fgColor == 'undefined')
fgColor = 35 ; // white wool
if (border){
drone.box(border,21,9,1);
drone.up().right();
}
drone.blocktype('00:00',fgColor,bgColor);
return {
start24: function(){
var clock = this;
function tick(){
var rolloverMins = 24*60;
var timeOfDayInMins = Math.floor(((world.time + 6000) % 24000) / 16.6667);
timeOfDayInMins = timeOfDayInMins % rolloverMins;
console.log('Minecraft time: ' + world.time + ' timeOfDayInMins: ' + timeOfDayInMins);
clock.update(timeOfDayInMins);
};
intervalId = setInterval(tick, 800);
},
stop24: function(){
clearInterval(intervalId);
},
update: function(secs){
var digits = [0,0,0,0],
s = secs % 60;
m = (secs - s) / 60;
digits[3] = s%10;
digits[2] = (s-digits[3])/10;
digits[1] = m%10;
digits[0] = (m-digits[1])/10;
//
// updating all 4 digits each time is expensive
// only update digits which have changed (in most cases - just 1)
//
if (digits[3] != lastSecs[3])
drone.right(14).blocktype(''+digits[3],fgColor,bgColor).left(14);
if (digits[2] != lastSecs[2])
drone.right(10).blocktype(''+digits[2],fgColor,bgColor).left(10);
if (digits[1] != lastSecs[1])
drone.right(4).blocktype(''+digits[1], fgColor, bgColor).left(4);
if (digits[0] != lastSecs[0])
drone.blocktype(''+digits[0], fgColor, bgColor);
lastSecs[0] = digits[0];
lastSecs[1] = digits[1];
lastSecs[2] = digits[2];
lastSecs[3] = digits[3];
}
};
};