First phase of transition from Bukkit to Canary.

Some of the plugins are not yet supported.
If you're feeling brave you can build from source using ant.
This commit is contained in:
walterhiggins 2014-09-29 23:42:41 +01:00
parent cc4f98474d
commit 19162c3688
55 changed files with 1436 additions and 808 deletions

View file

@ -1,7 +1,7 @@
<project name="scriptcraft" default="package" basedir="."> <project name="scriptcraft" default="package" basedir=".">
<property file="build.properties"/> <property file="build.properties"/>
<description>Builds the scriptcraft.jar file - a plugin for bukkit</description> <description>Builds the scriptcraft.jar file - a plugin for bukkit</description>
<property name="src" location="src/main/java"/> <property name="src.canary" location="src/main/java/canary"/>
<property name="build" location="target/classes"/> <property name="build" location="target/classes"/>
<property name="dist" location="target/" /> <property name="dist" location="target/" />
<property name="minecraft.dir" location="${dist}/minecraft" /> <property name="minecraft.dir" location="${dist}/minecraft" />
@ -24,46 +24,15 @@
</target> </target>
<target name="server-setup" depends="init" description="Downloads the latest bukkit dev jar"
unless="minecraft.present">
<mkdir dir="${minecraft.dir}" />
<echo>Retrieving CraftBukkit artifact info</echo>
<get src="http://dl.bukkit.org/api/1.0/downloads/projects/CraftBukkit/?_accept=application/xml"
verbose="true"
httpusecaches="false"
dest="${minecraft.dir}/bukkit.xml" />
<xslt in="${minecraft.dir}/bukkit.xml"
out="${minecraft.dir}/ant.properties.xml"
style="build/bukkit-to-url.xsl"/>
<xmlproperty file="${minecraft.dir}/ant.properties.xml" keeproot="true"/>
<echo>Retrieving CraftBukkit jar</echo>
<get src="${bukkit.url}"
dest="${minecraft.dir}/craftbukkit.jar"
verbose="true"/>
<echo>Creating default ops.txt for your user</echo>
<echo message="${op.name}" file="${minecraft.dir}/ops.txt" />
</target>
<target name="run" depends="server-setup, package, update-live-cb" description="Starts Bukkit with ScriptCraft">
<echo>Starting Bukkit with ScriptCraft</echo>
<java jar="${minecraft.dir}/craftbukkit.jar" maxmemory="1024m" fork="true" dir="${minecraft.dir}" />
</target>
<target name="compile" depends="init, server-setup" description="compile bukkit plugin source"> <target name="compile-canary" depends="init" description="compile canary plugin source">
<javac includeantruntime="false" <javac includeantruntime="false"
srcdir="${src}" srcdir="${src.canary}"
source="1.6" source="1.6"
target="1.6" target="1.6"
destdir="${build}" destdir="${build}"
debug="true" debug="true"
classpath="${minecraft.dir}/craftbukkit.jar" /> classpath="lib/canary.jar" />
</target> </target>
<target name="gendocs" depends="construct-ypgpm, construct-api-ref" description="Generate API documentation"> <target name="gendocs" depends="construct-ypgpm, construct-api-ref" description="Generate API documentation">
@ -87,14 +56,33 @@
</target> </target>
<target name="gen-events-helper" depends="compile-docs,server-setup,init"> <target name="gen-events-helper-canary" depends="compile-docs,init">
<mkdir dir="${dist}/js/lib"/> <mkdir dir="${dist}/js/lib"/>
<java classname="jscript" failonerror="true" fork="true" output="${dist}/js/lib/events-helper.js" error="${dist}/geneventserror.log"> <java classname="jscript" failonerror="true" fork="true" output="${dist}/js/lib/events-helper.js" error="${dist}/geneventserror.log">
<classpath> <classpath>
<pathelement path="${build}"/> <pathelement path="${build}"/>
<pathelement path="${minecraft.dir}/craftbukkit.jar"/> <pathelement path="lib/canary.jar"/>
</classpath> </classpath>
<arg value="src/generateEventsHelper.js"/> <arg value="src/generateEventsHelper.js"/>
<arg value="canary"/>
<arg value="lib/canary.jar"/>
<arg value="blockDestroy"/>
<arg value="net.canarymod.hook.player.BlockDestroyHook"/>
</java>
</target>
<target name="gen-events-helper-bukkit" depends="compile-docs,init">
<mkdir dir="${dist}/js/lib"/>
<java classname="jscript" failonerror="true" fork="true" output="${dist}/js/lib/events-helper.js" error="${dist}/geneventserror.log">
<classpath>
<pathelement path="${build}"/>
<pathelement path="lib/canary.jar"/>
</classpath>
<arg value="src/generateEventsHelper.js"/>
<arg value="canary"/>
<arg value="lib/canary.jar"/>
<arg value="Break"/>
<arg value="org.bukkit.event.block.BlockBreakEvent"/>
</java> </java>
</target> </target>
@ -148,7 +136,7 @@ Walter Higgins
<target name="zip_js" depends="zip_lib, zip_modules, zip_plugins"> <target name="zip_js" depends="zip_lib, zip_modules, zip_plugins">
</target> </target>
<target name="copy-js" depends="gen-events-helper,init"> <target name="copy-js" depends="gen-events-helper-canary,init">
<copy todir="${dist}/js"> <copy todir="${dist}/js">
<fileset dir="src/main/js"/> <fileset dir="src/main/js"/>
</copy> </copy>
@ -185,7 +173,7 @@ Walter Higgins
</zip> </zip>
</target> </target>
<target name="package" depends="gendocs,zip_js,compile" description="generate the distribution" > <target name="package" depends="gendocs,zip_js,compile-canary" description="generate the distribution" >
<!-- ensure plugin.yml is always copied --> <!-- ensure plugin.yml is always copied -->
<delete file="${build}/plugin.yml" /> <delete file="${build}/plugin.yml" />
<copy todir="${build}"> <copy todir="${build}">
@ -206,7 +194,7 @@ Walter Higgins
<delete dir="${dist}"/> <delete dir="${dist}"/>
</target> </target>
<target name="update-live-cb" depends="package" description="Copy the built plugin to the live craftbukkit folder for testing."> <target name="update-live-cb" depends="package" description="Copy the built plugin to the live folder for testing.">
<mkdir dir="${minecraft.dir}/plugins" /> <mkdir dir="${minecraft.dir}/plugins" />
<delete> <delete>
<fileset dir="${minecraft.dir}/plugins/" includes="scriptcraft*.*"/> <fileset dir="${minecraft.dir}/plugins/" includes="scriptcraft*.*"/>

View file

@ -171,7 +171,7 @@ called `location`. We can use that name like this...
Blackrock Castle 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 `'` When telling the computer to store some text, you have to put `'`
(that's the single-quote character) at the start and end (that's the single-quote character) at the start and end
of the text. The computer doesn't store these quote characters, only the of the text. The computer doesn't store these quote characters, only the

BIN
lib/canary.jar Normal file

Binary file not shown.

View file

