2014-01-02 19:46:46 +01:00
|
|
|
'use strict';
|
2013-02-10 14:42:32 +01:00
|
|
|
/************************************************************************
|
2013-02-10 18:52:37 +01:00
|
|
|
|
2013-12-24 11:02:34 +01:00
|
|
|
## Modules in Scriptcraft
|
|
|
|
|
|
|
|
ScriptCraft has a simple module loading system. In ScriptCraft, files
|
|
|
|
and modules are in one-to-one correspondence. As an example, foo.js
|
|
|
|
loads the module circle.js in the same directory.
|
|
|
|
*ScriptCraft now uses the same module system as Node.js - see [Node.js Modules][njsmod] for more details.*
|
|
|
|
|
|
|
|
[njsmod]: http://nodejs.org/api/modules.html
|
|
|
|
|
|
|
|
The contents of foo.js:
|
|
|
|
|
2014-02-04 22:36:00 +01:00
|
|
|
```javascript
|
|
|
|
var circle = require('./circle.js');
|
|
|
|
console.log( 'The area of a circle of radius 4 is '
|
|
|
|
+ circle.area(4));
|
|
|
|
```
|
2013-12-24 11:02:34 +01:00
|
|
|
|
|
|
|
The contents of circle.js:
|
|
|
|
|
2014-02-04 22:36:00 +01:00
|
|
|
```javascript
|
|
|
|
var PI = Math.PI;
|
|
|
|
exports.area = function (r) {
|
|
|
|
return PI * r * r;
|
|
|
|
};
|
|
|
|
exports.circumference = function (r) {
|
|
|
|
return 2 * PI * r;
|
|
|
|
};
|
|
|
|
```
|
2013-12-24 11:02:34 +01:00
|
|
|
|
|
|
|
The module circle.js has exported the functions area() and
|
|
|
|
circumference(). To add functions and objects to the root of your
|
|
|
|
module, you can add them to the special exports object.
|
|
|
|
|
|
|
|
Variables local to the module will be private, as though the module
|
|
|
|
was wrapped in a function. In this example the variable PI is private
|
|
|
|
to circle.js.
|
|
|
|
|
|
|
|
If you want the root of your module's export to be a function (such as
|
|
|
|
a constructor) or if you want to export a complete object in one
|
|
|
|
assignment instead of building it one property at a time, assign it to
|
|
|
|
module.exports instead of exports.
|
|
|
|
|
2013-12-18 00:49:00 +01:00
|
|
|
## Module Loading
|
|
|
|
|
2013-12-24 11:02:34 +01:00
|
|
|
When the ScriptCraft Java plugin is first installed, a new
|
2014-01-02 19:46:46 +01:00
|
|
|
subdirectory is created in the craftbukkit/plugins directory. If your
|
2013-12-24 11:02:34 +01:00
|
|
|
craftbukkit directory is called 'craftbukkit' then the new
|
|
|
|
subdirectories will be ...
|
|
|
|
|
2014-01-02 19:46:46 +01:00
|
|
|
* craftbukkit/plugins/scriptcraft/
|
|
|
|
* craftbukkit/plugins/scriptcraft/plugins
|
|
|
|
* craftbukkit/plugins/scriptcraft/modules
|
|
|
|
* craftbukkit/plugins/scriptcraft/lib
|
2013-12-24 11:02:34 +01:00
|
|
|
|
|
|
|
... The `plugins`, `modules` and `lib` directories each serve a different purpose.
|
|
|
|
|
2013-12-24 23:47:57 +01:00
|
|
|
### The plugins directory
|
2013-12-24 11:02:34 +01:00
|
|
|
|
|
|
|
At server startup the ScriptCraft Java plugin is loaded and begins
|
|
|
|
automatically loading and executing all of the modules (javascript
|
|
|
|
files with the extension `.js`) it finds in the `scriptcraft/plugins`
|
|
|
|
directory. All modules in the plugins directory are automatically
|
|
|
|
loaded into the `global` namespace. What this means is that anything a
|
|
|
|
module in the `plugins` directory exports becomes a global
|
|
|
|
variable. For example, if you have a module greeting.js in the plugins
|
|
|
|
directory....
|
|
|
|
|
2014-02-04 22:36:00 +01:00
|
|
|
```javascript
|
|
|
|
exports.greet = function(player) {
|
|
|
|
player.sendMessage('Hello ' + player.name);
|
|
|
|
};
|
|
|
|
```
|
2013-12-24 11:02:34 +01:00
|
|
|
|
|
|
|
... then `greet` becomes a global function and can be used at the
|
|
|
|
in-game (or server) command prompt like so...
|
|
|
|
|
2013-12-30 22:33:12 +01:00
|
|
|
/js greet(self)
|
2013-12-24 11:02:34 +01:00
|
|
|
|
|
|
|
... This differs from how modules (in NodeJS and commonJS
|
|
|
|
environments) normally work. If you want your module to be exported
|
|
|
|
globally, put it in the `plugins` directory. If you don't want your
|
|
|
|
module to be exported globally but only want it to be used by other
|
|
|
|
modules, then put it in the `modules` directory instead. If you've
|
|
|
|
used previous versions of ScriptCraft and have put your custom
|
|
|
|
javascript modules in the `js-plugins` directory, then put them in the
|
|
|
|
`scriptcraft/plugins` directory. To summarise, modules in this directory are ...
|
|
|
|
|
|
|
|
* Automatically loaded and run at server startup.
|
|
|
|
* Anything exported by modules becomes a global variable.
|
|
|
|
|
2013-12-24 23:47:57 +01:00
|
|
|
### The modules directory
|
2013-12-24 11:02:34 +01:00
|
|
|
|
|
|
|
The module directory is where you should place your modules if you
|
|
|
|
don't want to export globally. In javascript, it's considered best
|
|
|
|
practice not to have too many global variables, so if you want to
|
|
|
|
develop modules for others to use, or want to develop more complex
|
|
|
|
mods then your modules should be placed in the `modules` directory.
|
|
|
|
*Modules in the `modules` directory are not automatically loaded at
|
|
|
|
startup*, instead, they are loaded and used by other modules/plugins
|
|
|
|
using the standard `require()` function. This is the key difference
|
|
|
|
between modules in the `plugins` directory and modules in the
|
|
|
|
`modules` directory. Modules in the `plugins` directory are
|
|
|
|
automatically loaded and exported in to the global namespace at server
|
|
|
|
startup, modules in the `modules` directory are not.
|
|
|
|
|
2013-12-24 23:47:57 +01:00
|
|
|
### The lib directory
|
2013-12-24 11:02:34 +01:00
|
|
|
|
|
|
|
Modules in the `lib` directory are for use by ScriptCraft and some
|
|
|
|
core functions for use by module and plugin developers are also
|
|
|
|
provided. The `lib` directory is for internal use by ScriptCraft.
|
|
|
|
Modules in this directory are not automatically loaded nor are they
|
|
|
|
globally exported.
|
2013-02-10 20:36:39 +01:00
|
|
|
|
2013-12-28 09:44:40 +01:00
|
|
|
### plugins sub-directories
|
2013-12-18 00:49:00 +01:00
|
|
|
|
2013-12-24 11:02:34 +01:00
|
|
|
As of December 24 2013, the `scriptcraft/plugins` directory has the following sub-directories...
|
2013-02-10 20:36:39 +01:00
|
|
|
|
|
|
|
* drone - Contains the drone module and drone extensions. Drone was the first scriptcraft module.
|
|
|
|
* mini-games - Contains mini-games
|
2013-12-28 09:44:40 +01:00
|
|
|
* arrows - The arrows module - Changes the behaviour of Arrows: Explosive, Fireworks, Teleportation etc.
|
|
|
|
* signs - The signs module (includes example signs) - create interactive signs.
|
|
|
|
* chat - The chat plugin/module
|
|
|
|
* alias - The alias plugin/module - for creating custom aliases for commonly used commands.
|
2013-12-24 11:02:34 +01:00
|
|
|
* home - The home module - for setting homes and visiting other homes.
|
2013-02-10 20:36:39 +01:00
|
|
|
|
2013-12-28 23:49:13 +01:00
|
|
|
## Global variables
|
|
|
|
|
|
|
|
There are a couple of special javascript variables available in ScriptCraft...
|
|
|
|
|
|
|
|
### __plugin variable
|
|
|
|
The ScriptCraft JavaPlugin object.
|
|
|
|
|
|
|
|
### server variable
|
|
|
|
The Minecraft Server object
|
|
|
|
|
|
|
|
### self variable
|
2013-12-30 22:33:12 +01:00
|
|
|
The current player. (Note - this value should not be used in
|
|
|
|
multi-threaded scripts or event-handling code - it's not
|
|
|
|
thread-safe). This variable is only safe to use at the in-game prompt
|
|
|
|
and should *never* be used in modules. For example you can use it here...
|
|
|
|
|
|
|
|
/js console.log(self.name)
|
|
|
|
|
|
|
|
... but not in any javascript module you create yourself or in any
|
|
|
|
event handling code. `self` is a temporary short-lived variable which
|
|
|
|
only exists in the context of the in-game or server command prompts.
|
2013-12-28 23:49:13 +01:00
|
|
|
|
|
|
|
### config variable
|
|
|
|
ScriptCraft configuration - this object is loaded and saved at startup/shutdown.
|
|
|
|
|
|
|
|
### events variable
|
|
|
|
The events object is used to add new event handlers to Minecraft.
|
|
|
|
|
|
|
|
## Module variables
|
|
|
|
The following variables are available only within the context of Modules. (not available at in-game prompt).
|
|
|
|
|
2014-01-04 19:39:49 +01:00
|
|
|
### __filename variable
|
2013-12-28 23:49:13 +01:00
|
|
|
The current file - this variable is only relevant from within the context of a Javascript module.
|
|
|
|
|
2014-01-04 19:39:49 +01:00
|
|
|
### __dirname variable
|
2013-12-28 23:49:13 +01:00
|
|
|
The current directory - this variable is only relevant from within the context of a Javascript module.
|
|
|
|
|
2013-12-28 09:44:40 +01:00
|
|
|
## Global functions
|
|
|
|
|
|
|
|
ScripCraft provides some global functions which can be used by all plugins/modules...
|
|
|
|
|
|
|
|
### echo function
|
|
|
|
|
2013-12-28 23:49:13 +01:00
|
|
|
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).
|
2013-12-28 09:44:40 +01:00
|
|
|
|
2014-01-04 19:39:49 +01:00
|
|
|
#### Example
|
2013-12-28 09:44:40 +01:00
|
|
|
|
|
|
|
/js echo('Hello World')
|
2013-12-18 00:49:00 +01:00
|
|
|
|
2013-12-28 23:49:13 +01:00
|
|
|
For programmers familiar with Javascript web programming, an `alert`
|
|
|
|
function is also provided. `alert` works exactly the same as `echo`
|
|
|
|
e.g. `alert('Hello World')`.
|
|
|
|
|
2014-01-04 19:39:49 +01:00
|
|
|
#### Notes
|
2013-12-24 01:17:07 +01:00
|
|
|
|
2013-12-28 23:49:13 +01:00
|
|
|
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.
|
|
|
|
|
2014-01-04 19:39:49 +01:00
|
|
|
[plsm]: http://jd.bukkit.org/dev/apidocs/org/bukkit/command/CommandSender.html#sendMessage(java.lang.String)
|
2013-12-18 00:49:00 +01:00
|
|
|
|
2013-12-24 11:02:34 +01:00
|
|
|
### require() function
|
|
|
|
|
2013-12-28 23:49:13 +01:00
|
|
|
ScriptCraft's `require()` function is used to load modules. The
|
|
|
|
`require()` function takes a module name as a parameter and will try
|
|
|
|
to load the named module.
|
2013-12-24 11:02:34 +01:00
|
|
|
|
|
|
|
#### Parameters
|
|
|
|
|
|
|
|
* modulename - The name of the module to be loaded. Can be one of the following...
|
|
|
|
|
|
|
|
- A relative file path (with or without `.js` suffix)
|
|
|
|
- An absolute file path (with or without `.js` suffix)
|
|
|
|
- A relative directory path (uses node.js rules for directories)
|
|
|
|
- An absolute directory path (uses node.js rules for directories)
|
|
|
|
- A name of the form `'events'` - in which case the `lib` directory and `modules` directories are searched for the module.
|
|
|
|
|
|
|
|
#### Return
|
|
|
|
|
|
|
|
require() will return the loaded module's exports.
|
|
|
|
|
2014-01-13 22:06:17 +01:00
|
|
|
### scload() function
|
2013-12-24 11:02:34 +01:00
|
|
|
|
|
|
|
#### No longer recommended for use by Plugin/Module developers (deprecated)
|
2013-02-10 14:42:32 +01:00
|
|
|
|
2014-01-13 22:06:17 +01:00
|
|
|
scload() should only be used to load .json data.
|
2013-02-10 20:36:39 +01:00
|
|
|
|
2013-12-18 00:49:00 +01:00
|
|
|
#### Parameters
|
2013-02-10 20:36:39 +01:00
|
|
|
|
2013-12-18 00:49:00 +01:00
|
|
|
* filename - The name of the file to load.
|
2013-02-10 20:36:39 +01:00
|
|
|
* warnOnFileNotFound (optional - default: false) - warn if the file was not found.
|
|
|
|
|
2013-12-28 09:44:40 +01:00
|
|
|
#### Returns
|
2013-12-18 00:49:00 +01:00
|
|
|
|
2014-01-13 22:06:17 +01:00
|
|
|
scload() will return the result of the last statement evaluated in the file.
|
2013-02-10 20:36:39 +01:00
|
|
|
|
2013-12-18 00:49:00 +01:00
|
|
|
#### Example
|
2013-02-10 20:36:39 +01:00
|
|
|
|
2014-01-13 22:06:17 +01:00
|
|
|
scload("myFile.js"); // loads a javascript file and evaluates it.
|
2013-02-10 20:36:39 +01:00
|
|
|
|
2014-01-13 22:06:17 +01:00
|
|
|
var myData = scload("myData.json"); // loads a javascript file and evaluates it - eval'd contents are returned.
|
2013-02-10 20:36:39 +01:00
|
|
|
|
2014-01-04 19:39:49 +01:00
|
|
|
##### myData.json contents...
|
2013-02-10 20:36:39 +01:00
|
|
|
|
2014-01-04 19:39:49 +01:00
|
|
|
{ players: {
|
|
|
|
walterh: {
|
|
|
|
h: ["jsp home {1}"],
|
|
|
|
sunny:["time set 0",
|
|
|
|
"weather clear"]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-12-18 00:49:00 +01:00
|
|
|
|
2014-01-13 22:06:17 +01:00
|
|
|
### scsave() function
|
2013-12-18 00:49:00 +01:00
|
|
|
|
2014-01-13 22:06:17 +01:00
|
|
|
The scsave() function saves an in-memory javascript object to a
|
|
|
|
specified file. Under the hood, scsave() uses JSON (specifically
|
2013-02-17 18:43:28 +01:00
|
|
|
json2.js) to save the object. Again, there will usually be no need to
|
|
|
|
call this function directly as all javascript plugins' state are saved
|
|
|
|
automatically if they are declared using the `plugin()` function. Any
|
2014-01-13 22:06:17 +01:00
|
|
|
in-memory object saved using the `scsave()` function can later be
|
|
|
|
restored using the `scload()` function.
|
2013-02-17 18:43:28 +01:00
|
|
|
|
2013-12-18 00:49:00 +01:00
|
|
|
#### Parameters
|
2013-02-17 18:43:28 +01:00
|
|
|
|
|
|
|
* objectToSave : The object you want to save.
|
|
|
|
* filename : The name of the file you want to save it to.
|
|
|
|
|
2013-12-18 00:49:00 +01:00
|
|
|
#### Example
|
2013-02-17 18:43:28 +01:00
|
|
|
|
2014-02-04 22:36:00 +01:00
|
|
|
```javascript
|
|
|
|
var myObject = { name: 'John Doe',
|
|
|
|
aliases: ['John Ray', 'John Mee'],
|
|
|
|
date_of_birth: '1982/01/31' };
|
|
|
|
scsave(myObject, 'johndoe.json');
|
|
|
|
```
|
2013-02-17 18:43:28 +01:00
|
|
|
|
2014-01-04 19:39:49 +01:00
|
|
|
##### johndoe.json contents...
|
2013-02-17 18:43:28 +01:00
|
|
|
|
2014-01-04 19:39:49 +01:00
|
|
|
{ "name": "John Doe",
|
|
|
|
"aliases": ["John Ray", "John Mee"],
|
|
|
|
"date_of_birth": "1982/01/31"
|
|
|
|
};
|
2013-02-17 18:43:28 +01:00
|
|
|
|
2013-12-18 00:49:00 +01:00
|
|
|
### plugin() function
|
|
|
|
|
2013-02-17 18:43:28 +01:00
|
|
|
The `plugin()` function should be used to declare a javascript module
|
|
|
|
whose state you want to have managed by ScriptCraft - that is - a
|
|
|
|
Module whose state will be loaded at start up and saved at shut down.
|
|
|
|
A plugin is just a regular javascript object whose state is managed by
|
|
|
|
ScriptCraft. The only member of the plugin which whose persistence is
|
2013-12-24 01:17:07 +01:00
|
|
|
managed by Scriptcraft is `store` - this special member will be
|
2013-02-17 18:43:28 +01:00
|
|
|
automatically saved at shutdown and loaded at startup by
|
|
|
|
ScriptCraft. This makes it easier to write plugins which need to
|
|
|
|
persist data.
|
|
|
|
|
2013-12-18 00:49:00 +01:00
|
|
|
#### Parameters
|
2013-02-17 18:43:28 +01:00
|
|
|
|
|
|
|
* pluginName (String) : The name of the plugin - this becomes a global variable.
|
|
|
|
* pluginDefinition (Object) : The various functions and members of the plugin object.
|
2013-12-28 23:49:13 +01:00
|
|
|
* isPersistent (boolean - optional) : Specifies whether or not the
|
|
|
|
plugin/object state should be loaded and saved by ScriptCraft.
|
2013-02-17 18:43:28 +01:00
|
|
|
|
2013-12-18 00:49:00 +01:00
|
|
|
#### Example
|
|
|
|
|
2013-02-17 18:43:28 +01:00
|
|
|
See chat/color.js for an example of a simple plugin - one which lets
|
|
|
|
players choose a default chat color. See also [Anatomy of a
|
|
|
|
ScriptCraft Plugin][anatomy].
|
|
|
|
|
2014-01-02 19:46:46 +01:00
|
|
|
[anatomy]: ./Anatomy-of-a-Plugin.md
|
2013-02-17 18:43:28 +01:00
|
|
|
|
2013-12-18 00:49:00 +01:00
|
|
|
### command() function
|
|
|
|
|
2013-02-17 18:43:28 +01:00
|
|
|
The `command()` function is used to expose javascript functions for
|
|
|
|
use by non-operators (regular players). Only operators should be
|
|
|
|
allowed use raw javascript using the `/js ` command because it is too
|
|
|
|
powerful for use by regular players and can be easily abused. However,
|
|
|
|
the `/jsp ` command lets you (the operator / server administrator /
|
|
|
|
plugin author) safely expose javascript functions for use by players.
|
|
|
|
|
2013-12-18 00:49:00 +01:00
|
|
|
#### Parameters
|
2013-02-17 18:43:28 +01:00
|
|
|
|
2014-01-02 19:46:46 +01:00
|
|
|
* commandName : The name to give your command - the command will
|
|
|
|
be invoked like this by players `/jsp commandName`
|
|
|
|
* commandFunction: The javascript function which will be invoked when
|
|
|
|
the command is invoked by a player. The callback function in turn
|
|
|
|
takes 2 parameters...
|
|
|
|
|
|
|
|
* params : An Array of type String - the list of parameters
|
|
|
|
passed to the command.
|
|
|
|
* sender : The [CommandSender][bukcs] object that invoked the
|
|
|
|
command (this is usually a Player object but can be a Block
|
|
|
|
([BlockCommandSender][bukbcs]).
|
|
|
|
|
2013-02-17 18:43:28 +01:00
|
|
|
* options (Array - optional) : An array of command options/parameters
|
|
|
|
which the player can supply (It's useful to supply an array so that
|
|
|
|
Tab-Completion works for the `/jsp ` commands.
|
|
|
|
* intercepts (boolean - optional) : Indicates whether this command
|
|
|
|
can intercept Tab-Completion of the `/jsp ` command - advanced
|
|
|
|
usage - see alias/alias.js for example.
|
|
|
|
|
2013-12-18 00:49:00 +01:00
|
|
|
#### Example
|
|
|
|
|
2013-12-28 23:49:13 +01:00
|
|
|
See chat/colors.js or alias/alias.js or homes/homes.js for examples of
|
|
|
|
how to use the `command()` function.
|
2013-02-17 18:43:28 +01:00
|
|
|
|
2013-12-28 23:49:13 +01:00
|
|
|
### setTimeout() function
|
2013-10-13 22:08:31 +02:00
|
|
|
|
2013-12-28 23:49:13 +01:00
|
|
|
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.
|
2013-10-13 22:08:31 +02:00
|
|
|
|
2013-12-28 23:49:13 +01:00
|
|
|
If Node.js supports setTimeout() then it's probably good for ScriptCraft to support it too.
|
2013-02-17 18:43:28 +01:00
|
|
|
|
2013-12-28 23:49:13 +01:00
|
|
|
[btdoc]: http://jd.bukkit.org/beta/apidocs/org/bukkit/scheduler/BukkitTask.html
|
2013-12-28 09:44:40 +01:00
|
|
|
|
2013-12-28 23:49:13 +01:00
|
|
|
#### Example
|
|
|
|
|
2014-02-04 22:36:00 +01:00
|
|
|
```javascript
|
|
|
|
//
|
|
|
|
// start a storm in 5 seconds
|
|
|
|
//
|
|
|
|
setTimeout( function() {
|
|
|
|
var world = server.worlds.get(0);
|
|
|
|
world.setStorm(true);
|
|
|
|
}, 5000);
|
|
|
|
```
|
2013-12-28 23:49:13 +01:00
|
|
|
|
|
|
|
### clearTimeout() function
|
|
|
|
|
|
|
|
A scriptcraft implementation of clearTimeout().
|
|
|
|
|
|
|
|
### setInterval() function
|
|
|
|
|
|
|
|
This function mimics the setInterval() function used in browser-based
|
|
|
|
javascript. However, the function will only accept a function
|
|
|
|
reference, not a string of javascript code. Where setInterval() in
|
|
|
|
the browser returns a numeric value which can be subsequently passed
|
|
|
|
to clearInterval(), This implementation returns a [BukkitTask][btdoc]
|
|
|
|
object which can be subsequently passed to ScriptCraft's own
|
|
|
|
clearInterval() implementation.
|
|
|
|
|
|
|
|
If Node.js supports setInterval() then it's probably good for
|
|
|
|
ScriptCraft to support it too.
|
|
|
|
|
|
|
|
[btdoc]: http://jd.bukkit.org/beta/apidocs/org/bukkit/scheduler/BukkitTask.html
|
|
|
|
|
|
|
|
### clearInterval() function
|
|
|
|
|
|
|
|
A scriptcraft implementation of clearInterval().
|
|
|
|
|
|
|
|
### refresh() function
|
|
|
|
|
2014-01-02 19:46:46 +01:00
|
|
|
The refresh() function can be used to only reload the ScriptCraft
|
|
|
|
plugin (it's like the `reload` command except it only reloads
|
|
|
|
ScriptCraft). The refresh() function will ...
|
2013-12-28 23:49:13 +01:00
|
|
|
|
|
|
|
1. Disable the ScriptCraft plugin.
|
|
|
|
2. Unload all event listeners associated with the ScriptCraft plugin.
|
|
|
|
3. Enable the ScriptCraft plugin.
|
|
|
|
|
|
|
|
... refresh() can be used during development to reload only scriptcraft javascript files.
|
|
|
|
See [issue #69][issue69] for more information.
|
|
|
|
|
|
|
|
[issue69]: https://github.com/walterhiggins/ScriptCraft/issues/69
|
|
|
|
|
|
|
|
### addUnloadHandler() function
|
|
|
|
|
|
|
|
The addUnloadHandler() function takes a callback function as a
|
|
|
|
parameter. The callback will be called when the ScriptCraft plugin is
|
|
|
|
unloaded (usually as a result of a a `reload` command or server
|
|
|
|
shutdown).
|
2013-02-10 14:42:32 +01:00
|
|
|
|
2014-01-02 19:46:46 +01:00
|
|
|
This function provides a way for ScriptCraft modules to do any
|
|
|
|
required cleanup/housekeeping just prior to the ScriptCraft Plugin
|
|
|
|
unloading.
|
|
|
|
|
2013-02-10 14:42:32 +01:00
|
|
|
***/
|
2013-12-28 23:49:13 +01:00
|
|
|
|
2013-01-25 00:47:36 +01:00
|
|
|
/*
|
2013-01-26 18:49:11 +01:00
|
|
|
wph 20130124 - make self, plugin and server public - these are far more useful now that tab-complete works.
|
2013-01-25 00:47:36 +01:00
|
|
|
*/
|
2013-12-28 23:49:13 +01:00
|
|
|
var global = this;
|
2013-01-26 14:47:16 +01:00
|
|
|
var server = org.bukkit.Bukkit.server;
|
2013-12-28 23:49:13 +01:00
|
|
|
/*
|
|
|
|
private implementation
|
|
|
|
*/
|
2014-01-29 20:49:15 +01:00
|
|
|
function __onEnable ( __engine, __plugin, __script )
|
2013-12-30 22:33:12 +01:00
|
|
|
{
|
2014-01-29 20:49:15 +01:00
|
|
|
var File = java.io.File,
|
|
|
|
FileReader = java.io.FileReader,
|
|
|
|
BufferedReader = java.io.BufferedReader,
|
|
|
|
PrintWriter = java.io.PrintWriter,
|
|
|
|
FileWriter = java.io.FileWriter;
|
2014-03-13 23:49:03 +01:00
|
|
|
var debug = function(msg){
|
|
|
|
java.lang.System.out.println('DEBUG:' + msg);
|
|
|
|
};
|
2014-01-29 20:49:15 +01:00
|
|
|
var _canonize = function( file ) {
|
|
|
|
return '' + file.getCanonicalPath().replaceAll( '\\\\', '/' );
|
|
|
|
};
|
|
|
|
// lib (assumes scriptcraft.js is in craftbukkit/plugins/scriptcraft/lib directory
|
|
|
|
var libDir = __script.parentFile,
|
|
|
|
jsPluginsRootDir = libDir.parentFile, // scriptcraft
|
|
|
|
jsPluginsRootDirName = _canonize(jsPluginsRootDir),
|
|
|
|
logger = __plugin.logger;
|
|
|
|
|
|
|
|
/*
|
|
|
|
Save a javascript object to a file (saves using JSON notation)
|
|
|
|
*/
|
|
|
|
var _save = function( object, filename ) {
|
|
|
|
var objectToStr = null,
|
|
|
|
f,
|
|
|
|
out;
|
|
|
|
try {
|
|
|
|
objectToStr = JSON.stringify( object, null, 2 );
|
|
|
|
} catch( e ) {
|
|
|
|
print( 'ERROR: ' + e.getMessage() + ' while saving ' + filename );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
f = (filename instanceof File) ? filename : new File(filename);
|
|
|
|
out = new PrintWriter(new FileWriter(f));
|
|
|
|
out.println( objectToStr );
|
|
|
|
out.close();
|
|
|
|
};
|
|
|
|
/*
|
2014-03-13 23:49:03 +01:00
|
|
|
make sure eval is present: it's present on JRE 6, 7, and 8 on Linux
|
2014-01-29 20:49:15 +01:00
|
|
|
*/
|
|
|
|
if ( typeof eval == 'undefined' ) {
|
|
|
|
global.eval = function( str ) {
|
|
|
|
return __engine.eval( str );
|
2013-12-21 09:58:40 +01:00
|
|
|
};
|
2014-03-13 23:49:03 +01:00
|
|
|
}
|
2014-01-29 20:49:15 +01:00
|
|
|
/*
|
|
|
|
Load the contents of the file and evaluate as javascript
|
|
|
|
*/
|
|
|
|
var _load = function( filename, warnOnFileNotFound )
|
|
|
|
{
|
|
|
|
var result = null,
|
|
|
|
file = filename,
|
|
|
|
r,
|
|
|
|
parent,
|
|
|
|
reader,
|
|
|
|
br,
|
|
|
|
code,
|
|
|
|
wrappedCode;
|
2013-01-13 22:06:46 +01:00
|
|
|
|
2014-01-29 20:49:15 +01:00
|
|
|
if ( !( filename instanceof File ) ) {
|
|
|
|
file = new File(filename);
|
2014-01-13 22:06:17 +01:00
|
|
|
}
|
2014-01-29 20:49:15 +01:00
|
|
|
var canonizedFilename = _canonize( file );
|
2013-12-28 23:49:13 +01:00
|
|
|
|
2014-01-29 20:49:15 +01:00
|
|
|
if ( file.exists() ) {
|
|
|
|
reader = new FileReader( file );
|
|
|
|
br = new BufferedReader( reader );
|
|
|
|
code = '';
|
|
|
|
try {
|
|
|
|
while ( (r = br.readLine()) !== null ) {
|
|
|
|
code += r + '\n';
|
2014-02-10 21:55:32 +01:00
|
|
|
}
|
2014-01-29 20:49:15 +01:00
|
|
|
wrappedCode = '(' + code + ')';
|
|
|
|
result = __engine.eval( wrappedCode );
|
|
|
|
// issue #103 avoid side-effects of || operator on Mac Rhino
|
|
|
|
} catch ( e ) {
|
|
|
|
logger.severe( 'Error evaluating ' + canonizedFilename + ', ' + e );
|
|
|
|
}
|
|
|
|
finally {
|
|
|
|
try {
|
|
|
|
reader.close();
|
|
|
|
} catch ( re ) {
|
|
|
|
// fail silently on reader close error
|
2013-12-24 01:17:07 +01:00
|
|
|
}
|
2014-01-29 20:49:15 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( warnOnFileNotFound ) {
|
|
|
|
logger.warning( canonizedFilename + ' not found' );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
};
|
|
|
|
/*
|
|
|
|
now that load is defined, use it to load a global config object
|
|
|
|
*/
|
2014-02-16 19:29:15 +01:00
|
|
|
var configFile = new File(jsPluginsRootDir, 'data/');
|
|
|
|
configFile.mkdirs();
|
|
|
|
configFile = new File(configFile,'global-config.json');
|
|
|
|
var config = _load( configFile );
|
2014-01-29 20:49:15 +01:00
|
|
|
if ( !config ) {
|
|
|
|
config = { verbose: false };
|
|
|
|
}
|
|
|
|
global.config = config;
|
|
|
|
global.__plugin = __plugin;
|
|
|
|
/*
|
|
|
|
wph 20131229 Issue #103 JSON is not bundled with javax.scripting / Rhino on Mac.
|
|
|
|
*/
|
|
|
|
(function(){
|
|
|
|
var jsonFileReader = new FileReader( new File( jsPluginsRootDirName + '/lib/json2.js' ) );
|
|
|
|
var jsonLoaded = __engine['eval(java.io.Reader)']( jsonFileReader );
|
|
|
|
}());
|
|
|
|
|
|
|
|
/*
|
|
|
|
Unload Handlers
|
|
|
|
*/
|
|
|
|
var unloadHandlers = [];
|
|
|
|
var _addUnloadHandler = function( f ) {
|
|
|
|
unloadHandlers.push( f );
|
|
|
|
};
|
|
|
|
var _runUnloadHandlers = function() {
|
|
|
|
for ( var i = 0; i < unloadHandlers.length; i++ ) {
|
|
|
|
unloadHandlers[i]( );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
global.addUnloadHandler = _addUnloadHandler;
|
|
|
|
|
|
|
|
|
|
|
|
global.refresh = function( ) {
|
2014-03-08 22:01:25 +01:00
|
|
|
if ( typeof self !== 'undefined' ) {
|
|
|
|
if ( !self.op ) {
|
|
|
|
self.sendMessage('Only operators can refresh()');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2014-01-29 20:49:15 +01:00
|
|
|
__plugin.pluginLoader.disablePlugin( __plugin );
|
|
|
|
__plugin.pluginLoader.enablePlugin( __plugin );
|
|
|
|
};
|
|
|
|
|
|
|
|
var _echo = function ( msg ) {
|
|
|
|
if ( typeof self == 'undefined' ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
self.sendMessage( msg );
|
|
|
|
};
|
|
|
|
|
|
|
|
global.echo = _echo;
|
|
|
|
global.alert = _echo;
|
|
|
|
global.scload = _load;
|
|
|
|
global.scsave = _save;
|
|
|
|
|
|
|
|
var configRequire = _load( jsPluginsRootDirName + '/lib/require.js', true );
|
|
|
|
/*
|
|
|
|
setup paths to search for modules
|
|
|
|
*/
|
|
|
|
var modulePaths = [ jsPluginsRootDirName + '/lib/',
|
2014-02-10 21:55:32 +01:00
|
|
|
jsPluginsRootDirName + '/modules/' ];
|
2014-01-29 20:49:15 +01:00
|
|
|
|
|
|
|
if ( config.verbose ) {
|
|
|
|
logger.info( 'Setting up CommonJS-style module system. Root Directory: ' + jsPluginsRootDirName );
|
|
|
|
logger.info( 'Module paths: ' + JSON.stringify(modulePaths) );
|
|
|
|
}
|
|
|
|
var requireHooks = {
|
|
|
|
loading: function( path ) {
|
|
|
|
if ( config.verbose ) {
|
|
|
|
logger.info( 'loading ' + path );
|
|
|
|
}
|
|
|
|
},
|
|
|
|
loaded: function( path ) {
|
|
|
|
if ( config.verbose ) {
|
|
|
|
logger.info( 'loaded ' + path );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2014-03-13 23:49:03 +01:00
|
|
|
global.require = configRequire(
|
|
|
|
jsPluginsRootDirName,
|
|
|
|
modulePaths,
|
|
|
|
requireHooks,
|
2014-03-14 23:23:35 +01:00
|
|
|
function( code ) {
|
|
|
|
return __engine.eval( code );
|
2014-03-13 23:49:03 +01:00
|
|
|
}
|
|
|
|
);
|
2014-01-29 20:49:15 +01:00
|
|
|
|
|
|
|
require('js-patch')( global );
|
|
|
|
global.console = require('console');
|
|
|
|
/*
|
|
|
|
setup persistence
|
|
|
|
*/
|
|
|
|
require('persistence')( jsPluginsRootDir, global );
|
|
|
|
|
|
|
|
var cmdModule = require('command');
|
|
|
|
global.command = cmdModule.command;
|
|
|
|
var plugins = require('plugin');
|
|
|
|
global.__onTabComplete = require('tabcomplete');
|
|
|
|
global.plugin = plugins.plugin;
|
|
|
|
|
|
|
|
var events = require('events');
|
2014-03-15 19:06:23 +01:00
|
|
|
events.on( 'server.PluginDisableEvent', function( evt ) {
|
2014-01-29 20:49:15 +01:00
|
|
|
// save config
|
|
|
|
_save( global.config, new File( jsPluginsRootDir, 'data/global-config.json' ) );
|
|
|
|
|
|
|
|
_runUnloadHandlers();
|
|
|
|
org.bukkit.event.HandlerList['unregisterAll(org.bukkit.plugin.Plugin)'](__plugin);
|
|
|
|
});
|
|
|
|
// wph 20131226 - make events global as it is used by many plugins/modules
|
|
|
|
global.events = events;
|
|
|
|
|
|
|
|
|
|
|
|
global.__onCommand = function( sender, cmd, label, args) {
|
2014-02-10 21:55:32 +01:00
|
|
|
var jsArgs = [],
|
|
|
|
i = 0,
|
|
|
|
jsResult,
|
|
|
|
result,
|
|
|
|
cmdName,
|
|
|
|
fnBody;
|
2014-01-29 20:49:15 +01:00
|
|
|
for ( ; i < args.length ; i++ ) {
|
|
|
|
jsArgs.push( '' + args[i] );
|
|
|
|
}
|
2013-12-27 23:52:16 +01:00
|
|
|
|
2014-02-10 21:55:32 +01:00
|
|
|
result = false;
|
|
|
|
cmdName = ( '' + cmd.name ).toLowerCase();
|
2014-01-29 20:49:15 +01:00
|
|
|
if (cmdName == 'js')
|
|
|
|
{
|
|
|
|
result = true;
|
2014-02-10 21:55:32 +01:00
|
|
|
fnBody = jsArgs.join(' ');
|
2014-01-29 20:49:15 +01:00
|
|
|
global.self = sender;
|
|
|
|
global.__engine = __engine;
|
|
|
|
try {
|
2014-03-11 20:57:40 +01:00
|
|
|
jsResult = __engine.eval(fnBody);
|
2014-02-10 21:55:32 +01:00
|
|
|
if ( typeof jsResult != 'undefined' ) {
|
|
|
|
if ( jsResult == null) {
|
|
|
|
sender.sendMessage('(null)');
|
|
|
|
} else {
|
|
|
|
sender.sendMessage(jsResult);
|
|
|
|
}
|
|
|
|
}
|
2014-01-29 20:49:15 +01:00
|
|
|
} catch ( e ) {
|
|
|
|
logger.severe( 'Error while trying to evaluate javascript: ' + fnBody + ', Error: '+ e );
|
2014-02-10 21:55:32 +01:00
|
|
|
sender.sendMessage( 'Error while trying to evaluate javascript: ' + fnBody + ', Error: '+ e );
|
2014-01-29 20:49:15 +01:00
|
|
|
throw e;
|
|
|
|
} finally {
|
2014-03-11 20:57:40 +01:00
|
|
|
/*
|
|
|
|
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;
|
|
|
|
}
|
2014-01-29 20:49:15 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( cmdName == 'jsp' ) {
|
|
|
|
cmdModule.exec( jsArgs, sender );
|
|
|
|
result = true;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
};
|
2013-10-09 19:42:39 +02:00
|
|
|
|
2014-02-10 21:55:32 +01:00
|
|
|
plugins.autoload( global, new File(jsPluginsRootDir,'plugins'), logger );
|
2013-12-25 08:48:10 +01:00
|
|
|
/*
|
2014-01-29 20:49:15 +01:00
|
|
|
wph 20140102 - warn if legacy 'craftbukkit/js-plugins' or 'craftbukkit/scriptcraft' directories are present
|
2013-12-25 08:48:10 +01:00
|
|
|
*/
|
2014-01-29 20:49:15 +01:00
|
|
|
(function(){
|
|
|
|
var cbPluginsDir = jsPluginsRootDir.parentFile,
|
|
|
|
cbDir = new File(cbPluginsDir.canonicalPath).parentFile,
|
|
|
|
legacyExists = false,
|
|
|
|
legacyDirs = [new File( cbDir, 'js-plugins' ),
|
2014-02-10 21:55:32 +01:00
|
|
|
new File( cbDir, 'scriptcraft' )];
|
2014-01-14 23:54:49 +01:00
|
|
|
|
2014-01-29 20:49:15 +01:00
|
|
|
for ( var i = 0; i < legacyDirs.length; i++ ) {
|
|
|
|
if ( legacyDirs[i].exists()
|
2014-02-10 21:55:32 +01:00
|
|
|
&& legacyDirs[i].isDirectory() ) {
|
2013-12-24 01:17:07 +01:00
|
|
|
|
2014-02-10 21:55:32 +01:00
|
|
|
legacyExists = true;
|
2014-01-13 22:06:17 +01:00
|
|
|
|
2014-02-10 21:55:32 +01:00
|
|
|
console.warn('Legacy ScriptCraft directory %s was found. This directory is no longer used.',
|
2014-01-29 20:49:15 +01:00
|
|
|
legacyDirs[i].canonicalPath);
|
|
|
|
}
|
2014-01-02 19:46:46 +01:00
|
|
|
}
|
2014-01-29 20:49:15 +01:00
|
|
|
if ( legacyExists ) {
|
|
|
|
console.info( 'Please note that the working directory for %s is %s',
|
2014-02-10 21:55:32 +01:00
|
|
|
__plugin, jsPluginsRootDir.canonicalPath );
|
2014-01-02 19:46:46 +01:00
|
|
|
}
|
2014-01-29 20:49:15 +01:00
|
|
|
})();
|
|
|
|
|
2013-12-30 22:33:12 +01:00
|
|
|
}
|