From 67af4a8144f0c18c56fa1a9a93443a9a7c4b8e44 Mon Sep 17 00:00:00 2001 From: DemiPixel Date: Wed, 9 Dec 2015 17:34:03 -0800 Subject: [PATCH 1/8] Fix tp and setblock, implement relative position function, throw errors instead of returning, catch errors and display error --- src/lib/UserError.js | 5 +++++ src/lib/plugins/blocks.js | 18 ++++++------------ src/lib/plugins/commands.js | 24 +++++++++++++++++------- src/lib/plugins/tp.js | 17 ++++++----------- src/lib/plugins/updatePositions.js | 2 +- 5 files changed, 35 insertions(+), 31 deletions(-) create mode 100644 src/lib/UserError.js diff --git a/src/lib/UserError.js b/src/lib/UserError.js new file mode 100644 index 0000000..c111340 --- /dev/null +++ b/src/lib/UserError.js @@ -0,0 +1,5 @@ +class UserError extends Error { + +} + +module.exports = UserError; \ No newline at end of file diff --git a/src/lib/plugins/blocks.js b/src/lib/plugins/blocks.js index d47c383..7a77158 100644 --- a/src/lib/plugins/blocks.js +++ b/src/lib/plugins/blocks.js @@ -30,24 +30,18 @@ module.exports.player=function(player,serv) player.commands.add({ base: 'setblock', - info: 'to put a block', - usage: '/setblock ', + info: 'set a block at a position', + usage: '/setblock [data]', op: true, parse(str) { - var results = str.match(/^(~|~?-?[0-9]*) (~|~?-?[0-9]*) (~|~?-?[0-9]*) ([0-9]{1,3}) ([0-9]{1,3})/); + var results = str.match(/^(~|~?-?[0-9]+) (~|~?-?[0-9]+) (~|~?-?[0-9]+) ([0-9]{1,3})(?: ([0-9]{1,3}))?/); if(!results) return false; return results; }, action(params) { - var res = params.map((num, i) => { // parseInt parameters - if (num.indexOf('~') == 0) { - return (player.position[['', 'x', 'y', 'z'][i]] >> 5) + parseInt(num.slice(1) || 0); - } else { - return parseInt(num); // return parseInt>>5 if position, not id - } - }); - - player.setBlock(new Vec3(res[1], res[2], res[3]), res[4],res[5]); + var res = params.slice(1, 4); + res = res.map((val, i) => serv.posFromString(val, player.position[['x','y','z'][i]] / 32)) + player.setBlock(new Vec3(res[0], res[1], res[2]).floored(), params[4], params[5] || 0); } }); }; \ No newline at end of file diff --git a/src/lib/plugins/commands.js b/src/lib/plugins/commands.js index 0999d31..30211c8 100644 --- a/src/lib/plugins/commands.js +++ b/src/lib/plugins/commands.js @@ -1,3 +1,6 @@ +var Vec3 = require("vec3").Vec3; +var UserError = require('../UserError'); + module.exports.player=function(player, serv) { player.commands.add({ @@ -83,8 +86,7 @@ module.exports.player=function(player, serv) { }, action(sel) { var arr = serv.selectorString(sel, player.position.scaled(1/32), player.world); - if (arr instanceof Error) return arr.toString(); - else if (arr == null) return 'Could not find player'; + if (arr == null) return 'Could not find player'; else player.chat(JSON.stringify(arr.map(a => a.id))); } }); @@ -96,7 +98,8 @@ module.exports.player=function(player, serv) { if (res) player.chat('' + res); } catch(err) { - setTimeout(() => {throw err;}, 0); + if (err instanceof UserError) player.chat('Error: ' + err.toString()); + else setTimeout(() => {throw err;}, 0); } } }; @@ -126,7 +129,7 @@ module.exports.server = function(serv) { serv.selector = (type, opt) => { if (['all', 'random', 'near', 'entity'].indexOf(type) == -1) - return new Error('serv.selector(): type must be either [all, random, near, or entity]'); + throw new UserError('serv.selector(): type must be either [all, random, near, or entity]'); var count = typeof opt.count != 'undefined' ? count : @@ -214,7 +217,7 @@ module.exports.server = function(serv) { var player = serv.getPlayer(str); if (!player && str[0] != '@') return null; var match = str.match(/^@([a,r,p,e])(?:\[([^\]]+)\])?$/); - if (match == null) return new Error('Invalid selector format'); + if (match == null) throw new UserError('Invalid selector format'); var typeConversion = { a: 'all', r: 'random', @@ -227,10 +230,10 @@ module.exports.server = function(serv) { var err; opt.forEach(o => { var match = o.match(/^([^=]+)=([^=]+)$/); - if (match == null) err = new Error('Invalid selector option format: "' + o + '"'); + if (match == null) err = new UserError('Invalid selector option format: "' + o + '"'); else optPair.push({key: match[1], val: match[2]}); }); - if (err) return err; + if (err) throw err; var optConversion = { type: 'type', @@ -269,4 +272,11 @@ module.exports.server = function(serv) { return serv.selector(type, data); } + + serv.posFromString = (str, pos) => { + if (parseInt(str)) return parseInt(str); + if (str.match(/~-?\d+/)) return parseInt(str.slice(1)) + pos; + else if (str == '~') return pos; + else throw new UserError('Invalid position'); + }; } \ No newline at end of file diff --git a/src/lib/plugins/tp.js b/src/lib/plugins/tp.js index 0c0895d..2c48db1 100644 --- a/src/lib/plugins/tp.js +++ b/src/lib/plugins/tp.js @@ -2,11 +2,6 @@ var Vec3 = require("vec3").Vec3; module.exports.player = (player, serv) => { - var getPos = (num, dir='x', p=player) => { - if (num[0] == '~') return p.position[dir] + parseInt(num.slice(1, num.length) || 0)*32; - else return parseInt(num)*32; - } - player.commands.add({ base: 'teleport', aliases: ['tp'], @@ -26,9 +21,9 @@ module.exports.player = (player, serv) => { player_from.teleport(player_to.position.clone()); } else if(args.length === 3) { - let x = getPos(args[0], 'x'); - let y = getPos(args[1], 'y'); - let z = getPos(args[2], 'z'); + let x = serv.posFromString(args[0], player.position.x / 32); + let y = serv.posFromString(args[1], player.position.y / 32); + let z = serv.posFromString(args[2], player.position.z / 32); player.teleport(new Vec3(x, y, z)); } else if(args.length === 4) { @@ -37,9 +32,9 @@ module.exports.player = (player, serv) => { if(!(player_from = serv.getPlayer(args[0]))) return false; - let x = getPos(args[1], 'x', player_from); - let y = getPos(args[2], 'y', player_from); - let z = getPos(args[3], 'z', player_from); + let x = serv.posFromString(args[1], player_from.x / 32); + let y = serv.posFromString(args[2], player_from.y / 32); + let z = serv.posFromString(args[3], player_from.z / 32); player_from.teleport(new Vec3(x, y, z)); } diff --git a/src/lib/plugins/updatePositions.js b/src/lib/plugins/updatePositions.js index f10283e..9609581 100644 --- a/src/lib/plugins/updatePositions.js +++ b/src/lib/plugins/updatePositions.js @@ -99,7 +99,7 @@ module.exports.player=function(player) }; player.teleport = async (position) => { - await player.sendRelativePositionChange(position, false); + await player.sendRelativePositionChange(position.scaled(32).floored(), false); player.sendPosition(); } }; From fe2f220f10461b2f3dddd1a515791b4b89aed091 Mon Sep 17 00:00:00 2001 From: DemiPixel Date: Wed, 9 Dec 2015 18:31:05 -0800 Subject: [PATCH 2/8] Big changes to player/entity.sendPosition and entity/player.teleport. Not fully working yet. --- src/lib/behavior.js | 13 +++-- src/lib/plugins/commands.js | 3 +- src/lib/plugins/entities.js | 5 +- src/lib/plugins/login.js | 2 +- src/lib/plugins/physics.js | 10 ++-- src/lib/plugins/respawn.js | 2 +- src/lib/plugins/tp.js | 20 +++----- src/lib/plugins/updatePositions.js | 81 ++++++++++-------------------- src/lib/plugins/world.js | 2 +- 9 files changed, 55 insertions(+), 83 deletions(-) diff --git a/src/lib/behavior.js b/src/lib/behavior.js index 6469d95..c22fce6 100644 --- a/src/lib/behavior.js +++ b/src/lib/behavior.js @@ -13,13 +13,20 @@ module.exports = (obj) => { defaultCancel = dC; }; + var resp; + await obj.emitThen(eventName + '_cancel', data, cancel).catch((err)=> setTimeout(() => {throw err;},0)); await obj.emitThen(eventName, data, cancelled, cancelCount).catch((err)=> setTimeout(() => {throw err;},0)); - if (!hiddenCancelled && !cancelled) await func(data).catch((err)=> setTimeout(() => {throw err;},0)); - else if (cancelFunc && defaultCancel) await cancelFunc(data).catch((err)=> setTimeout(() => {throw err;},0)); + if (!hiddenCancelled && !cancelled) { + resp = await func(data).catch((err)=> setTimeout(() => {throw err;},0)); + if (typeof resp == 'undefined') resp = true; + } else if (cancelFunc && defaultCancel) { + resp = await cancelFunc(data).catch((err)=> setTimeout(() => {throw err;},0)); + if (typeof resp == 'undefined') resp = false; + } await obj.emitThen(eventName + '_done', data, cancelled).catch((err)=> setTimeout(() => {throw err;},0)); - return data; + return resp; } }; \ No newline at end of file diff --git a/src/lib/plugins/commands.js b/src/lib/plugins/commands.js index 30211c8..2ed331c 100644 --- a/src/lib/plugins/commands.js +++ b/src/lib/plugins/commands.js @@ -212,10 +212,11 @@ module.exports.server = function(serv) { else return sample.slice(count); // Negative, returns from end } - serv.selectorString = (str, pos, world) => { + serv.selectorString = (str, pos, world, allowUser=true) => { pos = pos.clone(); var player = serv.getPlayer(str); if (!player && str[0] != '@') return null; + else if (player) return allowUser ? [player] : null; var match = str.match(/^@([a,r,p,e])(?:\[([^\]]+)\])?$/); if (match == null) throw new UserError('Invalid selector format'); var typeConversion = { diff --git a/src/lib/plugins/entities.js b/src/lib/plugins/entities.js index b0b580b..f4e4cf9 100644 --- a/src/lib/plugins/entities.js +++ b/src/lib/plugins/entities.js @@ -19,9 +19,8 @@ module.exports.server=function(serv,options) { } } if (!entity.velocity || !entity.size) return; - var oldPosAndOnGround = await entity.calculatePhysics(delta); - if (!oldPosAndOnGround.oldPos.equals(new Vec3(0,0,0))) - if (entity.type == 'mob') entity.sendPosition(oldPosAndOnGround); + var posAndOnGround = await entity.calculatePhysics(delta); + if (entity.type == 'mob') entity.sendPosition(posAndOnGround); }) ).catch((err)=> setTimeout(() => {throw err;},0)); }); diff --git a/src/lib/plugins/login.js b/src/lib/plugins/login.js index b685927..cbf721d 100644 --- a/src/lib/plugins/login.js +++ b/src/lib/plugins/login.js @@ -158,7 +158,7 @@ module.exports.player=function(player,serv) sendLogin(); await player.sendMap(); player.sendSpawnPosition(); - player.sendPosition(); + player.sendSelfPosition(); player.updateHealth(player.health); diff --git a/src/lib/plugins/physics.js b/src/lib/plugins/physics.js index ba3b183..1a1a70d 100644 --- a/src/lib/plugins/physics.js +++ b/src/lib/plugins/physics.js @@ -27,14 +27,14 @@ module.exports.entity=function(entity){ entity.velocity.z = getFriction(entity.velocity.z, entity.friction.z, delta); } - var oldPos = entity.position.clone(); + var newPos = entity.position.clone(); - entity.position.x += getMoveAmount('x', xBlock, entity, delta, sizeSigned.x); - entity.position.y += getMoveAmount('y', yBlock, entity, delta, sizeSigned.y); - entity.position.z += getMoveAmount('z', zBlock, entity, delta, sizeSigned.z); + newPos.x += getMoveAmount('x', xBlock, entity, delta, sizeSigned.x); + newPos.y += getMoveAmount('y', yBlock, entity, delta, sizeSigned.y); + newPos.z += getMoveAmount('z', zBlock, entity, delta, sizeSigned.z); //serv.emitParticle(30, serv.overworld, entity.position.scaled(1/32), { size: new Vec3(0, 0, 0) }); - return { oldPos: oldPos, onGround: yBlock} + return { position: newPos, onGround: yBlock} }; diff --git a/src/lib/plugins/respawn.js b/src/lib/plugins/respawn.js index a1bdc89..c6ce56e 100644 --- a/src/lib/plugins/respawn.js +++ b/src/lib/plugins/respawn.js @@ -9,7 +9,7 @@ module.exports.player=function(player) gamemode:player.gameMode, levelType:'default' }); - player.sendPosition(); + player.sendSelfPosition(); player.updateHealth(20); player.nearbyEntities=[]; player.updateAndSpawn(); diff --git a/src/lib/plugins/tp.js b/src/lib/plugins/tp.js index 2c48db1..3b23135 100644 --- a/src/lib/plugins/tp.js +++ b/src/lib/plugins/tp.js @@ -9,17 +9,14 @@ module.exports.player = (player, serv) => { usage: '/teleport [target player] [y] [z]', op: true, parse(str) { - return str.match(/^(((\w* )?~?-?\d* ~?-?\d* ~?-?\d*)|(\w* \w*))$/) ? str.split(' ') : false; + return str.match(/^(((.* )?~?-?\d* ~?-?\d* ~?-?\d*)|(.+ .+))$/) ? str.split(' ') : false; }, action(args) { - if(args.length === 2 && args[0] !== args[1]) { - let player_from; - let player_to; + if(args.length === 2) { + let entities_from = serv.selectorString(args[0]); + let entity_to = serv.selectorString(args[1])[0]; - if(!(player_from = serv.getPlayer(args[0])) || !(player_to = serv.getPlayer(args[1]))) - return false; - - player_from.teleport(player_to.position.clone()); + entities_from.forEach(e => e.teleport(entity_to.position.scaled(1/32))); } else if(args.length === 3) { let x = serv.posFromString(args[0], player.position.x / 32); let y = serv.posFromString(args[1], player.position.y / 32); @@ -27,16 +24,13 @@ module.exports.player = (player, serv) => { player.teleport(new Vec3(x, y, z)); } else if(args.length === 4) { - let player_from; - - if(!(player_from = serv.getPlayer(args[0]))) - return false; + let entities_from = serv.selectorString(args[0]); let x = serv.posFromString(args[1], player_from.x / 32); let y = serv.posFromString(args[2], player_from.y / 32); let z = serv.posFromString(args[3], player_from.z / 32); - player_from.teleport(new Vec3(x, y, z)); + entities_from.forEach(e => e.teleport(new Vec3(x, y, z))); } } }); diff --git a/src/lib/plugins/updatePositions.js b/src/lib/plugins/updatePositions.js index 9609581..20445b9 100644 --- a/src/lib/plugins/updatePositions.js +++ b/src/lib/plugins/updatePositions.js @@ -39,55 +39,21 @@ module.exports.player=function(player) headYaw: convYaw }); }, () => { - player.sendPosition(); + player.sendSelfPosition(); }); } - player._client.on('position', ({x,y,z,onGround} = {}) => - player.sendRelativePositionChange((new Vec3(x, y, z)).toFixedPosition(), onGround)); + player._client.on('position', ({x,y,z,onGround} = {}) => { + console.log(x,y,z); + player.sendPosition((new Vec3(x, y, z)).toFixedPosition(), onGround); + }); player._client.on('position_look', ({x,y,z,onGround,yaw,pitch} = {}) => { - player.sendRelativePositionChange((new Vec3(x, y, z)).toFixedPosition(), onGround); + player.sendPosition((new Vec3(x, y, z)).toFixedPosition(), onGround); sendLook(yaw,pitch,onGround); }); - player.sendRelativePositionChange = (newPosition, onGround) => { - return player.behavior('move', { - onGround: onGround, - position: newPosition - }, async ({onGround, position}) => { - if (player.position.distanceTo(new Vec3(0, 0, 0)) != 0) { - var diff = position.minus(player.position); - if(diff.abs().x>127 || diff.abs().y>127 || diff.abs().z>127) - { - player._writeOthersNearby('entity_teleport', { - entityId:player.id, - x: position.x, - y: position.y, - z: position.z, - yaw: player.yaw, - pitch: player.pitch, - onGround: onGround - }); - } - else if (diff.distanceTo(new Vec3(0, 0, 0)) != 0) { - player._writeOthersNearby('rel_entity_move', { - entityId: player.id, - dX: diff.x, - dY: diff.y, - dZ: diff.z, - onGround: onGround - }); - } - } - player.position = position; - player.onGround = onGround; - }, () => { - player.sendPosition(); - }); - }; - - player.sendPosition = () => { + player.sendSelfPosition = () => { player._client.write('position', { x: player.position.x/32, y: player.position.y/32, @@ -99,25 +65,25 @@ module.exports.player=function(player) }; player.teleport = async (position) => { - await player.sendRelativePositionChange(position.scaled(32).floored(), false); - player.sendPosition(); + var notCancelled = await player.sendSelfPosition(position.scaled(32).floored(), false, true); + if (notCancelled) player.sendSelfPosition(); } }; module.exports.entity=function(entity,serv){ - entity.sendPosition = ({oldPos,onGround}) => { - entity.behavior('move', { - old: oldPos, + entity.sendPosition = (position, onGround, teleport=false) => { + if (entity.position.equals(position) && entity.onGround == onGround) return Promise.resolve(); + return entity.behavior(teleport ? 'teleport' : 'move', { + position: position, onGround: onGround - }, ({old,onGround}) => { - var diff = entity.position.minus(old); - + }, ({position,onGround}) => { + var diff = position.minus(entity.position); if(diff.abs().x>127 || diff.abs().y>127 || diff.abs().z>127) entity._writeOthersNearby('entity_teleport', { entityId: entity.id, - x: entity.position.x, - y: entity.position.y, - z: entity.position.z, + x: position.x, + y: position.y, + z: position.z, yaw: entity.yaw, pitch: entity.pitch, onGround: onGround @@ -129,13 +95,14 @@ module.exports.entity=function(entity,serv){ dZ: diff.z, onGround: onGround }, entity); + + entity.position = position; + entity.onGround = onGround; }, () => { - entity.position = oldPos; + if (entity.type == 'player') player.sendSelfPosition(); }); }; - - entity.sendVelocity = (vel, maxVel) => { var velocity = vel.scaled(32).floored(); // Make fixed point var maxVelocity = maxVel.scaled(32).floored(); @@ -152,6 +119,10 @@ module.exports.entity=function(entity,serv){ } }; + entity.teleport = (pos) => { // Overwritten in players inject above + entity.sendPosition(entity.position, false, true); + } + function addVelocityWithMax(current, newVel, max) { var x, y, z; if (current.x > max.x || current.x < -max.x) x = current.x; diff --git a/src/lib/plugins/world.js b/src/lib/plugins/world.js index 907b444..3dd9f9e 100644 --- a/src/lib/plugins/world.js +++ b/src/lib/plugins/world.js @@ -159,7 +159,7 @@ module.exports.player=function(player,serv,settings) { await player.sendMap(); - player.sendPosition(); + player.sendSelfPosition(); player.emit('change_world'); await player.waitPlayerLogin(); From cbb2068454a5a5a0f93de725f62482410bacea58 Mon Sep 17 00:00:00 2001 From: DemiPixel Date: Wed, 9 Dec 2015 21:53:29 -0800 Subject: [PATCH 3/8] Made /help not shit --- src/lib/command.js | 6 ++-- src/lib/plugins/commands.js | 54 +++++++++++++++++++----------- src/lib/plugins/updatePositions.js | 5 ++- 3 files changed, 41 insertions(+), 24 deletions(-) diff --git a/src/lib/command.js b/src/lib/command.js index 2e827ba..26a072c 100644 --- a/src/lib/command.js +++ b/src/lib/command.js @@ -3,6 +3,8 @@ class Command { this.params = params; this.parent = parent; this.hash = parent ? parent.hash : {}; + this.parentBase = (this.parent && this.parent.base && this.parent.base + ' ') || ''; + this.base = this.parentBase + (this.params.base || ''); this.updateHistory(); } @@ -44,9 +46,9 @@ class Command { updateHistory() { var all = '(.+?)'; - var list = [this.params.base]; + var list = [this.base]; if(this.params.aliases && this.params.aliases.length) { - this.params.aliases.forEach(al => list.unshift(al)); + this.params.aliases.forEach(al => list.unshift(this.parentBase + al)); } list.forEach((command) => { diff --git a/src/lib/plugins/commands.js b/src/lib/plugins/commands.js index 2ed331c..686cd3f 100644 --- a/src/lib/plugins/commands.js +++ b/src/lib/plugins/commands.js @@ -7,29 +7,45 @@ module.exports.player=function(player, serv) { base: 'help', info: 'to show all commands', usage: '/help [command]', - action(params) { - var c = params[0]; + parse(str) { + var params = str.split(' '); + var page = parseInt(params[params.length-1]); + var search = ''; + if (page) { + params.pop(); + } + search = params.join(' '); + return { search: search, page: (page && page - 1) || 0 }; + }, + action({search, page}) { + if (page < 0) return 'Page # must be >= 1'; var hash = player.commands.hash; - if(c) { - var f=player.commands.find(c); - if(f==undefined || f.length==0) return 'Command '+c+' not found'; - return f[0].params.usage + ' ' + f[0].params.info; + var PAGE_LENGTH = 8; + + var found = Object.keys(hash).filter(h => (h + ' ').indexOf((search && search + ' ') || '') == 0); + var totalPages = Math.floor(found.length / PAGE_LENGTH); + if (found.length > 1 && totalPages < page) { + return 'There are only ' + (totalPages + 1) + ' help pages.'; + } + + if (found.indexOf(search) != -1) { + var cmd = hash[search]; + player.chat('/' + cmd.base + ' -' + ((cmd.params && ' ' + cmd.params.info) || '=-=-=-=-=-=-=-=-')); + if (cmd.params && cmd.params.usage) player.chat(cmd.params.usage); + } else if (found.length > 1) { + player.chat('Help -=-=-=-=-=-=-=-=-'); + } + + if (found.length == 0) { + return 'Could not find any matches'; } else { - var used = []; - for(var key in hash) { - if(used.indexOf(hash[key]) > -1) continue; - used.push(hash[key]); - - if(hash[key].params.info && (player.op || !hash[key].params.op)) { - var str = hash[key].params.usage + ' ' + hash[key].params.info; - if(hash[key].params.aliases && hash[key].params.aliases.length) { - str += ' (aliases: ' + hash[key].params.aliases.join(', ') + ')'; - } - - player.chat(str); - } + found = found.sort(); + for (var i = PAGE_LENGTH*page; i < Math.min(PAGE_LENGTH*(page + 1), found.length); i++) { + var cmd = hash[found[i]]; + player.chat(cmd.params.base + ': ' + cmd.params.info); } + player.chat('--=[Page ' + (page + 1) + ' of ' + (totalPages + 1) + ']=--') } } }); diff --git a/src/lib/plugins/updatePositions.js b/src/lib/plugins/updatePositions.js index 20445b9..997116a 100644 --- a/src/lib/plugins/updatePositions.js +++ b/src/lib/plugins/updatePositions.js @@ -44,7 +44,6 @@ module.exports.player=function(player) } player._client.on('position', ({x,y,z,onGround} = {}) => { - console.log(x,y,z); player.sendPosition((new Vec3(x, y, z)).toFixedPosition(), onGround); }); @@ -88,13 +87,13 @@ module.exports.entity=function(entity,serv){ pitch: entity.pitch, onGround: onGround }); - else if (diff.distanceTo(new Vec3(0, 0, 0)) != 0) serv._writeNearby('rel_entity_move', { + else if (diff.distanceTo(new Vec3(0, 0, 0)) != 0) serv._writeOthersNearby('rel_entity_move', { entityId: entity.id, dX: diff.x, dY: diff.y, dZ: diff.z, onGround: onGround - }, entity); + }); entity.position = position; entity.onGround = onGround; From f38ea36c5575e1414a587f6db2e8a148cae13c25 Mon Sep 17 00:00:00 2001 From: DemiPixel Date: Thu, 10 Dec 2015 00:14:29 -0800 Subject: [PATCH 4/8] Make UserError in index.js --- src/index.js | 3 ++- src/lib/plugins/commands.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 5a676d6..e30e3f2 100644 --- a/src/index.js +++ b/src/index.js @@ -13,7 +13,8 @@ module.exports = { Command:require("./lib/command"), version:require("./lib/version"), generations:require("./lib/generations"), - experience:require("./lib/experience") + experience:require("./lib/experience"), + UserError:require("./lib/UserError") }; function createMCServer(options) { diff --git a/src/lib/plugins/commands.js b/src/lib/plugins/commands.js index 686cd3f..96a05ca 100644 --- a/src/lib/plugins/commands.js +++ b/src/lib/plugins/commands.js @@ -1,5 +1,5 @@ var Vec3 = require("vec3").Vec3; -var UserError = require('../UserError'); +var UserError = require('flying-squid').UserError; module.exports.player=function(player, serv) { From 9b0970b29187d0a92d78f3dace0345680ad8a293 Mon Sep 17 00:00:00 2001 From: DemiPixel Date: Thu, 10 Dec 2015 09:06:20 -0800 Subject: [PATCH 5/8] Fix tp, implement entity.selectorString --- src/lib/plugins/commands.js | 4 ++++ src/lib/plugins/tp.js | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/lib/plugins/commands.js b/src/lib/plugins/commands.js index 96a05ca..20b4d6e 100644 --- a/src/lib/plugins/commands.js +++ b/src/lib/plugins/commands.js @@ -120,6 +120,10 @@ module.exports.player=function(player, serv) { } }; +module.exports.entity = function(entity, serv) { + entity.selectorString = (str) => serv.selectorString(str, entity.position.scaled(1/32), entity.world); +} + module.exports.server = function(serv) { function shuffleArray(array) { diff --git a/src/lib/plugins/tp.js b/src/lib/plugins/tp.js index 3b23135..d6c7645 100644 --- a/src/lib/plugins/tp.js +++ b/src/lib/plugins/tp.js @@ -13,8 +13,8 @@ module.exports.player = (player, serv) => { }, action(args) { if(args.length === 2) { - let entities_from = serv.selectorString(args[0]); - let entity_to = serv.selectorString(args[1])[0]; + let entities_from = player.selectorString(args[0]); + let entity_to = player.selectorString(args[1])[0]; entities_from.forEach(e => e.teleport(entity_to.position.scaled(1/32))); } else if(args.length === 3) { @@ -24,7 +24,7 @@ module.exports.player = (player, serv) => { player.teleport(new Vec3(x, y, z)); } else if(args.length === 4) { - let entities_from = serv.selectorString(args[0]); + let entities_from = player.selectorString(args[0]); let x = serv.posFromString(args[1], player_from.x / 32); let y = serv.posFromString(args[2], player_from.y / 32); From b7aea8251fc14700087e7f21e7971d0b3b2469d9 Mon Sep 17 00:00:00 2001 From: DemiPixel Date: Thu, 10 Dec 2015 11:20:17 -0800 Subject: [PATCH 6/8] Fix tp, updatePosition, and tests --- src/index.js | 2 ++ src/lib/behavior.js | 8 +++++--- src/lib/plugins/entities.js | 2 +- src/lib/plugins/tp.js | 11 ++++++----- src/lib/plugins/updatePositions.js | 12 +++++++----- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/index.js b/src/index.js index e30e3f2..dd54436 100644 --- a/src/index.js +++ b/src/index.js @@ -40,5 +40,7 @@ class MCServer extends EventEmitter { this._server.on('error', error => this.emit('error',error)); this._server.on('listening', () => this.emit('listening',this._server.socketServer.address().port)); this.emit('asap'); + + process.on('unhandledRejection', err => this.emit('error',err)); } } \ No newline at end of file diff --git a/src/lib/behavior.js b/src/lib/behavior.js index c22fce6..f0274fd 100644 --- a/src/lib/behavior.js +++ b/src/lib/behavior.js @@ -19,14 +19,16 @@ module.exports = (obj) => { await obj.emitThen(eventName, data, cancelled, cancelCount).catch((err)=> setTimeout(() => {throw err;},0)); if (!hiddenCancelled && !cancelled) { - resp = await func(data).catch((err)=> setTimeout(() => {throw err;},0)); + resp = func(data); + if (resp instanceof Promise) resp = await resp.catch((err)=> setTimeout(() => {throw err;},0)); if (typeof resp == 'undefined') resp = true; } else if (cancelFunc && defaultCancel) { - resp = await cancelFunc(data).catch((err)=> setTimeout(() => {throw err;},0)); + resp = cancelFunc(data); + if (resp instanceof Promise) resp = await resp.catch((err)=> setTimeout(() => {throw err;},0)); if (typeof resp == 'undefined') resp = false; } - await obj.emitThen(eventName + '_done', data, cancelled).catch((err)=> setTimeout(() => {throw err;},0)); + return resp; } }; \ No newline at end of file diff --git a/src/lib/plugins/entities.js b/src/lib/plugins/entities.js index f4e4cf9..c373992 100644 --- a/src/lib/plugins/entities.js +++ b/src/lib/plugins/entities.js @@ -20,7 +20,7 @@ module.exports.server=function(serv,options) { } if (!entity.velocity || !entity.size) return; var posAndOnGround = await entity.calculatePhysics(delta); - if (entity.type == 'mob') entity.sendPosition(posAndOnGround); + if (entity.type == 'mob') entity.sendPosition(posAndOnGround.position, posAndOnGround.onGround); }) ).catch((err)=> setTimeout(() => {throw err;},0)); }); diff --git a/src/lib/plugins/tp.js b/src/lib/plugins/tp.js index d6c7645..3dc2191 100644 --- a/src/lib/plugins/tp.js +++ b/src/lib/plugins/tp.js @@ -23,14 +23,15 @@ module.exports.player = (player, serv) => { let z = serv.posFromString(args[2], player.position.z / 32); player.teleport(new Vec3(x, y, z)); + } else if(args.length === 4) { let entities_from = player.selectorString(args[0]); - let x = serv.posFromString(args[1], player_from.x / 32); - let y = serv.posFromString(args[2], player_from.y / 32); - let z = serv.posFromString(args[3], player_from.z / 32); - - entities_from.forEach(e => e.teleport(new Vec3(x, y, z))); + entities_from.forEach(e => e.teleport(new Vec3( + serv.posFromString(args[1], e.position.x / 32), + serv.posFromString(args[2], e.position.y / 32), + serv.posFromString(args[3], e.position.z / 32) + ))); } } }); diff --git a/src/lib/plugins/updatePositions.js b/src/lib/plugins/updatePositions.js index 997116a..55fe0af 100644 --- a/src/lib/plugins/updatePositions.js +++ b/src/lib/plugins/updatePositions.js @@ -64,17 +64,19 @@ module.exports.player=function(player) }; player.teleport = async (position) => { - var notCancelled = await player.sendSelfPosition(position.scaled(32).floored(), false, true); + var notCancelled = await player.sendPosition(position.scaled(32).floored(), false, true); if (notCancelled) player.sendSelfPosition(); } }; module.exports.entity=function(entity,serv){ entity.sendPosition = (position, onGround, teleport=false) => { + if (typeof position == 'undefined') throw new Error('undef'); if (entity.position.equals(position) && entity.onGround == onGround) return Promise.resolve(); - return entity.behavior(teleport ? 'teleport' : 'move', { + return entity.behavior('move', { position: position, - onGround: onGround + onGround: onGround, + teleport: teleport }, ({position,onGround}) => { var diff = position.minus(entity.position); if(diff.abs().x>127 || diff.abs().y>127 || diff.abs().z>127) @@ -87,7 +89,7 @@ module.exports.entity=function(entity,serv){ pitch: entity.pitch, onGround: onGround }); - else if (diff.distanceTo(new Vec3(0, 0, 0)) != 0) serv._writeOthersNearby('rel_entity_move', { + else if (diff.distanceTo(new Vec3(0, 0, 0)) != 0) entity._writeOthersNearby('rel_entity_move', { entityId: entity.id, dX: diff.x, dY: diff.y, @@ -119,7 +121,7 @@ module.exports.entity=function(entity,serv){ }; entity.teleport = (pos) => { // Overwritten in players inject above - entity.sendPosition(entity.position, false, true); + entity.sendPosition(pos.scaled(32), false, true); } function addVelocityWithMax(current, newVel, max) { From 32c01a088c7beb29c37695fd556839829289d504 Mon Sep 17 00:00:00 2001 From: DemiPixel Date: Thu, 10 Dec 2015 12:27:17 -0800 Subject: [PATCH 7/8] Improve contribute.md --- doc/CONTRIBUTE.md | 104 +++++++++++++++++----------------------------- 1 file changed, 39 insertions(+), 65 deletions(-) diff --git a/doc/CONTRIBUTE.md b/doc/CONTRIBUTE.md index df0847a..1f93ccf 100644 --- a/doc/CONTRIBUTE.md +++ b/doc/CONTRIBUTE.md @@ -5,93 +5,67 @@ Directory architecture : * app.js: specific settings and actually start the server -* index.js: contain the generic server implementation -* lib/: contain the classes and functions used in the plugins - * serverPlugins/: server plugins that do things general to the server, - properties and method are added to the server object in them - * playerPlugins/: player plugins that do things for each player, properties and method are added to the player object in them +* dist/: Contains "compiled" code (go to current directory in console and type `gulp` to generate this) +* src/: Source files for the project +* src/index.js: contain the generic server implementation +* src/lib: contain the classes and functions used in the plugins + * plugins/: All of the default plugins made to simulate vanilla + * worldGeneraions/: Contains default world generations, however plugins can use their own -Structure of a server plugin: +## Structure of a plugin ```js -module.exports=inject; -function inject(serv) -{ - // add methods and properties to serv +// Each of these are called an "inject" because you're injecting properties, events, methods, or data into the objects + +module.exports.server = function(serv) { // Create your server events here + serv.spawnPoint = ...; + serv.on('...', ...); } -``` -Structure of a player plugin : - -```js -module.exports=inject; - -function inject(serv,player) -{ - // add methods and properties to player - // you can use serv, but you shouldn't add things to it here +module.exports.entity = function(entity, serv) { // Called whenever an entity is created, do NOT do serv.on here + entity.health = 10; // Start with 10 health out of 20 + entity.on('...', ...); + // serv.on('...', ...); NOOOO } + +module.exports.player = function(player, serv) { // Player is a type of entity (entity inject is called first) with added properties and functions + player.setXp(100); // Example of a property player entities have but not other entities + player.on(',,,', ...); + // serv.on('...', .– don't even think about it +} + ``` ## 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. +logging uses methods and events from `log.js`. These include `serv.log(message)` and `serv.emit('error', err)`. ## Creating external plugins -Create a new repo, which will be published to npm when ready to be used. +Create a new repo, which will be published to npm when ready to be used. Create a file (probably `index.js`) in which you use a similar format as above (module.exports.xxxx). -Create a file in which you put an inject function like this : +In these inject functions you can use everything documented in the [api.md](api.md). -```js -module.exports=init; +Let's say you called your module fs-flying-horses and you published it to npm. -function init(flying-squid) { - return inject; -} +Now people can use install your plugin by simply typing: -function inject(serv) -{ - // add methods and properties to serv -} -``` +```npm install fs-flying-horses``` -In the init function, you can use anything flying-squid provide -(see [index.js](https://github.com/mhsjlw/flying-squid/blob/master/index.js#L11)). +### Testing your Plugin -In the inject function you can use everything documented in the [api.md](api.md) to add functionalities to the serv object. +For your convenience, you can put your plugin inside /src/plugins. An example might look like: +- src/plugins/ + - myPluginName/ + - index.js + - package.json + - node_modules + - ... + - myPluginName2.js (direct files are allowed but are impossible to publish, so it's best only to use them for testing) -Let's say you called your module flying-horses and you published it to npm. - -Now people can use your plugin that way : - -```js -var flyingSquid = require('flying-squid'); -var flyingHorses = require('flying-horses')(flyingSquid); -var serv = flyingSquid.createMCServer(/* your options there */); -// install the plugin -flyingHorses(serv); -``` - -As explained in the first part of this file, flying-squid has 2 kinds of plugins: server plugins, and player plugins. -We've explained until now how to create a server plugin and to use it with flying-squid. - -Within the same module, you can also create a player plugin. Here is the code you need to add to do that: - -```js -serv.on("newPlayer",function(player){ - injectPlayer(serv,player); -}); - -function injectPlayer(serv,player) -{ - // add methods and properties to player - // you can use serv, but you shouldn't add things to it here -} -``` +## Conclusion 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. From cd646972f79e194cd069a1399401af6f011f8002 Mon Sep 17 00:00:00 2001 From: DemiPixel Date: Thu, 10 Dec 2015 15:06:47 -0800 Subject: [PATCH 8/8] Fix help --- src/lib/command.js | 2 ++ src/lib/plugins/commands.js | 42 ++++++++++++++++++++----------------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/lib/command.js b/src/lib/command.js index 26a072c..463c7f7 100644 --- a/src/lib/command.js +++ b/src/lib/command.js @@ -3,6 +3,7 @@ class Command { this.params = params; this.parent = parent; this.hash = parent ? parent.hash : {}; + this.uniqueHash = parent ? parent.uniqueHash : {}; this.parentBase = (this.parent && this.parent.base && this.parent.base + ' ') || ''; this.base = this.parentBase + (this.params.base || ''); @@ -58,6 +59,7 @@ class Command { if(this.path) this.hash[this.path] = this; }); + this.uniqueHash[this.base] = this; } add(params) { diff --git a/src/lib/plugins/commands.js b/src/lib/plugins/commands.js index 20b4d6e..9b3fe2e 100644 --- a/src/lib/plugins/commands.js +++ b/src/lib/plugins/commands.js @@ -19,33 +19,37 @@ module.exports.player=function(player, serv) { }, action({search, page}) { if (page < 0) return 'Page # must be >= 1'; - var hash = player.commands.hash; + var hash = player.commands.uniqueHash; var PAGE_LENGTH = 8; var found = Object.keys(hash).filter(h => (h + ' ').indexOf((search && search + ' ') || '') == 0); - var totalPages = Math.floor(found.length / PAGE_LENGTH); - if (found.length > 1 && totalPages < page) { - return 'There are only ' + (totalPages + 1) + ' help pages.'; - } - if (found.indexOf(search) != -1) { - var cmd = hash[search]; - player.chat('/' + cmd.base + ' -' + ((cmd.params && ' ' + cmd.params.info) || '=-=-=-=-=-=-=-=-')); - if (cmd.params && cmd.params.usage) player.chat(cmd.params.usage); - } else if (found.length > 1) { - player.chat('Help -=-=-=-=-=-=-=-=-'); - } - - if (found.length == 0) { + if (found.length == 0) { // None found return 'Could not find any matches'; - } else { + } else if (found.length == 1) { // Single command found, giev info on command + var cmd = hash[found[0]]; + var usage = (cmd.params && cmd.params.usage) || cmd.base; + var info = (cmd.params && cmd.params.info) || 'No info'; + player.chat(usage + ': ' + info); + } else { // Multiple commands found, give list with pages + var totalPages = Math.ceil((found.length-1) / PAGE_LENGTH); + if (page >= totalPages) return 'There are only' + totalPages + ' help pages'; found = found.sort(); - for (var i = PAGE_LENGTH*page; i < Math.min(PAGE_LENGTH*(page + 1), found.length); i++) { - var cmd = hash[found[i]]; - player.chat(cmd.params.base + ': ' + cmd.params.info); + if (found.indexOf('search') != -1) { + var baseCmd = hash[search]; + player.chat(baseCmd.base + ' -' + ((baseCmd.params && baseCmd.params.info && ' ' + baseCmd.params.info) || '=-=-=-=-=-=-=-=-')); + } else { + player.chat('Help -=-=-=-=-=-=-=-=-'); } - player.chat('--=[Page ' + (page + 1) + ' of ' + (totalPages + 1) + ']=--') + for (var i = PAGE_LENGTH*page; i < Math.min(PAGE_LENGTH*(page + 1), found.length); i++) { + if (i == search) continue; + var cmd = hash[found[i]]; + var usage = (cmd.params && cmd.params.usage) || cmd.base; + var info = (cmd.params && cmd.params.info) || 'No info'; + player.chat(usage + ': ' + info); + } + player.chat('--=[Page ' + (page + 1) + ' of ' + totalPages + ']=--') } } });