@ -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, var File = java.io.File,
FileReader = java.io.FileReader, FileReader = java.io.FileReader,
FileInputStream = java.io.FileInputStream, FileInputStream = java.io.FileInputStream,
@ -6,27 +8,21 @@ var File = java.io.File,
Modifier = java.lang.reflect.Modifier, Modifier = java.lang.reflect.Modifier,
clz, clz,
ZipInputStream = java.util.zip.ZipInputStream, ZipInputStream = java.util.zip.ZipInputStream,
zis = new ZipInputStream(new FileInputStream('./target/minecraft/craftbukkit.jar')), zis = new ZipInputStream(new FileInputStream(args[1])),
entry = null; entry = null;
var content = [ var content = [
'/*********************', '/*********************',
'## Events Helper Module', '## Events Helper Module',
'The Events helper module provides a suite of functions - one for each possible event.', '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. ', '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 ', '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.', 'to choose from any of the approx. 160 different event types to listen to.',
'', '',
'### Usage', '### Usage',
'', '',
' events.blockBreak( function( event ) { ', ' events.' + args[2] + '( function( event ) { ',
' event.player.sendMessage(\'You broke a block!\'); ', ' echo( event.player, \'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!\');',
' });', ' });',
'', '',
'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.', '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) { while ( ( entry = zis.nextEntry) != null) {
var name = '' + entry.name; 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',''); name = name.replace(/\//g,'.').replace('.class','');
try { try {
clz = java.lang.Class.forName(name); clz = java.lang.Class.forName(name);
@ -50,8 +50,21 @@ while ( ( entry = zis.nextEntry) != null) {
continue; continue;
} }
var parts = name.split('.'); var parts = name.split('.');
var shortName = name.replace('org.bukkit.event.',''); var shortName = null;
var fname = parts.reverse().shift().replace(/^(.)/,function(a){ return a.toLowerCase();}).replace(/Event$/,''); 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 = [ var comment = [
'/*********************', '/*********************',
@ -70,7 +83,12 @@ while ( ( entry = zis.nextEntry) != null) {
out.println(comment[i]); out.println(comment[i]);
} }
out.println('exports.' + fname + ' = function(callback,priority){ '); 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('};'); out.println('};');
} }
} }

View file

@ -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<String> complete(MessageReceiver sender, String[] args, String cmd){
List<String> result = new ArrayList<String>();
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<String> jsComplete(MessageReceiver sender, String[] args){
return complete(sender, args, "js");
}
@TabComplete (commands = { "jsp" })
public List<String> jspComplete(MessageReceiver sender, String[] args){
return complete(sender, args, "jsp");
}
}

View file

