From f82d88cb3fad2939af2e89d4e07785173c2aea9f Mon Sep 17 00:00:00 2001 From: walterhiggins Date: Sat, 15 Mar 2014 18:06:23 +0000 Subject: [PATCH] Event handling rework. Simplified event handling and unregistering. --- docs/API-Reference.md | 35 +++++++++--------- ...YoungPersonsGuideToProgrammingMinecraft.md | 34 ++++++++++++------ src/docs/templates/ypgpm.md | 34 ++++++++++++------ src/main/js/lib/events.js | 36 +++++++++++-------- src/main/js/lib/scriptcraft.js | 2 +- src/main/js/modules/signs/menu.js | 2 +- src/main/js/plugins/alias/alias.js | 4 +-- src/main/js/plugins/arrows.js | 2 +- src/main/js/plugins/classroom/classroom.js | 2 +- src/main/js/plugins/commando/commando.js | 12 +++---- src/main/js/plugins/drone/drone.js | 2 +- .../examples/example-7-hello-events.js | 10 +++--- .../js/plugins/minigames/SnowballFight.js | 5 ++- src/main/js/plugins/minigames/cow-clicker.js | 6 ++-- 14 files changed, 108 insertions(+), 78 deletions(-) diff --git a/docs/API-Reference.md b/docs/API-Reference.md index a4b230b..75da1d1 100644 --- a/docs/API-Reference.md +++ b/docs/API-Reference.md @@ -679,8 +679,7 @@ This method is used to register event listeners. enclosing quotes). * callback - A function which will be called whenever the event - fires. The callback should take 2 parameters, listener (the Bukkit - registered listener for this callback) and event (the event fired). + fires. The callback should take a single parameter, event (the event fired). * priority (optional - default: "HIGHEST") - The priority the listener/callback takes over other listeners to the same @@ -690,16 +689,14 @@ This method is used to register event listeners. #### Returns -An org.bukkit.plugin.RegisteredListener object which can be used to -unregister the listener. This same object is passed to the callback -function each time the event is fired. +An object which can be used to unregister the listener. #### Example: The following code will print a message on screen every time a block is broken in the game ```javascript -events.on( 'block.BlockBreakEvent', function( listener, evt ) { +events.on( 'block.BlockBreakEvent', function( evt ) { evt.player.sendMessage( evt.player.name + ' broke a block!'); } ); ``` @@ -707,24 +704,28 @@ events.on( 'block.BlockBreakEvent', function( listener, evt ) { To handle an event only once and unregister from further events... ```javascript -events.on( 'block.BlockBreakEvent', function( listener, evt ) { +events.on( 'block.BlockBreakEvent', function( evt ) { evt.player.sendMessage( evt.player.name + ' broke a block!'); - evt.handlers.unregister( listener ); + this.unregister(); } ); +The `this` keyword when used inside the callback function refers to +the Listener object created by ScriptCraft. It has a single method +`unregister()` which can be used to stop listening. This is the same +object which is returned by the `events.on()` function. + To unregister a listener *outside* of the listener function... ```javascript -var myBlockBreakListener = events.on( 'block.BlockBreakEvent', function( l, e ) { ... } ); +var myBlockBreakListener = events.on( 'block.BlockBreakEvent', function( evt ) { ... } ); ... -var handlers = org.bukkit.event.block.BlockBreakEvent.getHandlerList(); -handlers.unregister(myBlockBreakListener); +myBlockBreakListener.unregister(); ``` To listen for events using a full class name as the `eventName` parameter... ```javascript -events.on( org.bukkit.event.block.BlockBreakEvent, function( listener, evt ) { +events.on( org.bukkit.event.block.BlockBreakEvent, function( evt ) { evt.player.sendMessage( evt.player.name + ' broke a block!'); } ); ``` @@ -1493,7 +1494,7 @@ Drones can be created in any of the following ways... block is broken at the block's location you would do so like this... - events.on('block.BlockBreakEvent',function( listener,event) { + events.on('block.BlockBreakEvent',function( event) { var location = event.block.location; var drone = new Drone(location); // do more stuff with the drone here... @@ -2429,9 +2430,9 @@ parameters... 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. + 'callback'). In ScriptCraft, this function takes a single + parameter, 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 @@ -2477,7 +2478,7 @@ cleaner and more readable. Similarly where you see a method like [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 ) { + events.on( 'player.PlayerJoinEvent', function( event ) { if ( event.player.op ) { event.player.sendMessage('Welcome to ' + __plugin); } diff --git a/docs/YoungPersonsGuideToProgrammingMinecraft.md b/docs/YoungPersonsGuideToProgrammingMinecraft.md index 6e5e762..1ad8abd 100644 --- a/docs/YoungPersonsGuideToProgrammingMinecraft.md +++ b/docs/YoungPersonsGuideToProgrammingMinecraft.md @@ -1046,7 +1046,7 @@ following code sends a message to any player who breaks a block in the game... ```javascript -events.on('block.BlockBreakEvent', function ( listener, event ) { +events.on('block.BlockBreakEvent', function ( event ) { var breaker = event.player; breaker.sendMessage('You broke a block'); } ); @@ -1057,7 +1057,7 @@ want to be called whenever a particular type of event occurs. In the above code the first parameter `'block.BlockBreakEvent'` is the type of event I want to listen for and the second parameter is the function I want to be called when that event occurs. The function I want called -in turn takes 2 parameters. The `event` object has all the information +in turn takes 1 parameter. The `event` object has all the information about the event which just occurred. I can tell who broke the block and send a message to the player. The important thing to note is that the function defined above will not be called until a player breaks a @@ -1076,13 +1076,13 @@ It's important to note that when browsing the Bukkit API's `events.on()` you can listen to such an event using either the fully qualified Class name... - events.on(org.bukkit.events.entity.EntityShootBowEvent, function( listener, event) { + events.on(org.bukkit.events.entity.EntityShootBowEvent, function( event ) { ... }); or an abbreviated name in string form... - events.on('entity.EntityShootBowEvent', function( listener, event) { + events.on('entity.EntityShootBowEvent', function( event ) { ... }); @@ -1093,7 +1093,7 @@ prepending the 'org.bukkit.events' package. For custom events (events which aren't in the org.bukkit.event tree) just specify the fully qualified class name instead. E.g. ... - events.on ( net.yourdomain.events.YourEvent, function(listener, event ) { + events.on ( net.yourdomain.events.YourEvent, function( event ) { ... }); @@ -1102,15 +1102,27 @@ just specify the fully qualified class name instead. E.g. ... If you want an event handler to only execute once, you can remove the handler like this... ```javascript -events.on('block.BlockBreakEvent', function( listener, evt ) { +events.on('block.BlockBreakEvent', function( evt ) { var breaker = evt.player; breaker.sendMessage('You broke a block'); - evt.handlers.unregister( listener ); + this.unregister(); } ); ``` -The `evt.handlers.unregister( listener );` statement will remove this -function from the list of listeners for this event. +The `this.unregister();` statement will remove this function from the +list of listeners for the event. The `this` keyword when used inside +an event handling function refers to a Listener object provided by +ScriptCraft, it has a single method `unregister()` which can be used +to stop listening for events. + +To unregister a listener *outside* of the listener function... + +```javascript +var myBlockBreakListener = events.on( 'block.BlockBreakEvent', function( evt ) { ... } ); +... +myBlockBreakListener.unregister(); +``` + ## Keeping Score - Lookup tables in Javascript @@ -1221,10 +1233,10 @@ keep a count of how many blocks each player has broken ... ```javascript var breaks = {}; // every time a player joins the game reset their block-break-count to 0 -events.on('player.PlayerJoinEvent', function(listener, event){ +events.on('player.PlayerJoinEvent', function( event ) { breaks[event.player] = 0; }); -events.on('block.BlockBreakEvent', function(listener, event){ +events.on('block.BlockBreakEvent', function( event ) { var breaker = event.player; var breakCount = breaks[breaker.name]; breakCount++; // increment the count. diff --git a/src/docs/templates/ypgpm.md b/src/docs/templates/ypgpm.md index 5d5467d..38d46c3 100644 --- a/src/docs/templates/ypgpm.md +++ b/src/docs/templates/ypgpm.md @@ -1010,7 +1010,7 @@ following code sends a message to any player who breaks a block in the game... ```javascript -events.on('block.BlockBreakEvent', function ( listener, event ) { +events.on('block.BlockBreakEvent', function ( event ) { var breaker = event.player; breaker.sendMessage('You broke a block'); } ); @@ -1021,7 +1021,7 @@ want to be called whenever a particular type of event occurs. In the above code the first parameter `'block.BlockBreakEvent'` is the type of event I want to listen for and the second parameter is the function I want to be called when that event occurs. The function I want called -in turn takes 2 parameters. The `event` object has all the information +in turn takes 1 parameter. The `event` object has all the information about the event which just occurred. I can tell who broke the block and send a message to the player. The important thing to note is that the function defined above will not be called until a player breaks a @@ -1040,13 +1040,13 @@ It's important to note that when browsing the Bukkit API's `events.on()` you can listen to such an event using either the fully qualified Class name... - events.on(org.bukkit.events.entity.EntityShootBowEvent, function( listener, event) { + events.on(org.bukkit.events.entity.EntityShootBowEvent, function( event ) { ... }); or an abbreviated name in string form... - events.on('entity.EntityShootBowEvent', function( listener, event) { + events.on('entity.EntityShootBowEvent', function( event ) { ... }); @@ -1057,7 +1057,7 @@ prepending the 'org.bukkit.events' package. For custom events (events which aren't in the org.bukkit.event tree) just specify the fully qualified class name instead. E.g. ... - events.on ( net.yourdomain.events.YourEvent, function(listener, event ) { + events.on ( net.yourdomain.events.YourEvent, function( event ) { ... }); @@ -1066,15 +1066,27 @@ just specify the fully qualified class name instead. E.g. ... If you want an event handler to only execute once, you can remove the handler like this... ```javascript -events.on('block.BlockBreakEvent', function( listener, evt ) { +events.on('block.BlockBreakEvent', function( evt ) { var breaker = evt.player; breaker.sendMessage('You broke a block'); - evt.handlers.unregister( listener ); + this.unregister(); } ); ``` -The `evt.handlers.unregister( listener );` statement will remove this -function from the list of listeners for this event. +The `this.unregister();` statement will remove this function from the +list of listeners for the event. The `this` keyword when used inside +an event handling function refers to a Listener object provided by +ScriptCraft, it has a single method `unregister()` which can be used +to stop listening for events. + +To unregister a listener *outside* of the listener function... + +```javascript +var myBlockBreakListener = events.on( 'block.BlockBreakEvent', function( evt ) { ... } ); +... +myBlockBreakListener.unregister(); +``` + ## Keeping Score - Lookup tables in Javascript @@ -1185,10 +1197,10 @@ keep a count of how many blocks each player has broken ... ```javascript var breaks = {}; // every time a player joins the game reset their block-break-count to 0 -events.on('player.PlayerJoinEvent', function(listener, event){ +events.on('player.PlayerJoinEvent', function( event ) { breaks[event.player] = 0; }); -events.on('block.BlockBreakEvent', function(listener, event){ +events.on('block.BlockBreakEvent', function( event ) { var breaker = event.player; var breakCount = breaks[breaker.name]; breakCount++; // increment the count. diff --git a/src/main/js/lib/events.js b/src/main/js/lib/events.js index 0da3004..34dfde0 100644 --- a/src/main/js/lib/events.js +++ b/src/main/js/lib/events.js @@ -27,8 +27,7 @@ This method is used to register event listeners. enclosing quotes). * callback - A function which will be called whenever the event - fires. The callback should take 2 parameters, listener (the Bukkit - registered listener for this callback) and event (the event fired). + fires. The callback should take a single parameter, event (the event fired). * priority (optional - default: "HIGHEST") - The priority the listener/callback takes over other listeners to the same @@ -38,16 +37,14 @@ This method is used to register event listeners. #### Returns -An org.bukkit.plugin.RegisteredListener object which can be used to -unregister the listener. This same object is passed to the callback -function each time the event is fired. +An object which can be used to unregister the listener. #### Example: The following code will print a message on screen every time a block is broken in the game ```javascript -events.on( 'block.BlockBreakEvent', function( listener, evt ) { +events.on( 'block.BlockBreakEvent', function( evt ) { evt.player.sendMessage( evt.player.name + ' broke a block!'); } ); ``` @@ -55,24 +52,28 @@ events.on( 'block.BlockBreakEvent', function( listener, evt ) { To handle an event only once and unregister from further events... ```javascript -events.on( 'block.BlockBreakEvent', function( listener, evt ) { +events.on( 'block.BlockBreakEvent', function( evt ) { evt.player.sendMessage( evt.player.name + ' broke a block!'); - evt.handlers.unregister( listener ); + this.unregister(); } ); +The `this` keyword when used inside the callback function refers to +the Listener object created by ScriptCraft. It has a single method +`unregister()` which can be used to stop listening. This is the same +object which is returned by the `events.on()` function. + To unregister a listener *outside* of the listener function... ```javascript -var myBlockBreakListener = events.on( 'block.BlockBreakEvent', function( l, e ) { ... } ); +var myBlockBreakListener = events.on( 'block.BlockBreakEvent', function( evt ) { ... } ); ... -var handlers = org.bukkit.event.block.BlockBreakEvent.getHandlerList(); -handlers.unregister(myBlockBreakListener); +myBlockBreakListener.unregister(); ``` To listen for events using a full class name as the `eventName` parameter... ```javascript -events.on( org.bukkit.event.block.BlockBreakEvent, function( listener, evt ) { +events.on( org.bukkit.event.block.BlockBreakEvent, function( evt ) { evt.player.sendMessage( evt.player.name + ' broke a block!'); } ); ``` @@ -118,9 +119,11 @@ exports.on = function( } } handlerList = eventType.getHandlerList( ); + + var result = { }; eventExecutor = new bkEventExecutor( ) { - execute: function( l, e ) { - handler( listener.reg, e ); + execute: function( l, evt ) { + handler.call( result, evt ); } }; /* @@ -133,5 +136,8 @@ exports.on = function( */ listener.reg = new bkRegisteredListener( __plugin, eventExecutor, priority, __plugin, true ); handlerList.register( listener.reg ); - return listener.reg; + result.unregister = function(){ + handlerList.unregister( listener.reg ); + }; + return result; }; diff --git a/src/main/js/lib/scriptcraft.js b/src/main/js/lib/scriptcraft.js index f35b09b..de0fb97 100644 --- a/src/main/js/lib/scriptcraft.js +++ b/src/main/js/lib/scriptcraft.js @@ -617,7 +617,7 @@ function __onEnable ( __engine, __plugin, __script ) global.plugin = plugins.plugin; var events = require('events'); - events.on( 'server.PluginDisableEvent', function( l, e ) { + events.on( 'server.PluginDisableEvent', function( evt ) { // save config _save( global.config, new File( jsPluginsRootDir, 'data/global-config.json' ) ); diff --git a/src/main/js/modules/signs/menu.js b/src/main/js/modules/signs/menu.js index 4d10c1d..df1c7af 100644 --- a/src/main/js/modules/signs/menu.js +++ b/src/main/js/modules/signs/menu.js @@ -184,7 +184,7 @@ signs.menu = function( /* String */ label, /* Array */ options, /* Function */ c // // update it every time player interacts with it. // -events.on( 'player.PlayerInteractEvent', function( listener, event ) { +events.on( 'player.PlayerInteractEvent', function( event ) { /* look up our list of menu signs. If there's a matching location and there's a sign, then update it. diff --git a/src/main/js/plugins/alias/alias.js b/src/main/js/plugins/alias/alias.js index 35f58e3..0626fc9 100644 --- a/src/main/js/plugins/alias/alias.js +++ b/src/main/js/plugins/alias/alias.js @@ -223,7 +223,7 @@ var _intercept = function( msg, invoker, exec ) { Intercept all command processing and replace with aliased commands if the command about to be issued matches an alias. */ -events.on( 'player.PlayerCommandPreprocessEvent', function( listener, evt ) { +events.on( 'player.PlayerCommandPreprocessEvent', function( evt ) { var invoker = evt.player; var exec = function( cmd ) { invoker.performCommand(cmd); @@ -237,7 +237,7 @@ events.on( 'player.PlayerCommandPreprocessEvent', function( listener, evt ) { command('void',function( ) { } ); -events.on( 'server.ServerCommandEvent', function( listener, evt ) { +events.on( 'server.ServerCommandEvent', function( evt ) { var invoker = evt.sender; var exec = function( cmd ) { invoker.server.dispatchCommand( invoker, cmd); diff --git a/src/main/js/plugins/arrows.js b/src/main/js/plugins/arrows.js index 82a9fd9..4e2c8b5 100644 --- a/src/main/js/plugins/arrows.js +++ b/src/main/js/plugins/arrows.js @@ -79,7 +79,7 @@ arrows.sign = function( cmdSender ) { /* event handler called when a projectile hits something */ -var _onArrowHit = function( listener, event ) { +var _onArrowHit = function( event ) { var projectile = event.entity, world = projectile.world, shooter = projectile.shooter, diff --git a/src/main/js/plugins/classroom/classroom.js b/src/main/js/plugins/classroom/classroom.js index af240b3..2f74caf 100644 --- a/src/main/js/plugins/classroom/classroom.js +++ b/src/main/js/plugins/classroom/classroom.js @@ -158,7 +158,7 @@ var classroom = plugin('classroom', { exports.classroom = classroom; -events.on( 'player.PlayerJoinEvent', function( listener, event ) { +events.on( 'player.PlayerJoinEvent', function( event ) { if ( _store.enableScripting ) { grantScripting(event.player); } diff --git a/src/main/js/plugins/commando/commando.js b/src/main/js/plugins/commando/commando.js index 55fa910..64437d6 100644 --- a/src/main/js/plugins/commando/commando.js +++ b/src/main/js/plugins/commando/commando.js @@ -84,8 +84,8 @@ exports.commando = function( name, func, options, intercepts ) { return result; }; -events.on( 'player.PlayerCommandPreprocessEvent', function( l, e ) { - var msg = '' + e.message; +events.on( 'player.PlayerCommandPreprocessEvent', function( evt ) { + var msg = '' + evt.message; var parts = msg.match( /^\/([^\s]+)/ ); if ( !parts ) { return; @@ -95,11 +95,11 @@ events.on( 'player.PlayerCommandPreprocessEvent', function( l, e ) { } var command = parts[1]; if ( commands[command] ) { - e.message = '/jsp ' + msg.replace( /^\//, '' ); + evt.message = '/jsp ' + msg.replace( /^\//, '' ); } } ); -events.on( 'server.ServerCommandEvent', function( l, e ) { - var msg = '' + e.command; +events.on( 'server.ServerCommandEvent', function( evt ) { + var msg = '' + evt.command; var parts = msg.match( /^\/*([^\s]+)/ ); if ( !parts ) { return; @@ -113,6 +113,6 @@ events.on( 'server.ServerCommandEvent', function( l, e ) { if ( config.verbose ) { console.log( 'Redirecting to : %s', newCmd ); } - e.command = newCmd; + evt.command = newCmd; } }); diff --git a/src/main/js/plugins/drone/drone.js b/src/main/js/plugins/drone/drone.js index 4a5aead..8af954c 100644 --- a/src/main/js/plugins/drone/drone.js +++ b/src/main/js/plugins/drone/drone.js @@ -118,7 +118,7 @@ Drones can be created in any of the following ways... block is broken at the block's location you would do so like this... - events.on('block.BlockBreakEvent',function( listener,event) { + events.on('block.BlockBreakEvent',function( event) { var location = event.block.location; var drone = new Drone(location); // do more stuff with the drone here... diff --git a/src/main/js/plugins/examples/example-7-hello-events.js b/src/main/js/plugins/examples/example-7-hello-events.js index b4d7d87..8723c91 100644 --- a/src/main/js/plugins/examples/example-7-hello-events.js +++ b/src/main/js/plugins/examples/example-7-hello-events.js @@ -31,9 +31,9 @@ parameters... 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. + 'callback'). In ScriptCraft, this function takes a single + parameter, 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 @@ -79,14 +79,14 @@ cleaner and more readable. Similarly where you see a method like [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 ) { + events.on( 'player.PlayerJoinEvent', function( event ) { if ( event.player.op ) { event.player.sendMessage('Welcome to ' + __plugin); } }); ***/ -events.on( 'player.PlayerJoinEvent', function( listener, event ) { +events.on( 'player.PlayerJoinEvent', function( event ) { if ( event.player.op ) { event.player.sendMessage( 'Welcome to ' + __plugin ); } diff --git a/src/main/js/plugins/minigames/SnowballFight.js b/src/main/js/plugins/minigames/SnowballFight.js index 9dccae6..5116caf 100644 --- a/src/main/js/plugins/minigames/SnowballFight.js +++ b/src/main/js/plugins/minigames/SnowballFight.js @@ -112,8 +112,7 @@ var _endGame = function( gameState ) { player.sendMessage( scores ); } } - handlerList = bkEntityDamageByEntityEvent.getHandlerList(); - handlerList.unregister( gameState.listener ); + gameState.listener.unregister(); gameState.inProgress = false; }; /* @@ -177,7 +176,7 @@ var createGame = function( duration, teams ) { /* this function is called every time a player is damaged by another entity/player */ - var _onSnowballHit = function( l, event ) { + var _onSnowballHit = function( event ) { var snowball = event.damager; if ( !snowball || !( snowball instanceof bkSnowball ) ) { return; diff --git a/src/main/js/plugins/minigames/cow-clicker.js b/src/main/js/plugins/minigames/cow-clicker.js index df83b0f..124b037 100644 --- a/src/main/js/plugins/minigames/cow-clicker.js +++ b/src/main/js/plugins/minigames/cow-clicker.js @@ -53,7 +53,7 @@ var store = {}, }; var scoreboard = require('minigames/scoreboard')(scoreboardConfig); -var _onPlayerInteract = function( listener, event ) { +var _onPlayerInteract = function( event ) { var player = event.player, clickedEntity = event.rightClicked, loc = clickedEntity.location; @@ -77,10 +77,10 @@ var _onPlayerInteract = function( listener, event ) { }, 200 ); } }; -var _onPlayerQuit = function( listener, event ) { +var _onPlayerQuit = function( event ) { _removePlayer( event.player ); }; -var _onPlayerJoin = function( listener, event ) { +var _onPlayerJoin = function( event ) { var gamePlayer = store[event.player.name]; if ( gamePlayer ) { _addPlayer( event.player, gamePlayer.score );