diff --git a/build.xml b/build.xml index 31ff0d1..e63da8c 100644 --- a/build.xml +++ b/build.xml @@ -74,6 +74,7 @@ + diff --git a/docs/API-Reference.md b/docs/API-Reference.md index 352f8f5..dd83f87 100644 --- a/docs/API-Reference.md +++ b/docs/API-Reference.md @@ -648,10 +648,9 @@ The following example illustrates how to use http.request to make a request to a Miscellaneous utility functions and classes to help with programming. - * locationToString(Location) - returns a bukkit Location object in string form. + * locationToString(Location) - returns a [bukkit Location][bkloc] object in string form. - * getPlayerObject(playerName) - returns the Player object for a named - player or `self` if no name is provided. + * player(playerName) - returns the Player object for a named player or `self` if no name is provided. * getPlayerPos(playerName) - returns the player's x,y,z and yaw (direction) for a named player or player or `self` if no parameter is provided. @@ -659,6 +658,28 @@ Miscellaneous utility functions and classes to help with programming. * getMousePos(playerName) - returns the x,y,z of the current block being targeted by the named player or player or `self` if no paramter is provided. +[bkloc]: http://jd.bukkit.org/dev/apidocs/org/bukkit/Location.html + +### player() function + +The utils.player() function will return a [bukkit Player][bkpl] object +with the given name. This function takes a single parameter +`playerName` which can be either a String or a [Player][bkpl] object - +if it's a Player object, then the same object is returned. If it's a +String, then it tries to find the player with that name. + +#### Parameters + + * playerName : A String or Player object. If no parameter is provided then player() will try to return the `self` variable . It is strongly recommended to provide a parameter. + +#### Example + + var utils = require('utils'); + var player = utils.player('walterh'); + player.sendMessage('Got you!'); + +[bkpl]: http://jd.bukkit.org/dev/apidocs/org/bukkit/entity/Player.html + ### foreach() function The utils.foreach() function is a utility function for iterating over @@ -707,19 +728,19 @@ and put the code there. The following example illustrates how to use foreach for immediate processing of an array... var utils = require('utils'); - var players = ["moe", "larry", "curly"]; + var players = ['moe', 'larry', 'curly']; utils.foreach (players, function(item){ - server.getPlayer(item).sendMessage("Hi " + item); + server.getPlayer(item).sendMessage('Hi ' + item); }); ... The `utils.foreach()` function can work with Arrays or any Java-style collection. This is important because many objects in the Bukkit API use Java-style collections... utils.foreach( server.onlinePlayers, function(player){ - player.chat("Hello!"); + player.chat('Hello!'); }); -... the above code sends a "Hello!" to every online player. +... the above code sends a 'Hello!' to every online player. The following example is a more complex use case - The need to build an enormous structure without hogging CPU usage... @@ -739,7 +760,7 @@ without hogging CPU usage... // assume this code is within a function/closure var player = self; var onDone = function(){ - player.sendMessage("Job Done!"); + player.sendMessage('Job Done!'); }; utils.foreach (a, processItem, null, 10, onDone); @@ -773,8 +794,8 @@ The utils.at() function will perform a given task at a given time every #### Parameters - * time24hr : The time in 24hr form - e.g. 9:30 in the morning is "09:30" while - 9:30 pm is "21:30", midnight is "00:00" and midday is "12:00" + * time24hr : The time in 24hr form - e.g. 9:30 in the morning is '09:30' while + 9:30 pm is '21:30', midnight is '00:00' and midday is '12:00' * callback : A javascript function which will be invoked at the given time. * worlds : (optional) An array of worlds. Each world has its own clock. If no array of worlds is specified, all the server's worlds are used. @@ -784,10 +805,10 @@ To warn players when night is approaching... var utils = require('utils'); - utils.at( "19:00", function() { + utils.at( '19:00', function() { utils.foreach( server.onlinePlayers, function(player){ - player.chat("The night is dark and full of terrors!"); + player.chat('The night is dark and full of terrors!'); }); }); diff --git a/src/main/javascript/modules/utils/utils.js b/src/main/javascript/modules/utils/utils.js index 840c45e..d5c76e8 100644 --- a/src/main/javascript/modules/utils/utils.js +++ b/src/main/javascript/modules/utils/utils.js @@ -3,10 +3,9 @@ Miscellaneous utility functions and classes to help with programming. - * locationToString(Location) - returns a bukkit Location object in string form. + * locationToString(Location) - returns a [bukkit Location][bkloc] object in string form. - * getPlayerObject(playerName) - returns the Player object for a named - player or `self` if no name is provided. + * player(playerName) - returns the Player object for a named player or `self` if no name is provided. * getPlayerPos(playerName) - returns the player's x,y,z and yaw (direction) for a named player or player or `self` if no parameter is provided. @@ -14,36 +13,87 @@ Miscellaneous utility functions and classes to help with programming. * getMousePos(playerName) - returns the x,y,z of the current block being targeted by the named player or player or `self` if no paramter is provided. +[bkloc]: http://jd.bukkit.org/dev/apidocs/org/bukkit/Location.html + ***/ -var _getPlayerObject = function ( playerName ) { - if (typeof playerName == "undefined"){ - if (typeof self == "undefined"){ +/************************************************************************ +### player() function + +The utils.player() function will return a [bukkit Player][bkpl] object +with the given name. This function takes a single parameter +`playerName` which can be either a String or a [Player][bkpl] object - +if it's a Player object, then the same object is returned. If it's a +String, then it tries to find the player with that name. + +#### Parameters + + * playerName : A String or Player object. If no parameter is provided then player() will try to return the `self` variable . It is strongly recommended to provide a parameter. + +#### Example + + var utils = require('utils'); + var player = utils.player('walterh'); + player.sendMessage('Got you!'); + +[bkpl]: http://jd.bukkit.org/dev/apidocs/org/bukkit/entity/Player.html + +***/ +var _player = function ( playerName ) { + if (typeof playerName == 'undefined'){ + if (typeof self == 'undefined'){ return null; } else { return self; } } else { - if (typeof playerName == "string") + if (typeof playerName == 'string') return org.bukkit.Bukkit.getPlayer(playerName); else return playerName; // assumes it's a player object } }; +var _locationToJSON = function(location){ + return { + world: ''+location.world.name, + x: location.x, + y: location.y, + z: location.z, + yaw: location.yaw, + pitch: location.pitch + }; +}; exports.locationToString = function(location){ - return JSON.stringify([""+location.world.name,location.x, location.y, location.z]); + return JSON.stringify(_locationToJSON(location)); +}; +exports.locationToJSON = _locationToJSON; + +exports.locationFromJSON = function(json){ + var world = org.bukkit.Bukkit.getWorld(json.world); + return new org.bukkit.Location(world, json.x, json.y , json.z, json.yaw, json.pitch); }; -exports.getPlayerObject = _getPlayerObject; +exports.player = _player; +exports.getPlayerObject = function(player){ + console.warn('utils.getPlayerObject() is deprecated. Use utils.player() instead.'); + return _player(player); +}; exports.getPlayerPos = function( player ) { - player = _getPlayerObject(player); - return player.location; + player = _player(player); + if (player){ + if (player instanceof org.bukkit.command.BlockCommandSender) + return player.block.location; + else + return player.location; + } + else + return null; }; exports.getMousePos = function (player) { - player = _getPlayerObject(player); + player = _player(player); if (!player) return null; // player might be CONSOLE or a CommandBlock @@ -104,19 +154,19 @@ and put the code there. The following example illustrates how to use foreach for immediate processing of an array... var utils = require('utils'); - var players = ["moe", "larry", "curly"]; + var players = ['moe', 'larry', 'curly']; utils.foreach (players, function(item){ - server.getPlayer(item).sendMessage("Hi " + item); + server.getPlayer(item).sendMessage('Hi ' + item); }); ... The `utils.foreach()` function can work with Arrays or any Java-style collection. This is important because many objects in the Bukkit API use Java-style collections... utils.foreach( server.onlinePlayers, function(player){ - player.chat("Hello!"); + player.chat('Hello!'); }); -... the above code sends a "Hello!" to every online player. +... the above code sends a 'Hello!' to every online player. The following example is a more complex use case - The need to build an enormous structure without hogging CPU usage... @@ -136,7 +186,7 @@ without hogging CPU usage... // assume this code is within a function/closure var player = self; var onDone = function(){ - player.sendMessage("Job Done!"); + player.sendMessage('Job Done!'); }; utils.foreach (a, processItem, null, 10, onDone); @@ -202,8 +252,8 @@ The utils.at() function will perform a given task at a given time every #### Parameters - * time24hr : The time in 24hr form - e.g. 9:30 in the morning is "09:30" while - 9:30 pm is "21:30", midnight is "00:00" and midday is "12:00" + * time24hr : The time in 24hr form - e.g. 9:30 in the morning is '09:30' while + 9:30 pm is '21:30', midnight is '00:00' and midday is '12:00' * callback : A javascript function which will be invoked at the given time. * worlds : (optional) An array of worlds. Each world has its own clock. If no array of worlds is specified, all the server's worlds are used. @@ -213,10 +263,10 @@ To warn players when night is approaching... var utils = require('utils'); - utils.at( "19:00", function() { + utils.at( '19:00', function() { utils.foreach( server.onlinePlayers, function(player){ - player.chat("The night is dark and full of terrors!"); + player.chat('The night is dark and full of terrors!'); }); }); @@ -224,14 +274,14 @@ To warn players when night is approaching... ***/ exports.at = function(time24hr, callback, worlds) { var forever = function(){ return true;}; - var timeParts = time24hr.split(":"); + var timeParts = time24hr.split(':'); var hrs = ((timeParts[0] * 1000) + 18000) % 24000; var mins; if (timeParts.length > 1) mins = (timeParts[1] / 60) * 1000; var timeMc = hrs + mins; - if (typeof worlds == "undefined"){ + if (typeof worlds == 'undefined'){ worlds = server.worlds; } _nicely(function(){ @@ -271,7 +321,7 @@ exports.find = function( dir , filter){ var recurse = function(dir, store){ var files, dirfile = new java.io.File(dir); - if (typeof filter == "undefined") + if (typeof filter == 'undefined') files = dirfile.list(); else files = dirfile.list(filter); diff --git a/src/main/javascript/plugins/arrows.js b/src/main/javascript/plugins/arrows.js index 9cf7783..a3d728f 100644 --- a/src/main/javascript/plugins/arrows.js +++ b/src/main/javascript/plugins/arrows.js @@ -76,8 +76,11 @@ for (var type in _types) { arrows[type] = (function(n){ return function(player){ - player = utils.getPlayerObject(player); - arrows.store.players[player.name] = n; + player = utils.player(player); + if (player) + arrows.store.players[player.name] = n; + else + console.warn('arrows.' + n + ' No player ' + player); }; })(_types[type]); } diff --git a/src/main/javascript/plugins/drone/drone.js b/src/main/javascript/plugins/drone/drone.js index 497a8b3..9eca9ca 100644 --- a/src/main/javascript/plugins/drone/drone.js +++ b/src/main/javascript/plugins/drone/drone.js @@ -1,4 +1,4 @@ -var _utils = require('utils'); +var utils = require('utils'); var blocks = require('blocks'); /********************************************************************* @@ -670,17 +670,26 @@ Drone = function(x,y,z,dir,world) { this.record = false; var usePlayerCoords = false; - var playerPos = _utils.getPlayerPos(); - if (typeof x == "undefined") + var player = self; + if (x instanceof org.bukkit.entity.Player){ + player = x; + } + var playerPos = utils.getPlayerPos(player); + var that = this; + var populateFromLocation = function(loc){ + that.x = loc.x; + that.y = loc.y; + that.z = loc.z; + that.dir = _getDirFromRotation(loc.yaw); + that.world = loc.world; + }; + var mp = utils.getMousePos(player); + if (typeof x == "undefined" || x instanceof org.bukkit.entity.Player) { - var mp = _utils.getMousePos(); if (mp){ - this.x = mp.x; - this.y = mp.y; - this.z = mp.z; + populateFromLocation(mp); if (playerPos) this.dir = _getDirFromRotation(playerPos.yaw); - this.world = mp.world; }else{ // base it on the player's current location usePlayerCoords = true; @@ -691,19 +700,11 @@ Drone = function(x,y,z,dir,world) if (!playerPos){ return null; } - this.x = playerPos.x; - this.y = playerPos.y; - this.z = playerPos.z; - this.dir = _getDirFromRotation(playerPos.yaw); - this.world = playerPos.world; + populateFromLocation(playerPos); } }else{ if (arguments[0] instanceof org.bukkit.Location){ - this.x = arguments[0].x; - this.y = arguments[0].y; - this.z = arguments[0].z; - this.dir = _getDirFromRotation(arguments[0].yaw); - this.world = arguments[0].world; + populateFromLocation(arguments[0]); }else{ this.x = x; this.y = y; @@ -714,7 +715,7 @@ Drone = function(x,y,z,dir,world) this.dir = dir%4; } if (typeof world == "undefined"){ - this.world = _getWorld(); + this.world = playerPos.world; }else{ this.world = world; } @@ -755,7 +756,7 @@ Drone.extend = function(name, func) }; global[name] = function(){ - var result = new Drone(); + var result = new Drone(self); result[name].apply(result,arguments); return result; }; @@ -1071,13 +1072,6 @@ Drone.PLAYER_STAIRS_FACING = [0,2,1,3]; Drone.PLAYER_SIGN_FACING = [4,2,5,3]; Drone.PLAYER_TORCH_FACING = [2,4,1,3]; -var _getWorld = function(){ - var pl = org.bukkit.entity.Player; - var cs = org.bukkit.command.BlockCommandSender; - var world = (self instanceof pl)?self.location.world:(self instanceof cs)?self.block.location.world:null; - return world; -}; - var _STAIRBLOCKS = {53: '5:0' // oak wood ,67: 4 // cobblestone ,108: 45 // brick diff --git a/src/main/javascript/plugins/examples/example-6-hello-player.js b/src/main/javascript/plugins/examples/example-6-hello-player.js new file mode 100644 index 0000000..c14734e --- /dev/null +++ b/src/main/javascript/plugins/examples/example-6-hello-player.js @@ -0,0 +1,36 @@ +/* + A simple minecraft plugin. + Usage: At the in-game prompt type ... + + /jsp hello-byname {player-name} + + ... substituting {player-name} with the name of a player currently + online and a message `Hello ...` will be sent to the named + player. + + This example builds on example-5 and also introduces a new concept - + use of shared modules. That is : modules which are not specific to + any one plugin or set of plugins but which can be used by all + plugins. Shared modules should be placed in the + `scriptcraft/modules` directory. + + * The utils module is used. Because the 'utils' module is + located in the modules folder we don't need to specify an exact + path, just 'utils' will do. + + * The `utils.player()` function is used to obtain a player object + matching the player name. Once a player object is obtained, a + message is sent to that player. +*/ + +var utils = require('utils'); +var greetings = require('./example-1-hello-module'); + +command('hello-byname', function( parameters, sender ) { + var playerName = parameters[0]; + var recipient = utils.player(playerName); + if (recipient) + greetings.hello(recipient); + else + sender.sendMessage('Player ' + playerName + ' not found.'); +}); diff --git a/src/main/javascript/plugins/examples/example-7-hello-events.js b/src/main/javascript/plugins/examples/example-7-hello-events.js new file mode 100644 index 0000000..bc8bf60 --- /dev/null +++ b/src/main/javascript/plugins/examples/example-7-hello-events.js @@ -0,0 +1,83 @@ +/* + A simple event-driven minecraft plugin. + + This example demonstrates event-driven programming. The code below + will display the version of ScriptCraft every time an operator joins + the game. This module is notable from previous modules for the + following reasons... + + 1. It does not export any functions or variables. That's fine. Not + all modules need export stuff. Code in this module will be + executed when the module is first loaded. Because it is in the + `/scriptcraft/plugins` directory, it will be loaded automatically + when the server starts up. + + 2. It uses ScriptCraft's `events.on()` function to add a new *Event + Handler*. An *Event Handler* is a just a function which gets + called whenever a particular *event* happens in the game. The + function defined below will only be executed whenever a player + joins the game. This style of program is sometimes refered to as + *Event-Driven Programming*. + +Adding new *Event Handlers* in ScriptCraft is relatively easy. Use the +`events.on()` function to add a new event handler. It takes 2 +parameters... + + 1. The Event Name, in this case `'player.PlayerJoinEvent'`. You can + browse [all possible Bukkit events][bkevts] (click the 'Next + Package' and 'Previous Package' links to browse). + + 2. The event handling function (also sometimes refered to as a + 'callback'). In ScriptCraft, this function takes 2 parameters, a + listener object and an event object. All of the information about + the event is in the event object. + +In the example below, if a player joins the server and is an operator, +then the ScriptCraft plugin information will be displayed to that +player. + +What's also notable about this example is how it uses the [Bukkit +API][bkapi]. The code... + + if (event.player.op) + +... is a succinct way of accessing object properties which in Java +would have to be written as ... + + if (event.getPlayer().isOp()) + +... ScriptCraft uses a special version of JavaScript which comes +bundled with Java (Minecraft is written in Java) and JavaScript in +Java can access properties of Java objects more succinctly than in +Java itself. What this means in practice is that when you're perusing +the [Bukkit API Reference][bkapi] and come across a method like +[Player.getAllowFlight()][bkgaf], you can write code like this... + + var allowFlight = player.getAllowFlight(); // java style + +... or the more succinct ... + + var allowFlight = player.allowFlight; // javascript style + +... Which style you choose is up to you but `player.allowFlight` is +cleaner and more readable. Similarly where you see a method like +[Player.setAllowFlight()][bksaf], you can write ... + + player.setAllowFlight(true); // java style + +... or the more readable... + + player.allowFlight = true; // javascript style + +... Which style you choose is up to you. + +[bkevts]: http://jd.bukkit.org/dev/apidocs/org/bukkit/event/package-summary.html +[bkgaf]: http://jd.bukkit.org/dev/apidocs/org/bukkit/entity/Player.html#getAllowFlight() +[bksaf]: http://jd.bukkit.org/dev/apidocs/org/bukkit/entity/Player.html#setAllowFlight() +[bkapi]: http://jd.bukkit.org/dev/apidocs/ +*/ +events.on('player.PlayerJoinEvent', function (listener, event){ + if (event.player.op) { + event.player.sendMessage('Welcome to ' + __plugin); + } +}); diff --git a/src/main/javascript/plugins/homes/homes.js b/src/main/javascript/plugins/homes/homes.js index 9c493cd..47d2b51 100644 --- a/src/main/javascript/plugins/homes/homes.js +++ b/src/main/javascript/plugins/homes/homes.js @@ -96,8 +96,8 @@ var homes = plugin("homes", { go: function(guest, host){ if (typeof host == "undefined") host = guest; - guest = utils.getPlayerObject(guest); - host = utils.getPlayerObject(host); + guest = utils.player(guest); + host = utils.player(host); var loc = _store.houses[host.name]; if (!loc){ guest.sendMessage(host.name + " has no home"); @@ -107,9 +107,8 @@ var homes = plugin("homes", { guest.sendMessage("You can't visit " + host.name + "'s home yet"); return; } - var worldName = loc[0], x = loc[1], y = loc[2], z=loc[3], yaw=loc[4]; var teleportCause = org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; - var homeLoc = new org.bukkit.Location(org.bukkit.Bukkit.getWorld(worldName),x,y,z,yaw,0); + var homeLoc = utils.locationFromJSON(loc); guest.teleport(homeLoc, teleportCause.PLUGIN); }, /* @@ -128,17 +127,12 @@ var homes = plugin("homes", { return false; }, set: function(player){ - player = utils.getPlayerObject(player); + player = utils.player(player); var loc = player.location; - _store.houses[player.name] = [""+loc.world.name - ,Math.floor(loc.x) - ,Math.floor(loc.y) - ,Math.floor(loc.z) - ,Math.floor(loc.yaw) - ,Math.floor(loc.pitch)]; + _store.houses[player.name] = utils.locationToJSON(loc); }, remove: function(player){ - player = utils.getPlayerObject(player); + player = utils.player(player); delete _store.houses[player.name]; }, /* ======================================================================== @@ -152,7 +146,7 @@ var homes = plugin("homes", { var result = []; for (var ohp in _store.openHouses) result.push(ohp); - player = utils.getPlayerObject(player); + player = utils.player(player); for (var host in _store.invites){ var guests = _store.invites[host]; for (var i = 0;i < guests.length; i++) @@ -165,7 +159,7 @@ var homes = plugin("homes", { list who can visit the player's home */ ilist: function(player){ - player = utils.getPlayerObject(player); + player = utils.player(player); var result = []; // if home is public - all players if (_store.openHouses[player.name]){ @@ -185,8 +179,8 @@ var homes = plugin("homes", { Invite a player to the home */ invite: function(host, guest){ - host = utils.getPlayerObject(host); - guest = utils.getPlayerObject(guest); + host = utils.player(host); + guest = utils.player(guest); var invitations = []; if (_store.invites[host.name]) invitations = _store.invites[host.name]; @@ -199,8 +193,8 @@ var homes = plugin("homes", { Uninvite someone to the home */ uninvite: function(host, guest){ - host = utils.getPlayerObject(host); - guest = utils.getPlayerObject(guest); + host = utils.player(host); + guest = utils.player(guest); var invitations = _store.invites[host.name]; if (!invitations) return; @@ -214,7 +208,7 @@ var homes = plugin("homes", { make the player's house public */ open: function(player, optionalMsg){ - player = utils.getPlayerObject(player); + player = utils.player(player); _store.openHouses[player.name] = true; if (typeof optionalMsg != "undefined") __plugin.server.broadcastMessage(optionalMsg); @@ -223,7 +217,7 @@ var homes = plugin("homes", { make the player's house private */ close: function(player){ - player = utils.getPlayerObject(player); + player = utils.player(player); delete _store.openHouses[player.name]; }, /* ======================================================================== @@ -236,7 +230,7 @@ var homes = plugin("homes", { return result; }, clear: function(player){ - player = utils.getPlayerObject(player); + player = utils.player(player); delete _store.houses[player.name]; delete _store.openHouses[player.name]; }, @@ -249,8 +243,8 @@ exports.homes = homes; define a set of command options that can be used by players */ var options = { - 'set': function(){homes.set();}, - 'delete': function(){ homes.remove();}, + 'set': function(params, sender){ homes.set(sender); }, + 'delete': function(params, sender ){ homes.remove(sender);}, 'help': function(params, sender){ sender.sendMessage(homes.help());}, 'list': function(params, sender){ var visitable = homes.list(); @@ -279,7 +273,7 @@ var options = { return; } var playerName = params[1]; - var guest = utils.getPlayerObject(playerName); + var guest = utils.player(playerName); if (!guest) sender.sendMessage(playerName + " is not here"); else @@ -291,7 +285,7 @@ var options = { return; } var playerName = params[1]; - var guest = utils.getPlayerObject(playerName); + var guest = utils.player(playerName); if (!guest) sender.sendMessage(playerName + " is not here"); else @@ -333,7 +327,7 @@ command("home", function ( params , sender) { if (option) option(params,sender); else{ - var host = utils.getPlayerObject(params[0]); + var host = utils.player(params[0]); if (!host) sender.sendMessage(params[0] + " is not here"); else