@ -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 [webcons]: https://developer.mozilla.org/en-US/docs/Web/API/console
***/ ***/
var logger = __plugin.logger, function argsToArray( args ) {
logMethodName = 'log(java.util.logging.Level,java.lang.String)';
var argsToArray = function( args ) {
var result = []; var result = [];
for ( var i =0; i < args.length; i++ ) { for ( var i =0; i < args.length; i++ ) {
result.push(args[i]); result.push(args[i]);
} }
return result; return result;
} }
var log = function( level, restOfArgs ) { function consMsg(params){
var args = argsToArray( restOfArgs ); var args = argsToArray(params);
if ( args.length > 1 ) { if ( args.length > 1 ) {
var msg = java.lang.String.format( args[0], args.slice(1) ); return java.lang.String.format( args[0], args.slice(1) );
logger[logMethodName]( level, msg );
} else { } 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 );
};

View file

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

View file

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

View file

@ -13,9 +13,7 @@ This method is used to register event listeners.
#### Parameters #### Parameters
* eventName - A java class. See [Bukkit API][buk] for * eventName - A Java class. See [Bukkit API][buk] for details of the many bukkit event types.
details of the many bukkit event types. Provide the full class name (without
enclosing quotes).
* callback - A function which will be called whenever the event * callback - A function which will be called whenever the event
fires. The callback should take a single parameter, event (the event fired). 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 The following code will print a message on screen every time a block is broken in the game
```javascript ```javascript
events.on( Packages.org.bukkit.event.block.BlockBreakEvent, function( evt ) { events.on( org.bukkit.block.BlockBreakEvent, function( evt ) {
evt.player.sendMessage( evt.player.name + ' broke a block!'); echo(evt.player, evt.player.name + ' broke a block!');
} ); } );
``` ```
To handle an event only once and unregister from further events... To handle an event only once and unregister from further events...
```javascript ```javascript
events.on( Packages.org.bukkit.event.block.BlockBreakEvent, function( evt ) { events.on( org.bukkit.block.BlockBreakEvent, function( evt ) {
evt.player.sendMessage( evt.player.name + ' broke a block!'); echo( evt.player, evt.player.name + ' broke a block!');
this.unregister(); this.unregister();
} ); } );
``` ```
@ -57,79 +55,22 @@ object which is returned by the `events.on()` function.
To unregister a listener *outside* of the listener function... To unregister a listener *outside* of the listener function...
```javascript ```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(); myBlockBreakListener.unregister();
``` ```
[buk2]: http://wiki.bukkit.org/Event_API_Reference [buk2]: http://wiki.bukkit.org/Event_API_Reference
[buk]: http://jd.bukkit.org/dev/apidocs/index.html?org/bukkit/event/Event.html [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'); var helper = require('events-helper');
for ( var func in helper ) { for ( var func in helper ) {
exports[func] = helper[func]; module.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;
}; };

View file

@ -1,4 +1,3 @@
module.exports = function( $ ) { module.exports = function( $ ) {
// wph 20140105 trim not availabe in String on Mac OS. // wph 20140105 trim not availabe in String on Mac OS.
@ -44,29 +43,35 @@ module.exports = function( $ ) {
return bind; return bind;
}(Array.prototype.slice)); }(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 sanity tests
a delay in milliseconds. However, bukkit's scheduler expects a delay in ticks
(where 1 tick = 1/20th second)
*/ */
var bukkitTask = server.scheduler.runTaskLater( __plugin, callback, Math.ceil( delayInMillis / 50 ) ); $.setTimeout(function(){
return bukkitTask; 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 ) { var runs = 3;
bukkitTask.cancel(); 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();
};
}; };

View file

@ -1,13 +1,19 @@
var File = java.io.File;
/* /*
wph 20140102 - warn if legacy 'craftbukkit/js-plugins' or 'craftbukkit/scriptcraft' directories are present wph 20140102 - warn if legacy 'mcserver/js-plugins' or
*/ 'mcserver/plugins/scriptcraft' directories are present
*/
module.exports = function( jsPluginsRootDir ) { module.exports = function( jsPluginsRootDir ) {
var cbPluginsDir = jsPluginsRootDir.parentFile, var mcServerDir = new File(jsPluginsRootDir.canonicalPath).parentFile;
cbDir = new File(cbPluginsDir.canonicalPath).parentFile, if (mcServerDir == null){
legacyExists = false, console.warn('Could not find parent directory for ' + jsPluginsRootDir.canonicalPath);
legacyDirs = [new File( cbDir, 'js-plugins' ), return;
new File( cbDir, 'scriptcraft' )]; }
var legacyExists = false,
legacyDirs = [
new File( mcServerDir, 'js-plugins' ),
new File( mcServerDir, 'plugins/scriptcraft' )
];
for ( var i = 0; i < legacyDirs.length; i++ ) { for ( var i = 0; i < legacyDirs.length; i++ ) {
if ( legacyDirs[i].exists() 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.', console.warn('Legacy ScriptCraft directory %s was found. This directory is no longer used.',
legacyDirs[i].canonicalPath); 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 ) { if ( legacyExists ) {

View file

@ -1,7 +1,6 @@
'use strict'; 'use strict';
var console = require('./console'), var File = java.io.File,
File = java.io.File,
FileWriter = java.io.FileWriter, FileWriter = java.io.FileWriter,
PrintWriter = java.io.PrintWriter; PrintWriter = java.io.PrintWriter;
/* /*
@ -32,7 +31,6 @@ var _plugin = function(/* String */ moduleName, /* Object */ moduleObject, isPer
exports.plugin = _plugin; exports.plugin = _plugin;
exports.autoload = function( context, pluginDir, logger, options ) { exports.autoload = function( context, pluginDir, logger, options ) {
var _canonize = function( file ) { var _canonize = function( file ) {
return '' + file.canonicalPath.replaceAll('\\\\','/'); return '' + file.canonicalPath.replaceAll('\\\\','/');
}; };
@ -67,10 +65,12 @@ exports.autoload = function( context, pluginDir, logger, options ) {
_listSourceFiles( sourceFiles, pluginDir ); _listSourceFiles( sourceFiles, pluginDir );
var len = sourceFiles.length; var len = sourceFiles.length;
if ( config.verbose ) { if ( config && config.verbose ) {
console.info( len + ' scriptcraft plugins found in ' + pluginDir ); logger.info( len + ' scriptcraft plugins found in ' + pluginDir );
} }
for ( var i = 0; i < len; i++ ) { for ( var i = 0; i < len; i++ ) {
pluginPath = _canonize( sourceFiles[i] ); pluginPath = _canonize( sourceFiles[i] );
module = {}; module = {};
@ -84,7 +84,7 @@ exports.autoload = function( context, pluginDir, logger, options ) {
} }
} catch ( e ) { } catch ( e ) {
if ( typeof logger != 'undefined' ) { if ( typeof logger != 'undefined' ) {
logger.severe( 'Plugin ' + pluginPath + ' ' + e ); logger.error( 'Plugin ' + pluginPath + ' ' + e );
} else { } else {
java.lang.System.out.println( 'Error: Plugin ' + pluginPath + ' ' + e ); java.lang.System.out.println( 'Error: Plugin ' + pluginPath + ' ' + e );
} }

View file

@ -209,7 +209,7 @@ When resolving module names to file paths, ScriptCraft uses the following rules.
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);
} }
throw errMsg; throw new Error(errMsg);
} }
canonizedFilename = _canonize(file); 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 This can be fixed by instead using __engine.eval
*/ */
throw new Error( "Error evaluating module " + path throw new Error( "Error evaluating module " + path
+ " line #" + e.lineNumber + " line #" + e.lineNumber
+ " : " + e.message, canonizedFilename, e.lineNumber ); + " : " + e.message, canonizedFilename, e.lineNumber );
} }
var __dirname = '' + file.parentFile.canonicalPath; var __dirname = '' + file.parentFile.canonicalPath;
var parameters = [ var parameters = [
@ -265,9 +265,20 @@ When resolving module names to file paths, ScriptCraft uses the following rules.
.apply(moduleInfo.exports, /* this */ .apply(moduleInfo.exports, /* this */
parameters); parameters);
} catch (e) { } 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 throw new Error( "Error executing module " + path
+ " line #" + e.lineNumber + " line #" + e.lineNumber
+ " : " + e.message, canonizedFilename, e.lineNumber ); + " : " + e.message + (snippet?('\n' + snippet):''), canonizedFilename, e.lineNumber );
} }
if ( hooks ) { if ( hooks ) {
hooks.loaded( canonizedFilename ); hooks.loaded( canonizedFilename );

View file

@ -70,7 +70,7 @@ directory....
```javascript ```javascript
exports.greet = function(player) { 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 ### 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 #### Example
/js echo('Hello World') /js echo( self, 'Hello World')
For programmers familiar with Javascript web programming, an `alert` For programmers familiar with Javascript web programming, an `alert`
function is also provided. `alert` works exactly the same as `echo` function is also provided. `alert` works exactly the same as `echo`
e.g. `alert('Hello World')`. e.g. `alert( self, '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)
### require() function ### require() function
@ -308,7 +302,7 @@ The `command()` function is used to expose javascript functions for use by non-o
// javascript code // javascript code
function boo( params, sender) { function boo( params, sender) {
sender.sendMessage( params[0] ); echo( sender, params[0] );
} }
command( boo ); command( boo );
@ -322,7 +316,7 @@ To use a callback for options (TAB-Completion) ...
function boo( params, sender ) { function boo( params, sender ) {
var receiver = server.getPlayer( params[0] ); var receiver = server.getPlayer( params[0] );
if ( receiver ){ if ( receiver ){
receiver.sendMessage( sender.name + ' says boo!'); echo( receiver, sender.name + ' says boo!');
} }
} }
command( boo, bukkit.playerNames ); 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 ### 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. 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 #### Example
```javascript ```javascript
@ -355,11 +347,7 @@ A scriptcraft implementation of clearTimeout().
### setInterval() function ### 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. 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.
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
### clearInterval() function ### 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. 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. wph 20130124 - make self, plugin and server public - these are far more useful now that tab-complete works.
*/ */
var global = this; var global = this;
var server = org.bukkit.Bukkit.server; var server;
/* /*
private implementation private implementation
*/ */
function __onEnable ( __engine, __plugin, __script ) var __onDisableImpl;
{ function __onDisable ( __engine, __plugin ) {
var File = java.io.File, __onDisableImpl( __engine, __plugin);
FileReader = java.io.FileReader, }
BufferedReader = java.io.BufferedReader, function __onEnable ( __engine, __plugin, __script ) {
PrintWriter = java.io.PrintWriter, function _echo( ) {
FileWriter = java.io.FileWriter; var sender, msg;
var debug = function(msg){ if (arguments.length == 2){
java.lang.System.out.println('DEBUG:' + msg); sender = arguments[0];
}; msg = arguments[1];
var _canonize = function( file ) { } 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( '\\\\', '/' ); 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) Save a javascript object to a file (saves using JSON notation)
*/ */
var _save = function( objToSave, filename ) { function _save( objToSave, filename ) {
var objectToStr = null, var objectToStr = null,
f, f,
out; out;
@ -431,17 +430,8 @@ function __onEnable ( __engine, __plugin, __script )
out = new PrintWriter(new FileWriter(f)); out = new PrintWriter(new FileWriter(f));
out.println( objectToStr ); out.println( objectToStr );
out.close(); out.close();
}; }
/* function _loadJSON( filename ){
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 ){
var result = null, var result = null,
file = filename, file = filename,
r, r,
@ -464,7 +454,7 @@ function __onEnable ( __engine, __plugin, __script )
} }
result = JSON.parse(contents); result = JSON.parse(contents);
} catch ( e ) { } catch ( e ) {
logger.severe( 'Error evaluating ' + canonizedFilename + ', ' + e ); logger.error( 'Error evaluating ' + canonizedFilename + ', ' + e );
} }
finally { finally {
try { try {
@ -475,12 +465,11 @@ function __onEnable ( __engine, __plugin, __script )
} }
} }
return result; return result;
}
};
/* /*
Load the contents of the file and evaluate as javascript Load the contents of the file and evaluate as javascript
*/ */
var _load = function( filename, warnOnFileNotFound ) function _load( filename, warnOnFileNotFound )
{ {
var result = null, var result = null,
file = filename, file = filename,
@ -508,7 +497,7 @@ function __onEnable ( __engine, __plugin, __script )
result = __engine.eval( wrappedCode ); result = __engine.eval( wrappedCode );
// issue #103 avoid side-effects of || operator on Mac Rhino // issue #103 avoid side-effects of || operator on Mac Rhino
} catch ( e ) { } catch ( e ) {
logger.severe( 'Error evaluating ' + canonizedFilename + ', ' + e ); logger.error( 'Error evaluating ' + canonizedFilename + ', ' + e );
} }
finally { finally {
try { try {
@ -523,7 +512,164 @@ function __onEnable ( __engine, __plugin, __script )
} }
} }
return result; 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 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'); configFile = new File(configFile,'global-config.json');
var config = _load( configFile ); var config = _load( configFile );
if ( !config ) { if ( !config ) {
config = { verbose: false }; config = { verbose: true };
} }
global.config = config; global.config = config;
global.__plugin = __plugin; global.__plugin = __plugin;
@ -544,45 +690,14 @@ function __onEnable ( __engine, __plugin, __script )
var jsonLoaded = __engine['eval(java.io.Reader)']( jsonFileReader ); 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.addUnloadHandler = _addUnloadHandler;
global.refresh = _refresh;
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.echo = _echo; global.echo = _echo;
global.alert = _echo; global.alert = _echo;
global.scload = _load; global.scload = _load;
global.scsave = _save; global.scsave = _save;
global.scloadJSON = _loadJSON; global.scloadJSON = _loadJSON;
global.isOp = _isOp;
var configRequire = _load( jsPluginsRootDirName + '/lib/require.js', true ); var configRequire = _load( jsPluginsRootDirName + '/lib/require.js', true );
/* /*
setup paths to search for modules setup paths to search for modules
@ -615,8 +730,11 @@ function __onEnable ( __engine, __plugin, __script )
} }
); );
require('js-patch')( global ); var testJSPatch = require('js-patch')( global );
global.console = require('console'); var console = require('console')(logger);
global.console = console;
testJSPatch(console);
/* /*
setup persistence setup persistence
*/ */
@ -634,86 +752,13 @@ function __onEnable ( __engine, __plugin, __script )
// wph 20131226 - make events global as it is used by many plugins/modules // wph 20131226 - make events global as it is used by many plugins/modules
global.events = events; global.events = events;
events.pluginDisable(function( evt ) { if (__plugin.canary) {
// save config // canary plugin doesn't get to handle its own plugin disable event
_save( global.config, new File( jsPluginsRootDir, 'data/global-config.json' ) ); } else {
events.pluginDisable(_onDisable);
_runUnloadHandlers(); }
org.bukkit.event.HandlerList['unregisterAll(org.bukkit.plugin.Plugin)'](__plugin); __onDisableImpl = _onDisable;
}); global.__onCommand = __onCommand;
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;
};
plugins.autoload( global, new File(jsPluginsRootDir,'plugins'), logger ); plugins.autoload( global, new File(jsPluginsRootDir,'plugins'), logger );
require('legacy-check')(jsPluginsRootDir); require('legacy-check')(jsPluginsRootDir);
} }

View file

@ -3,7 +3,7 @@ var _commands = require('command').commands;
/* /*
Tab completion for the /jsp commmand Tab completion for the /jsp commmand
*/ */
var __onTabCompleteJSP = function( result, cmdSender, pluginCmd, cmdAlias, cmdArgs ) { var __onTabCompleteJSP = function( result, cmdArgs ) {
var cmdInput = cmdArgs[0], var cmdInput = cmdArgs[0],
opts, opts,
cmd, cmd,

View file

@ -93,7 +93,7 @@ var _getProperties = function( o ) {
return result.sort(); return result.sort();
}; };
var onTabCompleteJS = function( result, cmdSender, pluginCmd, cmdAlias, cmdArgs ) { var onTabCompleteJS = function( ) {
var _globalSymbols, var _globalSymbols,
lastArg, lastArg,
@ -111,12 +111,33 @@ var onTabCompleteJS = function( result, cmdSender, pluginCmd, cmdAlias, cmdArgs
candidate, candidate,
re, re,
li, 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 ); cmdArgs = Array.prototype.slice.call( cmdArgs, 0 );
if ( pluginCmd.name == 'jsp' ) { if (__plugin.canary){
return tabCompleteJSP( result, cmdSender, pluginCmd, cmdAlias, cmdArgs ); // 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 global.self = cmdSender; // bring in self just for autocomplete

View file

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

View file

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

View file

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

View file

@ -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 create a firework at the given location
*/ */
var firework = function( location ) { function bukkitFirework( location ) {
var bkColor = org.bukkit.Color; var bkColor = org.bukkit.Color;
var bkFireworkEffect = org.bukkit.FireworkEffect; var bkFireworkEffect = org.bukkit.FireworkEffect;
var bkEntityType = org.bukkit.entity.EntityType; var bkEntityType = org.bukkit.entity.EntityType;
@ -77,7 +42,5 @@ var firework = function( location ) {
fwm.addEffect( effect ); fwm.addEffect( effect );
fwm.setPower( randInt( 2 ) + 1 ); fwm.setPower( randInt( 2 ) + 1 );
fw.setFireworkMeta( fwm ); fw.setFireworkMeta( fwm );
}; }
module.exports = bukkitFirework;
exports.firework = firework;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,4 +0,0 @@
{
name: 'fireworks',
main: './fireworks.js'
}

View file

@ -26,14 +26,14 @@ exports.numberguess = function(player){
} }
if ( +guess !== randomNumber ) { if ( +guess !== randomNumber ) {
if (+guess < randomNumber ) { if (+guess < randomNumber ) {
guesser.sendMessage('Too low - guess again'); echo( guesser, 'Too low - guess again');
} }
if (+guess > randomNumber ) { if (+guess > randomNumber ) {
guesser.sendMessage('Too high - guess again'); echo( guesser, 'Too high - guess again');
} }
repeat(); repeat();
} else { } 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. The `value` parameter will be the same as `this.value`, the `repeat` parameter will be the same as `this.repeat` and so on.
***/ ***/
if (__plugin.canary) {
var bkPrompt = org.bukkit.conversations.Prompt, module.exports = require('./canary/input');
bkConversationFactory = org.bukkit.conversations.ConversationFactory; } else {
module.exports = require('./bukkit/input');
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( );
} }
module.exports = asyncInput;

View file

@ -1,27 +1,5 @@
var bkItemStack = org.bukkit.inventory.ItemStack; if (__plugin.canary) {
module.exports = require('./canary/items');
var items = function( material, amount ) { } else {
material = material.toUpperCase(); module.exports = require('./bukkit/items');
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]);
} }

View file

@ -181,6 +181,10 @@ signs.menu = function( /* String */ label, /* Array */ options, /* Function */ c
return convertToMenuSign; return convertToMenuSign;
}; };
if (__plugin.canary){
console.warn('signs/menu is not yet supported in CanaryMod');
return;
}
// //
// update it every time player interacts with it. // update it every time player interacts with it.
// //

View file

@ -85,7 +85,7 @@ var signs = require('signs'),
var player = utils.player('tom1234'); var player = utils.player('tom1234');
var sign = signs.getTargetedBy( player ); var sign = signs.getTargetedBy( player );
if ( !sign ) { if ( !sign ) {
player.sendMessage('Not looking at a sign'); echo( player, 'Not looking at a sign');
} }
``` ```

View file

@ -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 ## Sounds Module
This module is a simple wrapper around the Bukkit Sound class and provides 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. a simpler way to play sounds. All of the org.bukkit.Sound Enum values are attached.
### Usage: ### Usage (Bukkit) :
var sounds = require('sounds'); var sounds = require('sounds');
sounds.play( bukkit.sound.VILLAGER_NO , self, 1, 0); // plays VILLAGER_NO sound at full volume and medium pitch 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. These methods are provided for convenience to help beginners explore sounds using TAB completion.
***/ ***/
exports.play = function(sound, locationOrHasLocation, volume, pitch) { if (__plugin.canary) {
var location = null; module.exports = require('./canary/sounds');
if (!locationOrHasLocation) } else {
return; module.exports = require('./bukkit/sounds');
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);
};

View file

@ -37,7 +37,7 @@ Example
------- -------
/js var boldGoldText = "Hello World".bold().gold(); /js var boldGoldText = "Hello World".bold().gold();
/js self.sendMessage( boldGoldText ); /js echo(self, boldGoldText );
<p style="color:gold;font-weight:bold">Hello World</p> <p style="color:gold;font-weight:bold">Hello World</p>

View file

@ -1,8 +1,14 @@
'use strict'; 'use strict';
var File = java.io.File, var File = java.io.File;
bkBukkit = org.bukkit.Bukkit,
bkLocation = org.bukkit.Location, if (__plugin.bukkit){
bkBlockCommandSender = org.bukkit.command.BlockCommandSender; 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 ## Utilities Module
@ -31,7 +37,7 @@ var utils = require('utils');
var name = 'walterh'; var name = 'walterh';
var player = utils.player(name); var player = utils.player(name);
if ( player ) { if ( player ) {
player.sendMessage('Got ' + name); echo(player, 'Got ' + name);
} else { } else {
console.log('No player named ' + name); console.log('No player named ' + name);
} }
@ -50,7 +56,11 @@ var _player = function ( playerName ) {
} }
} else { } else {
if ( typeof playerName == 'string' ) if ( typeof playerName == 'string' )
return bkBukkit.getPlayer( playerName ); if (__plugin.canary) {
return Canary.server.getPlayer( playerName );
} else {
return bkBukkit.getPlayer( playerName );
}
else else
return playerName; // assumes it's a player object return playerName; // assumes it's a player object
} }
@ -132,8 +142,14 @@ exports.locationFromJSON = function( json ) {
world = bkBukkit.getWorld( json[0] ); world = bkBukkit.getWorld( json[0] );
return new bkLocation( world, json[1], json[2] , json[3] ); return new bkLocation( world, json[1], json[2] , json[3] );
} else { } else {
world = bkBukkit.getWorld( json.world ); if (__plugin.canary){
return new bkLocation( world, json.x, json.y , json.z, json.yaw, json.pitch ); 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 ) { if ( !player ) {
return null; return null;
} }
// player might be CONSOLE or a CommandBlock var targetedBlock ;
if ( !player.getTargetBlock ) { if ( __plugin.canary ) {
return null; var cmLineTracer = Packages.net.canarymod.LineTracer;
} var lineTracer = new cmLineTracer(player);
var targetedBlock = player.getTargetBlock( null, 5 ); targetedBlock = lineTracer.getTargetBlock();
if ( targetedBlock == null || targetedBlock.isEmpty() ) { if (targetedBlock == null){
return 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; return targetedBlock.location;
}; };
@ -265,7 +291,7 @@ The following example illustrates how to use foreach for immediate processing of
var utils = require('utils'); var utils = require('utils');
var players = ['moe', 'larry', 'curly']; var players = ['moe', 'larry', 'curly'];
utils.foreach (players, function(item){ 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 // assume this code is within a function/closure
var player = self; var player = self;
var onDone = function(){ var onDone = function(){
player.sendMessage('Job Done!'); echo( player, 'Job Done!');
}; };
utils.foreach (a, processItem, null, 10, onDone); utils.foreach (a, processItem, null, 10, onDone);
``` ```
@ -720,3 +746,70 @@ exports.array = function( ){
} }
return result; 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;

View file

@ -93,16 +93,16 @@ var _set = function( params, player ) {
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.' ); echo( player, 'Alias ' + o.cmd + ' created.' );
}; };
var _remove = function( params, player ) { var _remove = function( params, player ) {
if ( _store.players[player.name] && _store.players[player.name][ params[0] ] ) { if ( _store.players[player.name] && _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.' ); echo( player, 'Alias ' + params[0] + ' removed.' );
} }
else{ else{
player.sendMessage( 'Alias ' + params[0] + ' does not exist.' ); echo( player, 'Alias ' + params[0] + ' does not exist.' );
} }
if ( player.op ) { if ( player.op ) {
if ( _store.global[params[0]] ) { if ( _store.global[params[0]] ) {
@ -113,30 +113,30 @@ var _remove = function( params, player ) {
var _global = function( params, player ) { var _global = function( params, player ) {
if ( !player.op ) { if ( !player.op ) {
player.sendMessage( 'Only operators can set global aliases. ' + echo( player, '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.' ); echo( player, 'Global alias ' + o.cmd + ' created.' );
}; };
var _list = function( params, player ) { var _list = function( params, player ) {
var alias = 0; var alias = 0;
try { try {
if ( _store.players[player.name] ) { if ( _store.players[player.name] ) {
player.sendMessage('Your aliases:'); echo( player, 'Your aliases:');
for ( alias in _store.players[player.name] ) { for ( alias in _store.players[player.name] ) {
player.sendMessage( alias + ' = ' + echo( player, 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.' ); echo( player, 'You have no player-specific aliases.' );
} }
player.sendMessage( 'Global aliases:' ); echo( player, 'Global aliases:' );
for ( alias in _store.global ) { for ( alias in _store.global ) {
player.sendMessage( alias + ' = ' + JSON.stringify( _store.global[alias] ) ); echo( player, alias + ' = ' + JSON.stringify( _store.global[alias] ) );
} }
} catch( e ) { } catch( e ) {
console.error( 'Error in list function: ' + e.message ); console.error( 'Error in list function: ' + e.message );
@ -144,7 +144,7 @@ var _list = function( params, player ) {
} }
}; };
var _help = function( params, player ) { var _help = function( params, player ) {
player.sendMessage( 'Usage:\n' + _usage ); echo( player, 'Usage:\n' + _usage );
}; };
var alias = plugin( 'alias', { var alias = plugin( 'alias', {
@ -160,7 +160,7 @@ var aliasCmd = command( 'alias', function( params, invoker ) {
var operation = params[0], var operation = params[0],
fn; fn;
if ( !operation ) { if ( !operation ) {
invoker.sendMessage( 'Usage:\n' + _usage ); echo( invoker, 'Usage:\n' + _usage );
return; return;
} }
/* /*
@ -175,7 +175,7 @@ var aliasCmd = command( 'alias', function( params, invoker ) {
return; return;
} }
} }
invoker.sendMessage( 'Usage:\n' + _usage ); echo( invoker, 'Usage:\n' + _usage );
}); });
var _intercept = function( msg, invoker, exec ) { 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 Intercept all command processing and replace with aliased commands if the
command about to be issued matches an alias. 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 ) { events.playerCommandPreprocess( function( evt ) {
var invoker = evt.player; var invoker = evt.player;
var exec = function( cmd ) { var exec = function( cmd ) {

View file

@ -24,7 +24,10 @@ as a parameter. For example: `/js arrows.explosive('player23')` makes
player23's arrows explosive. player23's arrows explosive.
***/ ***/
if (__plugin.canary){
console.warn('arrows plugin not yet supported in CanaryMod');
return;
}
var signs = require('signs'), var signs = require('signs'),
fireworks = require('fireworks'), fireworks = require('fireworks'),
utils = require('utils'), utils = require('utils'),

View file

@ -35,7 +35,7 @@ directory...
```javascript ```javascript
exports.hi = function( player ){ 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'); echo( player, 'Create your own minecraft mods by adding javascript (.js) files');
player.sendMessage(' Windows: Open Explorer, go to \\\\' + serverAddress + '\\players\\' + player.name); echo( player, ' Windows: Open Explorer, go to \\\\' + serverAddress + '\\players\\' + player.name);
player.sendMessage(' Macintosh: Open Finder, Go to smb://' + serverAddress + '/players/' + player.name); echo( player, ' Macintosh: Open Finder, Go to smb://' + serverAddress + '/players/' + player.name);
player.sendMessage(' Linux: Open Nautilus, 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 ) { if ( !sender.op ) {
console.log( 'Attempt to set classroom scripting without credentials: ' + sender.name ); 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; return;
} }
foreach( server.onlinePlayers, canScript ? grantScripting : revokeScripting); foreach( server.onlinePlayers, canScript ? grantScripting : revokeScripting);
_store.enableScripting = canScript; _store.enableScripting = canScript;
sender.sendMessage('Scripting turned ' + ( canScript ? 'on' : 'off' ) + echo( sender, 'Scripting turned ' + ( canScript ? 'on' : 'off' ) +
' for all players on server ' + serverAddress); ' for all players on server ' + serverAddress);
}, },
store: _store store: _store
@ -164,9 +164,16 @@ var classroom = plugin('classroom', {
exports.classroom = classroom; exports.classroom = classroom;
events.playerJoin( function( event ) { if (__plugin.canary){
if ( _store.enableScripting ) { events.connection( function( event ) {
grantScripting(event.player); if ( _store.enableScripting ) {
} grantScripting(event.player);
}, 'HIGHEST'); }
}, 'CRITICAL');
} else {
events.playerJoin( function( event ) {
if ( _store.enableScripting ) {
grantScripting(event.player);
}
}, 'HIGHEST');
}

View file

@ -2,6 +2,10 @@
A test of the commando plugin. A test of the commando plugin.
Adds a new `/js-time` command with 4 possible options: Dawn, Midday, Dusk, Midnight 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, var commando = require('./commando').commando,
times = ['Dawn','Midday','Dusk','Midnight']; times = ['Dawn','Midday','Dusk','Midnight'];
@ -16,7 +20,7 @@ commando( 'js-time' , function( params, sender ) {
} }
} }
} else { } else {
sender.sendMessage('This command only works in-world'); echo( sender, 'This command only works in-world');
} }
},times); },times);

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(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... ... then players can use this command by typing...
@ -46,7 +46,7 @@ of the ScriptCraft core.
var commando = require('../commando'); var commando = require('../commando');
commando('hi', function(args,player){ 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. ...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 [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 = {}; var commands = {};
exports.commando = function( name, func, options, intercepts ) { exports.commando = function( name, func, options, intercepts ) {

View file

@ -1,5 +1,5 @@
var Drone = require('../drone').Drone; var Drone = require('../drone').Drone;
var blocks = require('blocks');
// //
// Create a floor of colored tiles some of which emit light. // Create a floor of colored tiles some of which emit light.
// The tiles change color every second creating a strobe-lit dance-floor. // The tiles change color every second creating a strobe-lit dance-floor.
@ -27,13 +27,14 @@ function dancefloor(width,length)
var discoTicks = 30; var discoTicks = 30;
var task = null; var task = null;
var strobe = function() { var strobe = function() {
disco.rand(floorTiles,width,1,length); disco.rand(blocks.rainbow ,width,1,length);
if (!discoTicks--) if (!discoTicks--)
task.cancel(); clearInterval(task);
}; };
var now = 0; var now = 0;
var everySecond = 20; var everySecond = 20;
task = server.scheduler.runTaskTimer(__plugin,strobe,now,everySecond); task = setInterval( strobe, 1000);
return this; return this;
} }
Drone.extend(dancefloor); Drone.extend(dancefloor);

View file

@ -576,8 +576,15 @@ var putBlock = function( x, y, z, blockId, metadata, world ) {
} }
var block = world.getBlockAt( x, y, z ); var block = world.getBlockAt( x, y, z );
if ( block.typeId != blockId || block.data != metadata ) { if ( block.typeId != blockId || block.data != metadata ) {
block.setTypeIdAndData( blockId, metadata, false ); if (__plugin.canary) {
block.data = metadata; 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 ); putBlock( x, y, z, blockId, meta, world );
block = world.getBlockAt( x, y, z ); block = world.getBlockAt( x, y, z );
state = block.state; var getState, isSign, setLine;
if ( state instanceof bkSign ) { 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++ ) { 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; this.record = false;
var usePlayerCoords = false; var usePlayerCoords = false;
var player = (typeof self !== 'undefined' ? self : null); var player = (typeof self !== 'undefined' ? self : null);
if ( x instanceof bkPlayer ) { var playerPos;
if ( x.location && x.name) {
player = x; player = x;
} }
var playerPos = utils.getPlayerPos( player ); playerPos = x.location;
var that = this; var that = this;
var populateFromLocation = function( loc ) { var populateFromLocation = function( loc ) {
that.x = loc.x; that.x = loc.x;
that.y = loc.y; that.y = loc.y;
that.z = loc.z; that.z = loc.z;
that.dir = _getDirFromRotation(loc.yaw); that.dir = _getDirFromRotation(loc);
that.world = loc.world; that.world = loc.world;
}; };
var mp = utils.getMousePos( player ); var mp = utils.getMousePos( player );
if ( typeof x == 'undefined' || x instanceof bkPlayer ) { if ( typeof x == 'undefined' || x.location ) {
if ( mp ) { if ( mp ) {
populateFromLocation( mp ); populateFromLocation( mp );
if ( playerPos ) { if ( playerPos ) {
this.dir = _getDirFromRotation(playerPos.yaw); this.dir = _getDirFromRotation(playerPos);
} }
} else { } else {
// base it on the player's current location // base it on the player's current location
@ -640,14 +667,14 @@ var Drone = function( x, y, z, dir, world ) {
populateFromLocation( playerPos ); populateFromLocation( playerPos );
} }
} else { } else {
if ( arguments[0] instanceof bkLocation ) { if ( arguments[0].x && arguments[0].y && arguments[0].z ) {
populateFromLocation( arguments[ 0 ] ); populateFromLocation( arguments[ 0 ] );
} else { } else {
this.x = x; this.x = x;
this.y = y; this.y = y;
this.z = z; this.z = z;
if ( typeof dir == 'undefined' ) { if ( typeof dir == 'undefined' ) {
this.dir = _getDirFromRotation( playerPos.yaw ); this.dir = _getDirFromRotation( playerPos);
} else { } else {
this.dir = dir%4; this.dir = dir%4;
} }
@ -818,12 +845,13 @@ Drone.prototype._checkpoints = {};
Drone.extend(function chkpt( name ) { Drone.extend(function chkpt( name ) {
this._checkpoints[ name ] = { x:this.x, y:this.y, z:this.z, dir:this.dir }; this._checkpoints[ name ] = { x:this.x, y:this.y, z:this.z, dir:this.dir };
}); });
Drone.extend(function move( ) { 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.x = arguments[0].x;
this.y = arguments[0].y; this.y = arguments[0].y;
this.z = arguments[0].z; this.z = arguments[0].z;
this.dir = _getDirFromRotation(arguments[0].yaw ); this.dir = _getDirFromRotation(arguments[0] );
this.world = arguments[0].world; this.world = arguments[0].world;
} else if ( typeof arguments[0] === 'string' ) { } else if ( typeof arguments[0] === 'string' ) {
var coords = this._checkpoints[arguments[0]]; var coords = this._checkpoints[arguments[0]];
@ -901,7 +929,13 @@ Drone.extend( function down( n ) {
// position // position
// //
Drone.prototype.getLocation = function( ) { 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 // building
@ -916,7 +950,7 @@ Drone.extend( function sign( message, block ) {
if ( block != 63 && block != 68 ) { if ( block != 63 && block != 68 ) {
var usage = 'Usage: sign("message", "63:1") or sign("message","68:1")'; var usage = 'Usage: sign("message", "63:1") or sign("message","68:1")';
if ( this.player ) { if ( this.player ) {
this.player.sendMessage(usage); echo( this.player, usage);
} }
console.error(usage); console.error(usage);
return; return;
@ -994,11 +1028,8 @@ Drone.prototype.cuboida = function(/* Array */ blocks, w, h, d, overwrite, immed
_traverse[dir].depth( that, d, function traverseDepthCallback( ) { _traverse[dir].depth( that, d, function traverseDepthCallback( ) {
traverseHeight( that, h, function traverseHeightCallback( ) { traverseHeight( that, h, function traverseHeightCallback( ) {
_traverse[dir].width( that, w, function traverseWidthCallback( ) { _traverse[dir].width( that, w, function traverseWidthCallback( ) {
var block = that.world.getBlockAt( that.x, that.y, that.z ); var properBlock = blocksForBuild[ bi % len ];
var properBlock = blocksForBuild[ bi % len ]; putBlock( that.x, that.y, that.z, properBlock[0], properBlock[1], that.world);
if (overwrite || block.type.equals(bkMaterial.AIR) ) {
block.setTypeIdAndData( properBlock[0], properBlock[1], false );
}
bi++; bi++;
}); });
}); });
@ -1050,13 +1081,7 @@ Drone.prototype.cuboidX = function( blockType, meta, w, h, d, immediate ) {
return this; return this;
} }
var depthFunc = function( ) { var depthFunc = function( ) {
putBlock( that.x, that.y, that.z, blockType, meta, that.world );
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;
}; };
var heightFunc = function( ) { var heightFunc = function( ) {
_traverse[dir].depth( that, d, depthFunc ); _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 // 0 = east, 1 = south, 2 = west, 3 = north
// 46 to 135 = west // 46 to 135 = west
// 136 to 225 = north // 136 to 225 = north
// 226 to 315 = east // 226 to 315 = east
// 316 to 45 = south // 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 r = (r + 360 ) % 360; // east could be 270 or -90
if ( r > 45 && r <= 135 ) if ( r > 45 && r <= 135 )

View file

@ -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. permission since it relies on the `/js` command to execute.
exports.hello = function(player){ exports.hello = function(player){
player.sendMessage('Hello ' + player.name); echo( player, 'Hello ' + player.name);
}; };
***/ ***/
exports.hello = function( player ) { exports.hello = function( player ) {
player.sendMessage( 'Hello ' + player.name ); echo( player, 'Hello ' + player.name );
}; };

View file

@ -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 does not evaluate javascript code so this command is much more secure.
command('hello', function (parameters, player) { command('hello', function (parameters, player) {
player.sendMessage('Hello ' + player.name); echo( player, 'Hello ' + player.name);
}); });
***/ ***/
command( 'hello', function( parameters, player ) { command( 'hello', function( parameters, player ) {
player.sendMessage( 'Hello ' + player.name ); echo( player, 'Hello ' + player.name );
}); });

View file

@ -23,10 +23,10 @@ message for operators.
command('op-hello', function (parameters, player) { command('op-hello', function (parameters, player) {
if (!player.op){ if (!player.op){
player.sendMessage('Only operators can do this.'); echo( player, 'Only operators can do this.');
return; 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 this is how you limit based on player privileges
*/ */
if ( !player.op ) { if ( !player.op ) {
player.sendMessage( 'Only operators can do this.' ); echo( player, 'Only operators can do this.' );
return; return;
} }
player.sendMessage( 'Hello ' + player.name ); echo( player, 'Hello ' + player.name );
}); });

View file

@ -21,7 +21,7 @@ a fixed 'Hello ' to anything you like by passing a parameter.
command( 'hello-params', function ( parameters, player ) { command( 'hello-params', function ( parameters, player ) {
var salutation = parameters[0] ; 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 `. which appears after `jsp hello-params `.
*/ */
var salutation = parameters[0] ; var salutation = parameters[0] ;
player.sendMessage( salutation + ' ' + player.name ); echo( player, salutation + ' ' + player.name );
}); });

