UNPKG

codeconnection

Version:

Code minecraft education edition using nodeJS. An attempt to improve on Microsoft Code Connection.

317 lines (252 loc) 11.1 kB
#!/usr/bin/env node ////////////////////////////////////////////////////////////////// // This is the web server //////////////////////////////////////// // It takes the request for action and passes it to the ////////// // websocket for send and recieve from Minecraft ///////////////// ////////////////////////////////////////////////////////////////// const express = require('express') const app = express() //app gets json data sent to it app.use(express.json()); let isGettingInventory = false; let inventory = []; //this processes the search from the main page app.all( "/", async function (request, response) { //send error if minecraft not connected if (socket === undefined) { let noconnection = { body: { statusMessage: "Minecraft not connected." } } response.json(noconnection) return } let command = request.body let pieces = command.pieces delete command.pieces // console.log(command) let minecraftResponse = {} if (command.body.commandLine === "inventory") { console.log('inventory') isGettingInventory = true inventory = [] for (let i = 0; i < 28; i++) { inventory.push({}) } // console.log('start') //get agent position here command.body.commandLine = "agent getposition" pieces = 1 minecraftResponse = await new Promise((resolve, reject) => { resolveMap.set(command.header.requestId, { resolve: resolve, pieces: pieces } ) socket.send(JSON.stringify(command)) }) position = minecraftResponse.body.position // console.log(position) //get the items for (let i = 1; i <= 27; i++) { command.body.commandLine = "agent getitemcount " + i pieces = 2 minecraftResponse = await new Promise((resolve, reject) => { resolveMap.set(command.header.requestId, { resolve: resolve, pieces: pieces } ) socket.send(JSON.stringify(command)) }) let data = (JSON.parse(minecraftResponse.body.properties.Result)).stackCount inventory[i].count = data if (inventory[i].count === 0) { inventory[i].itemName = '' inventory[i].slot = i inventory[i].id = -1 inventory[i].count = 0 continue } // command.body.commandLine = "agent getitemdetail " + i //drop item // console.log(i) command.body.commandLine = "agent drop " + i + " 1 up" pieces = 2 minecraftResponse = await new Promise((resolve, reject) => { resolveMap.set(command.header.requestId, { resolve: resolve, pieces: pieces } ) socket.send(JSON.stringify(command)) }) // console.log(minecraftResponse) //scan for item command.body.commandLine = `/testfor @e[type=item,x=${position.x},y=${position.y},z=${position.z},dx=${2},dy=${2},dz=${2}]` pieces = 1 minecraftResponse = await new Promise((resolve, reject) => { resolveMap.set(command.header.requestId, { resolve: resolve, pieces: pieces } ) socket.send(JSON.stringify(command)) }) let items = minecraftResponse.body.victim //collect command.body.commandLine = `agent collect all` pieces = 2 minecraftResponse = await new Promise((resolve, reject) => { resolveMap.set(command.header.requestId, { resolve: resolve, pieces: pieces } ) socket.send(JSON.stringify(command)) }) data = (JSON.parse(minecraftResponse.body.properties.Result)).itemName inventory[i].itemName = items[0] inventory[i].slot = i } minecraftResponse = inventory } else { isGettingInventory = false; //default minecraftResponse = await new Promise((resolve, reject) => { resolveMap.set(command.header.requestId, { resolve: resolve, pieces: pieces } ) socket.send(JSON.stringify(command)) }) } response.json(minecraftResponse) } ) app.listen(3001) ///////////////////////////////////////////////////// //// SOCKET ///////////////////////////////////////// ///////////////////////////////////////////////////// //https://www.youtube.com/watch?v=bjanNXXwQbo //need to turn off encrypted websockets //hide HUD in video settings (because don't want to see all the command info on the screen) const WebSocket = require('ws') //to create the websocket const uuid = require('uuid') //to generate unique message ids console.log('On minecraft send command "/connect localhost:3000"') //message to user what to do const wss = new WebSocket.Server({ port: 3000 }) //creates the socket server let resolveMap = new Map() //used to store all the promises that commands make //these are resolved when the messages come back from Minecraft let socket; //need to extract the socket wss.on( 'connection', //runs when Minecraft connects to the server async function connection(_socket) { console.log('Minecraft connection established.') socket = _socket //subscribe to player messages socket.send( JSON.stringify( { "header": { "version": 1, "requestId": uuid.v4(), "messageType": "commandRequest", "messagePurpose": "subscribe" }, "body": { "eventName": "PlayerMessage" } } ) ) //subscribe to agentcommands socket.send( JSON.stringify( { "header": { "version": 1, "requestId": uuid.v4(), "messageType": "commandRequest", "messagePurpose": "subscribe" }, "body": { "eventName": "AgentCommand" } } ) ) //re cieves the messages back from Minecraft //messages are parsed to find the requestID //the promise for this is found in the map and resolved //the record is then removed let piecesLeft = 0 let pendingResolution; socket.on( 'message', (packet) => { let response = JSON.parse(packet) // console.log(response) // console.log(response) if (isGettingInventory) { if (piecesLeft !== 0) { piecesLeft-- if (piecesLeft === 0) { pendingResolution(response) } } else if (response.header.requestId) { if (resolveMap.get(response.header.requestId)) { let resolution = resolveMap.get(response.header.requestId) if (resolution.pieces !== 1) { pendingResolution = resolution.resolve piecesLeft = resolution.pieces - 1 } else { resolution.resolve(response) } resolveMap.delete(response.header.requestId) } } } else { //default //need piecesLeft because a lot of commands get two response packets from Minecraft //and the second packet has the important information in it if (piecesLeft !== 0) { piecesLeft-- if (piecesLeft === 0) { pendingResolution(response) } } else if (response.header.requestId) { if (resolveMap.get(response.header.requestId)) { let resolution = resolveMap.get(response.header.requestId) // console.log(response.body.statusMessage) // console.log(response.body.statusMessage.includes('fail')) if (response.body.statusMessage.includes('fail') || response.body.statusMessage.startsWith("Cannot issue command")) { resolution.pieces = 1 piecesLeft = 0 response.body.properties = {} response.body.properties.Result = JSON.stringify({ success: false }) } if (resolution.pieces !== 1) { pendingResolution = resolution.resolve piecesLeft = resolution.pieces - 1 } else { // console.log(response) resolution.resolve(response) } resolveMap.delete(response.header.requestId) } } } } ) } )