From 2955c5bcfd1a0214aedbf96db93bf922474b1909 Mon Sep 17 00:00:00 2001 From: DemiPixel Date: Mon, 2 Nov 2015 19:04:09 -0800 Subject: [PATCH 1/3] Support sound basics --- src/lib/playerPlugins/commands.js | 20 ++++++++++++++++++++ src/lib/playerPlugins/placeBlock.js | 1 + src/lib/playerPlugins/sound.js | 9 +++++++++ src/lib/serverPlugins/sound.js | 24 ++++++++++++++++++++++++ 4 files changed, 54 insertions(+) create mode 100644 src/lib/playerPlugins/sound.js create mode 100644 src/lib/serverPlugins/sound.js diff --git a/src/lib/playerPlugins/commands.js b/src/lib/playerPlugins/commands.js index 76747af..767d0c9 100644 --- a/src/lib/playerPlugins/commands.js +++ b/src/lib/playerPlugins/commands.js @@ -273,6 +273,26 @@ function inject(serv, player) { } }); + base.add({ + base: 'playsound', + info: 'to play sound for yourself', + usage: '/playsound [volume] [pitch]', + parse(str) { + return str.match(/([^ ]+)(?: ([^ ]+))?(?: ([^ ]+))?/); + }, + action(sound) { + if (!sound) { + player.chat('Usage: /playsound [volume] [pitch]'); + return; + } + player.chat('Playing "'+sound[1]+'" (volume: ' + parseFloat((sound[2] || 1.0)) + ', pitch: ' + parseFloat((sound[3] || 1.0)) + ')'); + player.playSound(sound[1], { + volume: parseFloat(sound[2]) || 1.0, + pitch: parseFloat(sound[3]) || 1.0 + }); + } + }) + serv.commands = base; player.handleCommand = (str) => { diff --git a/src/lib/playerPlugins/placeBlock.js b/src/lib/playerPlugins/placeBlock.js index ede0851..1efa2b6 100644 --- a/src/lib/playerPlugins/placeBlock.js +++ b/src/lib/playerPlugins/placeBlock.js @@ -9,6 +9,7 @@ function inject(serv,player) var referencePosition=new vec3(location.x,location.y,location.z); var directionVector=directionToVector[direction]; var placedPosition=referencePosition.plus(directionVector); + serv.playSound('random.click', player.world, placedPosition.clone().add(vec3(0.5, 0.5, 0.5))); if(heldItem.blockId!=323){ player.changeBlock(placedPosition,heldItem.blockId,heldItem.itemDamage); }else if(direction==1){ diff --git a/src/lib/playerPlugins/sound.js b/src/lib/playerPlugins/sound.js new file mode 100644 index 0000000..48a1301 --- /dev/null +++ b/src/lib/playerPlugins/sound.js @@ -0,0 +1,9 @@ +module.exports = inject; + +function inject(serv, player) { + player.playSound = (sound, opt={}) => { + console.log(sound, opt); + opt.whitelist = player; + serv.playSound(sound, player.world, null, opt); + } +} \ No newline at end of file diff --git a/src/lib/serverPlugins/sound.js b/src/lib/serverPlugins/sound.js new file mode 100644 index 0000000..ffc008d --- /dev/null +++ b/src/lib/serverPlugins/sound.js @@ -0,0 +1,24 @@ +module.exports = inject; + +function inject(serv) { + serv.playSound = (sound, world, position, {whitelist,blacklist=[],radius=32*32,volume=1.0,pitch=1.0}={}) => { + var players = (typeof whitelist != 'undefined' ? (typeof whitelist == 'array' ? whitelist : [whitelist]) : serv.getNearby({ + world: world, + position: position.scaled(32).floored(), + radius: radius // 32 blocks, fixed position + })); + players.filter(player => blacklist.indexOf(player) == -1) + .forEach(player => { + var pos = (position || player.entity.position.scaled(1/32)).scaled(8).floored(); + console.log('Data',sound, pos, volume, Math.round(pitch*63)); + player._client.write('named_sound_effect', { + soundName: sound, + x: pos.x, + y: pos.y, + z: pos.z, + volume: volume, + pitch: Math.round(pitch*63) + }); + }); + } +} \ No newline at end of file From 446dfa64d07d51557c8888abce6f44e0d9b0c8d4 Mon Sep 17 00:00:00 2001 From: DemiPixel Date: Thu, 5 Nov 2015 17:41:16 -0800 Subject: [PATCH 2/3] Lots of stuff. --- src/lib/playerPlugins/commands.js | 46 +++++++++++++++++++++++++++++ src/lib/playerPlugins/login.js | 1 + src/lib/playerPlugins/placeBlock.js | 31 ++++++++++--------- src/lib/playerPlugins/pvp.js | 1 + src/lib/playerPlugins/sound.js | 29 +++++++++++++++++- src/lib/serverPlugins/particle.js | 30 +++++++++++++++++++ src/lib/serverPlugins/sound.js | 13 +++++++- src/lib/serverPlugins/world.js | 7 ++++- 8 files changed, 141 insertions(+), 17 deletions(-) create mode 100644 src/lib/serverPlugins/particle.js diff --git a/src/lib/playerPlugins/commands.js b/src/lib/playerPlugins/commands.js index 767d0c9..b2d71f7 100644 --- a/src/lib/playerPlugins/commands.js +++ b/src/lib/playerPlugins/commands.js @@ -291,6 +291,52 @@ function inject(serv, player) { pitch: parseFloat(sound[3]) || 1.0 }); } + }); + + base.add({ + base: 'playsoundforall', + info: 'to play sound for everyone', + usage: '/playsoundforall [volume] [pitch]', + parse(str) { + return str.match(/([^ ]+)(?: ([^ ]+))?(?: ([^ ]+))?/); + }, + action(sound) { + if (!sound) { + player.chat('Usage: /playsoundforall [volume] [pitch]'); + return; + } + player.chat('Playing "'+sound[1]+'" (volume: ' + parseFloat((sound[2] || 1.0)) + ', pitch: ' + parseFloat((sound[3] || 1.0)) + ')'); + serv.playSound(sound[1], player.world, player.entity.position.scaled(1/32), { + volume: parseFloat(sound[2]) || 1.0, + pitch: parseFloat(sound[3]) || 1.0 + }); + } + }) + + base.add({ + base: 'particle', + info: 'emit a particle at a position', + usage: '/particle [amount] [ ]', + parse(str) { + return str.match(/(\d+)(?: (\d+))?(?: (\d+))?(?: (\d+))?(?: (\d+))?(?: (\d+))?/); + }, + action(data) { + if (!data) { + player.chat('Usage: /particle [amount] [ ]') + return; + } + var particle = parseInt(data[1]); + var amount = data[2] || 1; + if (amount >= 100000) { + chat('You cannot emit more than 100,000 particles!') + } + var size = data[5] ? Vec3(parseInt(data[3]), parseInt(data[4]), parseInt(data[5])) : Vec3(1, 1, 1); + player.chat('Emitting "' + data[1] + '" (count: ' + amount + ', size: ' + size.x + ',' + size.y + ',' + size.z + ')'); + serv.emitParticle(particle, player.world, player.entity.position.scaled(1/32), { + count: amount, + size: size + }); + } }) serv.commands = base; diff --git a/src/lib/playerPlugins/login.js b/src/lib/playerPlugins/login.js index 92bd149..1c554cc 100644 --- a/src/lib/playerPlugins/login.js +++ b/src/lib/playerPlugins/login.js @@ -13,6 +13,7 @@ function inject(serv,player) player.entity.player=player; player.entity.health = 20; player.entity.food = 20; + player.entity.crouching = false; // Needs added in prismarine-entity later player.playerViewDistance = 150; player.view=8; player.world=serv.overworld; diff --git a/src/lib/playerPlugins/placeBlock.js b/src/lib/playerPlugins/placeBlock.js index 1efa2b6..7f7ec42 100644 --- a/src/lib/playerPlugins/placeBlock.js +++ b/src/lib/playerPlugins/placeBlock.js @@ -9,20 +9,23 @@ function inject(serv,player) var referencePosition=new vec3(location.x,location.y,location.z); var directionVector=directionToVector[direction]; var placedPosition=referencePosition.plus(directionVector); - serv.playSound('random.click', player.world, placedPosition.clone().add(vec3(0.5, 0.5, 0.5))); - if(heldItem.blockId!=323){ - player.changeBlock(placedPosition,heldItem.blockId,heldItem.itemDamage); - }else if(direction==1){ - player.setBlock(placedPosition, 63, 0); - player._client.write('open_sign_entity', { - location:placedPosition - }); - }else{ - player.setBlock(placedPosition, 68, 0); - player._client.write('open_sign_entity', { - location:placedPosition - }); - } + player.world.getBlockType(referencePosition).then((id) => { + if([25].indexOf(id) != -1) return; + serv.playSound('random.click', player.world, placedPosition.clone().add(vec3(0.5, 0.5, 0.5))); + if(heldItem.blockId!=323){ + player.changeBlock(placedPosition,heldItem.blockId,heldItem.itemDamage); + }else if(direction==1){ + player.setBlock(placedPosition, 63, 0); + player._client.write('open_sign_entity', { + location:placedPosition + }); + }else{ + player.setBlock(placedPosition, 68, 0); + player._client.write('open_sign_entity', { + location:placedPosition + }); + } + }).catch((err)=> setTimeout(() => {throw err;},0)); }); } diff --git a/src/lib/playerPlugins/pvp.js b/src/lib/playerPlugins/pvp.js index 81672e8..aae4132 100644 --- a/src/lib/playerPlugins/pvp.js +++ b/src/lib/playerPlugins/pvp.js @@ -17,6 +17,7 @@ function inject(serv, player) var attackedPlayer = serv.entities[entityId].player; if(attackedPlayer.gameMode!=0) return; attackedPlayer.updateHealth(attackedPlayer.entity.health - 1); + serv.playSound('game.player.hurt', player.world, attackedPlayer.entity.position.scaled(1/32)); if(attackedPlayer.entity.health==0) attackedPlayer._writeOthers('entity_status',{ diff --git a/src/lib/playerPlugins/sound.js b/src/lib/playerPlugins/sound.js index 48a1301..b4d8071 100644 --- a/src/lib/playerPlugins/sound.js +++ b/src/lib/playerPlugins/sound.js @@ -1,9 +1,36 @@ +var vec3 = require('vec3'); + module.exports = inject; function inject(serv, player) { player.playSound = (sound, opt={}) => { - console.log(sound, opt); opt.whitelist = player; serv.playSound(sound, player.world, null, opt); } + + player._client.on('block_place', ({location}={}) => { + if (player.entity.crouching) return; + var pos=new vec3(location.x,location.y,location.z); + player.world.getBlockType(pos).then((id) => { + if (id != 25) return; + if (!player.world.blockEntityData[pos.toString()]) player.world.blockEntityData[pos.toString()] = {}; + var data = player.world.blockEntityData[pos.toString()]; + if (typeof data.note == 'undefined') data.note = -1; + data.note++; + data.note %= 25; + serv.playNoteBlock(player.world, pos, data.note); + }).catch((err)=> setTimeout(() => {throw err;},0)); + }); + + player._client.on('block_dig', ({location,status} = {}) => { + if (status != 0 || player.gameMode == 1) return; + var pos=new vec3(location.x,location.y,location.z); + player.world.getBlockType(pos).then((id) => { + if (id != 25) return; + if (!player.world.blockEntityData[pos.toString()]) player.world.blockEntityData[pos.toString()] = {}; + var data = player.world.blockEntityData[pos.toString()]; + if (typeof data.note == 'undefined') data.note = 0; + serv.playNoteBlock(player.world, pos, data.note); + }).catch((err)=> setTimeout(() => {throw err;},0)); + }); } \ No newline at end of file diff --git a/src/lib/serverPlugins/particle.js b/src/lib/serverPlugins/particle.js new file mode 100644 index 0000000..c83dc7c --- /dev/null +++ b/src/lib/serverPlugins/particle.js @@ -0,0 +1,30 @@ +var vec3 = require("vec3"); + +module.exports = inject; + +function inject(serv) { + serv.emitParticle = (particle, world, position, {whitelist,blacklist=[],radius=32*32,longDistance,size,count}={}) => { + var players = (typeof whitelist != 'undefined' ? (typeof whitelist == 'array' ? whitelist : [whitelist]) : serv.getNearby({ + world: world, + position: position.scaled(32).floored(), + radius: radius // 32 blocks, fixed position + })); + if (!size) size = vec3(1.0, 1.0, 1.0); + players.filter(player => blacklist.indexOf(player) == -1) + .forEach(player => { + player._client.write('world_particles', { + particleId: particle, + longDistance: longDistance || true, + x: position.x, + y: position.y, + z: position.z, + offsetX: size.x, + offsetY: size.y, + offsetZ: size.z, + particleData: 1.0, + particles: count || 1, + data: [] + }); + }); + } +} \ No newline at end of file diff --git a/src/lib/serverPlugins/sound.js b/src/lib/serverPlugins/sound.js index ffc008d..5ce5764 100644 --- a/src/lib/serverPlugins/sound.js +++ b/src/lib/serverPlugins/sound.js @@ -1,3 +1,5 @@ +var vec3 = require('vec3'); + module.exports = inject; function inject(serv) { @@ -10,7 +12,6 @@ function inject(serv) { players.filter(player => blacklist.indexOf(player) == -1) .forEach(player => { var pos = (position || player.entity.position.scaled(1/32)).scaled(8).floored(); - console.log('Data',sound, pos, volume, Math.round(pitch*63)); player._client.write('named_sound_effect', { soundName: sound, x: pos.x, @@ -21,4 +22,14 @@ function inject(serv) { }); }); } + + serv.playNoteBlock = (world, position, pitch) => { + serv.emitParticle(23, world, position.clone().add(vec3(0.5, 1.5, 0.5)), { + count: 1, + size: vec3(0, 0, 0) + }); + serv.playSound('note.harp', world, position, { pitch: serv.getNote(pitch) }); + } + + serv.getNote = note => 0.5 * Math.pow(Math.pow(2, 1/12), note); } \ No newline at end of file diff --git a/src/lib/serverPlugins/world.js b/src/lib/serverPlugins/world.js index 0f6e31c..8b6c4eb 100644 --- a/src/lib/serverPlugins/world.js +++ b/src/lib/serverPlugins/world.js @@ -22,7 +22,12 @@ function inject(serv,{regionFolder,generation={"name":"diamond_square","options" serv._worldSync=new WorldSync(serv.overworld); - serv.pregenWorld = (world, size=10) => { + // WILL BE REMOVED WHEN ACTUALLY IMPLEMENTED + serv.overworld.blockEntityData = {}; + serv.netherworld.blockEntityData = {}; + ////////////// + + serv.pregenWorld = (world, size=3) => { var promises = []; for (var x = -size; x < size; x++) { for (var z = -size; z < size; z++) { From 17ad68dced771d9e3ea7d37291bb28b0c6cfd8b2 Mon Sep 17 00:00:00 2001 From: DemiPixel Date: Thu, 5 Nov 2015 17:58:49 -0800 Subject: [PATCH 3/3] I love my docs --- doc/api.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/doc/api.md b/doc/api.md index dfddb12..fdda9f9 100644 --- a/doc/api.md +++ b/doc/api.md @@ -40,6 +40,10 @@ - [server.setTime(time)](#serversettimetime) - [server.setTickInterval(ticksPerSecond)](#serversettickintervaltickspersecond) - [server.setBlock(world, position, blockType, blockData)](#serversetblockworld-position-blocktype-blockdata) + - [server.playSound(sound, world, position, opt)](#serverplaysoundsound-world-position-opt) + - [server.playNoteBlock(world, position, pitch)](#serverplaynoteblockworld-position-pitch) + - [server.getNote(note)](#servergetnotenote) + - [server.emitParticle(particle, world, position, opt)](#serveremitparticleparticle-world-position-opt) - [Low level methods](#low-level-methods) - [server._writeAll(packetName, packetFields)](#server_writeallpacketname-packetfields) - [server._writeArray(packetName, packetFields, playerArray)](#server_writearraypacketname-packetfields-playerarray) @@ -75,6 +79,7 @@ - [player.spawnAPlayer(spawnedPlayer)](#playerspawnaplayerspawnedplayer) - [player.despawnPlayers(despawnedPlayers)](#playerdespawnplayersdespawnedplayers) - [player.updateAndSpawnNearbyPlayers()](#playerupdateandspawnnearbyplayers) + - [player.playSound(sound, opt)](#playerplaysoundsound-opt) - [Low level properties](#low-level-properties) - [player._client](#player_client) - [Low level methods](#low-level-methods-1) @@ -242,6 +247,38 @@ Use `server.stopTickInterval()` if you want but this method already calls that a Saves block in world and sends block update to all players of the same world. +#### server.playSound(sound, world, position, opt) + +Plays `sound` (string, google "minecraft sound list") to all players in `opt.radius`. +If position is null, will play at the location of every player (taking into account whitelist and blacklist). + +Opt: +- whitelist: Array of players that can hear the sound (can be a player object) +- blacklist: Array of players who cannot hear the sound +- radius: Radius that sound can be heard (in fixed position so remember to multiply by 32, default 32*32) +- volume: float from 0-1 (default 1.0) +- pitch: float from 0.5 to 2 (default 1.0) + +#### server.playNoteBlock(world, position, pitch) + +Plays noteblock in world at position. `pitch` is from 0-24 + +#### server.getNote(note) + +Get pitch. `note` should be between 0-24 and your output is from 0.5 to 2.0 + +#### server.emitParticle(particle, world, position, opt) + +Emits particle (see [id list](http://wiki.vg/Protocol#Particle)) at `position` in `world`. + +Opt: +- whitelist: Array of players that can see the particle (can be a player object) +- blacklist: Array of players who cannot see the particle +- radius: Radius that the particle can be seen from +- longDistance: I don't know what this is. I think this is pointless with our implenetation of radius, not sure though... +- size: vec3 of the size. (0,0,0) will be at an exact position, (10,10,10) will be very spread out (particles less dense) +- count: Number of particles. 100,000,000+ will crash the client. Try not to go over 100,000 (sincerely, minecraft clients) + ### Low level methods #### server._writeAll(packetName, packetFields) @@ -381,6 +418,10 @@ Despawn `despawnedPlayers` for `player`. Spawn and despawn the correct players depending on distance for `player`. +#### player.playSound(sound, opt) + +Easy way to only play a sound for one player. Same opt as serv.playSound except no `whitelist`. + ### Low level properties #### player._client