View file

@ -38,7 +38,7 @@ Source Code ...
if ( recipient ) { if ( recipient ) {
greetings.hello( recipient ); greetings.hello( recipient );
} else { } 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 ) { if ( recipient ) {
greetings.hello( recipient ); greetings.hello( recipient );
} else { } else {
sender.sendMessage( 'Player ' + playerName + ' not found.' ); echo( sender, 'Player ' + playerName + ' not found.' );
} }
}); });

View file

@ -80,7 +80,7 @@ cleaner and more readable. Similarly where you see a method like
events.on( 'player.PlayerJoinEvent', function( event ) { events.on( 'player.PlayerJoinEvent', function( event ) {
if ( event.player.op ) { 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 ) { events.playerJoin( function( event ) {
if ( event.player.op ) { if ( event.player.op ) {
event.player.sendMessage('Welcome to ' + __plugin); echo( event.player, 'Welcome to ' + __plugin);
} }
}); });
***/ ***/
events.playerJoin( function( event ) { // wph 20140927 - event handler differs depending on framework.
if ( event.player.op ) {
event.player.sendMessage( 'Welcome to ' + __plugin ); var onJoin = __plugin.canary ? events.connection : events.playerJoin;
onJoin( function( event ) {
if ( isOp(event.player) ) {
echo( event.player, 'Welcome to ' + __plugin );
} }
}); });

View file

@ -106,11 +106,11 @@ var homes = plugin( 'homes', {
host = utils.player( host ); host = utils.player( host );
loc = _store.houses[ host.name ]; loc = _store.houses[ host.name ];
if ( !loc ) { if ( !loc ) {
guest.sendMessage( host.name + ' has no home' ); echo( guest, host.name + ' has no home' );
return; return;
} }
if ( !this._canVisit( guest, host ) ) { 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; return;
} }
homeLoc = utils.locationFromJSON( loc ); homeLoc = utils.locationFromJSON( loc );
@ -213,8 +213,8 @@ var homes = plugin( 'homes', {
} }
invitations.push( guest.name ); invitations.push( guest.name );
_store.invites[host.name] = invitations; _store.invites[host.name] = invitations;
guest.sendMessage( host.name + ' has invited you to their home.' ); echo( guest, host.name + ' has invited you to their home.' );
guest.sendMessage( 'type "/jsp home ' + host.name + '" to accept' ); echo( guest, 'type "/jsp home ' + host.name + '" to accept' );
}, },
/* /*
Uninvite someone to the home Uninvite someone to the home
@ -290,16 +290,16 @@ var options = {
}, },
'help': function( params, sender ) { 'help': function( params, sender ) {
sender.sendMessage( homes.help() ); echo( sender, homes.help() );
}, },
'list': function( params, sender ) { 'list': function( params, sender ) {
var visitable = homes.list(); var visitable = homes.list();
if ( visitable.length == 0 ) { if ( visitable.length == 0 ) {
sender.sendMessage( 'There are no homes to visit' ); echo( sender, 'There are no homes to visit' );
return; return;
} else { } else {
sender.sendMessage([ echo( sender, [
'You can visit any of these ' + visitable.length + ' homes' 'You can visit any of these ' + visitable.length + ' homes'
,visitable.join(', ') ,visitable.join(', ')
]); ]);
@ -309,9 +309,9 @@ var options = {
'ilist': function( params, sender ) { 'ilist': function( params, sender ) {
var potentialVisitors = homes.ilist(); var potentialVisitors = homes.ilist();
if ( potentialVisitors.length == 0 ) { if ( potentialVisitors.length == 0 ) {
sender.sendMessage('No one can visit your home'); echo( sender, 'No one can visit your home');
} else { } else {
sender.sendMessage([ echo( sender, [
'These ' + potentialVisitors.length + 'players can visit your home', 'These ' + potentialVisitors.length + 'players can visit your home',
potentialVisitors.join(', ')]); potentialVisitors.join(', ')]);
} }
@ -319,13 +319,13 @@ var options = {
'invite': function( params, sender ) { 'invite': function( params, sender ) {
if ( params.length == 1 ) { if ( params.length == 1 ) {
sender.sendMessage( 'You must provide a player name' ); echo( sender, 'You must provide a player name' );
return; return;
} }
var playerName = params[1]; var playerName = params[1];
var guest = utils.player( playerName ); var guest = utils.player( playerName );
if ( !guest ) { if ( !guest ) {
sender.sendMessage( playerName + ' is not here' ); echo( sender, playerName + ' is not here' );
} else { } else {
homes.invite( sender, guest ); homes.invite( sender, guest );
} }
@ -333,13 +333,13 @@ var options = {
'uninvite': function( params, sender ) { 'uninvite': function( params, sender ) {
if ( params.length == 1 ) { if ( params.length == 1 ) {
sender.sendMessage( 'You must provide a player name' ); echo( sender, 'You must provide a player name' );
return; return;
} }
var playerName = params[1]; var playerName = params[1];
var guest = utils.player( playerName ); var guest = utils.player( playerName );
if ( !guest ) { if ( !guest ) {
sender.sendMessage( playerName + ' is not here' ); echo( sender, playerName + ' is not here' );
} else { } else {
homes.uninvite( sender, guest ); homes.uninvite( sender, guest );
} }
@ -347,25 +347,25 @@ var options = {
'public': function( params, sender ) { 'public': function( params, sender ) {
homes.open( sender, params.slice( 1 ).join(' ') ); 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 ) { 'private': function( params, sender ) {
homes.close( 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 ) { 'listall': function( params, sender ) {
if ( !sender.isOp() ) { if ( !sender.isOp() ) {
sender.sendMessage( 'Only operators can do this' ); echo( sender, 'Only operators can do this' );
} else { } else {
sender.sendMessage( homes.listall().join(', ') ); echo( sender, homes.listall().join(', ') );
} }
}, },
'clear': function( params, sender ) { 'clear': function( params, sender ) {
if ( !sender.isOp() ) { if ( !sender.isOp() ) {
sender.sendMessage( 'Only operators can do this' ); echo( sender, 'Only operators can do this' );
} else { } else {
homes.clear( params[1], sender ); homes.clear( params[1], sender );
} }
@ -393,7 +393,7 @@ command( 'home', function ( params , sender) {
} else { } else {
host = utils.player( params[0] ); host = utils.player( params[0] );
if ( !host ) { if ( !host ) {
sender.sendMessage( params[0] + ' is not here' ); echo( sender, params[0] + ' is not here' );
} else { } else {
homes.go( sender, host ); homes.go( sender, host );
} }

View file

@ -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 = {}, var store = {},
bkBukkit = org.bukkit.Bukkit, bkBukkit = org.bukkit.Bukkit,
bkCow = org.bukkit.entity.Cow, bkCow = org.bukkit.entity.Cow,
@ -122,7 +126,7 @@ var _addPlayer = function( player, score ) {
store[ player.name ] = { score: score }; store[ player.name ] = { score: score };
scoreboard.update( 'cowclicker', player, store[ player.name ].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 ) { var _removePlayer = function( player, notify ) {
@ -144,8 +148,8 @@ var _removePlayer = function( player, notify ) {
delete store[ player.name ]; delete store[ player.name ];
if ( notify && player ) { if ( notify && player ) {
player.sendMessage( 'You clicked ' + playerScore + ' cows! ' + echo( player, 'You clicked ' + playerScore + ' cows! ' +
'You must be tired after all that clicking.' ); 'You must be tired after all that clicking.' );
} }
}; };

View file

@ -12,38 +12,40 @@ var signs = require('signs');
// //
var onDinnerChoice = function(event){ 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){ 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 = { exports.signs = {
menu_food: function(cmdSender){ menu_food: function(cmdSender){
var sign = signs.getTargetedBy(cmdSender); var sign = signs.getTargetedBy(cmdSender);
if (!sign){ if (!sign){
throw new Error('You must look at an existing 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);
} }
} 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);
}
};

View file

@ -16,26 +16,37 @@ press TAB. Visit
for a list of possible entities (creatures) which can be spawned. for a list of possible entities (creatures) which can be spawned.
***/ ***/
var entities = [], var entities = [];
bkEntityType = org.bukkit.entity.EntityType; var entityType = null;
if (__plugin.canary){
var entitytypes = bkEntityType.values(); entityType = Packages.net.canarymod.api.entity.EntityType;
}else {
entityType = org.bukkit.entity.EntityType;
}
var entitytypes = entityType.values();
for ( var t in entitytypes ) { for ( var t in entitytypes ) {
if ( entitytypes[t] && entitytypes[t].ordinal ) { if ( entitytypes[t] && entitytypes[t].ordinal ) {
entities.push(entitytypes[t].name()); entities.push(entitytypes[t].name());
} }
} }
command( 'spawn', function( parameters, sender ) { command( 'spawn', function( parameters, sender ) {
if ( !sender.op ) { if ( !isOp(sender) ) {
sender.sendMessage( 'Only operators can perform this command' ); echo( sender, 'Only operators can perform this command' );
return; return;
} }
var location = sender.location; var location = sender.location;
if ( !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; return;
} }
var world = location.world; var world = location.world || sender.world;
var type = ('' + parameters[0]).toUpperCase(); 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 ); }, entities );

View file

@ -0,0 +1,4 @@
main-class = org.scriptcraftjs.canarymod.ScriptCraftPlugin
isLibrary = false
author = walter higgins
version = 2.1.10

View file

@ -7,12 +7,12 @@ var __scboot = null;
FileReader = java.io.FileReader, FileReader = java.io.FileReader,
FileOutputStream = java.io.FileOutputStream, FileOutputStream = java.io.FileOutputStream,
ZipInputStream = java.util.zip.ZipInputStream, ZipInputStream = java.util.zip.ZipInputStream,
jsPlugins = new File('plugins/scriptcraft'), //jsPlugins = new File('plugins/scriptcraft'),
jsPlugins = new File('scriptcraft'),
initScript = 'lib/scriptcraft.js'; initScript = 'lib/scriptcraft.js';
var unzip = function(path, logger, plugin) { var unzip = function(zis, logger) {
var zis = new ZipInputStream(plugin.getResource(path)), var entry,
entry,
reason = null, reason = null,
unzipFile = false, unzipFile = false,
zTime = 0, zTime = 0,
@ -57,14 +57,13 @@ var __scboot = null;
/* /*
Called from Java plugin Called from Java plugin
*/ */
__scboot = function ( plugin, engine ) __scboot = function ( plugin, engine, classLoader )
{ {
var logger = plugin.logger, var logger = plugin.logman,
cfg = plugin.config,
cfgName,
initScriptFile = new File(jsPlugins,initScript), initScriptFile = new File(jsPlugins,initScript),
zips = ['lib','plugins','modules'], zips = ['lib','plugins','modules'],
i = 0, i = 0,
zis,
len = zips.length; len = zips.length;
if (!jsPlugins.exists()){ if (!jsPlugins.exists()){
@ -74,14 +73,25 @@ var __scboot = null;
} }
for (i = 0; i < len;i++){ for (i = 0; i < len;i++){
cfgName = 'extract-js.' + zips[i]; if ( plugin.canary ) {
if (cfg.getBoolean(cfgName)){ zis = new ZipInputStream(classLoader.getResourceAsStream(zips[i] + '.zip'));
unzip( zips[i] + '.zip',logger,plugin); 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(); if (plugin.bukkit) {
plugin.saveDefaultConfig();
engine.eval(new FileReader(initScriptFile)); }
__onEnable(engine, plugin, initScriptFile); try {
engine.eval(new FileReader(initScriptFile));
__onEnable(engine, plugin, initScriptFile);
}catch ( e ){
logger.error('Error evaluating ' + initScriptFile + ': ' + e);
throw e;
}
}; };
})(); })();