Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/test/externalTests/plugins/testCommon.js
Views: 789
const { Vec3 } = require('vec3')12const { spawn } = require('child_process')3const { once } = require('../../../lib/promise_utils')4const process = require('process')5const assert = require('assert')6const { sleep, onceWithCleanup, withTimeout } = require('../../../lib/promise_utils')78const timeout = 50009module.exports = inject1011function inject (bot) {12console.log(bot.version)1314bot.test = {}15bot.test.groundY = bot.supportFeature('tallWorld') ? -60 : 416bot.test.sayEverywhere = sayEverywhere17bot.test.clearInventory = clearInventory18bot.test.becomeSurvival = becomeSurvival19bot.test.becomeCreative = becomeCreative20bot.test.fly = fly21bot.test.teleport = teleport22bot.test.resetState = resetState23bot.test.setInventorySlot = setInventorySlot24bot.test.placeBlock = placeBlock25bot.test.runExample = runExample26bot.test.tellAndListen = tellAndListen27bot.test.selfKill = selfKill28bot.test.wait = function (ms) {29return new Promise((resolve) => { setTimeout(resolve, ms) })30}3132bot.test.awaitItemReceived = async (command) => {33const p = once(bot.inventory, 'updateSlot')34bot.chat(command)35await p // await getting the item36}37// setting relative to true makes x, y, & z relative using ~38bot.test.setBlock = async ({ x = 0, y = 0, z = 0, relative, blockName }) => {39const { x: _x, y: _y, z: _z } = relative ? bot.entity.position.floored().offset(x, y, z) : { x, y, z }40const block = bot.blockAt(new Vec3(_x, _y, _z))41if (block.name === blockName) {42return43}44const p = once(bot.world, `blockUpdate:(${_x}, ${_y}, ${_z})`)45const prefix = relative ? '~' : ''46bot.chat(`/setblock ${prefix}${x} ${prefix}${y} ${prefix}${z} ${blockName}`)47await p48}4950let grassName51if (bot.supportFeature('itemsAreNotBlocks')) {52grassName = 'grass_block'53} else if (bot.supportFeature('itemsAreAlsoBlocks')) {54grassName = 'grass'55}5657const layerNames = [58'bedrock',59'dirt',60'dirt',61grassName,62'air',63'air',64'air',65'air',66'air'67]6869async function resetBlocksToSuperflat () {70const groundY = 471for (let y = groundY + 4; y >= groundY - 1; y--) {72const realY = y + bot.test.groundY - 473bot.chat(`/fill ~-5 ${realY} ~-5 ~5 ${realY} ~5 ` + layerNames[y])74}75await bot.test.wait(100)76}7778async function placeBlock (slot, position) {79bot.setQuickBarSlot(slot - 36)80// always place the block on the top of the block below it, i guess.81const referenceBlock = bot.blockAt(position.plus(new Vec3(0, -1, 0)))82return bot.placeBlock(referenceBlock, new Vec3(0, 1, 0))83}8485// always leaves you in creative mode86async function resetState () {87await becomeCreative()88await clearInventory()89bot.creative.startFlying()90await teleport(new Vec3(0, bot.test.groundY, 0))91await bot.waitForChunksToLoad()92await resetBlocksToSuperflat()93await sleep(1000)94await clearInventory()95}9697async function becomeCreative () {98// console.log('become creative')99return setCreativeMode(true)100}101102async function becomeSurvival () {103return setCreativeMode(false)104}105106const gameModeChangedMessages = ['commands.gamemode.success.self', 'gameMode.changed']107108async function setCreativeMode (value) {109const getGM = val => val ? 'creative' : 'survival'110// this function behaves the same whether we start in creative mode or not.111// also, creative mode is always allowed for ops, even if server.properties says force-gamemode=true in survival mode.112let i = 0113const msgProm = onceWithCleanup(bot, 'message', {114timeout,115checkCondition: msg => gameModeChangedMessages.includes(msg.translate) && i++ > 0 && bot.game.gameMode === getGM(value)116})117118// do it three times to ensure that we get feedback119bot.chat(`/gamemode ${getGM(value)}`)120bot.chat(`/gamemode ${getGM(!value)}`)121bot.chat(`/gamemode ${getGM(value)}`)122return msgProm123}124125async function clearInventory () {126const msgProm = onceWithCleanup(bot, 'message', {127timeout,128checkCondition: msg => msg.translate === 'commands.clear.success.single' || msg.translate === 'commands.clear.success'129})130bot.chat('/give @a stone 1')131bot.inventory.on('updateSlot', (...e) => {132// console.log('inventory.updateSlot', e)133})134await onceWithCleanup(bot.inventory, 'updateSlot', { timeout: 1000 * 20, checkCondition: (slot, oldItem, newItem) => newItem?.name === 'stone' })135bot.chat('/clear') // don't rely on the message (as it'll come to early), wait for the result of /clear instead136await msgProm // wait for the message so it doesn't leak into chat tests137138// Check that the inventory is clear139for (const slot of bot.inventory.slots) {140if (slot && slot.itemCount <= 0) throw new Error('Inventory was not cleared: ' + JSON.stringify(bot.inventory.slots))141}142}143144// you need to be in creative mode for this to work145async function setInventorySlot (targetSlot, item) {146assert(item === null || item.name !== 'unknown', `item should not be unknown ${JSON.stringify(item)}`)147return bot.creative.setInventorySlot(targetSlot, item)148}149150async function teleport (position) {151if (bot.supportFeature('hasExecuteCommand')) {152bot.test.sayEverywhere(`/execute in overworld run teleport ${bot.username} ${position.x} ${position.y} ${position.z}`)153} else {154bot.test.sayEverywhere(`/tp ${bot.username} ${position.x} ${position.y} ${position.z}`)155}156return onceWithCleanup(bot, 'move', {157timeout,158checkCondition: () => bot.entity.position.distanceTo(position) < 0.9159})160}161162function sayEverywhere (message) {163bot.chat(message)164console.log(message)165}166167async function fly (delta) {168return bot.creative.flyTo(bot.entity.position.plus(delta))169}170171async function tellAndListen (to, what, listen) {172const chatMessagePromise = onceWithCleanup(bot, 'chat', {173timeout,174checkCondition: (username, message) => username === to && listen(message)175})176177bot.chat(what)178179return chatMessagePromise180}181182async function runExample (file, run) {183let childBotName184185const detectChildJoin = async () => {186const [message] = await onceWithCleanup(bot, 'message', {187timeout,188checkCondition: message => message.json.translate === 'multiplayer.player.joined'189})190childBotName = message.json.with[0].insertion191bot.chat(`/tp ${childBotName} 50 ${bot.test.groundY} 0`)192setTimeout(() => {193bot.chat('loaded')194}, 5000)195}196197const runExampleOnReady = async () => {198await onceWithCleanup(bot, 'chat', {199checkCondition: (username, message) => message === 'Ready!'200})201return run(childBotName)202}203204const child = spawn('node', [file, '127.0.0.1', `${bot.test.port}`])205206// Useful to debug child processes:207child.stdout.on('data', (data) => { console.log(`${data}`) })208child.stderr.on('data', (data) => { console.error(`${data}`) })209210const closeExample = async (err) => {211console.log('kill process ' + child.pid)212213try {214process.kill(child.pid, 'SIGTERM')215const [code] = await onceWithCleanup(child, 'close', { timeout: 1000 })216console.log('close requested', code)217} catch (e) {218console.log(e)219console.log('process termination failed, process may already be closed')220}221222if (err) {223throw err224}225}226227try {228await withTimeout(Promise.all([detectChildJoin(), runExampleOnReady()]), 30000)229} catch (err) {230console.log(err)231return closeExample(err)232}233return closeExample()234}235236function selfKill () {237bot.chat('/kill @p')238}239240// Debug packet IO when tests are re-run with "Enable debug logging" - https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#default-environment-variables241if (process.env.RUNNER_DEBUG) {242bot._client.on('packet', function (data, meta) {243if (['chunk', 'time', 'light', 'alive'].some(e => meta.name.includes(e))) return244console.log('->', meta.name, JSON.stringify(data)?.slice(0, 250))245})246const oldWrite = bot._client.write247bot._client.write = function (name, data) {248if (['alive', 'pong', 'ping'].some(e => name.includes(e))) return249console.log('<-', name, JSON.stringify(data)?.slice(0, 250))250oldWrite.apply(bot._client, arguments)251}252BigInt.prototype.toJSON ??= function () { // eslint-disable-line253return this.toString()254}255}256}257258259