Skip to content

Commit

Permalink
initial commit of mineflayer-voxel plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
vogonistic committed Feb 6, 2013
0 parents commit 281a3be
Show file tree
Hide file tree
Showing 8 changed files with 358 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/node_modules
/public/client.js
/public/textures
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# mineflayer-voxel

Attempt at visualizing what the bot is up to using voxel.js

### Roadmap

* Integrate properly with terrain generation system of voxel.js
* Send lots of terrain initially
* Display mobs
* Allow bot to highlight data

### Precondition

You must extract textures from minecraft.jar (Note, must be snapshot, not the current release!).

`node extract_textures.js <path_to_minecraft.jar>`

### Usage

`npm start`
135 changes: 135 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
var createGame = require('voxel-engine')
var io = window.io
, socket = io.connect(undefined, {reconnect:false})
, botEntity
, entities = {}

socket.on('spawn', function(position) {
pixelPosition = position.map(function(v) { return v*25; })
pixelPosition[1] += 1.62*25;
console.log('spawn:', position, pixelPosition);
if (!window.game) {
var game = createGame({
// generate: function() { return 0; },
generate: generate_blockCache,
startingPosition: pixelPosition,
worldOrigin: pixelPosition,

texturePath: './textures/blocks/',
materials: ['dirt', ['grass_top', 'dirt', 'grass_side'], ['tree_top', 'tree_top', 'tree_side'], 'leaves', 'stone', 'wood'],
materialParams: { transparent: false }
})

var container = document.querySelector('#gameCanvas')
game.appendTo(container)
container.addEventListener('click', function() {
game.requestPointerLock(container)
});

window.game = game;
}

// Look down at the ground
// window.game.controls.pitchObject.rotation.x = -1.5

var groundPos = window.game.tilespaceToWorldspace(position[0], position[1] - 1, position[2])
window.game.setBlock(groundPos, 1);
})

socket.on('entity', function (newEntity) {
botEntity = newEntity;
});

socket.on('entitySpawn', function (newEntity) {
entities[newEntity.id] = newEntity;
});

socket.on('entityMoved', function (newEntity) {
entities[newEntity.id] = newEntity;
});

socket.on('entityGone', function(oldEntity) {
delete entities[oldEntity.id];
});

socket.on('blockUpdate', function(block) {
var type = materialIndex(block.name);
var pos = positionToVector3(block.position);
if (type !== -1) {
var voxel = window.game.voxels.voxelAtPosition(pos);
if (!voxel) {
window.game.voxels.requestMissingChunks(pos);
}

window.game.setBlock(positionToVector3(block.position), type);
} else {
console.log('blockUpdate: '+block.name+' ('+type+')', pos);
}
})

var blockCache = {}
window.blockCache = blockCache
window.hits = 0;
socket.on('blockMultiUpdate', function(data) {
window._testdata = data
console.log('blockMultiUpdate', data)
// var start = positionToVector3(data.start);
var size = data.size;
var i = 0;
for (x = 0; x <= data.size[0]; ++x) {
for (y = 0; y <= data.size[1]; ++y) {
for (z = 0; z <= data.size[2]; ++z) {
var pos = positionToVector3([data.start[0]+x, data.start[1]+y, data.start[2]+z]);
var cachePos = [data.start[0]+x, data.start[1]+y, data.start[2]+z].map(function(v) {return Math.floor(v)}).join('|');
var obj = {position:pos, name:data.data[i++]}
blockCache[cachePos] = obj;
}
}
}
})

function generate_blockCache(x,y,z) {
var cachePos = [x,y,z].join('|');
var cachedBlock = blockCache[cachePos];
var material = 0;
if (cachedBlock) {
window.hits ++;
material = materialIndex(cachedBlock.name);
if (material === -1) material = 0;
}
return material;
}

function positionToVector3(position) {
var cubeSize = window.game !== undefined ? window.game.cubeSize : 25;
return {
x: position[0]*cubeSize,
y: position[1]*cubeSize,
z: position[2]*cubeSize
}
}

function materialIndex(name) {
return {
'air':0,
'snow':0,
'dirt': 1,
'grass': 2,
'log': 3,
'leaves': 4,
'stone': 5,
'wood': 6
}[name] || -1;
}

function getPlayerPosition() {
var cs = window.game.cubeSize;
var pos = window.game.controls.yawObject.position;
return {
x: pos.x / cs,
y: pos.y / cs - 1.5,
z: pos.z / cs
};
}

function noop() {}
25 changes: 25 additions & 0 deletions extract_textures.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
var child_process = require('child_process');
var path = require('path');

if (process.argv.length !== 3) {
console.log('Usage: '+process.argv[1]+' <path to minecraft.jar>');
process.exit(1)
}

var file = process.argv[2];
var filetype = child_process.exec('file '+file, function(error, stdout) {
if (!stdout.match(/Zip archive data/)) {
console.log('File type doesnt match a java archive.');
process.exit(1);
}

var unzipList = child_process.exec('unzip -l "'+file+'" | grep textures/blocks/quartz', function(error, stdout, stderr) {
if (error) {
console.log('Error: No quartz blocks found in archive. Is the minecraft.jar new enough? Try a snapshot.');
process.exit(1);
}

var home = path.join(path.dirname(process.argv[1]), 'public');
unzip = child_process.spawn('unzip', [file, 'textures*', '-d', home], { stdio:['ignore', process.stdout, process.stderr] });
})
})
100 changes: 100 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
module.exports = init;

