From 8f364579cd07b026ffaa6f48235d0c2d806b0875 Mon Sep 17 00:00:00 2001 From: DemiPixel Date: Sun, 6 Sep 2015 12:57:34 -0700 Subject: [PATCH 1/5] Start of plugins --- .gitignore | 2 + examples/plugins/noplanks/index.js | 13 ++++ examples/plugins/noplanks/package.json | 11 ++++ lib/cancelEvent.js | 21 +++++++ lib/playerPlugins/placeBlock.js | 9 +++ lib/serverPlugins/login.js | 6 ++ lib/serverPlugins/plugins.js | 82 ++++++++++++++++++++++++++ package.json | 1 + plugins/README.md | 25 ++++++++ 9 files changed, 170 insertions(+) create mode 100644 examples/plugins/noplanks/index.js create mode 100644 examples/plugins/noplanks/package.json create mode 100644 lib/cancelEvent.js create mode 100644 lib/serverPlugins/plugins.js create mode 100644 plugins/README.md diff --git a/.gitignore b/.gitignore index 3c3629e..30ed14f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ node_modules +plugins/* +!plugins/README.md \ No newline at end of file diff --git a/examples/plugins/noplanks/index.js b/examples/plugins/noplanks/index.js new file mode 100644 index 0000000..0e44f93 --- /dev/null +++ b/examples/plugins/noplanks/index.js @@ -0,0 +1,13 @@ +module.exports=inject; + +function inject(serv, player, self) { + serv.broadcast('Hey ' + player.username + '!'); + player.setGameMode(1); + + player.on('block_place_cancel', function(e, cancel) { // Users can't place any wood planks! + if (e.id == '5') { + cancel(); + player.sendBlock(e.position, 0); + } + }); +} \ No newline at end of file diff --git a/examples/plugins/noplanks/package.json b/examples/plugins/noplanks/package.json new file mode 100644 index 0000000..828bdd6 --- /dev/null +++ b/examples/plugins/noplanks/package.json @@ -0,0 +1,11 @@ +{ + "name": "flying-squid-test", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "DemiPixel ", + "license": "ISC" +} diff --git a/lib/cancelEvent.js b/lib/cancelEvent.js new file mode 100644 index 0000000..f2eedca --- /dev/null +++ b/lib/cancelEvent.js @@ -0,0 +1,21 @@ +module.exports = emit; + +function emit(target, eventName, args, defaultFunc) { + var hiddenCancelled = false; + var cancelled = false; + var cancel = function(hidden) { // Hidden shouldn't be used often but it's not hard to implement so meh + if (hidden) hiddenCancelled = true; + else cancelled = true; + } + + target.emit(eventName + '_cancel', args, cancel); + + target.emit(eventName, args, cancelled); + + if (!hiddenCancelled && !cancelled) { + if (defaultFunc) defaultFunc(); + return true; + } else { + return false + } +} \ No newline at end of file diff --git a/lib/playerPlugins/placeBlock.js b/lib/playerPlugins/placeBlock.js index f309ae6..60c8a56 100644 --- a/lib/playerPlugins/placeBlock.js +++ b/lib/playerPlugins/placeBlock.js @@ -1,4 +1,5 @@ var vec3 = require("vec3"); +var cancelEmit = require("../cancelEvent"); module.exports=inject; @@ -9,6 +10,14 @@ function inject(serv,player) var referencePosition=new vec3(packet.location.x,packet.location.y,packet.location.z); var directionVector=directionToVector[packet.direction]; var placedPosition=referencePosition.plus(directionVector); + + var doDefault = cancelEmit(player, "blockPlace", { + reference: referencePosition, + position: placedPosition, + id: packet.heldItem.blockId + }); + if (!doDefault) return; + player.changeBlock(placedPosition,packet.heldItem.blockId); }); } diff --git a/lib/serverPlugins/login.js b/lib/serverPlugins/login.js index bb7ee0d..2d6f364 100644 --- a/lib/serverPlugins/login.js +++ b/lib/serverPlugins/login.js @@ -15,5 +15,11 @@ function inject(serv,options) } serv.emit("newPlayer",player); player.login(); + + player.plugins = Array(); + for(var pluginName in serv.plugins) { // External plugins + require(serv.plugins[pluginName].path)(serv, player, serv.plugins[pluginName], options); + player.plugins[serv.plugins[pluginName].id] = {}; // Give object to save data per plugin per player, referenced by plugin ID + } }); } \ No newline at end of file diff --git a/lib/serverPlugins/plugins.js b/lib/serverPlugins/plugins.js new file mode 100644 index 0000000..27e75ea --- /dev/null +++ b/lib/serverPlugins/plugins.js @@ -0,0 +1,82 @@ +module.exports = inject; + +var fs = require('fs'); + +function inject(serv) { + getNodeModules(serv, setPluginsFromModules); + + var pluginPath = __dirname.match(/(.*?)\/lib/)[1] + '/plugins'; // Prob a cleaner way to do this + fs.readdir(pluginPath, function(err, arr) { + if (!arr) setPlugins([], serv); + else { + var plugins = Array(); + for (var a in arr) { + if (arr[a].indexOf('.') == 0 || arr[a] == 'README.md') continue; + plugins.push({ + name: arr[a], + path: pluginPath + '/' + arr[a] + }); + } + setPlugins(plugins, serv); + } + }); + + serv.plugins = Array(); + serv.getPlugin = function(name) { + return serv.plugins[name] || null; + } +} + +function setPluginsFromModules(err, modules, serv) { + if (err) { + console.log('ERROR: Error loading node_modules; Cannot load external plugins! /lib/serverPlugins/plugins.js'); + serv.emit('error',err); + return; + } + + var plugins = Array(); + for (var m in modules) { + if (m.indexOf('flying-squid-') == 0) { + var pluginName = m.replace('flying-squid-',''); + plugins.push({ + name: pluginName, + path: pluginName + }); + } + } + setPlugins(plugins, serv); +} + +var loadCount = 0; +var allPlugins; +function setPlugins(plugins, serv) { + loadCount++; + if (loadCount < 2) { // Wait for both plugins folder and node_modules to load + allPlugins = plugins; + return; + } else { + plugins = plugins.concat(allPlugins).sort(); // Sorting makes it easy to check duplicates + } + + var id = 0; + for (var p in plugins) { + serv.plugins[plugins[p].name] = { // Other info about plugin here, TODO: Add events (i.e. ".on"), allow cancels? + id: id, + path: plugins[p].path, + name: plugins[p].name + }; + console.log('Loaded plugin: ' + plugins[p].name); + id++; + if (p < plugins.length-1 && plugins[p].name == plugins[p+1].name) { // Only checks for two duplicates, TODO: check for 3+ duplicates + p++; + } + } + console.log('Loaded ' + id + ' Plugin' + (id != 1 ? 's' : '') ); +} + +function getNodeModules(serv, cb) { + require('child_process').exec('npm ls --json', function(err, stdout, stderr) { + if (err) return cb(err, null, serv); + cb(null, JSON.parse(stdout).dependencies, serv); + }); +} \ No newline at end of file diff --git a/package.json b/package.json index 02a3a83..3ee3f3e 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "prismarine-chunk": "git://github.com/rom1504/prismarine-chunk.git#use-prismarine-block", "prismarine-entity": "0.1.0", "prismarine-world": "git://github.com/rom1504/prismarine-world.git#implementation", + "random-seed": "^0.2.0", "request": "^2.61.0", "requireindex": "~1.0.0", "vec3": "0.1.3" diff --git a/plugins/README.md b/plugins/README.md new file mode 100644 index 0000000..4ad288e --- /dev/null +++ b/plugins/README.md @@ -0,0 +1,25 @@ +## Do you really need to use this folder?? + +If you know of a plugin on npm or git, simply use in console + +``` +npm install --save flying-squid-plugin-name +``` + +Or for a git repository: + +``` +npm install --save git+https://git@github.com/yourname/repo.git +``` + +## Using /plugins + +Simply create a folder inside of /plugins with the name of your plugin. Inside, do `npm init` and create your index.js! + +You need this because npm complains about modules inside of node_modules that are not inside package.json. + +**USE THIS SPARINGLY!** + +## Contributors + +.gitignore ignores everything in this folder except for README.md. Don't worry about removing contents in order to push! \ No newline at end of file From 6771c3186b721371e20aaa02e7af695420bdb063 Mon Sep 17 00:00:00 2001 From: DemiPixel Date: Mon, 7 Sep 2015 15:06:23 -0700 Subject: [PATCH 2/5] Added many more cancelable events and more documentation! --- doc/api.md | 101 ++++++++++++++++++++++++++++++-- doc/contribute.md | 25 ++++++++ lib/playerPlugins/animations.js | 3 + lib/playerPlugins/chat.js | 16 ++++- lib/playerPlugins/digging.js | 33 +++++++++++ lib/playerPlugins/placeBlock.js | 2 +- lib/playerPlugins/pvp.js | 10 +++- 7 files changed, 182 insertions(+), 8 deletions(-) diff --git a/doc/api.md b/doc/api.md index 28e021c..7128894 100644 --- a/doc/api.md +++ b/doc/api.md @@ -39,8 +39,17 @@ - ["spawned"](#spawned) - ["disconnected"](#disconnected) - ["error" (error)](#error-error-1) - - ["chat" (message)](#chat-message) - ["kicked" (kicker,reason)](#kicked-kickerreason) + - [Cancelable Events](#cancelable-events) + - ["chatMessage"](#chatmessage) + - ["chat"](#chat) + - ["command"](#command) + - ["startDig"](#startdig) + - ["stopDig"](#stopdig) + - ["finishDig"](#finishdig) + - ["placeBlock"](#placeblock) + - ["attackPlayer"](#attackplayer) + - ["animation_arm"](#animation_arm) - [Methods](#methods-1) - [player.login()](#playerlogin) - [player.ban(reason)](#playerbanreason) @@ -202,14 +211,96 @@ Fires when the player disconnected Fires when there is an error. -#### "chat" (message) - -Fires when the player says `message`. - #### "kicked" (kicker,reason) `kicker` kick the player with `reason` +### Cancelable Events + +This type of event is emitted by the the player with the option to cancel a default. It is primarily used by external plugins. +This type of event is emitted twice. For example, if a player digs a block, both digBlock\_cancel and digBlock are emitted. +digBlock\_cancel has the ability to cancel the default action. digBlock allows plugins to check if the default has been cancelled before it runs. An example with finishDig: + +```js +player.on("finishDig_cancel", function(event, cancel) { + if (event.block.id == 1) { // If player mined stone (id == 1) + cancel(); // Do not break the block in the world, do not send block change to others + } +}); +``` + +```js +player.on("finishDig", function(event, cancelled) { + if (!cancelled) { // Make sure another plugin has not cancelled the default response + if (event.block.id == 1) player.chat("You broke stone!"); + } +}); +``` + +For these, the cancel event is always originalName_cancel with arguments (event, cancel) + +The "check cancel" event is always originalName with arguments (event, cancelled) + +#### "chatMessage" + +Fires when a user sends any message to the server (even a command) + +- message: String sent by player + +#### "chat" + +Fires when a user sends a message that does not start with a `/` (i.e. not a command). + +- message: String sent by the player + +#### "command" + +Fires when a user starts a message with a `/`. + +- message: String sent by player but without the `/` + +#### "startDig" + +Fires when a player begins to break a blog (even in creative) + +- position: Position block is being mined in the world +- block: Block at that position in world + +#### "stopDig" + +Fires when a player choses to stop breaking a block + +- position: Position block is being mined in the world +- block: Block at that position in world + +#### "finishDig" + +Fires when a player has finished mining a block. If the player is in creative, this will be called immediately after `startDig`. + +- time: Time it took to mine block (0 if player is in creative) +- position: Position block is being mined in the world +- block: Block at that position in world + +#### "placeBlock" + +Fires when a user places a block + +- reference: Position that the player right-clicked on to place the block +- position: Position the user wishes to place the block +- id: Id of the block they are placing + +`position` and `id` will soon be replaced by `block` which will contain a Block object. + +#### "attackPlayer" + +Fires when one player attacks another + +- attacked: Player who was attacked + +#### "animation_arm" + +Fires when a player wants to "punch" (including anything they're holding). + ### Methods #### player.login() diff --git a/doc/contribute.md b/doc/contribute.md index aad5066..724d3b8 100644 --- a/doc/contribute.md +++ b/doc/contribute.md @@ -43,6 +43,31 @@ in log.js of playerPlugins or serverPlugins. ## Creating external plugins +When you're making an external plugin, create a repo and publish to NPM your code so others can use it. + +However, if you simply want to fool around, create a folder, use `npm init`, and drag it into the "plugins" folder. + +Your file's base should look like this: + +```js +module.exports = inject; + +function inject(serv, player, self, opt) { + +} +``` + +- serv is the Server object. Use this to broadcast messages, set blocks, etc +- player is a Player object. You can make changes to the player or check for events from them. +- self is your plugin. You may need your plugin id, so you'll use `self.id`. +- opt is any options the server has while running. + +Since the plugin is its own node module, you can install any other modules inside of it! + +Checks the API.md for information about what events you can check for on the server or player! + +## Creating external plugins OLD + Create a new repo, which will be published to npm when ready to be used. Create a file in which you put an inject function like this : diff --git a/lib/playerPlugins/animations.js b/lib/playerPlugins/animations.js index a556fc9..f1dced0 100644 --- a/lib/playerPlugins/animations.js +++ b/lib/playerPlugins/animations.js @@ -3,6 +3,9 @@ module.exports=inject; function inject(serv, player) { player._client.on("arm_animation", function(packet) { + var doDefault = cancelEmit(player, "animation_arm", {}); + if (!doDefault) return; + player._writeOthers("animation", { entityId: player.entity.id, animation: 0 diff --git a/lib/playerPlugins/chat.js b/lib/playerPlugins/chat.js index df89d7d..0cf0f1c 100644 --- a/lib/playerPlugins/chat.js +++ b/lib/playerPlugins/chat.js @@ -3,13 +3,27 @@ module.exports=inject; function inject(serv, player) { player._client.on('chat', function (packet) { + var doDefault = cancelEmit(player, "chatMessage", { + message: packet.message + }); + if (!doDefault) return; + if(packet.message[0]=="/") { + var doDefault = cancelEmit(player, "command", { + message: packet.message.slice(1) + }); + if (!doDefault) return; + var command = packet.message.slice(1); player.handleCommand(command); } else { + var doDefault = cancelEmit(player, "chat", { + message: packet.message + }); + if (!doDefault) return; + serv.broadcast('<' + player.username + '>' + ' ' + packet.message); - player.emit("chat",packet.message); } }); diff --git a/lib/playerPlugins/digging.js b/lib/playerPlugins/digging.js index ff8c63e..ce989c5 100644 --- a/lib/playerPlugins/digging.js +++ b/lib/playerPlugins/digging.js @@ -1,4 +1,5 @@ var Vec3 = require("vec3"); +var cancelEmit = require("../cancelEvent"); module.exports=inject; @@ -6,6 +7,13 @@ function inject(serv,player) { player._client.on("block_dig",function(packet){ var pos=new Vec3(packet.location); + + var doDefault = cancelEmit(player, "startDig", { + position: pos, + block: serv.world.getBlock(pos) + }); + if (!doDefault) return; + currentlyDugBlock=serv.world.getBlock(pos); if(currentlyDugBlock.type==0) return; if(packet.status==0 && player.gameMode!=1) @@ -46,6 +54,13 @@ function inject(serv,player) newDestroyState=newDestroyState>9 ? 9 : newDestroyState; if(newDestroyState!=lastDestroyState) { + var doDefault = cancelEmit(player, "breakAnimation", { + lastState: lastDestroyState, + position: location, + block: currentlyDugBlock + }); + if (!doDefault) return; + lastDestroyState=newDestroyState; player._writeOthers("block_break_animation",{ "entityId":currentAnimationId, @@ -59,6 +74,13 @@ function inject(serv,player) function cancelDigging(location) { clearInterval(animationInterval); + + var doDefault = cancelEmit(player, "stopDig", { + position: pos, + block: serv.world.getBlock(pos) + }); + if (!doDefault) return; + player._writeOthers("block_break_animation",{ "entityId":currentAnimationId, "location":location, @@ -71,6 +93,12 @@ function inject(serv,player) clearInterval(animationInterval); var diggingTime=new Date()-startDiggingTime; if(expectedDiggingTime-diggingTime<100) + var doDefault = cancelEmit(player, "finishDig", { + time: diggingTime, + position: pos, + block: serv.world.getBlock(pos) + }); + if (!doDefault) return; player.changeBlock(location,0); else { @@ -84,6 +112,11 @@ function inject(serv,player) function creativeDigging(location) { + var doDefault = cancelEmit(player, "finishDig", { + time: 0, + position: pos, + block: serv.world.getBlock(pos) + }); player.changeBlock(location,0); } diff --git a/lib/playerPlugins/placeBlock.js b/lib/playerPlugins/placeBlock.js index 60c8a56..a2b452a 100644 --- a/lib/playerPlugins/placeBlock.js +++ b/lib/playerPlugins/placeBlock.js @@ -11,7 +11,7 @@ function inject(serv,player) var directionVector=directionToVector[packet.direction]; var placedPosition=referencePosition.plus(directionVector); - var doDefault = cancelEmit(player, "blockPlace", { + var doDefault = cancelEmit(player, "placeBlock", { // TODO, make block object and send it (instead of ID) reference: referencePosition, position: placedPosition, id: packet.heldItem.blockId diff --git a/lib/playerPlugins/pvp.js b/lib/playerPlugins/pvp.js index d179865..d72423d 100644 --- a/lib/playerPlugins/pvp.js +++ b/lib/playerPlugins/pvp.js @@ -1,3 +1,5 @@ +var cancelEmit = require("../cancelEvent"); + module.exports=inject; function inject(serv, player) @@ -15,6 +17,12 @@ function inject(serv, player) function attackEntity(entityId) { var attackedPlayer = serv.entities[entityId].player; + + var doDefault = cancelEmit(player, "attackPlayer", { + attacked: attackedPlayer + }); + if (!doDefault) return; + if(attackedPlayer.gameMode!=0) return; attackedPlayer.updateHealth(attackedPlayer.entity.health - 1); @@ -32,7 +40,7 @@ function inject(serv, player) player._client.on("use_entity", function(packet) { if(packet.mouse == 1) { - attackEntity(packet.target); + if (packet.target.player) attackEntity(packet.target); } }); From d62f91f7086e80c8d96109e3942dd78d5b698379 Mon Sep 17 00:00:00 2001 From: DemiPixel Date: Mon, 7 Sep 2015 15:09:23 -0700 Subject: [PATCH 3/5] Small bug --- lib/playerPlugins/digging.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/playerPlugins/digging.js b/lib/playerPlugins/digging.js index ce989c5..1daf3f7 100644 --- a/lib/playerPlugins/digging.js +++ b/lib/playerPlugins/digging.js @@ -92,7 +92,7 @@ function inject(serv,player) { clearInterval(animationInterval); var diggingTime=new Date()-startDiggingTime; - if(expectedDiggingTime-diggingTime<100) + if(expectedDiggingTime-diggingTime<100) { var doDefault = cancelEmit(player, "finishDig", { time: diggingTime, position: pos, @@ -100,6 +100,7 @@ function inject(serv,player) }); if (!doDefault) return; player.changeBlock(location,0); + } else { player._client.write("block_change",{ From 0aae8c6c8ec7f1784efa0b1bd83e897acb24c497 Mon Sep 17 00:00:00 2001 From: DemiPixel Date: Wed, 9 Sep 2015 00:44:48 -0700 Subject: [PATCH 4/5] Fixing bugs, added world-guard example, updated API a bit --- doc/api.md | 4 +- examples/plugins/world-guard/index.js | 158 ++++++++++++++++++++++ examples/plugins/world-guard/package.json | 11 ++ lib/playerPlugins/animations.js | 2 + lib/playerPlugins/chat.js | 2 + lib/playerPlugins/digging.js | 5 +- lib/serverPlugins/login.js | 2 +- 7 files changed, 179 insertions(+), 5 deletions(-) create mode 100644 examples/plugins/world-guard/index.js create mode 100644 examples/plugins/world-guard/package.json diff --git a/doc/api.md b/doc/api.md index 7128894..1665d4d 100644 --- a/doc/api.md +++ b/doc/api.md @@ -40,7 +40,7 @@ - ["disconnected"](#disconnected) - ["error" (error)](#error-error-1) - ["kicked" (kicker,reason)](#kicked-kickerreason) - - [Cancelable Events](#cancelable-events) + - [Cancelable Behaviors](#cancelable-behaviors) - ["chatMessage"](#chatmessage) - ["chat"](#chat) - ["command"](#command) @@ -215,7 +215,7 @@ Fires when there is an error. `kicker` kick the player with `reason` -### Cancelable Events +### Cancelable Behaviors This type of event is emitted by the the player with the option to cancel a default. It is primarily used by external plugins. This type of event is emitted twice. For example, if a player digs a block, both digBlock\_cancel and digBlock are emitted. diff --git a/examples/plugins/world-guard/index.js b/examples/plugins/world-guard/index.js new file mode 100644 index 0000000..2201c15 --- /dev/null +++ b/examples/plugins/world-guard/index.js @@ -0,0 +1,158 @@ +module.exports = inject; + +function inject(serv, player, self) { + + player.plugins[self.id].pos = { + 1: null, + 2: null + }; + player.plugins[self.id].op = false; + self.areas = []; + + player = player; + + player.on('command_cancel', function(e, cancel) { + var player = this; + var text = e.message; + var split = text.split(' '); + if (split[0] != 'wg') return; + else cancel(); + var opped = player.plugins[self.id].op; + + if (split[1] == 'pos1' && opped) { + self.setPosition(player, 1, player.entity.position.x>>5, player.entity.position.z>>5); + player.chat('Set pos1 at ' + (player.entity.position.x>>5) + ',' + (player.entity.position.z>>5)); + } + else if (split[1] == 'pos2' && opped) { + self.setPosition(player, 2, player.entity.position.x>>5, player.entity.position.z>>5); + player.chat('Set pos2 at ' + (player.entity.position.x>>5) + ',' + (player.entity.position.z>>5)); + } + else if (split[1] == 'set' && opped) { + var success = self.setArea(player.plugins[self.id].pos); + if (!success) { + player.chat('You need to set two positions to set an area. Move to the location you want and use:'); + player.chat('"/wg pos1" or "/wg pos2"'); + } else { + player.chat('Successfully set area! (Size: ' + success.width + 'x' + success.length + ')'); + self.clearPosition(player, 1); + self.clearPosition(player, 2); + } + } else if (split[1] == 'clear' && opped) { + self.clearPosition(player, 1); + self.clearPosition(player, 2); + player.chat('Cleared positions'); + } else if (split[1] == 'op') { + var playerTarget = serv.getPlayer(split[2]); + if (!playerTarget) { + player.chat('No such player "' + split[2] + '"'); + } else { + playerTarget.plugins[self.id].op = true; + player.chat('WG Opped ' + split[2]); + } + } else if (split[1] == 'deop' && opped) { + var playerTarget = serv.getPlayer(split[2]); + if (!playerTarget) { + player.chat('No such player "' + split[2] + '"'); + } else { + playerTarget.plugins[self.id].op = false; + player.chat('WG Deopped ' + split[2]); + } + } else if (split[1] == 'help') { + var messages = [ + 'World Guard is used to restrict building areas!', + 'Use /wg pos1 or /wg pos2 to set your two positions.', + 'Use /wg set to confirm the positions.', + 'Use /wg op to allow a user to set positions or build/mine in restricted areas', + 'Use /wg deop to remove op.', + 'Use /wg clear to clear positions', + 'Use /wg list to list all restricted areas you are in (and their IDs)', + 'Use /wg delete to delete a restricted area' + ]; + for (var m in messages) { + player.chat(messages[m]); + } + } else if (split[1] == 'list' && opped) { + var areas = self.areasInPosition(player.entity.position.x>>5, player.entity.position.z>>5); + if (!areas.length) { + player.chat('You are not in any restricted areas!'); + } else player.chat('==== LIST OF AREAS ===='); + for (var a in areas) { + var ar = areas[a]; + var str = ar[0] + '] ' + ar[1][1].x + ',' + ar[1][1].z + ' to ' + ar[1][2].x + ',' + ar[1][2].z; + str += ' (' + (Math.abs(ar[1][1].x - ar[1][2].x)+1) + 'x' + (Math.abs(ar[1][1].z - ar[1][2].z)+1) + ')'; + player.chat(str); + } + } else if (split[1] == 'delete' && opped) { + if (!self.areas[split[2]]) { + player.chat('Area with id ' + split[2] + ' does not exist!'); + } else { + self.deleteArea(split[2]); + player.chat('Deleted area (id ' + split[2] + ')'); + } + } else { + player.chat('Not a valid World Guard command! Use /wg help'); + } + }); + + player.on('placeBlock_cancel', function(e, cancel) { + if (player.plugins[self.id].op === true) return; + if (self.areasInPosition(e.position.x, e.position.z).length) { + cancel(); + player.sendBlock(e.position, 0); + } + }); + + player.on('finishDig_cancel', function(e, cancel) { + if (player.plugins[self.id].op === true) return; + if (self.areasInPosition(e.position.x, e.position.z).length) { + cancel(); + player.sendBlock(e.position, e.block.type); + } + }); + + self.setPosition = function(player, which, x, z) { + if (which != 1 && which != 2) return; + + player.plugins[self.id].pos[which] = { x: x, z: z} + }; + + self.clearPosition = function(player, which) { + if (which != 1 && which != 2) return; + player.plugins[self.id].pos[which] = null; + } + + self.setArea = function(pos) { + if (!pos[1] || !pos[2]) return false; + + self.areas.push({ + 1: { + x: pos[1].x, + z: pos[1].z + }, + 2: { + x: pos[2].x, + z: pos[2].z + } + }); + return { + width: Math.abs(pos[1].x-pos[2].x) + 1, + length: Math.abs(pos[1].z-pos[2].z) + 1 + } + } + + self.deleteArea = function(id) { + self.areas[id] = null; + } + + self.areasInPosition = function(x, z) { + var inside = []; + for (var a in self.areas) { + if (!self.areas[a]) continue; + var x1 = self.areas[a][1].x, x2 = self.areas[a][2].x, z1 = self.areas[a][1].z, z2 = self.areas[a][2].z; + if (x >= Math.min(x1,x2) && x <= Math.max(x1,x2) && z >= Math.min(z1,z2) && z <= Math.max(z1, z2)) { + inside.push([a, self.areas[a]]); + } + } + return inside; + } +} \ No newline at end of file diff --git a/examples/plugins/world-guard/package.json b/examples/plugins/world-guard/package.json new file mode 100644 index 0000000..5b54599 --- /dev/null +++ b/examples/plugins/world-guard/package.json @@ -0,0 +1,11 @@ +{ + "name": "world-guard", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "DemiPixel ", + "license": "ISC" +} diff --git a/lib/playerPlugins/animations.js b/lib/playerPlugins/animations.js index f1dced0..7b47d88 100644 --- a/lib/playerPlugins/animations.js +++ b/lib/playerPlugins/animations.js @@ -1,3 +1,5 @@ +var cancelEmit = require("../cancelEvent"); + module.exports=inject; function inject(serv, player) diff --git a/lib/playerPlugins/chat.js b/lib/playerPlugins/chat.js index 0cf0f1c..319cdd4 100644 --- a/lib/playerPlugins/chat.js +++ b/lib/playerPlugins/chat.js @@ -1,3 +1,5 @@ +var cancelEmit = require("../cancelEvent"); + module.exports=inject; function inject(serv, player) diff --git a/lib/playerPlugins/digging.js b/lib/playerPlugins/digging.js index 1daf3f7..8f6885a 100644 --- a/lib/playerPlugins/digging.js +++ b/lib/playerPlugins/digging.js @@ -115,9 +115,10 @@ function inject(serv,player) { var doDefault = cancelEmit(player, "finishDig", { time: 0, - position: pos, - block: serv.world.getBlock(pos) + position: location, + block: serv.world.getBlock(location) }); + if (!doDefault) return; player.changeBlock(location,0); } diff --git a/lib/serverPlugins/login.js b/lib/serverPlugins/login.js index 2d6f364..ce9ee05 100644 --- a/lib/serverPlugins/login.js +++ b/lib/serverPlugins/login.js @@ -18,8 +18,8 @@ function inject(serv,options) player.plugins = Array(); for(var pluginName in serv.plugins) { // External plugins - require(serv.plugins[pluginName].path)(serv, player, serv.plugins[pluginName], options); player.plugins[serv.plugins[pluginName].id] = {}; // Give object to save data per plugin per player, referenced by plugin ID + require(serv.plugins[pluginName].path)(serv, player, serv.plugins[pluginName], options); } }); } \ No newline at end of file From b15f3941f18489ba9597ad5f48871094c3b83e01 Mon Sep 17 00:00:00 2001 From: DemiPixel Date: Fri, 11 Sep 2015 16:40:17 -0700 Subject: [PATCH 5/5] Updates to plugins --- lib/playerPlugins/commands.js | 4 ++ lib/serverPlugins/login.js | 3 +- lib/serverPlugins/plugins.js | 71 ++++++++++++++++++++++++++++------- 3 files changed, 63 insertions(+), 15 deletions(-) diff --git a/lib/playerPlugins/commands.js b/lib/playerPlugins/commands.js index 13f9a5e..23a2c2e 100644 --- a/lib/playerPlugins/commands.js +++ b/lib/playerPlugins/commands.js @@ -87,6 +87,10 @@ function inject(serv, player, options) { }); } } + else if (results = command.match(/^reload/)) { + serv.reloadPlugins(); + player.chat('Reloaded ' + serv.plugins.length + ' plugins.'); + } else player.chat("Invalid command."); } diff --git a/lib/serverPlugins/login.js b/lib/serverPlugins/login.js index ce9ee05..8f4fbbf 100644 --- a/lib/serverPlugins/login.js +++ b/lib/serverPlugins/login.js @@ -19,7 +19,8 @@ function inject(serv,options) player.plugins = Array(); for(var pluginName in serv.plugins) { // External plugins player.plugins[serv.plugins[pluginName].id] = {}; // Give object to save data per plugin per player, referenced by plugin ID - require(serv.plugins[pluginName].path)(serv, player, serv.plugins[pluginName], options); + var plug = require(serv.plugins[pluginName].path)(serv, player, serv.plugins[pluginName], options); + } }); } \ No newline at end of file diff --git a/lib/serverPlugins/plugins.js b/lib/serverPlugins/plugins.js index 27e75ea..6c4d505 100644 --- a/lib/serverPlugins/plugins.js +++ b/lib/serverPlugins/plugins.js @@ -3,7 +3,54 @@ module.exports = inject; var fs = require('fs'); function inject(serv) { - getNodeModules(serv, setPluginsFromModules); + + serv.loadPlugins = loadPlugins; + + serv.loadPlugins(); + + function resetPlayers() { + for (var p in serv.players) { + var player = serv.players[p] + player.plugins = Array(); + for (var pl in serv.plugins) { + var plugin = serv.plugins[pl]; + player.plugins[plugin.id] = {}; + require(plugin.path)(serv, player, plugin); + } + console.log(serv.players[p].plugins); + } + } + + serv.reloadPlugins = function() { + console.log('RELOADING DOES NOT WORK'); + return; + serv.emit('pluginend'); + resetPlayers(); + } + + serv.fullReloadPlugins = function(cb) { + console.log('RELOADING DOES NOT WORK'); + return; + serv.emit('pluginend'); + serv.loadPlugins(function() { + resetPlayers(); + cb(); + }); + } + + serv.getPlugin = function(name) { + return serv.plugins[name] || null; + } +} + +function loadPlugins(cb) { + var serv = this; + serv.plugins = Array(); + + loadCount = 0; + allPlugins = null; + + getNodeModules(serv, setPluginsFromModules, cb); var pluginPath = __dirname.match(/(.*?)\/lib/)[1] + '/plugins'; // Prob a cleaner way to do this fs.readdir(pluginPath, function(err, arr) { @@ -17,17 +64,12 @@ function inject(serv) { path: pluginPath + '/' + arr[a] }); } - setPlugins(plugins, serv); + setPlugins(plugins, serv, cb); } }); - - serv.plugins = Array(); - serv.getPlugin = function(name) { - return serv.plugins[name] || null; - } } -function setPluginsFromModules(err, modules, serv) { +function setPluginsFromModules(err, modules, serv, cb) { if (err) { console.log('ERROR: Error loading node_modules; Cannot load external plugins! /lib/serverPlugins/plugins.js'); serv.emit('error',err); @@ -44,12 +86,12 @@ function setPluginsFromModules(err, modules, serv) { }); } } - setPlugins(plugins, serv); + setPlugins(plugins, serv, cb); } var loadCount = 0; var allPlugins; -function setPlugins(plugins, serv) { +function setPlugins(plugins, serv, cb) { loadCount++; if (loadCount < 2) { // Wait for both plugins folder and node_modules to load allPlugins = plugins; @@ -67,16 +109,17 @@ function setPlugins(plugins, serv) { }; console.log('Loaded plugin: ' + plugins[p].name); id++; - if (p < plugins.length-1 && plugins[p].name == plugins[p+1].name) { // Only checks for two duplicates, TODO: check for 3+ duplicates + if (p < plugins.length-1 && plugins[p].name == plugins[parseInt(p)+1].name) { // Only checks for two duplicates, TODO: check for 3+ duplicates p++; } } console.log('Loaded ' + id + ' Plugin' + (id != 1 ? 's' : '') ); + if (cb) cb(); } -function getNodeModules(serv, cb) { +function getNodeModules(serv, cb, cb2) { require('child_process').exec('npm ls --json', function(err, stdout, stderr) { - if (err) return cb(err, null, serv); - cb(null, JSON.parse(stdout).dependencies, serv); + if (err) return cb(err, null, serv, cb2); + cb(null, JSON.parse(stdout).dependencies, serv, cb2); }); } \ No newline at end of file