diff --git a/.circleci/config.yml b/.circleci/config.yml index df8c3ed..e16171a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,6 +2,7 @@ version: 2 jobs: build: + parallelism: 2 docker: - image: circleci/node:10 steps: diff --git a/src/index.js b/src/index.js index c7b3206..691dac6 100644 --- a/src/index.js +++ b/src/index.js @@ -17,7 +17,8 @@ module.exports = { generations: require('./lib/generations'), experience: require('./lib/experience'), UserError: require('./lib/user_error'), - portal_detector: require('./lib/portal_detector') + portal_detector: require('./lib/portal_detector'), + supportedVersions } function createMCServer (options) { diff --git a/test/common/parallel.js b/test/common/parallel.js new file mode 100644 index 0000000..824116f --- /dev/null +++ b/test/common/parallel.js @@ -0,0 +1,31 @@ +const nodeIndex = parseInt(process.env.CIRCLE_NODE_INDEX) +const nodeTotal = parseInt(process.env.CIRCLE_NODE_TOTAL) +const parallel = process.env.CIRCLE_NODE_INDEX !== undefined && process.env.CIRCLE_NODE_TOTAL !== undefined +const mc = require('../../') + +// expected values : +// (0,4,10) -> (0,2) +// (1,4,10) -> (3,5) +// (2,4,10) -> (6,8) +// (3,4,10) -> (9,9) +function testedRange (nodeIndex, nodeTotal, numberOfVersions) { + const nbFirsts = Math.ceil(numberOfVersions / nodeTotal) + if (nodeIndex === (nodeTotal - 1)) { + return { + firstVersion: nbFirsts * nodeIndex, + lastVersion: numberOfVersions - 1 + } + } + + return { + firstVersion: nodeIndex * nbFirsts, + lastVersion: (nodeIndex + 1) * nbFirsts - 1 + } +} +console.log({ nodeIndex, nodeTotal, versions: mc.supportedVersions.length }) +const { firstVersion, lastVersion } = parallel ? testedRange(nodeIndex, nodeTotal, mc.supportedVersions.length) : { + firstVersion: 0, + lastVersion: mc.supportedVersions.length - 1 +} + +module.exports = { firstVersion, lastVersion } diff --git a/test/mineflayer.test.js b/test/mineflayer.test.js index 20552ed..e0503b8 100644 --- a/test/mineflayer.test.js +++ b/test/mineflayer.test.js @@ -4,7 +4,6 @@ const squid = require('flying-squid') const settings = require('../config/default-settings') const mineflayer = require('mineflayer') const { Vec3 } = require('vec3') -const Item = require('prismarine-item')('1.8') function assertPosEqual (actual, expected) { expect(actual.distanceTo(expected)).toBeLessThan(1) @@ -12,228 +11,243 @@ function assertPosEqual (actual, expected) { const once = require('event-promise') -describe('server with mineflayer connection', () => { - jest.setTimeout(60 * 1000) - let bot - let bot2 - let serv +const { firstVersion, lastVersion } = require('./common/parallel') - async function onGround (bot) { - await new Promise((resolve) => { - const l = () => { - if (bot.entity.onGround) { - bot.removeListener('move', l) - resolve() - } - } - bot.on('move', l) - }) +squid.supportedVersions.forEach((supportedVersion, i) => { + if (!(i >= firstVersion && i <= lastVersion)) { + return } - async function waitMessage (bot, message) { - const msg1 = await once(bot, 'message') - expect(msg1.extra[0].text).toEqual(message) - } + const mcData = require('minecraft-data')(supportedVersion) + const version = mcData.version - async function waitMessages (bot, messages) { - const toReceive = messages.reduce((acc, message) => { - acc[message] = 1 - return acc - }, {}) - const received = {} - return new Promise(resolve => { - const listener = msg => { - const message = msg.extra[0].text - if (!toReceive[message]) throw new Error('Received ' + message + ' , expected to receive one of ' + messages) - if (received[message]) throw new Error('Received ' + message + ' two times') - received[message] = 1 - if (Object.keys(received).length === messages.length) { - bot.removeListener('message', listener) - resolve() - } - } - bot.on('message', listener) - }) - } + const Item = require('prismarine-item')(supportedVersion) - async function waitLoginMessage (bot) { - return Promise.all([waitMessages(bot, ['bot joined the game.', 'bot2 joined the game.'])]) - } + describe('server with mineflayer connection ' + version.minecraftVersion, () => { + jest.setTimeout(60 * 1000) + let bot + let bot2 + let serv - beforeEach(async () => { - const options = settings - options['online-mode'] = false - options['port'] = 25566 - options['view-distance'] = 2 - options['worldFolder'] = undefined - options['logging'] = false - - serv = squid.createMCServer(options) - - await once(serv, 'listening') - bot = mineflayer.createBot({ - host: 'localhost', - port: 25566, - username: 'bot', - version: '1.8' - }) - bot2 = mineflayer.createBot({ - host: 'localhost', - port: 25566, - username: 'bot2', - version: '1.8' - }) - - await Promise.all([once(bot, 'login'), once(bot2, 'login')]) - bot.entity.onGround = false - bot2.entity.onGround = false - }) - - afterEach(async () => { - await serv.quit() - }) - - describe('actions', () => { - function waitSpawnZone (bot, view) { - const nbChunksExpected = (view * 2) * (view * 2) - let c = 0 - return new Promise(resolve => { - const listener = () => { - c++ - if (c === nbChunksExpected) { - bot.removeListener('chunkColumnLoad', listener) + async function onGround (bot) { + await new Promise((resolve) => { + const l = () => { + if (bot.entity.onGround) { + bot.removeListener('move', l) resolve() } } - bot.on('chunkColumnLoad', listener) + bot.on('move', l) }) } - test('can dig', async () => { - await Promise.all([waitSpawnZone(bot, 2), waitSpawnZone(bot2, 2), onGround(bot), onGround(bot2)]) + async function waitMessage (bot, message) { + const msg1 = await once(bot, 'message') + expect(msg1.extra[0].text).toEqual(message) + } - const pos = bot.entity.position.offset(0, -1, 0).floored() - bot.dig(bot.blockAt(pos)) + async function waitMessages (bot, messages) { + const toReceive = messages.reduce((acc, message) => { + acc[message] = 1 + return acc + }, {}) + const received = {} + return new Promise(resolve => { + const listener = msg => { + const message = msg.extra[0].text + if (!toReceive[message]) throw new Error('Received ' + message + ' , expected to receive one of ' + messages) + if (received[message]) throw new Error('Received ' + message + ' two times') + received[message] = 1 + if (Object.keys(received).length === messages.length) { + bot.removeListener('message', listener) + resolve() + } + } + bot.on('message', listener) + }) + } - let [, newBlock] = await once(bot2, 'blockUpdate', {array: true}) - assertPosEqual(newBlock.position, pos) - expect(newBlock.type).toEqual(0) + async function waitLoginMessage (bot) { + return Promise.all([waitMessages(bot, ['bot joined the game.', 'bot2 joined the game.'])]) + } + + beforeEach(async () => { + const PORT = Math.round(30000 + Math.random() * 20000) + const options = settings + options['online-mode'] = false + options['port'] = PORT + options['view-distance'] = 2 + options['worldFolder'] = undefined + options['logging'] = false + options['version'] = version.minecraftVersion + + serv = squid.createMCServer(options) + + await once(serv, 'listening') + bot = mineflayer.createBot({ + host: 'localhost', + port: PORT, + username: 'bot', + version: version.minecraftVersion + }) + bot2 = mineflayer.createBot({ + host: 'localhost', + port: PORT, + username: 'bot2', + version: version.minecraftVersion + }) + + await Promise.all([once(bot, 'login'), once(bot2, 'login')]) + bot.entity.onGround = false + bot2.entity.onGround = false }) - test('can place a block', async () => { - await Promise.all([waitSpawnZone(bot, 2), waitSpawnZone(bot2, 2), onGround(bot), onGround(bot2)]) + afterEach(async () => { + await serv.quit() + }) - const pos = bot.entity.position.offset(0, -2, 0).floored() - bot.dig(bot.blockAt(pos)) + describe('actions', () => { + function waitSpawnZone (bot, view) { + const nbChunksExpected = (view * 2) * (view * 2) + let c = 0 + return new Promise(resolve => { + const listener = () => { + c++ + if (c === nbChunksExpected) { + bot.removeListener('chunkColumnLoad', listener) + resolve() + } + } + bot.on('chunkColumnLoad', listener) + }) + } - let [, newBlock] = await once(bot2, 'blockUpdate', {array: true}) - assertPosEqual(newBlock.position, pos) - expect(newBlock.type).toEqual(0) + test('can dig', async () => { + await Promise.all([waitSpawnZone(bot, 2), waitSpawnZone(bot2, 2), onGround(bot), onGround(bot2)]) - bot.creative.setInventorySlot(36, new Item(1, 1)) - await new Promise((resolve) => { - bot.inventory.on('windowUpdate', (slot, oldItem, newItem) => { - if (slot === 36 && newItem && newItem.type === 1) { resolve() } + const pos = bot.entity.position.offset(0, -1, 0).floored() + bot.dig(bot.blockAt(pos)) + + let [, newBlock] = await once(bot2, 'blockUpdate', {array: true}) + assertPosEqual(newBlock.position, pos) + expect(newBlock.type).toEqual(0) + }) + + test('can place a block', async () => { + await Promise.all([waitSpawnZone(bot, 2), waitSpawnZone(bot2, 2), onGround(bot), onGround(bot2)]) + + const pos = bot.entity.position.offset(0, -2, 0).floored() + bot.dig(bot.blockAt(pos)) + + let [, newBlock] = await once(bot2, 'blockUpdate', {array: true}) + assertPosEqual(newBlock.position, pos) + expect(newBlock.type).toEqual(0) + + bot.creative.setInventorySlot(36, new Item(1, 1)) + await new Promise((resolve) => { + bot.inventory.on('windowUpdate', (slot, oldItem, newItem) => { + if (slot === 36 && newItem && newItem.type === 1) { resolve() } + }) + }) + + bot.placeBlock(bot.blockAt(pos.offset(0, -1, 0)), new Vec3(0, 1, 0)); + + [, newBlock] = await once(bot2, 'blockUpdate', {array: true}) + assertPosEqual(newBlock.position, pos) + expect(newBlock.type).toEqual(1) + }) + }) + + describe('commands', () => { + jest.setTimeout(10 * 1000) + test('has an help command', async () => { + await waitLoginMessage(bot) + bot.chat('/help') + await once(bot, 'message') + }) + test('can use /particle', async () => { + bot.chat('/particle 5 10 100 100 100') + await once(bot._client, 'world_particles') + }) + test('can use /playsound', async () => { + bot.chat('/playsound ambient.weather.rain') + await once(bot, 'soundEffectHeard') + }) + + function waitDragon () { + return new Promise((resolve) => { + const listener = (entity) => { + if (entity.name === 'EnderDragon') { + bot.removeListener('entitySpawn', listener) + resolve() + } + } + bot.on('entitySpawn', listener) + }) + } + + test('can use /summon', async () => { + bot.chat('/summon EnderDragon') + await waitDragon() + }) + test('can use /kill', async () => { + bot.chat('/summon EnderDragon') + await waitDragon() + bot.chat('/kill @e[type=EnderDragon]') + const entity = await once(bot, 'entityDead') + expect(entity.name).toEqual('EnderDragon') + }) + describe('can use /tp', () => { + test('can tp myself', async () => { + bot.chat('/tp 2 3 4') + await once(bot, 'forcedMove') + assertPosEqual(bot.entity.position, new Vec3(2, 3, 4)) + }) + test('can tp somebody else', async () => { + bot.chat('/tp bot2 2 3 4') + await once(bot2, 'forcedMove') + assertPosEqual(bot2.entity.position, new Vec3(2, 3, 4)) + }) + test('can tp to somebody else', async () => { + await onGround(bot) + bot.chat('/tp bot2 bot') + await once(bot2, 'forcedMove') + assertPosEqual(bot2.entity.position, bot.entity.position) + }) + test('can tp with relative positions', async () => { + await onGround(bot) + const initialPosition = bot.entity.position.clone() + bot.chat('/tp ~1 ~-2 ~3') + await once(bot, 'forcedMove') + assertPosEqual(bot.entity.position, initialPosition.offset(1, -2, 3)) + }) + test('can tp somebody else with relative positions', async () => { + await Promise.all([onGround(bot), onGround(bot2)]) + const initialPosition = bot2.entity.position.clone() + bot.chat('/tp bot2 ~1 ~-2 ~3') + await once(bot2, 'forcedMove') + assertPosEqual(bot2.entity.position, initialPosition.offset(1, -2, 3)) }) }) - - bot.placeBlock(bot.blockAt(pos.offset(0, -1, 0)), new Vec3(0, 1, 0)); - - [, newBlock] = await once(bot2, 'blockUpdate', {array: true}) - assertPosEqual(newBlock.position, pos) - expect(newBlock.type).toEqual(1) - }) - }) - - describe('commands', () => { - jest.setTimeout(10 * 1000) - test('has an help command', async () => { - await waitLoginMessage(bot) - bot.chat('/help') - await once(bot, 'message') - }) - test('can use /particle', async () => { - bot.chat('/particle 5 10 100 100 100') - await once(bot._client, 'world_particles') - }) - test('can use /playsound', async () => { - bot.chat('/playsound ambient.weather.rain') - await once(bot, 'soundEffectHeard') - }) - - function waitDragon () { - return new Promise((resolve) => { - const listener = (entity) => { - if (entity.name === 'EnderDragon') { - bot.removeListener('entitySpawn', listener) - resolve() - } - } - bot.on('entitySpawn', listener) + test('can use /deop', async () => { + await waitLoginMessage(bot) + bot.chat('/deop bot') + await waitMessage(bot, 'bot is deopped') + bot.chat('/op bot') + await waitMessage(bot, 'You do not have permission to use this command') + serv.getPlayer('bot').op = true }) - } - - test('can use /summon', async () => { - bot.chat('/summon EnderDragon') - await waitDragon() - }) - test('can use /kill', async () => { - bot.chat('/summon EnderDragon') - await waitDragon() - bot.chat('/kill @e[type=EnderDragon]') - const entity = await once(bot, 'entityDead') - expect(entity.name).toEqual('EnderDragon') - }) - describe('can use /tp', () => { - test('can tp myself', async () => { - bot.chat('/tp 2 3 4') - await once(bot, 'forcedMove') - assertPosEqual(bot.entity.position, new Vec3(2, 3, 4)) + test('can use /setblock', async () => { + await once(bot, 'chunkColumnLoad') + bot.chat('/setblock 1 2 3 95 0') + let [, newBlock] = await once(bot, 'blockUpdate:' + new Vec3(1, 2, 3), {array: true}) + expect(newBlock.type).toEqual(95) }) - test('can tp somebody else', async () => { - bot.chat('/tp bot2 2 3 4') - await once(bot2, 'forcedMove') - assertPosEqual(bot2.entity.position, new Vec3(2, 3, 4)) + test('can use /xp', async () => { + bot.chat('/xp 100') + await once(bot, 'experience') + expect(bot.experience.points).toEqual(100) }) - test('can tp to somebody else', async () => { - await onGround(bot) - bot.chat('/tp bot2 bot') - await once(bot2, 'forcedMove') - assertPosEqual(bot2.entity.position, bot.entity.position) - }) - test('can tp with relative positions', async () => { - await onGround(bot) - const initialPosition = bot.entity.position.clone() - bot.chat('/tp ~1 ~-2 ~3') - await once(bot, 'forcedMove') - assertPosEqual(bot.entity.position, initialPosition.offset(1, -2, 3)) - }) - test('can tp somebody else with relative positions', async () => { - await Promise.all([onGround(bot), onGround(bot2)]) - const initialPosition = bot2.entity.position.clone() - bot.chat('/tp bot2 ~1 ~-2 ~3') - await once(bot2, 'forcedMove') - assertPosEqual(bot2.entity.position, initialPosition.offset(1, -2, 3)) - }) - }) - test('can use /deop', async () => { - await waitLoginMessage(bot) - bot.chat('/deop bot') - await waitMessage(bot, 'bot is deopped') - bot.chat('/op bot') - await waitMessage(bot, 'You do not have permission to use this command') - serv.getPlayer('bot').op = true - }) - test('can use /setblock', async () => { - await once(bot, 'chunkColumnLoad') - bot.chat('/setblock 1 2 3 95 0') - let [, newBlock] = await once(bot, 'blockUpdate:' + new Vec3(1, 2, 3), {array: true}) - expect(newBlock.type).toEqual(95) - }) - test('can use /xp', async () => { - bot.chat('/xp 100') - await once(bot, 'experience') - expect(bot.experience.points).toEqual(100) }) }) }) diff --git a/test/portal.test.js b/test/portal.test.js index 6ff8878..c5db7f1 100644 --- a/test/portal.test.js +++ b/test/portal.test.js @@ -1,250 +1,260 @@ /* eslint-env jest */ -const { - detectFrame, - findPotentialLines, - findBorder, - getAir, - generateLine, - generatePortal, - makeWorldWithPortal -} = require('flying-squid').portal_detector('1.8') +const squid = require('flying-squid') +const { firstVersion, lastVersion } = require('./common/parallel') -const { Vec3 } = require('vec3') +squid.supportedVersions.forEach((supportedVersion, i) => { + if (!(i >= firstVersion && i <= lastVersion)) return -describe('generate portal', () => { - test('generate a line', () => { - expect(generateLine(new Vec3(3, 1, 1), new Vec3(1, 0, 0), 2)).toEqual([new Vec3(3, 1, 1), new Vec3(4, 1, 1)]) - }) + const mcData = require('minecraft-data')(supportedVersion) + const version = mcData.version - test('generate a portal', () => { - expect(generatePortal(new Vec3(2, 1, 1), new Vec3(1, 0, 0), 4, 5)).toEqual({ - 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)) + const { + detectFrame, + findPotentialLines, + findBorder, + getAir, + generateLine, + generatePortal, + makeWorldWithPortal + } = squid.portal_detector(version.minecraftVersion) + + const { Vec3 } = require('vec3') + + describe('generate portal ' + version.minecraftVersion, () => { + test('generate a line', () => { + expect(generateLine(new Vec3(3, 1, 1), new Vec3(1, 0, 0), 2)).toEqual([new Vec3(3, 1, 1), new Vec3(4, 1, 1)]) }) - }) -}) -describe('detect portal', () => { - jest.setTimeout(60 * 1000) - const portalData = [] - - portalData.push({ - name: 'simple portal frame x', - 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)] - }) - - const {bottom, left, right, top, air} = generatePortal(new Vec3(2, 1, 2), new Vec3(1, 0, 0), 4, 5) - - 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([], [bottom, left, right, top]) - }) - - portalData.push({ - name: 'huge simple portal frame z', - bottomLeft: new Vec3(2, 1, 1), - direction: new Vec3(0, 0, 1), - width: 50, - height: 50, - additionalAir: [], - additionalObsidian: [] - }) - - portalData.forEach(({name, bottomLeft, direction, width, height, additionalAir, additionalObsidian}) => { - const portal = generatePortal(bottomLeft, direction, width, height) - const {bottom, left, right, top, air} = portal - describe('Detect ' + name, () => { - const expectedBorder = {bottom, left, right, top} - - let world - beforeAll(async function () { - world = await makeWorldWithPortal(portal, additionalAir, additionalObsidian) - }) - - describe('detect potential first lines', () => { - test('detect potential first lines from bottom left', async () => { - let potentialLines = await findPotentialLines(world, bottom[0], new Vec3(0, 1, 0)) - expect(potentialLines).toContainEqual({ - 'direction': direction, - 'line': bottom - }) - }) - - test('detect potential first lines from bottom right', async () => { - let potentialLines = await findPotentialLines(world, bottom[bottom.length - 1], new Vec3(0, 1, 0)) - expect(potentialLines).toContainEqual({ - 'direction': direction, - 'line': bottom - }) - }) - - test('detect potential first lines from top left', async () => { - let potentialLines = await findPotentialLines(world, top[0], new Vec3(0, -1, 0)) - expect(potentialLines).toContainEqual({ - 'direction': direction, - 'line': top - }) - }) - - test('detect potential first lines from top right', async () => { - let potentialLines = await findPotentialLines(world, top[top.length - 1], new Vec3(0, -1, 0)) - expect(potentialLines).toContainEqual({ - 'direction': direction, - 'line': top - }) - }) - - test('detect potential first lines from left top', async () => { - let potentialLines = await findPotentialLines(world, left[left.length - 1], direction) - expect(potentialLines).toEqual([{ - 'direction': new Vec3(0, 1, 0), - 'line': left - }]) - }) - - test('detect potential first lines from right bottom', async () => { - let potentialLines = await findPotentialLines(world, right[0], direction.scaled(-1)) - expect(potentialLines).toEqual([{ - 'direction': new Vec3(0, 1, 0), - 'line': right - }]) - }) - }) - - describe('find borders', () => { - test('find borders from bottom', async () => { - const border = await findBorder(world, { - 'direction': direction, - 'line': bottom - }, new Vec3(0, 1, 0)) - expect(border).toEqual(expectedBorder) - }) - - test('find borders from top', async () => { - const border = await findBorder(world, { - 'direction': direction, - 'line': top - }, new Vec3(0, -1, 0)) - expect(border).toEqual(expectedBorder) - }) - - test('find borders from left', async () => { - const border = await findBorder(world, { - 'direction': new Vec3(0, 1, 0), - 'line': left - }, direction) - expect(border).toEqual(expectedBorder) - }) - test('find borders from right', async () => { - const border = await findBorder(world, { - 'direction': new Vec3(0, 1, 0), - 'line': right - }, direction.scaled(-1)) - expect(border).toEqual(expectedBorder) - }) - }) - - describe('detect portals', () => { - test('detect portals from bottom left', async () => { - const portals = await detectFrame(world, bottom[0], new Vec3(0, 1, 0)) - expect(portals).toEqual([portal]) - }) - test('detect portals from top left', async () => { - const portals = await detectFrame(world, top[0], new Vec3(0, -1, 0)) - expect(portals).toEqual([portal]) - }) - test('detect portals from right top', async () => { - const portals = await detectFrame(world, right[right.length - 1], direction.scaled(-1)) - expect(portals).toEqual([portal]) - }) - }) - - test('get air', () => { - const foundAir = getAir(expectedBorder) - expect(foundAir).toEqual(air) + test('generate a portal', () => { + expect(generatePortal(new Vec3(2, 1, 1), new Vec3(1, 0, 0), 4, 5)).toEqual({ + 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("doesn't detect non-portal", () => { - const portalData = [] + describe('detect portal ' + version.minecraftVersion, () => { + jest.setTimeout(60 * 1000) + const 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.push({ + name: 'simple portal frame x', + 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)] + }) + + const {bottom, left, right, top, air} = generatePortal(new Vec3(2, 1, 2), new Vec3(1, 0, 0), 4, 5) + + 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([], [bottom, left, right, top]) + }) + + portalData.push({ + name: 'huge simple portal frame z', + bottomLeft: new Vec3(2, 1, 1), + direction: new Vec3(0, 0, 1), + width: 50, + height: 50, + additionalAir: [], + additionalObsidian: [] + }) + + portalData.forEach(({name, bottomLeft, direction, width, height, additionalAir, additionalObsidian}) => { + const portal = generatePortal(bottomLeft, direction, width, height) + const {bottom, left, right, top, air} = portal + describe('Detect ' + name, () => { + const expectedBorder = {bottom, left, right, top} + + let world + beforeAll(async function () { + world = await makeWorldWithPortal(portal, additionalAir, additionalObsidian) + }) + + describe('detect potential first lines', () => { + test('detect potential first lines from bottom left', async () => { + let potentialLines = await findPotentialLines(world, bottom[0], new Vec3(0, 1, 0)) + expect(potentialLines).toContainEqual({ + 'direction': direction, + 'line': bottom + }) + }) + + test('detect potential first lines from bottom right', async () => { + let potentialLines = await findPotentialLines(world, bottom[bottom.length - 1], new Vec3(0, 1, 0)) + expect(potentialLines).toContainEqual({ + 'direction': direction, + 'line': bottom + }) + }) + + test('detect potential first lines from top left', async () => { + let potentialLines = await findPotentialLines(world, top[0], new Vec3(0, -1, 0)) + expect(potentialLines).toContainEqual({ + 'direction': direction, + 'line': top + }) + }) + + test('detect potential first lines from top right', async () => { + let potentialLines = await findPotentialLines(world, top[top.length - 1], new Vec3(0, -1, 0)) + expect(potentialLines).toContainEqual({ + 'direction': direction, + 'line': top + }) + }) + + test('detect potential first lines from left top', async () => { + let potentialLines = await findPotentialLines(world, left[left.length - 1], direction) + expect(potentialLines).toEqual([{ + 'direction': new Vec3(0, 1, 0), + 'line': left + }]) + }) + + test('detect potential first lines from right bottom', async () => { + let potentialLines = await findPotentialLines(world, right[0], direction.scaled(-1)) + expect(potentialLines).toEqual([{ + 'direction': new Vec3(0, 1, 0), + 'line': right + }]) + }) + }) + + describe('find borders', () => { + test('find borders from bottom', async () => { + const border = await findBorder(world, { + 'direction': direction, + 'line': bottom + }, new Vec3(0, 1, 0)) + expect(border).toEqual(expectedBorder) + }) + + test('find borders from top', async () => { + const border = await findBorder(world, { + 'direction': direction, + 'line': top + }, new Vec3(0, -1, 0)) + expect(border).toEqual(expectedBorder) + }) + + test('find borders from left', async () => { + const border = await findBorder(world, { + 'direction': new Vec3(0, 1, 0), + 'line': left + }, direction) + expect(border).toEqual(expectedBorder) + }) + test('find borders from right', async () => { + const border = await findBorder(world, { + 'direction': new Vec3(0, 1, 0), + 'line': right + }, direction.scaled(-1)) + expect(border).toEqual(expectedBorder) + }) + }) + + describe('detect portals', () => { + test('detect portals from bottom left', async () => { + const portals = await detectFrame(world, bottom[0], new Vec3(0, 1, 0)) + expect(portals).toEqual([portal]) + }) + test('detect portals from top left', async () => { + const portals = await detectFrame(world, top[0], new Vec3(0, -1, 0)) + expect(portals).toEqual([portal]) + }) + test('detect portals from right top', async () => { + const portals = await detectFrame(world, right[right.length - 1], direction.scaled(-1)) + expect(portals).toEqual([portal]) + }) + }) + + test('get air', () => { + const foundAir = getAir(expectedBorder) + expect(foundAir).toEqual(air) + }) + }) + }) }) - portalData.forEach(({name, bottomLeft, direction, width, height, additionalAir, additionalObsidian}) => { - const portal = generatePortal(bottomLeft, direction, width, height) - const {bottom, right, top} = portal - describe("doesn't detect detect " + name, () => { - let world - beforeAll(async function () { - world = await makeWorldWithPortal(portal, additionalAir, additionalObsidian) - }) + describe("doesn't detect non-portal " + version.minecraftVersion, () => { + const portalData = [] - describe("doesn't detect portals", () => { - test("doesn't detect portals from bottom left", async () => { - const portals = await detectFrame(world, bottom[0], new Vec3(0, 1, 0)) - expect(portals).toEqual([]) + 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}) => { + const portal = generatePortal(bottomLeft, direction, width, height) + const {bottom, right, top} = portal + describe("doesn't detect detect " + name, () => { + let world + beforeAll(async function () { + world = await makeWorldWithPortal(portal, additionalAir, additionalObsidian) }) - test("doesn't detect portals from top left", async () => { - const portals = await detectFrame(world, top[0], new Vec3(0, -1, 0)) - expect(portals).toEqual([]) - }) - test("doesn't detect portals from right top", async () => { - const portals = await detectFrame(world, right[right.length - 1], direction.scaled(-1)) - expect(portals).toEqual([]) + + describe("doesn't detect portals", () => { + test("doesn't detect portals from bottom left", async () => { + const portals = await detectFrame(world, bottom[0], new Vec3(0, 1, 0)) + expect(portals).toEqual([]) + }) + test("doesn't detect portals from top left", async () => { + const portals = await detectFrame(world, top[0], new Vec3(0, -1, 0)) + expect(portals).toEqual([]) + }) + test("doesn't detect portals from right top", async () => { + const portals = await detectFrame(world, right[right.length - 1], direction.scaled(-1)) + expect(portals).toEqual([]) + }) }) }) }) diff --git a/test/simple.test.js b/test/simple.test.js index 59edf81..feb98bb 100644 --- a/test/simple.test.js +++ b/test/simple.test.js @@ -5,33 +5,46 @@ const squid = require('flying-squid') const settings = require('../config/default-settings') -describe('server', () => { - let serv +const { firstVersion, lastVersion } = require('./common/parallel') - beforeAll(done => { - const options = settings - options['online-mode'] = false - options['port'] = 25566 - options['view-distance'] = 2 - options['worldFolder'] = undefined - options['logging'] = false - serv = squid.createMCServer(options) +squid.supportedVersions.forEach((supportedVersion, i) => { + if (!(i >= firstVersion && i <= lastVersion)) { + return + } + const PORT = Math.round(30000 + Math.random() * 20000) - serv.on('listening', () => { - done() + const mcData = require('minecraft-data')(supportedVersion) + const version = mcData.version + + describe(`simple server ${version.minecraftVersion}`, () => { + let serv + + beforeAll(done => { + const options = settings + options['online-mode'] = false + options['port'] = PORT + options['view-distance'] = 2 + options['worldFolder'] = undefined + options['logging'] = false + options['version'] = version.minecraftVersion + serv = squid.createMCServer(options) + + serv.on('listening', () => { + done() + }) }) - }) - afterAll(done => { - serv._server.close() - serv._server.on('close', () => { - done() + afterAll(done => { + serv._server.close() + serv._server.on('close', () => { + done() + }) }) - }) - test('is running', done => { - const client = net.Socket() - client.connect(serv._server.socketServer.address().port, '127.0.0.1', done) - client.on('error', done) + test('is running', done => { + const client = net.Socket() + client.connect(serv._server.socketServer.address().port, '127.0.0.1', done) + client.on('error', done) + }) }) })