function init(mineflayer) {
return inject;
}

function inject(bot, options) {
options = options || {};
var path = require('path')
, express = require('express')
, app = express()
, server = require('http').createServer(app)
, io = require('socket.io').listen(server)
, port = options.port || 0
, host = options.host || '0.0.0.0'

io.set('log level', 0);

app.use(express.static(path.join(__dirname, 'public')));

server.listen(port, function() {
console.info("Listening at http://" + host + ":" + server.address().port);
});

io.sockets.on('connection', function (socket) {
// socket.emit('spawn', serializedPosition(bot.entity.position));
// var area = [2,2,2]
var area = [16,16,16]
var start = bot.entity.position.offset(-area[0]/2, -area[1]/2, -area[2]/2).floored();
var buffer = {
start: serializedPosition(start),
size: area,
data: []
}

for (x = 0; x <= buffer.size[0]; ++x) {
for (y = 0; y <= buffer.size[1]; ++y) {
for (z = 0; z <= buffer.size[2]; ++z) {
var pos = start.offset(x, y, z);
var block = bot.blockAt(pos);
// if (block.type !== 0) {
// socket.emit('blockUpdate', serializedBlock(block))
// }
// if (z === 0) console.log([buffer.start[0]+x, buffer.start[1]+y, buffer.start[2]+z])
buffer.data.push(block.name);
}
}
}
// setTimeout(function() {
socket.emit('blockMultiUpdate', buffer)
socket.emit('spawn', serializedPosition(bot.entity.position));
// }, 2000)

bot.on('spawn', function() {
socket.emit('spawn', serializedPosition(bot.entity.position));
})

bot.on('move', function() {
socket.emit('entity', bot.entity);
});

bot.on('entitySpawn', function(entity) {
socket.emit('entitySpawn', entity);
});

bot.on('entityGone', function(entity) {
socket.emit('entityGone', entity);
});

bot.on('entityMoved', function(entity) {
socket.emit('entityMoved', entity);
});

bot.on('blockUpdate', function(oldBlock, newBlock) {
// console.log('blockUpdate new:'+(newBlock ? newBlock.name : '?')+' old:'+(oldBlock ? oldBlock.name : '?'))
if (!newBlock) return;
socket.emit('blockUpdate', serializedBlock(newBlock));
})

socket.on('controlState', function(state) {
bot.setControlState(state.name, state.value);
});

socket.on('look', function(look) {
bot.look(look.yaw, look.pitch);
});

function serializedPosition(position) {
return [position.x, position.y, position.z]
}

function serializedBlock(block) {
return {
name: block.name,
position: serializedPosition(block.position)
}
}

});
}
19 changes: 19 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "mineflayer-voxel",
"version": "0.0.1",
"description": "A plugin to give you a web-based view of your mineflayer bot.",
"main": "index.js",
"author": "Kent Karlsson <vogonistic@gmail.com>",
"license": "BSD",
"dependencies": {
"express": "~3.0.6",
"socket.io": "~0.9.13",
"mineflayer": "*",
"mineflayer-navigate": "*",
"voxel-engine": "*"
},
"scripts": {
"prestart": "browserify app.js -o public/client.js",
"start": "node run.js"
}
}
12 changes: 12 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html>
<head>
<title>Mineflayer Client</title>
</head>
<body>
<div id="gameCanvas">
</div>
<script src="/socket.io/socket.io.js"></script>
<script src="/client.js"></script>
</body>
</html>
44 changes: 44 additions & 0 deletions run.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
var mineflayer = require('mineflayer');
var vec3 = mineflayer.vec3;
var navigatePlugin = require('mineflayer-navigate')(mineflayer);
var voxelPlugin = require('./index.js')(mineflayer);
var bot = mineflayer.createBot();

navigatePlugin(bot);
voxelPlugin(bot, {port: 13333});

bot.navigate.on('pathPartFound', function (path) {
bot.chat("Going " + path.length + " meters in the general direction for now.");
});
bot.navigate.on('pathFound', function (path) {
bot.chat("I can get there in " + path.length + " moves.");
});
bot.navigate.on('cannotFind', function () {
bot.chat("unable to find path");
});
bot.navigate.on('arrived', function () {
bot.chat("I have arrived");
});
bot.navigate.on('stop', function() {
bot.chat("stopping");
});
var lookInterval, lookTarget;
bot.on('chat', function(username, message) {
if (username === bot.username) return;
var target = bot.players[username].entity;
if (message === 'come') {
bot.navigate.to(target.position);
} else if (message === 'stop') {
bot.navigate.stop();
bot.clearControlStates();
clearInterval(lookInterval);
} else if (message === 'watch') {
clearInterval(lookInterval);
lookInterval = setInterval(look, 100);
lookTarget = target;
}
});

function look() {
bot.lookAt(lookTarget.position.offset(0, lookTarget.height, 0));
}

0 comments on commit 281a3be

Please sign in to comment.