I casually play minecraft from time to time and run a small server for group play. Things are kept mostly vanilla, but code and hacking excites me as much as (or more than) mining and crafting. I wanted a way to do something simple – say boom in chat, and wherever I am in world, a small fireworks jubilee sets off. Written in nodejs/javascript for convenience.

OK, for starters, this post isn't a walk-through. It won't explain things like directory references, but those should be self-explanatory. The goal of this post is to show the code that makes it go boom. First, to read the chat, just tail the server log file. I'm using a helper library that handles things like reconnecting to the file when the log rotates.
const { Tail } = require(`${__dirname}/Tail.js`)
let tail = new Tail(`${__dirname}/../logs/latest.log`)
tail.on('line', line => {
let matched = line.match(/^\[\d\d:\d\d:\d\d\] \[Server thread\/INFO\]: <(.+?)> (.+)$/)
if(matched){
let action = matched[2].toLowerCase()
debug(`${matched[1]} said ${matched[2]}`)
if(action == "boom") boom(matched[1])
}
})
tail.on('error', err =>{ debug(`ERROR: ${err}`) })The second library for interacting with the server is rcon-client, which allows the script to send commands (and queries) to the server. This also means the server needs RCON enabled.
const { Rcon } = require(`${__dirname}/rcon-client/lib/`)
const rcon = new Rcon({host:'localhost', port:25575, password:'apass'})
rcon.on('authenticated', ()=>{ say(`Hey everybody! HAL reconnected.`) })
rcon.on('end', ()=>{ debug(`RCON ended`) })
rcon.on("error", err=>{ debug(`RCON Error ${err}`) })
async function init(){
debug(`Going to initalize the RCON`)
await rcon.connect()
}
init().catch(debug)So those are the two pieces that handle communication with the server. Now it's time for the fun stuff – making the fireworks go boom. First things first, the script needs to find the player position when the player says boom. The script uses data get entity <player> Pos.
const { Firework } = require('./boom')
function rI(max=10,abs=false){ //just a random int helper func.
let i = Math.floor(Math.random() * Math.floor(max))
let a = Math.round(Math.random())
if(a||abs) return i
return -i
}
async function boom(player){
let pos = await rcon.send(`data get entity ${player} Pos`)
let coords = pos.match(/\[(.+?), (.+?), (.+?)\]/)
if(coords){
coords.forEach((m,i)=>{ coords[i] = parseInt(m) })
let count = rI(60,true)
debug(`Launching ${count} fireworks!`)
for(var x=1; x<count; x++){
let fwcmd = `summon firework_rocket ${coords[1]+rI()} ${coords[2]} ${coords[3]+rI()} ${Firework.make()}`
//debug(fwcmd)
setTimeout(()=>{ rcon.send(fwcmd) }, rI(3000))
}
}
}The final piece is making the fireworks. For this, I checked out digminecraft's fireworks generator. The script uses the /summon variant to summon fireworks near the player. Looking at the boom function in the previous block, fireworks are summoned on a random interval in a randomized 10-block grid around the player. Because the syntax of the firework command is a bit messy, I wrote a small function to contain the mess. Elements of the fireworks are randomized.
function firework(){
function randomBinary(){ return Math.round(Math.random()) }
function randomInt(max=1,abs=true){ //TODO: might exclude max.
let i = Math.floor(Math.random() * Math.floor(max))
if(abs || randomBinary()) return i
return -i
}
let LIFE = [ 15,20,25,30,35,40,45,50,55,60 ]
let COLORS = [
1973019, //Black
2651799, //Cyan
6719955, //Light Blue
11743532,//Red
11250603,//Light Gray
12801229,//Magenta
3887386, //Green
4408131, //Gray
15435844,//Orange
5320730, //Brown
14188952,//Pink
15790320,//White
2437522, //Blue
4312372, //Lime
8073150, //Purple
14602026,//Yellow
]
let getColors = function(){
let colors = []
for(x=0;x<=randomInt(4);x++){
let color = randomInt(COLORS.length-1)
colors.push(COLORS[color])
}
return colors
}
let getExplosion = function(){
let explosion = {
Type: randomInt(4).toString(), //['small', 'big', 'star', 'creeper', 'burst']
Flicker: randomBinary().toString(),
Trail: randomBinary().toString(),
Colors: getColors()
}
if(randomBinary()) explosion.FadeColors = getColors()
return explosion
}
this.make = function(){
let rocket = {
LifeTime: LIFE[randomInt(LIFE.length)],
FireworksItem: {
id: "firework_rocket",
Count: 1,//randomInt(4)+1,
tag: { Fireworks: {
Flight: (randomInt(3)+1).toString(),
Explosions: [ getExplosion() ]
} }
}
}
//Turn javascript object into minecraft command syntax:
return JSON.stringify(rocket).replace(/"/g,'').replace(/Colors:\[/g,'Colors:[I;')
}
}
exports.Firework = new firework()