Fix issue #111, reorg of lib/ and (undoc'd) persistence
This commit is contained in:
parent
c77e78c2e5
commit
aefc98f172
18 changed files with 514 additions and 106 deletions
11
build.xml
11
build.xml
|
@ -7,13 +7,6 @@
|
|||
<property name="minecraft.dir" location="${dist}/minecraft" />
|
||||
<property name="js-plugins-dir" value="scriptcraft"/>
|
||||
<property name="http.agent" value="'Walter'" />
|
||||
<target name="testy">
|
||||
<echo message="${http.agent}"/>
|
||||
<get src="http://dl.bukkit.org/api/1.0/downloads/projects/CraftBukkit/?_accept=application/xml"
|
||||
verbose="true"
|
||||
httpusecaches="false"
|
||||
dest="${minecraft.dir}/waltbukkit.xml" />
|
||||
</target>
|
||||
<target name="init">
|
||||
<property file="build.local.properties"/>
|
||||
<tstamp>
|
||||
|
@ -144,7 +137,7 @@ Walter Higgins
|
|||
|
||||
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
|
||||
<mkdir dir="${dist}/${DSTAMP}" />
|
||||
<jar jarfile="${dist}/${DSTAMP}/ScriptCraft.jar" basedir="${build}"/>
|
||||
<jar jarfile="${dist}/${DSTAMP}/scriptcraft.jar" basedir="${build}"/>
|
||||
</target>
|
||||
|
||||
<target name="clean" description="clean up" >
|
||||
|
@ -157,6 +150,6 @@ Walter Higgins
|
|||
<fileset dir="${minecraft.dir}/plugins/" includes="scriptcraft*.*"/>
|
||||
</delete>
|
||||
<mkdir dir="${minecraft.dir}/plugins" />
|
||||
<copy file="${dist}/${DSTAMP}/ScriptCraft.jar" todir="${minecraft.dir}/plugins"/>
|
||||
<copy file="${dist}/${DSTAMP}/scriptcraft.jar" todir="${minecraft.dir}/plugins"/>
|
||||
</target>
|
||||
</project>
|
||||
|
|
|
@ -117,6 +117,8 @@ Walter Higgins
|
|||
* [Example Plugin #7 - Listening for events, Greet players when they join the game.](#example-plugin-7---listening-for-events-greet-players-when-they-join-the-game)
|
||||
* [Arrows Plugin](#arrows-plugin)
|
||||
* [Usage:](#usage-6)
|
||||
* [Spawn Plugin](#spawn-plugin)
|
||||
* [Usage](#usage-7)
|
||||
* [alias Plugin](#alias-plugin)
|
||||
* [Examples](#examples-2)
|
||||
* [Classroom Plugin](#classroom-plugin)
|
||||
|
@ -135,6 +137,10 @@ Walter Higgins
|
|||
* [Example](#example-1)
|
||||
* [SnowballFight mini-game](#snowballfight-mini-game)
|
||||
* [Description](#description-2)
|
||||
* [Cow Clicker Mini-Game](#cow-clicker-mini-game)
|
||||
* [How to Play](#how-to-play)
|
||||
* [Rules](#rules)
|
||||
* [Gameplay Mechanics](#gameplay-mechanics)
|
||||
|
||||
## Modules in Scriptcraft
|
||||
|
||||
|
@ -2340,6 +2346,18 @@ All of the above functions can take an optional player object or name
|
|||
as a parameter. For example: `/js arrows.explosive('player23')` makes
|
||||
player23's arrows explosive.
|
||||
|
||||
## Spawn Plugin
|
||||
|
||||
Allows in-game operators to easily spawn creatures at current location.
|
||||
|
||||
### Usage
|
||||
|
||||
/jsp spawn cow
|
||||
/jsp spawn sheep
|
||||
/jsp spawn wolf
|
||||
|
||||
See <http://jd.bukkit.org/beta/apidocs/org/bukkit/entity/EntityType.html> for a list of possible entities (creatures) which can be spawned.
|
||||
|
||||
## alias Plugin
|
||||
|
||||
The alias module lets players and server admins create their own
|
||||
|
@ -2621,3 +2639,44 @@ player returns to their previous mode of play (creative or
|
|||
survival). Create a small arena with a couple of small buildings for
|
||||
cover to make the game more fun.
|
||||
|
||||
## Cow Clicker Mini-Game
|
||||
|
||||
### How to Play
|
||||
|
||||
At the in-game prompt type `jsp cowclicker` to start or stop
|
||||
playing. Right-Click on Cows to score points. No points for killing
|
||||
cows (hint: use the same keyboard keys you'd use for opening doors).
|
||||
|
||||
Every time you click a cow your score increases by 1 point. Your score
|
||||
is displayed in a side-bar along the right edge of of the screen.
|
||||
|
||||
![cow clicker](img/cowclicker.png)
|
||||
|
||||
### Rules
|
||||
|
||||
* You can join and leave the Cow Clicker game at any time by typing
|
||||
`/jsp cowclicker` at the in-game prompt.
|
||||
|
||||
* Once you leave the game, your score is reset to zero.
|
||||
|
||||
* You can disconnect from the server and your score will be saved for
|
||||
the next time you join.
|
||||
|
||||
### Gameplay Mechanics
|
||||
|
||||
This is meant as a trivially simple use of the [Bukkit Scoreboard
|
||||
API][bukscore]. There are many things you'll want to consider when constructing
|
||||
your own mini-game...
|
||||
|
||||
* Is the game itself a long-lived game - that is - should players and
|
||||
scores be persisted (stored) between server restarts?
|
||||
|
||||
* What should happen when a player quits the server - should this also be
|
||||
understood as quitting the mini-game?
|
||||
|
||||
* What should happen when a player who was previously playing the
|
||||
mini-game, joins the server - should they automatically resume the
|
||||
mini-game?
|
||||
|
||||
[bukscore]: http://jd.bukkit.org/beta/apidocs/org/bukkit/scoreboard/package-summary.html
|
||||
|
||||
|
|
|
@ -35,11 +35,11 @@ using the more succinct...
|
|||
it is easier to read. The important thing to remember when using the
|
||||
Bukkit (or any Java API) from Javascript is that for any Java Bean, a
|
||||
property called `propertyName` will have a getter called
|
||||
`getPropertyName()` and a setter called `setPropertyName`. From this
|
||||
`getPropertyName()` and a setter called `setPropertyName()`. From this
|
||||
rule you can infer what any Bukkit class properties are. For example,
|
||||
the [Bukkit Player][bukpl] object has the following methods...
|
||||
|
||||
* float getWalSpeed()
|
||||
* float getWalkSpeed()
|
||||
* void setWalkSpeed(float speed)
|
||||
|
||||
... so from this you can infer that every Player object has a
|
||||
|
@ -61,7 +61,7 @@ the world in which a player is located...
|
|||
If you're new to Java and the [Bukkit API][bukapi] is the first time
|
||||
you've browsed Java documentation, you may be wondering where the
|
||||
`location` property came from - the `location` property is "inherited"
|
||||
by one of the Player classes super-classes. You'll see the
|
||||
from one of the Player class's super-classes (it's ancestors). You'll see the
|
||||
`getLocation()` method listed under a section titled **Methods
|
||||
inherited from interface org.bukkit.entity.Entity** in the
|
||||
[Player][bukpl] javadoc page.
|
||||
|
|
BIN
docs/img/cowclicker.png
Normal file
BIN
docs/img/cowclicker.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 98 KiB |
|
@ -1,3 +1,25 @@
|
|||
# 2014 01 12
|
||||
|
||||
## Important
|
||||
The ScriptCraft.jar file has been renamed scriptcraft.jar (see bug fix
|
||||
details below). This means that you will have to remove the existing
|
||||
`plugins/ScriptCraft.jar` file if present.
|
||||
|
||||
Bug Fix: On Mac OS, the plugins/scriptcraft directory is copied to
|
||||
plugins/ScriptCraftPlugin the 2nd time ScriptCraftPlugin is loaded.
|
||||
This has been fixed by changing the plugin name from ScriptCraftPlugin
|
||||
to scriptcraft. The jar file has also been rename from
|
||||
ScriptCraft.jar to scriptcraft.jar.
|
||||
|
||||
New command: `jsp spawn` lets in-game operators spawn any type of
|
||||
entity. For example `/jsp spawn cow` will spawn a cow at the in-game
|
||||
operator's current location.
|
||||
|
||||
New minigame: Cow Clicker. A simple demonstration of using Bukkit's
|
||||
Scoreboard API. Players click cows to score points. Scores are
|
||||
displayed in a side bar on screen. Players join or leave the game by
|
||||
typing `/jsp cowclicker` at the in-game prompt.
|
||||
|
||||
# 2014 01 05
|
||||
|
||||
Bug Fix: On Mac OS, alias plugin caused Exceptions due to missing
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
args = args.slice(1);
|
||||
|
||||
// wph 20140105 trim not availabe in String on Mac OS.
|
||||
if (typeof String.prototype.trim == 'undefined'){
|
||||
String.prototype.trim = function(){
|
||||
return this.replace(/^\s+|\s+$/g,'');
|
||||
};
|
||||
}
|
||||
|
||||
var template = args[0];
|
||||
|
||||
var BufferedReader = java.io.BufferedReader;
|
||||
|
|
|
@ -29,7 +29,7 @@ public class ScriptCraftPlugin extends JavaPlugin implements Listener
|
|||
/**
|
||||
* Unzips bundled javascript code.
|
||||
*/
|
||||
private void unzipJS()
|
||||
private void unzipJS() throws IOException
|
||||
{
|
||||
//
|
||||
// does the js-plugins directory exist?
|
||||
|
@ -37,9 +37,13 @@ public class ScriptCraftPlugin extends JavaPlugin implements Listener
|
|||
File jsPlugins = new File(JS_PLUGINS_DIR);
|
||||
if (!jsPlugins.exists())
|
||||
{
|
||||
getLogger().finest("Directory " + JS_PLUGINS_DIR + " does not exist.");
|
||||
getLogger().finest("Initializing " + JS_PLUGINS_DIR + " directory with contents from plugin archive.");
|
||||
jsPlugins.mkdir();
|
||||
getLogger().info("Directory " + jsPlugins.getCanonicalPath() + " does not exist.");
|
||||
getLogger().info("Initializing " + jsPlugins.getCanonicalPath() + " directory with contents from plugin archive.");
|
||||
try{
|
||||
jsPlugins.mkdirs();
|
||||
}catch(Exception e){
|
||||
throw new RuntimeException("Failed to create directory " + jsPlugins.getCanonicalPath() + ":" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
ZipInputStream zis = new ZipInputStream(getResource(JS_PLUGINS_ZIP));
|
||||
|
@ -48,7 +52,7 @@ public class ScriptCraftPlugin extends JavaPlugin implements Listener
|
|||
while ( ( entry = zis.getNextEntry() ) != null)
|
||||
{
|
||||
String filename = entry.getName();
|
||||
//File newFile = new File(jsPlugins.getName() + File.separator + filename);
|
||||
|
||||
File newFile = new File(jsPlugins, filename);
|
||||
|
||||
//create all non exists folders
|
||||
|
@ -59,17 +63,23 @@ public class ScriptCraftPlugin extends JavaPlugin implements Listener
|
|||
//
|
||||
// only write out to file if zip entry is newer than file
|
||||
//
|
||||
String reason = null;
|
||||
long zTime = entry.getTime();
|
||||
boolean unzip = false;
|
||||
if (!newFile.exists())
|
||||
if (!newFile.exists()){
|
||||
reason = "NE";
|
||||
unzip = true;
|
||||
}
|
||||
else{
|
||||
long fTime = newFile.lastModified();
|
||||
if (zTime > fTime)
|
||||
if (zTime > fTime){
|
||||
reason = "" + new Long((zTime-fTime)/3600000) + "h";
|
||||
unzip = true;
|
||||
}
|
||||
|
||||
}
|
||||
if (unzip){
|
||||
getLogger().info("Unzipping " + newFile.getCanonicalPath());
|
||||
getLogger().info("Unzipping " + newFile.getCanonicalPath() + " (" + reason + ")" );
|
||||
FileOutputStream fout = new FileOutputStream(newFile);
|
||||
for (int c = zis.read(); c != -1; c = zis.read()) {
|
||||
fout.write(c);
|
||||
|
@ -90,9 +100,9 @@ public class ScriptCraftPlugin extends JavaPlugin implements Listener
|
|||
@Override
|
||||
public void onEnable()
|
||||
{
|
||||
unzipJS();
|
||||
FileReader reader = null;
|
||||
try{
|
||||
unzipJS();
|
||||
ScriptEngineManager factory = new ScriptEngineManager();
|
||||
File bootScript = new File(JS_PLUGINS_DIR + "/lib/scriptcraft.js");
|
||||
this.engine = factory.getEngineByName("JavaScript");
|
||||
|
@ -103,6 +113,7 @@ public class ScriptCraftPlugin extends JavaPlugin implements Listener
|
|||
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
this.getLogger().severe(e.getMessage());
|
||||
}finally {
|
||||
if (reader != null){
|
||||
try {
|
||||
|
|
33
src/main/javascript/lib/js-patch.js
Normal file
33
src/main/javascript/lib/js-patch.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
|
||||
module.exports = function($){
|
||||
|
||||
// wph 20140105 trim not availabe in String on Mac OS.
|
||||
if (typeof String.prototype.trim == 'undefined'){
|
||||
String.prototype.trim = function(){
|
||||
return this.replace(/^\s+|\s+$/g,'');
|
||||
};
|
||||
}
|
||||
|
||||
$.setTimeout = function( callback, delayInMillis){
|
||||
/*
|
||||
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)
|
||||
*/
|
||||
var bukkitTask = server.scheduler.runTaskLater(__plugin, callback, delayInMillis/50);
|
||||
return bukkitTask;
|
||||
};
|
||||
$.clearTimeout = function(bukkitTask){
|
||||
bukkitTask.cancel();
|
||||
};
|
||||
|
||||
$.setInterval = function(callback, intervalInMillis){
|
||||
var delay = intervalInMillis/ 50;
|
||||
var bukkitTask = server.scheduler.runTaskTimer(__plugin, callback, delay, delay);
|
||||
return bukkitTask;
|
||||
};
|
||||
$.clearInterval = function(bukkitTask){
|
||||
bukkitTask.cancel();
|
||||
};
|
||||
};
|
||||
|
37
src/main/javascript/lib/persistence.js
Normal file
37
src/main/javascript/lib/persistence.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
|
||||
var _dataDir = null;
|
||||
var _persistentData = {};
|
||||
|
||||
module.exports = function( rootDir, $ ){
|
||||
|
||||
_dataDir = new java.io.File( rootDir, 'data');
|
||||
|
||||
$.persist = function(name, data, write){
|
||||
var i, dataFromFile;
|
||||
if (typeof data == 'undefined')
|
||||
data = {};
|
||||
if (typeof write == 'undefined')
|
||||
write = false;
|
||||
if (!write){
|
||||
dataFromFile = $.load(_dataDir.canonicalPath + '/' + name + '-store.json');
|
||||
if (dataFromFile){
|
||||
for (i in dataFromFile){
|
||||
data[i] = dataFromFile[i];
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// flush data to file
|
||||
$.save(data, _dataDir.canonicalPath + '/' + name + '-store.json');
|
||||
}
|
||||
_persistentData[name] = data;
|
||||
return data;
|
||||
};
|
||||
|
||||
$.addUnloadHandler(function(){
|
||||
for (var name in _persistentData){
|
||||
var data = _persistentData[name];
|
||||
$.save(data, _dataDir.canonicalPath + '/' + name + '-store.json');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -3,23 +3,6 @@ var console = require('./console');
|
|||
var File = java.io.File;
|
||||
var FileWriter = java.io.FileWriter;
|
||||
var PrintWriter = java.io.PrintWriter;
|
||||
|
||||
/*
|
||||
Save a javascript object to a file (saves using JSON notation)
|
||||
*/
|
||||
var _save = function(object, filename){
|
||||
var objectToStr = null;
|
||||
try{
|
||||
objectToStr = JSON.stringify(object,null,2);
|
||||
}catch(e){
|
||||
print("ERROR: " + e.getMessage() + " while saving " + filename);
|
||||
return;
|
||||
}
|
||||
var f = (filename instanceof File) ? filename : new File(filename);
|
||||
var out = new PrintWriter(new FileWriter(f));
|
||||
out.println( objectToStr );
|
||||
out.close();
|
||||
};
|
||||
/*
|
||||
plugin management
|
||||
*/
|
||||
|
@ -34,25 +17,18 @@ var _plugin = function(/* String */ moduleName, /* Object */ moduleObject, isPer
|
|||
return _plugins[moduleName].module;
|
||||
|
||||
var pluginData = {persistent: isPersistent, module: moduleObject};
|
||||
moduleObject.store = moduleObject.store || {};
|
||||
if (typeof moduleObject.store == 'undefined')
|
||||
moduleObject.store = {};
|
||||
|
||||
_plugins[moduleName] = pluginData;
|
||||
|
||||
if (isPersistent){
|
||||
if (!moduleObject.store){
|
||||
moduleObject.store = {};
|
||||
}
|
||||
var loadedStore = load(dataDir.canonicalPath + "/" + moduleName + "-store.json");
|
||||
if (loadedStore){
|
||||
for (var i in loadedStore){
|
||||
moduleObject.store[i] = loadedStore[i];
|
||||
}
|
||||
}
|
||||
moduleObject.store = persist(moduleName, moduleObject.store);
|
||||
}
|
||||
return moduleObject;
|
||||
};
|
||||
|
||||
exports.plugin = _plugin;
|
||||
exports.save = _save;
|
||||
|
||||
var scriptCraftDir = null;
|
||||
var pluginDir = null;
|
||||
|
@ -65,7 +41,7 @@ exports.autoload = function(dir) {
|
|||
dataDir = new File(dir, "data");
|
||||
|
||||
var _canonize = function(file){
|
||||
return "" + file.getCanonicalPath().replaceAll("\\\\","/");
|
||||
return '' + file.canonicalPath.replaceAll("\\\\","/");
|
||||
};
|
||||
/*
|
||||
recursively walk the given directory and return a list of all .js files
|
||||
|
@ -78,9 +54,7 @@ exports.autoload = function(dir) {
|
|||
if (file.isDirectory()){
|
||||
_listSourceFiles(store,file);
|
||||
}else{
|
||||
if ((file.getCanonicalPath().endsWith(".js")
|
||||
|| file.getCanonicalPath().endsWith(".coffee"))
|
||||
) {
|
||||
if ( file.canonicalPath.endsWith('.js') ){
|
||||
store.push(file);
|
||||
}
|
||||
}
|
||||
|
@ -97,11 +71,11 @@ exports.autoload = function(dir) {
|
|||
|
||||
var len = sourceFiles.length;
|
||||
if (config.verbose)
|
||||
console.info(len + " scriptcraft plugins found.");
|
||||
console.info(len + ' scriptcraft plugins found.');
|
||||
for (var i = 0;i < len; i++){
|
||||
var pluginPath = _canonize(sourceFiles[i]);
|
||||
if (config.verbose)
|
||||
console.info("Loading plugin: " + pluginPath);
|
||||
console.info('Loading plugin: ' + pluginPath);
|
||||
var module = {};
|
||||
try {
|
||||
module = require(pluginPath);
|
||||
|
@ -119,13 +93,3 @@ exports.autoload = function(dir) {
|
|||
_reload(pluginDir);
|
||||
};
|
||||
|
||||
addUnloadHandler(function(){
|
||||
//
|
||||
// save all plugins which have persistent data
|
||||
//
|
||||
for (var moduleName in _plugins){
|
||||
var pluginData = _plugins[moduleName];
|
||||
if (pluginData.persistent)
|
||||
_save(pluginData.module.store, dataDir.canonicalPath + "/" + moduleName + "-store.json");
|
||||
}
|
||||
});
|
||||
|
|
|
@ -187,11 +187,12 @@ When resolving module names to file paths, ScriptCraft uses the following rules.
|
|||
{
|
||||
var file = resolveModuleToFile(path, parentFile);
|
||||
if (!file){
|
||||
var errMsg = java.lang.String
|
||||
.format("require() failed to find matching file for module '%s' " +
|
||||
"while searching directory '%s' and paths %s.",
|
||||
[path, parentFile.canonicalPath, JSON.stringify(modulePaths)]);
|
||||
console.warn(errMsg);
|
||||
var errMsg = '' + java.lang.String.format("require() failed to find matching file for module '%s' " +
|
||||
"in working directory '%s' ", [path, parentFile.canonicalPath]);
|
||||
if (! ( (''+path).match(/^\./) )){
|
||||
errMsg = errMsg + ' and not found in paths ' + JSON.stringify(modulePaths);
|
||||
}
|
||||
logger.warning(errMsg);
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
var canonizedFilename = _canonize(file);
|
||||
|
@ -242,7 +243,7 @@ When resolving module names to file paths, ScriptCraft uses the following rules.
|
|||
.apply(moduleInfo.exports, /* this */
|
||||
parameters);
|
||||
} catch (e){
|
||||
console.error("Error:" + e + " while executing module " + canonizedFilename);
|
||||
logger.severe('Error:' + e + ' while executing module ' + canonizedFilename);
|
||||
throw e;
|
||||
}
|
||||
if (verbose)
|
||||
|
|
|
@ -422,7 +422,9 @@ function __onEnable (__engine, __plugin, __script)
|
|||
return ;
|
||||
var File = java.io.File
|
||||
,FileReader = java.io.FileReader
|
||||
,BufferedReader = java.io.BufferedReader;
|
||||
,BufferedReader = java.io.BufferedReader
|
||||
,PrintWriter = java.io.PrintWriter
|
||||
,FileWriter = java.io.FileWriter;
|
||||
|
||||
var _canonize = function(file){
|
||||
return "" + file.getCanonicalPath().replaceAll("\\\\","/");
|
||||
|
@ -432,6 +434,23 @@ function __onEnable (__engine, __plugin, __script)
|
|||
var jsPluginsRootDir = libDir.parentFile; // scriptcraft
|
||||
var jsPluginsRootDirName = _canonize(jsPluginsRootDir);
|
||||
|
||||
/*
|
||||
Save a javascript object to a file (saves using JSON notation)
|
||||
*/
|
||||
var _save = function(object, filename){
|
||||
var objectToStr = null;
|
||||
try{
|
||||
objectToStr = JSON.stringify(object,null,2);
|
||||
}catch(e){
|
||||
print("ERROR: " + e.getMessage() + " while saving " + filename);
|
||||
return;
|
||||
}
|
||||
var f = (filename instanceof File) ? filename : new File(filename);
|
||||
var out = new PrintWriter(new FileWriter(f));
|
||||
out.println( objectToStr );
|
||||
out.close();
|
||||
};
|
||||
|
||||
var _loaded = {};
|
||||
/*
|
||||
Load the contents of the file and evaluate as javascript
|
||||
|
@ -487,7 +506,7 @@ function __onEnable (__engine, __plugin, __script)
|
|||
/*
|
||||
now that load is defined, use it to load a global config object
|
||||
*/
|
||||
var config = _load(new File(jsPluginsRootDir, "data/global-config.json" ));
|
||||
var config = _load(new File(jsPluginsRootDir, 'data/global-config.json' ));
|
||||
if (!config)
|
||||
config = {verbose: false};
|
||||
global.config = config;
|
||||
|
@ -510,27 +529,6 @@ function __onEnable (__engine, __plugin, __script)
|
|||
}
|
||||
};
|
||||
|
||||
global.setTimeout = function( callback, delayInMillis){
|
||||
/*
|
||||
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)
|
||||
*/
|
||||
var bukkitTask = server.scheduler.runTaskLater(__plugin, callback, delayInMillis/50);
|
||||
return bukkitTask;
|
||||
};
|
||||
global.clearTimeout = function(bukkitTask){
|
||||
bukkitTask.cancel();
|
||||
};
|
||||
|
||||
global.setInterval = function(callback, intervalInMillis){
|
||||
var delay = intervalInMillis/ 50;
|
||||
var bukkitTask = server.scheduler.runTaskTimer(__plugin, callback, delay, delay);
|
||||
return bukkitTask;
|
||||
};
|
||||
global.clearInterval = function(bukkitTask){
|
||||
bukkitTask.cancel();
|
||||
};
|
||||
global.refresh = function(){
|
||||
__plugin.pluginLoader.disablePlugin(__plugin);
|
||||
__plugin.pluginLoader.enablePlugin(__plugin);
|
||||
|
@ -547,6 +545,7 @@ function __onEnable (__engine, __plugin, __script)
|
|||
global.echo = _echo;
|
||||
global.alert = _echo;
|
||||
global.load = _load;
|
||||
global.save = _save;
|
||||
|
||||
global.addUnloadHandler = _addUnloadHandler;
|
||||
|
||||
|
@ -556,21 +555,30 @@ function __onEnable (__engine, __plugin, __script)
|
|||
*/
|
||||
var modulePaths = [jsPluginsRootDirName + '/lib/',
|
||||
jsPluginsRootDirName + '/modules/'];
|
||||
global.require = fnRequire(__plugin.logger, __engine, config.verbose, jsPluginsRootDirName, modulePaths);
|
||||
global.require = fnRequire(__plugin.logger,
|
||||
__engine,
|
||||
config.verbose,
|
||||
jsPluginsRootDirName,
|
||||
modulePaths);
|
||||
|
||||
require('js-patch')(global);
|
||||
global.console = require('console');
|
||||
/*
|
||||
setup persistence
|
||||
*/
|
||||
require('persistence')(jsPluginsRootDir,global);
|
||||
|
||||
global.command = require('command').command;
|
||||
var plugins = require('plugin');
|
||||
|
||||
global.__onTabComplete = require('tabcomplete');
|
||||
|
||||
global.plugin = plugins.plugin;
|
||||
global.save = plugins.save;
|
||||
|
||||
var events = require('events');
|
||||
events.on('server.PluginDisableEvent',function(l,e){
|
||||
// save config
|
||||
plugins.save(global.config, new File(jsPluginsRootDir, "data/global-config.json" ));
|
||||
save(global.config, new File(jsPluginsRootDir, "data/global-config.json" ));
|
||||
|
||||
_runUnloadHandlers();
|
||||
org.bukkit.event.HandlerList["unregisterAll(org.bukkit.plugin.Plugin)"](__plugin);
|
||||
|
@ -625,10 +633,12 @@ function __onEnable (__engine, __plugin, __script)
|
|||
for (var i = 0; i < legacyDirs.length; i++){
|
||||
if (legacyDirs[i].exists() && legacyDirs[i].isDirectory()){
|
||||
legacyExists = true;
|
||||
console.warn('Legacy ScriptCraft directory ' + legacyDirs[i].canonicalPath + ' was found. This directory is no longer used.');
|
||||
console.warn('Legacy ScriptCraft directory %s was found. This directory is no longer used.',
|
||||
legacyDirs[i].canonicalPath);
|
||||
}
|
||||
}
|
||||
if (legacyExists){
|
||||
console.info('Please note that the working directory for ' + __plugin + ' is ' + jsPluginsRootDir.canonicalPath);
|
||||
console.info('Please note that the working directory for %s is %s',
|
||||
__plugin, jsPluginsRootDir.canonicalPath);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,9 +77,3 @@ for (var method in formattingCodes){
|
|||
return function(){return c+this;};
|
||||
}(formattingCodes[method]);
|
||||
}
|
||||
// wph 20140105 trim not availabe in String on Mac OS.
|
||||
if (!String.prototype.trim){
|
||||
String.prototype.trim = function(){
|
||||
return this.replace(/^\s+|\s+$/g,'');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ var classroom = plugin("classroom", {
|
|||
allowScripting: function (/* boolean: true or false */ canScript, sender) {
|
||||
if (typeof sender == 'undefined'){
|
||||
console.log("Attempt to set classroom scripting without credentials");
|
||||
console.log("classroom.allowScripting(boolean, sender)");
|
||||
return;
|
||||
}
|
||||
if (!sender.op){
|
||||
|
|
|
@ -15,8 +15,20 @@ Once the game begins, guess a number by typing the `/` character
|
|||
followed by a number between 1 and 10.
|
||||
|
||||
***/
|
||||
|
||||
var sb = function(cmd){
|
||||
org.bukkit.Bukkit.dispatchCommand(server.consoleSender, 'scoreboard ' + cmd)
|
||||
};
|
||||
|
||||
exports.Game_NumberGuess = {
|
||||
start: function(sender) {
|
||||
|
||||
var guesses = 0;
|
||||
|
||||
sb('objectives add NumberGuess dummy Guesses');
|
||||
sb('players set ' + sender.name + ' NumberGuess ' + guesses);
|
||||
sb('objectives setdisplay sidebar NumberGuess');
|
||||
|
||||
importPackage(org.bukkit.conversations);
|
||||
|
||||
var number = Math.ceil(Math.random() * 10);
|
||||
|
@ -38,6 +50,7 @@ exports.Game_NumberGuess = {
|
|||
if (s == number){
|
||||
setTimeout(function(){
|
||||
ctx.forWhom.sendRawMessage("You guessed Correct!");
|
||||
sb('objectives remove NumberGuess');
|
||||
},100);
|
||||
return null;
|
||||
}else{
|
||||
|
@ -45,6 +58,9 @@ exports.Game_NumberGuess = {
|
|||
ctx.setSessionData("hint","too low\n");
|
||||
if (s > number)
|
||||
ctx.setSessionData("hint","too high\n");
|
||||
guesses++;
|
||||
sb('players set ' + sender.name + ' NumberGuess ' + guesses);
|
||||
|
||||
return prompt;
|
||||
}
|
||||
},
|
||||
|
|
225
src/main/javascript/plugins/minigames/cow-clicker.js
Normal file
225
src/main/javascript/plugins/minigames/cow-clicker.js
Normal file
|
@ -0,0 +1,225 @@
|
|||
/*************************************************************************
|
||||
## Cow Clicker Mini-Game
|
||||
|
||||
### How to Play
|
||||
|
||||
At the in-game prompt type `jsp cowclicker` to start or stop
|
||||
playing. Right-Click on Cows to score points. No points for killing
|
||||
cows (hint: use the same keyboard keys you'd use for opening doors).
|
||||
|
||||
Every time you click a cow your score increases by 1 point. Your score
|
||||
is displayed in a side-bar along the right edge of of the screen.
|
||||
|
||||
![cow clicker](img/cowclicker.png)
|
||||
|
||||
### Rules
|
||||
|
||||
* You can join and leave the Cow Clicker game at any time by typing
|
||||
`/jsp cowclicker` at the in-game prompt.
|
||||
|
||||
* Once you leave the game, your score is reset to zero.
|
||||
|
||||
* You can disconnect from the server and your score will be saved for
|
||||
the next time you join.
|
||||
|
||||
### Gameplay Mechanics
|
||||
|
||||
This is meant as a trivially simple use of the [Bukkit Scoreboard
|
||||
API][bukscore]. There are many things you'll want to consider when constructing
|
||||
your own mini-game...
|
||||
|
||||
* Is the game itself a long-lived game - that is - should players and
|
||||
scores be persisted (stored) between server restarts?
|
||||
|
||||
* What should happen when a player quits the server - should this also be
|
||||
understood as quitting the mini-game?
|
||||
|
||||
* What should happen when a player who was previously playing the
|
||||
mini-game, joins the server - should they automatically resume the
|
||||
mini-game?
|
||||
|
||||
[bukscore]: http://jd.bukkit.org/beta/apidocs/org/bukkit/scoreboard/package-summary.html
|
||||
|
||||
***/
|
||||
|
||||
var store = {};
|
||||
|
||||
var scoreboardConfig = {
|
||||
cowclicker: {SIDEBAR: 'Cows Clicked'}
|
||||
};
|
||||
|
||||
/*
|
||||
The scoreboard is a simple wrapper around the Bukkit Scoreboard API.
|
||||
It's only concerned with display of scores, not maintaining them - that's the game's job.
|
||||
*/
|
||||
var scoreboard = (function(options){
|
||||
var temp = {};
|
||||
var ccScoreboard;
|
||||
var DisplaySlot = org.bukkit.scoreboard.DisplaySlot;
|
||||
|
||||
return {
|
||||
start: function(){
|
||||
var objective, slot;
|
||||
ccScoreboard = server.scoreboardManager.getNewScoreboard();
|
||||
for (objective in options){
|
||||
var ccObj = ccScoreboard.registerNewObjective(objective,'dummy');
|
||||
for (slot in options[objective]){
|
||||
ccObj.displaySlot = DisplaySlot[slot];
|
||||
ccObj.displayName = options[objective][slot];
|
||||
}
|
||||
}
|
||||
},
|
||||
stop: function(){
|
||||
var objective, slot;
|
||||
for (objective in options){
|
||||
ccScoreboard.getObjective(objective).unregister();
|
||||
for (slot in options[objective]){
|
||||
ccScoreboard.clearSlot(DisplaySlot[slot]);
|
||||
}
|
||||
}
|
||||
},
|
||||
update: function(objective,player,score){
|
||||
if (player.scoreboard && player.scoreboard != ccScoreboard)
|
||||
{
|
||||
temp[player.name] = player.scoreboard;
|
||||
player.scoreboard = ccScoreboard;
|
||||
}
|
||||
ccScoreboard.getObjective(objective).getScore(player).score = score;
|
||||
},
|
||||
restore: function(player){
|
||||
// offlineplayers don't have a scoreboard
|
||||
if (player.scoreboard)
|
||||
player.scoreboard = temp[player.name];
|
||||
}
|
||||
};
|
||||
}(scoreboardConfig));
|
||||
|
||||
var _onPlayerInteract = function(listener, event){
|
||||
var player = event.player;
|
||||
var Bukkit = org.bukkit.Bukkit;
|
||||
|
||||
if (!store[player.name])
|
||||
return;
|
||||
|
||||
var clickedEntity = event.rightClicked;
|
||||
var loc = clickedEntity.location;
|
||||
var sound = function(snd,vol,pitch){
|
||||
loc.world.playSound(loc,snd,vol,pitch);
|
||||
};
|
||||
if (clickedEntity instanceof org.bukkit.entity.Cow)
|
||||
{
|
||||
store[player.name].score++;
|
||||
scoreboard.update('cowclicker', player, store[player.name].score);
|
||||
|
||||
Bukkit.dispatchCommand(player, 'me clicked a cow!');
|
||||
sound(org.bukkit.Sound.CLICK,1,1);
|
||||
setTimeout(function(){
|
||||
sound(org.bukkit.Sound.COW_HURT,10,0.85)
|
||||
},200);
|
||||
}
|
||||
};
|
||||
var _onPlayerQuit = function(listener, event){
|
||||
_removePlayer(event.player)
|
||||
};
|
||||
var _onPlayerJoin = function(listener, event){
|
||||
var gamePlayer = store[event.player.name];
|
||||
if (gamePlayer)
|
||||
_addPlayer(event.player, gamePlayer.score);
|
||||
};
|
||||
|
||||
var _startGame = function(){
|
||||
if (config.verbose)
|
||||
console.log('Staring game: Cow Clicker');
|
||||
|
||||
events.on('player.PlayerQuitEvent', _onPlayerQuit);
|
||||
events.on('player.PlayerJoinEvent', _onPlayerJoin);
|
||||
events.on('player.PlayerInteractEntityEvent', _onPlayerInteract);
|
||||
|
||||
scoreboard.start();
|
||||
|
||||
store = persist('cowclicker',store);
|
||||
for (var p in store){
|
||||
var player = server.getPlayer(p);
|
||||
if (player){
|
||||
/*
|
||||
only add online players
|
||||
*/
|
||||
var score = store[p].score;
|
||||
_addPlayer(player, score);
|
||||
}
|
||||
}
|
||||
};
|
||||
var _addPlayer = function(player,score){
|
||||
if (config.verbose)
|
||||
console.log('Adding player %s to Cow Clicker game',player);
|
||||
|
||||
if (typeof score == 'undefined')
|
||||
score = 0;
|
||||
store[player.name] = {score: score};
|
||||
scoreboard.update('cowclicker', player,store[player.name].score);
|
||||
|
||||
player.sendMessage('Go forth and click some cows!');
|
||||
};
|
||||
|
||||
var _removePlayer = function(player,notify){
|
||||
|
||||
if (player instanceof org.bukkit.OfflinePlayer && player.player)
|
||||
player = player.player;
|
||||
|
||||
if (!store[player.name])
|
||||
return;
|
||||
if (config.verbose)
|
||||
console.log('Removing player %s from Cow Clicker', player);
|
||||
|
||||
var playerScore = store[player.name].score;
|
||||
|
||||
scoreboard.restore(player);
|
||||
|
||||
delete store[player.name];
|
||||
if (notify && player){
|
||||
player.sendMessage('You clicked ' + playerScore + ' cows! ' +
|
||||
'You must be tired after all that clicking.');
|
||||
}
|
||||
};
|
||||
var _removeAllPlayers = function(notify){
|
||||
if (typeof notify == 'undefined')
|
||||
notify = false;
|
||||
for (var p in store){
|
||||
var player = server.getOfflinePlayer(p);
|
||||
if (player)
|
||||
_removePlayer(player,notify);
|
||||
delete store[p];
|
||||
}
|
||||
}
|
||||
var _stopGame = function(removePlayers){
|
||||
if (typeof removePlayers == 'undefined')
|
||||
removePlayers = true;
|
||||
if (config.verbose)
|
||||
console.log('Stopping game: Cow Clicker');
|
||||
scoreboard.stop();
|
||||
if (!removePlayers)
|
||||
return;
|
||||
_removeAllPlayers(false);
|
||||
persist('cowclicker',store.pers,'w');
|
||||
|
||||
};
|
||||
/*
|
||||
start the game automatically when this module is loaded.
|
||||
*/
|
||||
_startGame();
|
||||
/*
|
||||
players can join and leave the game by typing `jsp cowclicker`
|
||||
*/
|
||||
command('cowclicker', function(params, sender){
|
||||
if (!store[sender.name])
|
||||
_addPlayer(sender);
|
||||
else
|
||||
_removePlayer(sender);
|
||||
});
|
||||
/*
|
||||
stop the game when ScriptCraft is unloaded.
|
||||
*/
|
||||
addUnloadHandler(function(){
|
||||
_stopGame(false);
|
||||
});
|
||||
|
35
src/main/javascript/plugins/spawn.js
Normal file
35
src/main/javascript/plugins/spawn.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*************************************************************************
|
||||
## Spawn Plugin
|
||||
|
||||
Allows in-game operators to easily spawn creatures at current location.
|
||||
|
||||
### Usage
|
||||
|
||||
/jsp spawn cow
|
||||
/jsp spawn sheep
|
||||
/jsp spawn wolf
|
||||
|
||||
This command supports TAB completion so to see a list of possible
|
||||
entitities, type `/jsp spawn ' at the in-game command prompt, then
|
||||
press TAB. Visit
|
||||
<http://jd.bukkit.org/beta/apidocs/org/bukkit/entity/EntityType.html>
|
||||
for a list of possible entities (creatures) which can be spawned.
|
||||
|
||||
***/
|
||||
var entities = [];
|
||||
var Types = org.bukkit.entity.EntityType
|
||||
for (var t in Types){
|
||||
if (Types[t] && Types[t].ordinal){
|
||||
entities.push(t);
|
||||
}
|
||||
}
|
||||
command('spawn', function(parameters, sender){
|
||||
if (!sender.op){
|
||||
sender.sendMessage('Only operators can perform this command');
|
||||
return;
|
||||
}
|
||||
var location = sender.location;
|
||||
var world = location.world;
|
||||
var type = ('' + parameters[0]).toUpperCase();
|
||||
world.spawnEntity(location, org.bukkit.entity.EntityType[type]);
|
||||
},entities);
|
|
@ -1,4 +1,4 @@
|
|||
name: ScriptCraftPlugin
|
||||
name: scriptcraft
|
||||
main: net.walterhiggins.scriptcraft.ScriptCraftPlugin
|
||||
version: [[version]]
|
||||
commands:
|
||||
|
|
Reference in a new issue