diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c494604 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "app/wsmc"] + path = app/wsmc + url = https://github.com/deathcap/wsmc diff --git a/app/package.json b/app/package.json index 6ff080b..f098635 100644 --- a/app/package.json +++ b/app/package.json @@ -61,5 +61,8 @@ "scripts": { "start": "beefy app.js -- --debug" }, - "license": "MIT" + "license": "MIT", + "devDependencies": { + "browserify": "^13.0.0" + } } diff --git a/app/wsmc b/app/wsmc new file mode 160000 index 0000000..9377604 --- /dev/null +++ b/app/wsmc @@ -0,0 +1 @@ +Subproject commit 9377604d1b31420286f27382df1ccbe178fd8450 diff --git a/circle.yml b/circle.yml new file mode 100644 index 0000000..1dcea41 --- /dev/null +++ b/circle.yml @@ -0,0 +1,20 @@ +machine: + node: + version: 4 + java: + version: oraclejdk7 +checkout: + post: + # clone the wsmc submodule (see https://circleci.com/docs/configuration) + - git submodule sync + - git submodule update --init + # package voxel-clientmc + - npm install + - (cd app && npm install) + - ./app/node_modules/.bin/browserify app/app.js > app/wsmc/src/main/resources/www/bundle.js + # build wsmc/Java with the bundled voxel-clientmc + - (cd app/wsmc && mvn package) + +test: + post: + - cp -r app/wsmc/target/wsmc*.jar $CIRCLE_ARTIFACTS/ diff --git a/clientmc.js b/clientmc.js index 28514b0..b43881c 100644 --- a/clientmc.js +++ b/clientmc.js @@ -114,7 +114,7 @@ class ClientMC extends EventEmitter const hash = document.location.hash; if (hash.length < 2) { // try anonymous auth - username = 'mcwebchatuserX'; + username = 'user1'; } else { username = hash.substring(1); // remove # } @@ -128,6 +128,7 @@ class ClientMC extends EventEmitter // pass some useful data to the worker this.mfworkerStream.write({cmd: 'setVariables', + username: username, translateBlockIDs: this.translateBlockIDs, reverseBlockIDs: this.reverseBlockIDs, defaultBlockID: this.defaultBlockID, diff --git a/mf-worker.js b/mf-worker.js index 8130222..d7455d6 100644 --- a/mf-worker.js +++ b/mf-worker.js @@ -8,12 +8,13 @@ const Writable = require('stream').Writable; const through = require('through'); const ndarray = require('ndarray'); const vec3Object = require('vec3'); // note: object type used by mineflayer, NOT gl-vec3 which is just a typed array :( +const isBuffer = require('is-buffer'); module.exports = function(self) { console.log('mf-worker initializing',self); self.readStream = ParentStream().pipe(toBufferStream).pipe(through(function write(event) { - if (Buffer.isBuffer(event)) { + if (isBuffer(event)) { // buffer data passes through to readStream -> duplexStream for bot this.queue(event); } else { @@ -39,56 +40,6 @@ module.exports = function(self) { self.duplexStream = duplexer(self.writeStream, self.readStream); - self.bot = mineflayer.createBot({ - username: 'user1', // TODO - stream: self.duplexStream, - noPacketFramer: true - }); - - console.log('mf-worker bot',self.bot); - - self.bot.on('game', function() { - console.log('mf-worker spawn position: '+JSON.stringify(self.bot.spawnPoint)); - self.postMessage({cmd: 'spawn', spawnPoint: self.bot.spawnPoint}); - }); - - self.bot.on('kicked', function(reason) { - self.postMessage({cmd: 'kicked', reason: reason}); - }); - - self.bot.on('message', function(message) { - //self.console.logNode(tellraw2dom(message.json)); // TODO: send back to parent - console.log('mf-worker chat message', message); - self.postMessage({cmd: 'chat', message: message}); - }); - - self.bot.on('error', function(err) { - console.log('WebSocket error', err); - self.postMessage({cmd: 'error', error: err}); - }); - - self.bot.on('close', function() { - console.log('WebSocket closed'); - self.postMessage({cmd: 'close'}); - }); - - self.bot.on('chunkColumnLoad', function(point) { - self.addColumn(point); - }); - - let pos = [0,0,0]; - self.bot.on('blockUpdate', function(oldBlock, newBlock) { - console.log('blockUpdate', oldBlock, newBlock); - const position = newBlock.position; - pos[0] = position.x; - pos[1] = position.y; - pos[2] = position.z; - const val = self.translateBlockID((newBlock.type << 4) | newBlock.metadata); - self.postMessage({cmd: 'setBlock', position: pos, value: val}); - //self.game.setBlock(pos, val); - }); - // TODO: also handle mass block update (event? would like to optimize multi_block_change, but..) - // Translate packed MC block ID (lower 4 bits metadata, upper 12 block) to 16-bit voxel ID self.translateBlockID = function(mcPackedID) { let ourBlockID; @@ -255,46 +206,6 @@ module.exports = function(self) { self.postMessage({cmd: 'chunks', chunks: chunkCache}); // TODO: transferrable }; - self.bot.on('blockBreakProgressObserved', function(block, destroyStage) { - self.postMessage({cmd: 'blockBreakProgressObserved', position:[block.position.x, block.position.y, block.position.z], destroyStage: destroyStage}); - }); - self.bot.on('blockBreakProgressEnd', function(block) { - self.postMessage({cmd: 'blockBreakProgressEnd', position:[block.position.x, block.position.y, block.position.z]}); - }); - - - self.bot.on('move', function() { // TODO: also support entityMoved, other entities, players, mobs - // player move - self.postMessage({cmd: 'move', position:[self.bot.entity.position.x, self.bot.entity.position.y, self.bot.entity.position.z]}); - }); - - self.bot.on('soundEffectHeard', function(soundName, position, volume, pitch) { - //console.log('soundEffectHeard',arguments); - // TODO: event.x,y,z(location?), volume, pitch - 3D sound https://github.com/deathcap/voxel-sfx/issues/3 Positional audio? (voxel-audio) - self.postMessage({cmd: 'sound', soundName:soundName}); - }); - - self.bot._client.on('held_item_slot', function(packet) { // TODO: this really should be emitted in mineflayer - //packet.slot - const slot = self.bot.quickBarSlot; - console.log('held_item_slot',slot); - self.postMessage({cmd: 'heldItemSlot', slot:slot}); - }); - - self.bot.on('setSlot:0', function(oldItem, newItem) { // slot 0 is player inventory - console.log('setSlot',oldItem,newItem); - if (!oldItem && !newItem) return; // TODO: why does mineflayer send this? - self.postMessage({cmd: 'setSlot', oldItem:oldItem, newItem:newItem}); - }); - // TODO: window items packet? for setting multiple slots - - self.bot._client.on('resource_pack_send', function(packet) { // TODO: mineflayer api - self.postMessage({cmd: 'resourcePack', url:packet.url, hash:packet.hash}); - }); - - // if we exist (the webworker), socket is connected - self.bot._client.emit('connect'); - // handlers called for main thread self.chat = function(event) { @@ -305,6 +216,100 @@ module.exports = function(self) { for (let key in event) { self[key] = event[key]; } + + // Now that the main thread has gave us the necessary data (username, ...), initialize the bot + + self.bot = mineflayer.createBot({ + username: self.username, + stream: self.duplexStream, + noPacketFramer: true + }); + + console.log('mf-worker bot',self.bot); + + self.bot.on('game', function() { + console.log('mf-worker spawn position: '+JSON.stringify(self.bot.spawnPoint)); + self.postMessage({cmd: 'spawn', spawnPoint: self.bot.spawnPoint}); + }); + + self.bot.on('kicked', function(reason) { + self.postMessage({cmd: 'kicked', reason: reason}); + }); + + self.bot.on('message', function(message) { + //self.console.logNode(tellraw2dom(message.json)); // TODO: send back to parent + console.log('mf-worker chat message', message); + self.postMessage({cmd: 'chat', message: message}); + }); + + self.bot.on('error', function(err) { + console.log('WebSocket error', err); + self.postMessage({cmd: 'error', error: err}); + }); + + self.bot.on('close', function() { + console.log('WebSocket closed'); + self.postMessage({cmd: 'close'}); + }); + + self.bot.on('chunkColumnLoad', function(point) { + self.addColumn(point); + }); + + let pos = [0,0,0]; + self.bot.on('blockUpdate', function(oldBlock, newBlock) { + console.log('blockUpdate', oldBlock, newBlock); + const position = newBlock.position; + pos[0] = position.x; + pos[1] = position.y; + pos[2] = position.z; + const val = self.translateBlockID((newBlock.type << 4) | newBlock.metadata); + self.postMessage({cmd: 'setBlock', position: pos, value: val}); + //self.game.setBlock(pos, val); + }); + // TODO: also handle mass block update (event? would like to optimize multi_block_change, but..) + + self.bot.on('blockBreakProgressObserved', function(block, destroyStage) { + self.postMessage({cmd: 'blockBreakProgressObserved', position:[block.position.x, block.position.y, block.position.z], destroyStage: destroyStage}); + }); + self.bot.on('blockBreakProgressEnd', function(block) { + self.postMessage({cmd: 'blockBreakProgressEnd', position:[block.position.x, block.position.y, block.position.z]}); + }); + + + self.bot.on('move', function() { // TODO: also support entityMoved, other entities, players, mobs + // player move + self.postMessage({cmd: 'move', position:[self.bot.entity.position.x, self.bot.entity.position.y, self.bot.entity.position.z]}); + }); + + self.bot.on('soundEffectHeard', function(soundName, position, volume, pitch) { + //console.log('soundEffectHeard',arguments); + // TODO: event.x,y,z(location?), volume, pitch - 3D sound https://github.com/deathcap/voxel-sfx/issues/3 Positional audio? (voxel-audio) + self.postMessage({cmd: 'sound', soundName:soundName}); + }); + + self.bot._client.on('held_item_slot', function(packet) { // TODO: this really should be emitted in mineflayer + //packet.slot + const slot = self.bot.quickBarSlot; + console.log('held_item_slot',slot); + self.postMessage({cmd: 'heldItemSlot', slot:slot}); + }); + + self.bot.on('setSlot:0', function(oldItem, newItem) { // slot 0 is player inventory + console.log('setSlot',oldItem,newItem); + if (!oldItem && !newItem) return; // TODO: why does mineflayer send this? + self.postMessage({cmd: 'setSlot', oldItem:oldItem, newItem:newItem}); + }); + // TODO: window items packet? for setting multiple slots + + self.bot._client.on('resource_pack_send', function(packet) { // TODO: mineflayer api + self.postMessage({cmd: 'resourcePack', url:packet.url, hash:packet.hash}); + }); + + // if we exist (the webworker), socket is connected + self.bot._client.emit('connect'); + + }; // http://wiki.vg/Protocol#Player_Digging diff --git a/package.json b/package.json index 600087b..0208d70 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "dependencies": { "duplexer": "^0.1.1", "ever": "0.0.3", + "is-buffer": "^1.1.2", "itempile": "^1.0.2", "minecraft-data": "^0.19.1", "ndarray": "^1.0.14",