From 539b9c1314cf9997afacedd9563070aacc7dfc3e Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Sat, 12 Dec 2015 06:45:39 +0100 Subject: [PATCH 1/5] implement portal detection and use it when flint and steel is used currently places cactus instead of nether block because nether block seems to require the multi block change packet lot of tests are already there, but some more need to be added, it seems some cases don't work (when the portal have edges it seems) --- package.json | 6 +- src/index.js | 3 +- src/lib/plugins/useItem.js | 30 ++++++++ src/lib/portal_detector.js | 87 ++++++++++++++++++++++ test/portal_detector.js | 148 +++++++++++++++++++++++++++++++++++++ 5 files changed, 271 insertions(+), 3 deletions(-) create mode 100644 src/lib/plugins/useItem.js create mode 100644 src/lib/portal_detector.js create mode 100644 test/portal_detector.js diff --git a/package.json b/package.json index 0d1563a..8fa5efe 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,8 @@ "dependencies": { "babel-runtime": "^5.4.4", "emit-then": "^1.0.2", + "event-promise": "0.0.1", + "flatmap": "0.0.3", "minecraft-data": "0.7.0", "minecraft-protocol": "0.16.3", "mkdirp": "0.5.1", @@ -38,11 +40,11 @@ "prismarine-world": "0.3.3", "prismarine-world-sync": "0.1.0", "random-seed": "^0.2.0", + "range": "0.0.3", "request-promise": "^0.4.3", "requireindex": "~1.0.0", "spiralloop": "1.0.2", - "vec3": "0.1.3", - "event-promise": "0.0.1" + "vec3": "0.1.3" }, "license": "MIT", "repository": { diff --git a/src/index.js b/src/index.js index 87a4874..65e1a30 100644 --- a/src/index.js +++ b/src/index.js @@ -14,7 +14,8 @@ module.exports = { version:require("./lib/version"), generations:require("./lib/generations"), experience:require("./lib/experience"), - UserError:require("./lib/user_error") + UserError:require("./lib/user_error"), + portal_detector:require('./lib/portal_detector') }; function createMCServer(options) { diff --git a/src/lib/plugins/useItem.js b/src/lib/plugins/useItem.js new file mode 100644 index 0000000..4eef4e1 --- /dev/null +++ b/src/lib/plugins/useItem.js @@ -0,0 +1,30 @@ +var items=require("minecraft-data")(require("flying-squid").version).items; +var Vec3 = require("vec3").Vec3; +var {detectFrame,getAir}=require("flying-squid").portal_detector; + +module.exports.player=function(player,serv) +{ + player._client.on("block_place",({direction,heldItem,location} = {}) => { + if (direction == -1 || heldItem.blockId == -1 || !items[heldItem.blockId]) return; + var referencePosition = new Vec3(location.x, location.y, location.z); + var directionVector = directionToVector[direction]; + var position = referencePosition.plus(directionVector); + + var item= items[heldItem.blockId]; + if(item.name=="flint_and_steel") + player.use_flint_and_steel(referencePosition,directionVector); + }); + + player.use_flint_and_steel=async (referencePosition,direction) => { + let block=await player.world.getBlock(referencePosition); + if(block.name=="obsidian") + { + var frames=await detectFrame(player.world,referencePosition,direction); + if(frames.length==0) + return; + var air=getAir(frames[0]); + air.forEach(pos => player.setBlock(pos,81,0)) + } + }; +}; +var directionToVector=[new Vec3(0,-1,0),new Vec3(0,1,0),new Vec3(0,0,-1),new Vec3(0,0,1),new Vec3(-1,0,0),new Vec3(1,0,0)]; \ No newline at end of file diff --git a/src/lib/portal_detector.js b/src/lib/portal_detector.js new file mode 100644 index 0000000..ca79c61 --- /dev/null +++ b/src/lib/portal_detector.js @@ -0,0 +1,87 @@ +var Vec3 = require("vec3").Vec3; +var assert = require('assert'); +var flatMap = require('flatmap'); +var range = require('range').range; + +module.exports={detectFrame,findPotentialLines,findBorder,getAir}; + +async function findLineInDirection(world,startingPoint,type,direction,directionV) +{ + var line=[]; + var point=startingPoint; + while((await world.getBlock(point)).name==type && (await world.getBlockType(point.plus(directionV)))==0) + { + line.push(point); + point=point.plus(direction); + } + return line; +} + +async function findLine(world,startingPoint,type,direction,directionV) +{ + var firstSegment=(await findLineInDirection(world,startingPoint.plus(direction.scaled(-1)),type,direction.scaled(-1),directionV)).reverse(); + var secondSegment=await findLineInDirection(world,startingPoint,type,direction,directionV); + return firstSegment.concat(secondSegment); +} + + +async function findPotentialLines(world,startingPoint,directionV) +{ + var firstLineDirection=directionV.y!=0 ? [new Vec3(1,0,0),new Vec3(0,0,1)] : + [new Vec3(0,1,0)]; + return (await Promise.all(firstLineDirection + .map(async d => ({direction:d,line:(await findLine(world,startingPoint,'obsidian',d,directionV))})))) + .filter(line => (line.line.length>=3 && line.direction.y!=0) || + (line.line.length>=2 && line.direction.y==0)); +} + +function positiveOrder(line,direction) +{ + if(direction.x==-1 || direction.y==-1 || direction.z==-1) + return line.reverse(); + return line; +} + +async function findBorder(world,{line,direction},directionV) +{ + var bottom=line; + if(bottom.length==0) + return []; + var left=await findLineInDirection(world,bottom[0].plus(direction.scaled(-1).plus(directionV)),'obsidian',directionV,direction); + var right=await findLineInDirection(world,bottom[line.length-1].plus(direction).plus(directionV),'obsidian', + directionV,direction); + if(left.length!=right.length) + return null; + var top=await findLineInDirection(world,left[left.length-1].plus(direction).plus(directionV),'obsidian', + direction,directionV); + if(bottom.length!=top.length) + return null; + left=positiveOrder(left,directionV); + right=positiveOrder(right,directionV); + top=positiveOrder(top,direction); + + + if(direction.y!=0) + [bottom,left,right,top]=[left,bottom,top,right]; + + [bottom,top]=directionV.y<0 ? [top,bottom] : [bottom,top]; + var horDir=direction.x!=0 || directionV.x!=0 ? 'x' :'z'; + [left,right]=direction[horDir]<0 || directionV[horDir]<0 ? [right,left] : [left,right]; + + return [bottom,left,right,top]; +} + +async function detectFrame(world,startingPoint,directionV) +{ + let potentialLines=await findPotentialLines(world,startingPoint,directionV); + + return (await Promise.all(potentialLines + .map(line => findBorder(world,line,directionV)))) + .filter(border => border!=null); +} + +function getAir(border) +{ + var [bottom,,,top]=border; + return flatMap(bottom,pos => range(1,top[0].y-bottom[0].y).map(i => pos.offset(0,i,0))); +} \ No newline at end of file diff --git a/test/portal_detector.js b/test/portal_detector.js new file mode 100644 index 0000000..aaead4c --- /dev/null +++ b/test/portal_detector.js @@ -0,0 +1,148 @@ +var {detectFrame,findPotentialLines,findBorder,getAir}=require("flying-squid").portal_detector; +var World = require('prismarine-world'); +var Chunk = require('prismarine-chunk')(require("flying-squid").version); +var Vec3 = require("vec3").Vec3; +var assert = require('assert'); + + +describe("Detect portal", function() { + + + + var bottom=[new Vec3(3, 1, 1), new Vec3(4, 1, 1)]; + var left=[new Vec3(2, 2, 1), new Vec3(2, 3, 1), new Vec3(2, 4, 1)]; + var right=[new Vec3(5, 2, 1), new Vec3(5, 3, 1), new Vec3(5, 4, 1)]; + var top=[new Vec3(3, 5, 1), new Vec3(4, 5, 1)]; + var expectedBorder=[ + bottom, + left, + right, + top + ]; + var air=[new Vec3(3, 2, 1),new Vec3(3, 3, 1),new Vec3(3, 4, 1),new Vec3(4, 2, 1),new Vec3(4, 3, 1),new Vec3(4, 4, 1)]; + + var world; + before(function(){ + world=new World(); + var chunk=new Chunk(); + + expectedBorder.forEach(border => border.forEach(pos => chunk.setBlockType(pos,49))); + air.forEach(pos => chunk.setBlockType(pos,0)); + + return world.setColumn(0,0,chunk); + }); + + + describe("detect potential first lines",function(){ + it("detect potential first lines from bottom left", async function() { + let potentialLines=await findPotentialLines(world,bottom[0],new Vec3(0,1,0)); + assert.deepEqual(potentialLines,[ + { + "direction": new Vec3(1,0,0), + "line": bottom + } + ]); + }); + + it("detect potential first lines from bottom right", async function() { + let potentialLines=await findPotentialLines(world,bottom[bottom.length-1],new Vec3(0,1,0)); + assert.deepEqual(potentialLines,[ + { + "direction": new Vec3(1,0,0), + "line": bottom + } + ]); + }); + + + it("detect potential first lines from top left", async function() { + let potentialLines=await findPotentialLines(world,top[0],new Vec3(0,-1,0)); + assert.deepEqual(potentialLines,[ + { + "direction": new Vec3(1,0,0), + "line": top + } + ]); + }); + + it("detect potential first lines from top right", async function() { + let potentialLines=await findPotentialLines(world,top[top.length-1],new Vec3(0,-1,0)); + assert.deepEqual(potentialLines,[ + { + "direction": new Vec3(1,0,0), + "line": top + } + ]); + }); + + it("detect potential first lines from left top", async function() { + let potentialLines=await findPotentialLines(world,left[left.length-1],new Vec3(1,0,0)); + assert.deepEqual(potentialLines,[ + { + "direction": new Vec3(0,1,0), + "line": left + } + ]); + }); + + it("detect potential first lines from right bottom", async function() { + let potentialLines=await findPotentialLines(world,right[0],new Vec3(-1,0,0)); + assert.deepEqual(potentialLines,[ + { + "direction": new Vec3(0,1,0), + "line": right + } + ]); + }); + }); + + + describe("find borders",function() { + it("find borders from bottom", async function () { + var border = await findBorder(world, { + "direction": new Vec3(1, 0, 0), + "line": bottom + }, new Vec3(0, 1, 0)); + assert.deepEqual(border, expectedBorder) + }); + + it("find borders from top", async function () { + var border = await findBorder(world, { + "direction": new Vec3(1, 0, 0), + "line": top + }, new Vec3(0, -1, 0)); + assert.deepEqual(border, expectedBorder) + }); + + it("find borders from left", async function () { + var border = await findBorder(world, { + "direction": new Vec3(0, 1, 0), + "line": left + }, new Vec3(1, 0, 0)); + assert.deepEqual(border, expectedBorder) + }); + it("find borders from right", async function () { + var border = await findBorder(world, { + "direction": new Vec3(0, 1, 0), + "line": right + }, new Vec3(-1, 0, 0)); + assert.deepEqual(border, expectedBorder) + }); + }); + + describe("detect portals",function(){ + it("detect portals from bottom left",async function() { + var portals=await detectFrame(world,bottom[0],new Vec3(0,1,0)); + assert.deepEqual(portals,[expectedBorder]) + }); + it("detect portals from right top",async function() { + var portals=await detectFrame(world,right[right.length-1],new Vec3(-1,0,0)); + assert.deepEqual(portals,[expectedBorder]) + }) + }); + + it("get air",function(){ + var foundAir=getAir(expectedBorder); + assert.deepEqual(foundAir,air); + }); +}); From adcd35b985ffc22e77a64b1ab9772bf8e287fc6e Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Sun, 13 Dec 2015 20:07:45 +0100 Subject: [PATCH 2/5] make portal test more general to test for several portal kinds --- test/portal_detector.js | 266 +++++++++++++++++++++------------------- 1 file changed, 141 insertions(+), 125 deletions(-) diff --git a/test/portal_detector.js b/test/portal_detector.js index aaead4c..542dcd2 100644 --- a/test/portal_detector.js +++ b/test/portal_detector.js @@ -3,146 +3,162 @@ var World = require('prismarine-world'); var Chunk = require('prismarine-chunk')(require("flying-squid").version); var Vec3 = require("vec3").Vec3; var assert = require('assert'); +var range = require('range').range; describe("Detect portal", function() { - - - var bottom=[new Vec3(3, 1, 1), new Vec3(4, 1, 1)]; - var left=[new Vec3(2, 2, 1), new Vec3(2, 3, 1), new Vec3(2, 4, 1)]; - var right=[new Vec3(5, 2, 1), new Vec3(5, 3, 1), new Vec3(5, 4, 1)]; - var top=[new Vec3(3, 5, 1), new Vec3(4, 5, 1)]; - var expectedBorder=[ - bottom, - left, - right, - top - ]; - var air=[new Vec3(3, 2, 1),new Vec3(3, 3, 1),new Vec3(3, 4, 1),new Vec3(4, 2, 1),new Vec3(4, 3, 1),new Vec3(4, 4, 1)]; - - var world; - before(function(){ - world=new World(); - var chunk=new Chunk(); - - expectedBorder.forEach(border => border.forEach(pos => chunk.setBlockType(pos,49))); - air.forEach(pos => chunk.setBlockType(pos,0)); - - return world.setColumn(0,0,chunk); + var portalData=[]; + portalData.push({ + name:"simple portal frame x", + bottom:[new Vec3(3, 1, 1), new Vec3(4, 1, 1)], + left:[new Vec3(2, 2, 1), new Vec3(2, 3, 1), new Vec3(2, 4, 1)], + right:[new Vec3(5, 2, 1), new Vec3(5, 3, 1), new Vec3(5, 4, 1)], + top:[new Vec3(3, 5, 1), new Vec3(4, 5, 1)], + air:[new Vec3(3, 2, 1),new Vec3(3, 3, 1),new Vec3(3, 4, 1),new Vec3(4, 2, 1),new Vec3(4, 3, 1),new Vec3(4, 4, 1)], + additionalAir:[], + additionalObsidian:[] }); + portalData.forEach(({name,bottom,left,right,top,air,additionalAir,additionalObsidian}) => { + describe("Detect "+name,() => { + var expectedBorder=[ + bottom, + left, + right, + top + ]; - describe("detect potential first lines",function(){ - it("detect potential first lines from bottom left", async function() { - let potentialLines=await findPotentialLines(world,bottom[0],new Vec3(0,1,0)); - assert.deepEqual(potentialLines,[ - { - "direction": new Vec3(1,0,0), - "line": bottom - } - ]); - }); + var world; + before(function(){ + world=new World(); + var chunk=new Chunk(); - it("detect potential first lines from bottom right", async function() { - let potentialLines=await findPotentialLines(world,bottom[bottom.length-1],new Vec3(0,1,0)); - assert.deepEqual(potentialLines,[ - { - "direction": new Vec3(1,0,0), - "line": bottom - } - ]); - }); + expectedBorder.forEach(border => border.forEach(pos => chunk.setBlockType(pos,49))); + air.forEach(pos => chunk.setBlockType(pos,0)); + + additionalAir.forEach(pos => chunk.setBlockType(pos,0)); + additionalObsidian.forEach(pos => chunk.setBlockType(pos,49)); - it("detect potential first lines from top left", async function() { - let potentialLines=await findPotentialLines(world,top[0],new Vec3(0,-1,0)); - assert.deepEqual(potentialLines,[ - { - "direction": new Vec3(1,0,0), - "line": top - } - ]); - }); + return world.setColumn(0,0,chunk); + }); - it("detect potential first lines from top right", async function() { - let potentialLines=await findPotentialLines(world,top[top.length-1],new Vec3(0,-1,0)); - assert.deepEqual(potentialLines,[ - { - "direction": new Vec3(1,0,0), - "line": top - } - ]); - }); - it("detect potential first lines from left top", async function() { - let potentialLines=await findPotentialLines(world,left[left.length-1],new Vec3(1,0,0)); - assert.deepEqual(potentialLines,[ - { - "direction": new Vec3(0,1,0), - "line": left - } - ]); - }); + describe("detect potential first lines",function(){ + it("detect potential first lines from bottom left", async function() { + let potentialLines=await findPotentialLines(world,bottom[0],new Vec3(0,1,0)); + assert.deepEqual(potentialLines,[ + { + "direction": new Vec3(1,0,0), + "line": bottom + } + ]); + }); - it("detect potential first lines from right bottom", async function() { - let potentialLines=await findPotentialLines(world,right[0],new Vec3(-1,0,0)); - assert.deepEqual(potentialLines,[ - { - "direction": new Vec3(0,1,0), - "line": right - } - ]); + it("detect potential first lines from bottom right", async function() { + let potentialLines=await findPotentialLines(world,bottom[bottom.length-1],new Vec3(0,1,0)); + assert.deepEqual(potentialLines,[ + { + "direction": new Vec3(1,0,0), + "line": bottom + } + ]); + }); + + + it("detect potential first lines from top left", async function() { + let potentialLines=await findPotentialLines(world,top[0],new Vec3(0,-1,0)); + assert.deepEqual(potentialLines,[ + { + "direction": new Vec3(1,0,0), + "line": top + } + ]); + }); + + it("detect potential first lines from top right", async function() { + let potentialLines=await findPotentialLines(world,top[top.length-1],new Vec3(0,-1,0)); + assert.deepEqual(potentialLines,[ + { + "direction": new Vec3(1,0,0), + "line": top + } + ]); + }); + + it("detect potential first lines from left top", async function() { + let potentialLines=await findPotentialLines(world,left[left.length-1],new Vec3(1,0,0)); + assert.deepEqual(potentialLines,[ + { + "direction": new Vec3(0,1,0), + "line": left + } + ]); + }); + + it("detect potential first lines from right bottom", async function() { + let potentialLines=await findPotentialLines(world,right[0],new Vec3(-1,0,0)); + assert.deepEqual(potentialLines,[ + { + "direction": new Vec3(0,1,0), + "line": right + } + ]); + }); + }); + + + describe("find borders",function() { + it("find borders from bottom", async function () { + var border = await findBorder(world, { + "direction": new Vec3(1, 0, 0), + "line": bottom + }, new Vec3(0, 1, 0)); + assert.deepEqual(border, expectedBorder) + }); + + it("find borders from top", async function () { + var border = await findBorder(world, { + "direction": new Vec3(1, 0, 0), + "line": top + }, new Vec3(0, -1, 0)); + assert.deepEqual(border, expectedBorder) + }); + + it("find borders from left", async function () { + var border = await findBorder(world, { + "direction": new Vec3(0, 1, 0), + "line": left + }, new Vec3(1, 0, 0)); + assert.deepEqual(border, expectedBorder) + }); + it("find borders from right", async function () { + var border = await findBorder(world, { + "direction": new Vec3(0, 1, 0), + "line": right + }, new Vec3(-1, 0, 0)); + assert.deepEqual(border, expectedBorder) + }); + }); + + describe("detect portals",function(){ + it("detect portals from bottom left",async function() { + var portals=await detectFrame(world,bottom[0],new Vec3(0,1,0)); + assert.deepEqual(portals,[expectedBorder]) + }); + it("detect portals from right top",async function() { + var portals=await detectFrame(world,right[right.length-1],new Vec3(-1,0,0)); + assert.deepEqual(portals,[expectedBorder]) + }) + }); + + it("get air",function(){ + var foundAir=getAir(expectedBorder); + assert.deepEqual(foundAir,air); + }); }); }); - describe("find borders",function() { - it("find borders from bottom", async function () { - var border = await findBorder(world, { - "direction": new Vec3(1, 0, 0), - "line": bottom - }, new Vec3(0, 1, 0)); - assert.deepEqual(border, expectedBorder) - }); - - it("find borders from top", async function () { - var border = await findBorder(world, { - "direction": new Vec3(1, 0, 0), - "line": top - }, new Vec3(0, -1, 0)); - assert.deepEqual(border, expectedBorder) - }); - - it("find borders from left", async function () { - var border = await findBorder(world, { - "direction": new Vec3(0, 1, 0), - "line": left - }, new Vec3(1, 0, 0)); - assert.deepEqual(border, expectedBorder) - }); - it("find borders from right", async function () { - var border = await findBorder(world, { - "direction": new Vec3(0, 1, 0), - "line": right - }, new Vec3(-1, 0, 0)); - assert.deepEqual(border, expectedBorder) - }); - }); - - describe("detect portals",function(){ - it("detect portals from bottom left",async function() { - var portals=await detectFrame(world,bottom[0],new Vec3(0,1,0)); - assert.deepEqual(portals,[expectedBorder]) - }); - it("detect portals from right top",async function() { - var portals=await detectFrame(world,right[right.length-1],new Vec3(-1,0,0)); - assert.deepEqual(portals,[expectedBorder]) - }) - }); - - it("get air",function(){ - var foundAir=getAir(expectedBorder); - assert.deepEqual(foundAir,air); - }); }); From 703b42abea7395dabd0410207ea36242d38973fb Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Mon, 14 Dec 2015 00:45:08 +0100 Subject: [PATCH 3/5] some fixes in findBorder, add more tests --- src/lib/portal_detector.js | 10 ++- test/portal_detector.js | 146 ++++++++++++++++++++++++++----------- 2 files changed, 111 insertions(+), 45 deletions(-) diff --git a/src/lib/portal_detector.js b/src/lib/portal_detector.js index ca79c61..53833c2 100644 --- a/src/lib/portal_detector.js +++ b/src/lib/portal_detector.js @@ -49,13 +49,14 @@ async function findBorder(world,{line,direction},directionV) return []; var left=await findLineInDirection(world,bottom[0].plus(direction.scaled(-1).plus(directionV)),'obsidian',directionV,direction); var right=await findLineInDirection(world,bottom[line.length-1].plus(direction).plus(directionV),'obsidian', - directionV,direction); - if(left.length!=right.length) + directionV,direction.scaled(-1)); + if(left.length==0 || left.length!=right.length) return null; var top=await findLineInDirection(world,left[left.length-1].plus(direction).plus(directionV),'obsidian', - direction,directionV); + direction,directionV.scaled(-1)); if(bottom.length!=top.length) return null; + left=positiveOrder(left,directionV); right=positiveOrder(right,directionV); top=positiveOrder(top,direction); @@ -68,6 +69,9 @@ async function findBorder(world,{line,direction},directionV) var horDir=direction.x!=0 || directionV.x!=0 ? 'x' :'z'; [left,right]=direction[horDir]<0 || directionV[horDir]<0 ? [right,left] : [left,right]; + if(bottom.length<2 || top.length<2 || left.length<3 || right.length<3) + return null; + return [bottom,left,right,top]; } diff --git a/test/portal_detector.js b/test/portal_detector.js index 542dcd2..12ae5f9 100644 --- a/test/portal_detector.js +++ b/test/portal_detector.js @@ -2,25 +2,95 @@ var {detectFrame,findPotentialLines,findBorder,getAir}=require("flying-squid").p var World = require('prismarine-world'); var Chunk = require('prismarine-chunk')(require("flying-squid").version); var Vec3 = require("vec3").Vec3; -var assert = require('assert'); +var assert = require('chai').assert; var range = require('range').range; +var flatMap = require('flatmap'); +function generateLine(startingPoint,direction,length) { + return range(0,length).map(i => startingPoint.plus(direction.scaled(i))); +} + +function generatePortal(bottomLeft,direction,width,height){ + var directionV=new Vec3(0,1,0); + return { + bottom:generateLine(bottomLeft.plus(direction),direction,width-2), + left:generateLine(bottomLeft.plus(directionV),directionV,height-2), + right:generateLine(bottomLeft.plus(direction.scaled(width-1)).plus(directionV),directionV,height-2), + top:generateLine(bottomLeft.plus(directionV.scaled(height-1).plus(direction)),direction,width-2), + air:flatMap(generateLine(bottomLeft.plus(direction).plus(directionV),direction,width-2), + p => generateLine(p,directionV,height-2)) + } +} + +describe("Generate portal",function(){ + it("generate a line",() => { + assert.deepEqual(generateLine(new Vec3(3,1,1),new Vec3(1,0,0),2),[new Vec3(3, 1, 1), new Vec3(4, 1, 1)]) + }); + it("generate a portal", () => { + assert.deepEqual(generatePortal(new Vec3(2,1,1),new Vec3(1,0,0),4,5),{ + bottom:generateLine(new Vec3(3,1,1),new Vec3(1,0,0),2), + left:generateLine(new Vec3(2,2,1),new Vec3(0,1,0),3), + right:generateLine(new Vec3(5,2,1),new Vec3(0,1,0),3), + top:generateLine(new Vec3(3,5,1),new Vec3(1,0,0),2), + air:generateLine(new Vec3(3,2,1),new Vec3(0,1,0),3).concat(generateLine(new Vec3(4,2,1),new Vec3(0,1,0),3)) + }) + }); +}); describe("Detect portal", function() { + var portalData=[]; portalData.push({ name:"simple portal frame x", - bottom:[new Vec3(3, 1, 1), new Vec3(4, 1, 1)], - left:[new Vec3(2, 2, 1), new Vec3(2, 3, 1), new Vec3(2, 4, 1)], - right:[new Vec3(5, 2, 1), new Vec3(5, 3, 1), new Vec3(5, 4, 1)], - top:[new Vec3(3, 5, 1), new Vec3(4, 5, 1)], - air:[new Vec3(3, 2, 1),new Vec3(3, 3, 1),new Vec3(3, 4, 1),new Vec3(4, 2, 1),new Vec3(4, 3, 1),new Vec3(4, 4, 1)], + bottomLeft:new Vec3(2,1,1), + direction:new Vec3(1,0,0), + width:4, + height:5, additionalAir:[], additionalObsidian:[] }); + portalData.push({ + name:"simple portal frame z", + bottomLeft:new Vec3(2,1,1), + direction:new Vec3(0,0,1), + width:4, + height:5, + additionalAir:[], + additionalObsidian:[] + }); + portalData.push({ + name:"big simple portal frame x", + bottomLeft:new Vec3(2,1,1), + direction:new Vec3(1,0,0), + width:10, + height:10, + additionalAir:[], + additionalObsidian:[] + }); + portalData.push({ + name:"simple portal frame x with borders", + bottomLeft:new Vec3(2,1,1), + direction:new Vec3(1,0,0), + width:4, + height:5, + additionalAir:[], + additionalObsidian:[new Vec3(2,1,1),new Vec3(5,1,1),new Vec3(2,6,1),new Vec3(5,6,1)] + }); + var {bottom,left,right,top,air}=generatePortal(new Vec3(2,1,2),new Vec3(1,0,0),4,5); - portalData.forEach(({name,bottom,left,right,top,air,additionalAir,additionalObsidian}) => { + portalData.push({ + name:"2 portals", + bottomLeft:new Vec3(2,1,1), + direction:new Vec3(1,0,0), + width:4, + height:5, + additionalAir:air, + additionalObsidian:[].concat.apply([], [bottom, left, right,top]) + }); + + portalData.forEach(({name,bottomLeft,direction,width,height,additionalAir,additionalObsidian}) => { + var {bottom,left,right,top,air}=generatePortal(bottomLeft,direction,width,height); describe("Detect "+name,() => { var expectedBorder=[ bottom, @@ -48,63 +118,51 @@ describe("Detect portal", function() { describe("detect potential first lines",function(){ it("detect potential first lines from bottom left", async function() { let potentialLines=await findPotentialLines(world,bottom[0],new Vec3(0,1,0)); - assert.deepEqual(potentialLines,[ - { - "direction": new Vec3(1,0,0), + assert.include(potentialLines,{ + "direction": direction, "line": bottom - } - ]); + }); }); it("detect potential first lines from bottom right", async function() { let potentialLines=await findPotentialLines(world,bottom[bottom.length-1],new Vec3(0,1,0)); - assert.deepEqual(potentialLines,[ - { - "direction": new Vec3(1,0,0), + assert.include(potentialLines,{ + "direction": direction, "line": bottom - } - ]); + }); }); it("detect potential first lines from top left", async function() { let potentialLines=await findPotentialLines(world,top[0],new Vec3(0,-1,0)); - assert.deepEqual(potentialLines,[ - { - "direction": new Vec3(1,0,0), + assert.include(potentialLines,{ + "direction": direction, "line": top - } - ]); + }); }); it("detect potential first lines from top right", async function() { let potentialLines=await findPotentialLines(world,top[top.length-1],new Vec3(0,-1,0)); - assert.deepEqual(potentialLines,[ - { - "direction": new Vec3(1,0,0), + assert.include(potentialLines,{ + "direction": direction, "line": top - } - ]); + }); }); it("detect potential first lines from left top", async function() { - let potentialLines=await findPotentialLines(world,left[left.length-1],new Vec3(1,0,0)); - assert.deepEqual(potentialLines,[ - { + let potentialLines=await findPotentialLines(world,left[left.length-1],direction); + assert.include(potentialLines,{ "direction": new Vec3(0,1,0), "line": left - } - ]); + }); }); it("detect potential first lines from right bottom", async function() { - let potentialLines=await findPotentialLines(world,right[0],new Vec3(-1,0,0)); - assert.deepEqual(potentialLines,[ - { + let potentialLines=await findPotentialLines(world,right[0],direction.scaled(-1)); + assert.include(potentialLines,{ "direction": new Vec3(0,1,0), "line": right - } - ]); + }); }); }); @@ -112,7 +170,7 @@ describe("Detect portal", function() { describe("find borders",function() { it("find borders from bottom", async function () { var border = await findBorder(world, { - "direction": new Vec3(1, 0, 0), + "direction": direction, "line": bottom }, new Vec3(0, 1, 0)); assert.deepEqual(border, expectedBorder) @@ -120,7 +178,7 @@ describe("Detect portal", function() { it("find borders from top", async function () { var border = await findBorder(world, { - "direction": new Vec3(1, 0, 0), + "direction": direction, "line": top }, new Vec3(0, -1, 0)); assert.deepEqual(border, expectedBorder) @@ -130,14 +188,14 @@ describe("Detect portal", function() { var border = await findBorder(world, { "direction": new Vec3(0, 1, 0), "line": left - }, new Vec3(1, 0, 0)); + },direction); assert.deepEqual(border, expectedBorder) }); it("find borders from right", async function () { var border = await findBorder(world, { "direction": new Vec3(0, 1, 0), "line": right - }, new Vec3(-1, 0, 0)); + }, direction.scaled(-1)); assert.deepEqual(border, expectedBorder) }); }); @@ -147,8 +205,12 @@ describe("Detect portal", function() { var portals=await detectFrame(world,bottom[0],new Vec3(0,1,0)); assert.deepEqual(portals,[expectedBorder]) }); + it("detect portals from top left",async function() { + var portals=await detectFrame(world,top[0],new Vec3(0,-1,0)); + assert.deepEqual(portals,[expectedBorder]) + }); it("detect portals from right top",async function() { - var portals=await detectFrame(world,right[right.length-1],new Vec3(-1,0,0)); + var portals=await detectFrame(world,right[right.length-1],direction.scaled(-1)); assert.deepEqual(portals,[expectedBorder]) }) }); From 3d6dd9faecfd6e20254b18ff783693fa54728504 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Mon, 14 Dec 2015 02:58:00 +0100 Subject: [PATCH 4/5] doesn't detect portal if there is air in it, add test to check that --- src/lib/portal_detector.js | 25 ++++++++-- test/portal_detector.js | 93 ++++++++++++++++++++++++++++---------- 2 files changed, 90 insertions(+), 28 deletions(-) diff --git a/src/lib/portal_detector.js b/src/lib/portal_detector.js index 53833c2..b4535ea 100644 --- a/src/lib/portal_detector.js +++ b/src/lib/portal_detector.js @@ -72,20 +72,37 @@ async function findBorder(world,{line,direction},directionV) if(bottom.length<2 || top.length<2 || left.length<3 || right.length<3) return null; - return [bottom,left,right,top]; + return {bottom,left,right,top}; } async function detectFrame(world,startingPoint,directionV) { let potentialLines=await findPotentialLines(world,startingPoint,directionV); - return (await Promise.all(potentialLines + return asyncFilter((await Promise.all(potentialLines .map(line => findBorder(world,line,directionV)))) - .filter(border => border!=null); + .filter(border => border!=null) + .map(({bottom,left,right,top}) => ({bottom,left,right,top,air:getAir({bottom,left,right,top})})), + async ({air}) => await isAllAir(world,air)); +} + +async function asyncEvery(array,pred) { + return Promise.all(array.map(x => pred(x).then(y => y ? true : Promise.reject(false)))) + .then(results => true) + .catch(x => false); +} + +function asyncFilter(array,pred) { + return Promise.all(array.map(e => pred(e).then(a => a ? e : null))).then(r => r.filter(a => a!=null)); +} + +async function isAllAir(world,blocks) +{ + return asyncEvery(blocks,async block => (await world.getBlockType(block))==0); } function getAir(border) { - var [bottom,,,top]=border; + var {bottom,top}=border; return flatMap(bottom,pos => range(1,top[0].y-bottom[0].y).map(i => pos.offset(0,i,0))); } \ No newline at end of file diff --git a/test/portal_detector.js b/test/portal_detector.js index 12ae5f9..d22ade2 100644 --- a/test/portal_detector.js +++ b/test/portal_detector.js @@ -22,6 +22,24 @@ function generatePortal(bottomLeft,direction,width,height){ } } + +async function makeWorldWithPortal(portal,additionalAir,additionalObsidian) +{ + var {bottom,left,right,top,air}=portal; + var world=new World(); + var chunk=new Chunk(); + + [bottom,left,right,top].forEach(border => border.forEach(pos => chunk.setBlockType(pos,49))); + air.forEach(pos => chunk.setBlockType(pos,0)); + + additionalAir.forEach(pos => chunk.setBlockType(pos,0)); + additionalObsidian.forEach(pos => chunk.setBlockType(pos,49)); + + + await world.setColumn(0,0,chunk); + return world; +} + describe("Generate portal",function(){ it("generate a line",() => { assert.deepEqual(generateLine(new Vec3(3,1,1),new Vec3(1,0,0),2),[new Vec3(3, 1, 1), new Vec3(4, 1, 1)]) @@ -38,8 +56,6 @@ describe("Generate portal",function(){ }); describe("Detect portal", function() { - - var portalData=[]; portalData.push({ name:"simple portal frame x", @@ -89,29 +105,16 @@ describe("Detect portal", function() { additionalObsidian:[].concat.apply([], [bottom, left, right,top]) }); + portalData.forEach(({name,bottomLeft,direction,width,height,additionalAir,additionalObsidian}) => { - var {bottom,left,right,top,air}=generatePortal(bottomLeft,direction,width,height); + var portal=generatePortal(bottomLeft,direction,width,height); + var {bottom,left,right,top,air}=portal; describe("Detect "+name,() => { - var expectedBorder=[ - bottom, - left, - right, - top - ]; + var expectedBorder={bottom,left,right,top}; var world; - before(function(){ - world=new World(); - var chunk=new Chunk(); - - expectedBorder.forEach(border => border.forEach(pos => chunk.setBlockType(pos,49))); - air.forEach(pos => chunk.setBlockType(pos,0)); - - additionalAir.forEach(pos => chunk.setBlockType(pos,0)); - additionalObsidian.forEach(pos => chunk.setBlockType(pos,49)); - - - return world.setColumn(0,0,chunk); + before(async function(){ + world=await makeWorldWithPortal(portal,additionalAir,additionalObsidian); }); @@ -203,15 +206,15 @@ describe("Detect portal", function() { describe("detect portals",function(){ it("detect portals from bottom left",async function() { var portals=await detectFrame(world,bottom[0],new Vec3(0,1,0)); - assert.deepEqual(portals,[expectedBorder]) + assert.deepEqual(portals,[portal]) }); it("detect portals from top left",async function() { var portals=await detectFrame(world,top[0],new Vec3(0,-1,0)); - assert.deepEqual(portals,[expectedBorder]) + assert.deepEqual(portals,[portal]) }); it("detect portals from right top",async function() { var portals=await detectFrame(world,right[right.length-1],direction.scaled(-1)); - assert.deepEqual(portals,[expectedBorder]) + assert.deepEqual(portals,[portal]) }) }); @@ -224,3 +227,45 @@ describe("Detect portal", function() { }); + + +describe("Doesn't detect non-portal",function() { + var portalData=[]; + + portalData.push({ + name:"simple portal frame x with one obsidian in the middle", + bottomLeft:new Vec3(2,1,1), + direction:new Vec3(1,0,0), + width:5, + height:5, + additionalAir:[], + additionalObsidian:[new Vec3(4,3,1)] + }); + + portalData.forEach(({name,bottomLeft,direction,width,height,additionalAir,additionalObsidian}) => { + var portal = generatePortal(bottomLeft, direction, width, height); + var {bottom,left,right,top,air}=portal; + describe("Doesn't detect detect " + name, () => { + var world; + before(async function () { + world=await makeWorldWithPortal(portal, additionalAir, additionalObsidian); + }); + + describe("doesn't detect portals",function(){ + it("doesn't detect portals from bottom left",async function() { + var portals=await detectFrame(world,bottom[0],new Vec3(0,1,0)); + assert.deepEqual(portals,[]) + }); + it("doesn't detect portals from top left",async function() { + var portals=await detectFrame(world,top[0],new Vec3(0,-1,0)); + assert.deepEqual(portals,[]) + }); + it("doesn't detect portals from right top",async function() { + var portals=await detectFrame(world,right[right.length-1],direction.scaled(-1)); + assert.deepEqual(portals,[]) + }) + }); + + }); + }); +}); From d9eb820e3ffa2d781e3cbd5bd886b10a8837a5ce Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Mon, 14 Dec 2015 04:01:55 +0100 Subject: [PATCH 5/5] cactus -> portal --- src/lib/plugins/useItem.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/plugins/useItem.js b/src/lib/plugins/useItem.js index 4eef4e1..28be69d 100644 --- a/src/lib/plugins/useItem.js +++ b/src/lib/plugins/useItem.js @@ -23,7 +23,7 @@ module.exports.player=function(player,serv) if(frames.length==0) return; var air=getAir(frames[0]); - air.forEach(pos => player.setBlock(pos,81,0)) + air.forEach(pos => player.setBlock(pos,90,(frames[0].bottom[0].x-frames[0].bottom[1].x)!=0 ? 1 : 2)); } }; };