diff --git a/doc/api.md b/doc/api.md index f328a05..643ae95 100644 --- a/doc/api.md +++ b/doc/api.md @@ -41,6 +41,8 @@ - ["chat" (message)](#chat-message) - [Methods](#methods-1) - [player.login()](#playerlogin) + - [player.ban(reason)](#playerbanreason) + - [player.kick(reason)](#playerkickreason) - [player.getOthers()](#playergetothers) - [player.chat(message)](#playerchatmessage) - [player.changeBlock(position,blockType)](#playerchangeblockpositionblocktype) @@ -50,8 +52,6 @@ - [player.setGameMode(gameMode)](#playersetgamemodegamemode) - [player.handleCommand(command)](#playerhandlecommandcommand) - [player.updateHealth(health)](#playerupdatehealthhealth) - - [player.kick(reason)](#playerkickreason) - - [player.ban(banReason,kickReason)](#playerbanbanreasonkickreason) - [Low level properties](#low-level-properties) - [player._client](#player_client) - [Low level methods](#low-level-methods) @@ -148,8 +148,6 @@ Returns player object with that username or, if no such player is on the server, Bans players given a username. Mainly used if player is not online, otherwise use `player.ban()`. -Callback first argument returns `true` if there is a UUID for that username, `false` otherwise. - #### server.ban(uuid,reason) Ban player given a uuid. If the player is online, using `player.ban()`. Bans with reason or `You are banned!`. @@ -158,8 +156,6 @@ Ban player given a uuid. If the player is online, using `player.ban()`. Bans wit Pardons a player given a username. -Callback returns `false` if UUID does not exist or player is not banned. It returns `true` otherwise. - #### server.pardon(uuid) Pardons a player given their uuid. Returns `false` if they are not banned. @@ -210,6 +206,14 @@ Fires when the player says `message`. login +#### player.ban(reason) + +bans player with `reason` + +#### player.kick(reason) + +kicks player with `reason` + #### player.getOthers() return the other players than `player` @@ -222,7 +226,8 @@ sends `message` to the player change the block at position `position` to `blockType` -this will not change the block for the user themself. It is mainly useful when a user places a block and only needs to send it to other players on the server +this will not change the block for the user themself. It is mainly useful when a user places a block +and only needs to send it to other players on the server #### player.sendBlock(position,blockType) @@ -250,14 +255,6 @@ handle `command` update the player health. -#### player.kick(reason) - -Kicks a player with the reason given or `You were kicked!`. - -#### player.ban(banReason,kickReason) - -Kicks the player with `kickReason`, then bans them with reason `banReason`. - ### Low level properties #### player._client diff --git a/doc/contribute.md b/doc/contribute.md index 3c63c7a..aad5066 100644 --- a/doc/contribute.md +++ b/doc/contribute.md @@ -35,6 +35,12 @@ function inject(serv,player) } ``` +## Logs and event + +In order to keep logging independent from the rest of the server and to let people react in other ways than logging, +server and player events should be emitting and the logging should only take place in response to these events +in log.js of playerPlugins or serverPlugins. + ## Creating external plugins Create a new repo, which will be published to npm when ready to be used. @@ -54,7 +60,8 @@ function inject(serv) } ``` -In the init function, you can use anything craftyjs provide (see [index.js](https://github.com/mhsjlw/flying-squid/blob/master/index.js#L11)). +In the init function, you can use anything craftyjs provide +(see [index.js](https://github.com/mhsjlw/flying-squid/blob/master/index.js#L11)). In the inject function you can use everything documented in the [api.md](api.md) to add functionnalities to the serv object. @@ -87,4 +94,6 @@ function injectPlayer(serv,player) } ``` -In this document, we explained how to create a simple plugin with just one file, but you can cut your code in several files by having several inject function and putting them in different files, just like flying-squid does for its internal plugins. +In this document, we explained how to create a simple plugin with just one file, but you can cut your code + in several files by having several inject function and putting them in different files, just like flying-squid does + for its internal plugins. diff --git a/lib/playerPlugins/commands.js b/lib/playerPlugins/commands.js index 6362c2c..13f9a5e 100644 --- a/lib/playerPlugins/commands.js +++ b/lib/playerPlugins/commands.js @@ -1,90 +1,95 @@ var Vec3 = require('vec3'); -module.exports=inject; +module.exports = inject; -function inject(serv, player, options) -{ - function handleCommand(command) - { +function inject(serv, player, options) { + function handleCommand(command) { var results; - if(options.commands[command]) + if (options.commands[command]) player.chat("" + options.commands[command]); - else if(results=command.match(/^gamemode ([0-3])$/)) { - var gameMode=parseInt(results[1]); + else if (results = command.match(/^gamemode ([0-3])$/)) { + var gameMode = parseInt(results[1]); player.setGameMode(gameMode); } - else if(results=command.match(/^setblock/)) { // Like old version which uses ids - results = command.match(/^setblock (~|~?-?[0-9]*) (~|~?-?[0-9]*) (~|~?-?[0-9]*) ([0-9]{1,3})/); - if(!results) { - player.chat("Usage: /setblock "); - } - else { - results = results.map(function(num, i) { // parseInt paramaters - if (num.indexOf('~') == 0) { - return (player.entity.position[['','x', 'y', 'z'][i]]>>5) + parseInt(num.slice(1) || 0); - } - else - return parseInt(num); // return parseInt>>5 if position, not id - }); - serv.setBlock(new Vec3(results[1], results[2], results[3]), results[4]); - } + else if (results = command.match(/^setblock/)) { // Like old version which uses ids + results = command.match(/^setblock (~|~?-?[0-9]*) (~|~?-?[0-9]*) (~|~?-?[0-9]*) ([0-9]{1,3})/); + if (!results) { + player.chat("Usage: /setblock "); + } + else { + results = results.map(function (num, i) { // parseInt paramaters + if (num.indexOf('~') == 0) { + return (player.entity.position[['', 'x', 'y', 'z'][i]] >> 5) + parseInt(num.slice(1) || 0); + } + else + return parseInt(num); // return parseInt>>5 if position, not id + }); + serv.setBlock(new Vec3(results[1], results[2], results[3]), results[4]); + } } - else if(results=command.match(/^kick/)) { - results = command.match(/^kick ([a-zA-Z0-9]+) ?(.*)/); - if (!results) { - player.chat("Usage: /kick [reason]"); + else if (results = command.match(/^kick/)) { + results = command.match(/^kick ([a-zA-Z0-9]+)(?: (.*))?/); + if (!results) { + player.chat("Usage: /kick [reason]"); + } + else { + var username = results[1]; + var reason = results[2]; + + var kickPlayer = serv.getPlayer(username); + if (!kickPlayer) + player.chat(results[1] + " is not on this server!"); + else { + kickPlayer.kick(reason); + kickPlayer.emit("kicked",player,reason); + } + } + } + else if (results = command.match(/^ban/)) { + results = command.match(/^ban ([a-zA-Z0-9]+)(?: (.*))?/); + if (!results) { + player.chat("Usage: /ban [reason]"); + } + else { + username = results[1]; + reason = results[2]; + var banPlayer = serv.getPlayer(username); + if (banPlayer) { + banPlayer.ban(reason); + serv.emit("banned",player,username,reason); } else { - var kickPlayer = serv.getPlayer(results[1]); - if (!kickPlayer) { - player.chat(results[1] + " is not on this server!"); + serv.banUsername(username, reason, function (err) { + if(err) { + player.chat(results[1] + " is not a valid player!"); } else { - kickPlayer.kick(results[2] ? "\"" + results[2] + "\"" : "Kicked from server."); - serv.log(player.username + " kicked " + results[1] + (results[2] ? " (" + results[2] + ")" : "")); + serv.emit("banned",player,username,reason); + player.chat(results[1] + " was banned"); } + }); } + } } - else if(results=command.match(/^ban/)) { - results = command.match(/^ban ([a-zA-Z0-9]+) ?(.*)/); - if (!results) { - player.chat("Usage: /ban [reason]"); - } - else { - var banPlayer = serv.getPlayer(results[1]); - var kickReason = "You were banned!" + (results[2] ? " Reason: " + results[2] : ""); - var banReason = "You are banned!" + (results[2] ? " Reason: " + results[2] : ""); - if (banPlayer) banPlayer.ban(banReason, kickReason); - else { - serv.banUsername(results[1], banReason, function(success) { - if (success) { - serv.log(player.username + " banned " + results[1] + (results[2] ? " (" + results[2] + ")" : "")); - player.chat(results[1] + " was banned"); - } else { - player.chat(results[1] + " is not a valid player!"); - } - }); - } - } - } - else if(results=command.match(/^pardon/)) { - results = command.match(/^pardon ([a-zA-Z0-9]+)/); - if (!results) { - player.chat("Usage: /pardon "); - } - else { - serv.pardonUsername(results[1], function(success) {; - if (success) { - player.chat(results[1] + " is unbanned"); - } else { - player.chat(results[1] + " is not banned"); - } - }); - } + else if (results = command.match(/^pardon/)) { + results = command.match(/^pardon ([a-zA-Z0-9]+)/); + if (!results) { + player.chat("Usage: /pardon "); + } + else { + serv.pardonUsername(results[1], function (err) { + if(err) { + player.chat(results[1] + " is not banned"); + } + else { + player.chat(results[1] + " is unbanned"); + } + }); + } } else player.chat("Invalid command."); } - player.handleCommand=handleCommand; + player.handleCommand = handleCommand; } \ No newline at end of file diff --git a/lib/playerPlugins/log.js b/lib/playerPlugins/log.js index a548299..e4216fb 100644 --- a/lib/playerPlugins/log.js +++ b/lib/playerPlugins/log.js @@ -24,4 +24,8 @@ function inject(serv,player) serv.log("[INFO] " + message); }); + player.on("kicked",function(kicker,reason){ + serv.log(kicker.username + " kicked " + player.username + (reason ? " (" + reason + ")" : "")); + }) + } \ No newline at end of file diff --git a/lib/playerPlugins/login.js b/lib/playerPlugins/login.js index 925c29a..cb75cc8 100644 --- a/lib/playerPlugins/login.js +++ b/lib/playerPlugins/login.js @@ -1,6 +1,4 @@ var Entity=require("prismarine-entity"); -var vec3 = require("vec3"); -var moment = require("moment"); module.exports=inject; @@ -9,16 +7,6 @@ function transformUuid(s) return s.split("-").map(function(item) { return parseInt(item, 16); }); } -function plainUuid(s) -{ - return s.replace(/-/g, ''); -} - -function toFixedPosition(p) -{ - return new vec3(Math.floor(p.x*32),Math.floor(p.y*32),Math.floor(p.z*32)) -} - function inject(serv,player) { function addPlayer() @@ -99,18 +87,6 @@ function inject(serv,player) }); player.gameMode=gameMode; } - - function kick(reason) - { - player._client.write('kick_disconnect', { - reason: reason ? JSON.stringify(reason) : '"You were kicked!"' - }); - } - - function ban(reason, kickReason) { - player.kick(kickReason || reason || "You were banned!"); - serv.ban(plainUuid(player._client.uuid), reason); - } function fillTabList() { @@ -165,7 +141,6 @@ function inject(serv,player) function spawn() { - var spawnPoint=toFixedPosition(player.spawnPoint); player._writeOthers('named_entity_spawn',{ entityId: player.entity.id, playerUUID: transformUuid(player._client.uuid), @@ -192,13 +167,12 @@ function inject(serv,player) player._client.end("You are already connected"); return; } - addPlayer(); // Added before kicking so no errors in deleting entity - - if (serv.bannedPlayers[plainUuid(player._client.uuid)]) { - player.kick(serv.bannedPlayers[plainUuid(player._client.uuid)].reason); - return; + if (serv.bannedPlayers[player._client.uuid]) { + player.kick(serv.bannedPlayers[player._client.uuid].reason); + return; } - + + addPlayer(); sendLogin(); sendMap(); sendSpawnPosition(); @@ -217,8 +191,6 @@ function inject(serv,player) player.setGameMode=setGameMode; - player.kick=kick; - player.ban=ban; player.login=login; player.sendInitialPosition=sendInitialPosition; player.spawn=spawn; diff --git a/lib/playerPlugins/logout.js b/lib/playerPlugins/logout.js index b456e2e..c17d7ca 100644 --- a/lib/playerPlugins/logout.js +++ b/lib/playerPlugins/logout.js @@ -8,21 +8,23 @@ function transformUuid(s) function inject(serv,player) { player._client.on('end', function () { - serv.broadcast(player.username + ' quit the game.', "yellow"); - player._writeOthers('player_info', { - action: 4, - data: [{ - UUID: transformUuid(player._client.uuid) - }] - }); - player._writeOthers('entity_destroy', {'entityIds': [player.entity.id]}); - delete serv.entities[player.entity.id]; - player.emit('disconnected'); - var index = serv.players.indexOf(player); - if (index > -1) { - serv.players.splice(index,1); + if(player.entity) { + serv.broadcast(player.username + ' quit the game.', "yellow"); + player._writeOthers('player_info', { + action: 4, + data: [{ + UUID: transformUuid(player._client.uuid) + }] + }); + player._writeOthers('entity_destroy', {'entityIds': [player.entity.id]}); + delete serv.entities[player.entity.id]; + player.emit('disconnected'); + var index = serv.players.indexOf(player); + if (index > -1) { + serv.players.splice(index, 1); + } + delete serv.uuidToPlayer[player._client.uuid]; } - delete serv.uuidToPlayer[player._client.uuid]; }); diff --git a/lib/playerPlugins/moderation.js b/lib/playerPlugins/moderation.js new file mode 100644 index 0000000..37e85c4 --- /dev/null +++ b/lib/playerPlugins/moderation.js @@ -0,0 +1,29 @@ +var moment=require("moment"); + +module.exports=inject; + +function inject(serv,player) +{ + function kick(reason) + { + player._client.write('kick_disconnect', { + reason: reason ? JSON.stringify(reason) : '"You were kicked!"' + }); + } + + function ban(reason) { + reason = reason || "You were banned!"; + player.kick(reason); + var uuid=player._client.uuid; + serv.ban(uuid, reason); + } + + function pardon() { + var uuid=player._client.uuid; + return serv.pardon(uuid); + } + + player.kick=kick; + player.ban=ban; + player.pardon=pardon; +} \ No newline at end of file diff --git a/lib/serverPlugins/log.js b/lib/serverPlugins/log.js index 24a205b..5a25ace 100644 --- a/lib/serverPlugins/log.js +++ b/lib/serverPlugins/log.js @@ -16,6 +16,10 @@ function inject(serv,settings) log('[INFO]: Server listening on port '+port); }); + serv.on("banned",function(banner,bannedUsername,reason){ + serv.log(banner.username + " banned " + bannedUsername + (reason ? " (" + reason + ")" : "")); + }); + var logFile=path.join("logs",timeStarted + ".log"); function log(message) { diff --git a/lib/serverPlugins/login.js b/lib/serverPlugins/login.js index b82a41b..bb7ee0d 100644 --- a/lib/serverPlugins/login.js +++ b/lib/serverPlugins/login.js @@ -2,8 +2,6 @@ var path = require('path'); var requireIndex = require('requireindex'); var playerPlugins = requireIndex(path.join(__dirname,'..', 'playerPlugins')); var Player=require("../player"); -var moment=require("moment"); -var request=require("request"); module.exports = inject; @@ -18,48 +16,4 @@ function inject(serv,options) serv.emit("newPlayer",player); player.login(); }); - - function ban(uuid, reason) { - serv.bannedPlayers[uuid] = { - time: +moment(), - reason: reason || "You are banned!" - }; - } - - function getUUIDFromUsername(username, cb) { - request('https://api.mojang.com/users/profiles/minecraft/' + username, function(err, res, body) { - cb(body ? JSON.parse(body).id : null); - }); - } - - function banUsername(username, reason, cb) { - serv.getUUIDFromUsername(username, function(uuid) { - if (!uuid) return cb ? cb(false) : false; - serv.ban(uuid, reason); - if (cb) cb(true); - }); - } - - function pardonUsername(username, cb) { - serv.getUUIDFromUsername(username, function(uuid) { - if (!cb) return; - if (!uuid) return cb(false); - else return cb(pardon(uuid)); - }); - } - - function pardon(uuid) { - if (serv.bannedPlayers[uuid]) { - delete serv.bannedPlayers[uuid]; - return true; - } else { - return false; - } - } - - serv.bannedPlayers = {}; - serv.ban = ban; - serv.banUsername = banUsername; - serv.pardonUsername = pardonUsername; - serv.getUUIDFromUsername = getUUIDFromUsername; } \ No newline at end of file diff --git a/lib/serverPlugins/moderation.js b/lib/serverPlugins/moderation.js new file mode 100644 index 0000000..77814af --- /dev/null +++ b/lib/serverPlugins/moderation.js @@ -0,0 +1,75 @@ +var moment=require("moment"); +var request=require("request"); +var nodeUuid=require('node-uuid'); + +module.exports = inject; + +function inject(serv) +{ + + function ban(uuid, reason) { + serv.bannedPlayers[uuid] = { + time: +moment(), + reason: reason || "You are banned!" + }; + } + + function uuidInParts(plainUUID) + { + return nodeUuid.unparse(nodeUuid.parse(plainUUID)); + } + + function getUUIDFromUsername(username, cb) { + request('https://api.mojang.com/users/profiles/minecraft/' + username, function(err, res, body) { + if(!body || err) + { + cb(new Error("username not found")); + return; + } + cb(null,uuidInParts(JSON.parse(body).id)); + }); + } + + function banUsername(username, reason, cb) { + serv.getUUIDFromUsername(username, function(err,uuid) { + if(err) + { + cb(err); + return; + } + serv.ban(uuid, reason); + cb(); + }); + } + + function pardonUsername(username, cb) { + serv.getUUIDFromUsername(username, function(err,uuid) { + if(err) + { + cb(err); + return; + } + var result=pardon(uuid); + if(!result) + { + cb(new Error("Player wasn't banned.")); + return; + } + cb(); + }); + } + + function pardon(uuid) { + if (serv.bannedPlayers[uuid]) { + delete serv.bannedPlayers[uuid]; + return true; + } + return false; + } + + serv.bannedPlayers = {}; + serv.ban = ban; + serv.banUsername = banUsername; + serv.pardonUsername = pardonUsername; + serv.getUUIDFromUsername = getUUIDFromUsername; +} \ No newline at end of file diff --git a/lib/serverPlugins/players.js b/lib/serverPlugins/players.js index cd65f87..73c2717 100644 --- a/lib/serverPlugins/players.js +++ b/lib/serverPlugins/players.js @@ -6,7 +6,7 @@ function inject(serv) serv.players=[]; serv.uuidToPlayer={}; serv.entities={}; - + function getPlayer(username) { for (var p in serv.players) { if (serv.players[p].username == username) return serv.players[p]