From b5d22e57f93993325d8c96a28ca1ee6ab8a70173 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Sat, 28 Nov 2015 18:23:26 +0100 Subject: [PATCH] improve code with webstorm suggestion + split entities.js into spawn.js and other files --- README.md | 2 +- doc/API.md | 10 +- src/lib/behavior.js | 4 +- src/lib/command.js | 6 +- src/lib/plugins/behavior.js | 6 +- src/lib/plugins/blocks.js | 8 +- src/lib/plugins/chat.js | 2 +- src/lib/plugins/chest.js | 2 +- src/lib/plugins/commands.js | 2 +- src/lib/plugins/communication.js | 4 +- src/lib/plugins/daycycle.js | 6 +- src/lib/plugins/digging.js | 5 +- src/lib/plugins/entities.js | 283 +-------------------- src/lib/plugins/external.js | 16 +- src/lib/plugins/inventory.js | 67 +++-- src/lib/plugins/moderation.js | 6 +- src/lib/plugins/modpe.js | 2 +- src/lib/plugins/particle.js | 2 +- src/lib/plugins/physics.js | 1 - src/lib/plugins/placeBlock.js | 4 +- src/lib/plugins/pvp.js | 6 +- src/lib/plugins/sound.js | 4 +- src/lib/plugins/spawn.js | 223 ++++++++++++++++ src/lib/plugins/updatePositions.js | 31 ++- src/lib/plugins/world.js | 2 +- src/lib/worldGenerations/all_the_blocks.js | 2 +- src/lib/worldGenerations/grass_field.js | 2 +- src/lib/worldGenerations/nether.js | 2 +- src/lib/worldGenerations/superflat.js | 9 +- test/mineflayer.js | 2 +- 30 files changed, 361 insertions(+), 360 deletions(-) create mode 100644 src/lib/plugins/spawn.js diff --git a/README.md b/README.md index a6b83b8..a537092 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,6 @@ You can add server plugins and player plugins in your package, following [CONTRI - [@roblabla](https://github.com/roblabla) for helping out with the protocols - [@rom1504](https://github.com/rom1504) for massive contributions to the code - [@demipixel](https://github.com/demipixel) - - The PrismarineJS team for creating prismarine-chunk and node-minecraft-protcol + - The PrismarineJS team for creating prismarine-chunk and node-minecraft-protocol - [wiki.vg](http://wiki.vg/Protocol) for documenting minecraft protocols - All of our other awesome contributors! diff --git a/doc/API.md b/doc/API.md index 50a4874..c248b27 100644 --- a/doc/API.md +++ b/doc/API.md @@ -511,10 +511,10 @@ player.on('move_cancel', ({position}, cancel) => { }); ``` -If we keep Plugin B and replace Plugin A with Plugin C, we'll see that the player can move freely but will not recieve the +If we keep Plugin B and replace Plugin A with Plugin C, we'll see that the player can move freely but will not receive the word "HI" and other players will be unable to see their movements. -Finally, there is hidden cancel. This is the second paramater in cancel, and allows plugins to hide the fact that they cancelled +Finally, there is hidden cancel. This is the second parameter in cancel, and allows plugins to hide the fact that they cancelled the default action from other plugins. It's best not to use this, but I know somebody will someday need this. Plugin D @@ -529,9 +529,9 @@ their position and other players will not see the player move. #### FORMAT -Defition of behavior. +Definition of behavior. - var1: Variable with value, can be changed (default: defaultValue) -- var2 (u): Variable with value. You can change it however it will not have any effect on the defautl action (and could screw with other plugins, watch out!). U stands for unused +- var2 (u): Variable with value. You can change it however it will not have any effect on the default action (and could screw with other plugins, watch out!). U stands for unused Default: What happens if this isn't cancelled. @@ -819,7 +819,7 @@ sends `message` to the player change the block at position `position` to `blockType` and `blockData` -this will not change the block for the user themself. It is mainly useful when a user places a block +this will not change the block for the user himself. It is mainly useful when a user places a block and only needs to send it to other players on the server #### player.sendBlock(position,blockType,blockData) diff --git a/src/lib/behavior.js b/src/lib/behavior.js index e9a2b8e..6469d95 100644 --- a/src/lib/behavior.js +++ b/src/lib/behavior.js @@ -11,7 +11,7 @@ module.exports = (obj) => { cancelCount++; } defaultCancel = dC; - } + }; await obj.emitThen(eventName + '_cancel', data, cancel).catch((err)=> setTimeout(() => {throw err;},0)); await obj.emitThen(eventName, data, cancelled, cancelCount).catch((err)=> setTimeout(() => {throw err;},0)); @@ -22,4 +22,4 @@ module.exports = (obj) => { await obj.emitThen(eventName + '_done', data, cancelled).catch((err)=> setTimeout(() => {throw err;},0)); return data; } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/lib/command.js b/src/lib/command.js index fafc62a..20a4721 100644 --- a/src/lib/command.js +++ b/src/lib/command.js @@ -15,9 +15,9 @@ class Command { var ended = space + '(.*)'; - var finded = command.match(new RegExp('^' + key + ended)); - if(finded) { - res = [this.hash[key], finded]; + var found = command.match(new RegExp('^' + key + ended)); + if(found) { + res = [this.hash[key], found]; } } diff --git a/src/lib/plugins/behavior.js b/src/lib/plugins/behavior.js index 3e25155..b41178f 100644 --- a/src/lib/plugins/behavior.js +++ b/src/lib/plugins/behavior.js @@ -2,8 +2,8 @@ var Behavior = require('../behavior'); module.exports.server = function(serv) { serv.behavior = new Behavior(serv); -} +}; -module.exports.entity = function(entity, serv) { +module.exports.entity = function (entity) { entity.behavior = new Behavior(entity); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/lib/plugins/blocks.js b/src/lib/plugins/blocks.js index efd5528..43d00b4 100644 --- a/src/lib/plugins/blocks.js +++ b/src/lib/plugins/blocks.js @@ -15,9 +15,9 @@ module.exports.player=function(player,serv) player.sendBlock = (position, blockType, blockData) => // Call from player.setBlock unless you want "local" fake blocks player.behavior('sendBlock', { position: position, - id: blockType, - data: blockData - }, ({position, id, damage}) => { + blockType: blockType, + blockData: blockData + }, ({position, blockType, blockData}) => { player._client.write("block_change",{ location:position, type:blockType<<4 | blockData @@ -38,7 +38,7 @@ module.exports.player=function(player,serv) return results; }, action(params) { - var res = params.map((num, i) => { // parseInt paramaters + var res = params.map((num, i) => { // parseInt parameters if (num.indexOf('~') == 0) { return (player.position[['', 'x', 'y', 'z'][i]] >> 5) + parseInt(num.slice(1) || 0); } else { diff --git a/src/lib/plugins/chat.js b/src/lib/plugins/chat.js index 8629993..38bad80 100644 --- a/src/lib/plugins/chat.js +++ b/src/lib/plugins/chat.js @@ -17,7 +17,7 @@ module.exports.player=function(player,serv) player.behavior('chat', { message: message, broadcastMessage: '<' + player.username + '>' + ' ' + message - }, ({message, broadcast, broadcastMessage}) => { + }, ({broadcastMessage}) => { serv.broadcast(broadcastMessage); }); } diff --git a/src/lib/plugins/chest.js b/src/lib/plugins/chest.js index 7b475fd..18a91b7 100644 --- a/src/lib/plugins/chest.js +++ b/src/lib/plugins/chest.js @@ -25,4 +25,4 @@ module.exports.player=function(player) } }); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/lib/plugins/commands.js b/src/lib/plugins/commands.js index 9e3ca3f..61f99c6 100644 --- a/src/lib/plugins/commands.js +++ b/src/lib/plugins/commands.js @@ -76,7 +76,7 @@ module.exports.player=function(player) { player.handleCommand = async (str) => { try { - var res = await player.commands.use(str) + var res = await player.commands.use(str); if (res) player.chat('' + res); } catch(err) { diff --git a/src/lib/plugins/communication.js b/src/lib/plugins/communication.js index 6018302..7df5fc0 100644 --- a/src/lib/plugins/communication.js +++ b/src/lib/plugins/communication.js @@ -41,11 +41,11 @@ module.exports.entity=function(entity,serv) .filter((e) => e.type == 'player'); entity.nearbyPlayers = (radius=entity.viewDistance*32) => entity.nearbyEntities - .filter(e => e.type == 'player') + .filter(e => e.type == 'player'); entity._writeOthers = (packetName, packetFields) => serv._writeArray(packetName, packetFields, entity.getOtherPlayers()); entity._writeOthersNearby = (packetName, packetFields) => serv._writeArray(packetName, packetFields, entity.getNearbyPlayers()); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/lib/plugins/daycycle.js b/src/lib/plugins/daycycle.js index af3ce5a..5649a2b 100644 --- a/src/lib/plugins/daycycle.js +++ b/src/lib/plugins/daycycle.js @@ -18,7 +18,7 @@ module.exports.server=function(serv) { old: serv.time, newTime: serv.time + 20 }, ({newTime}) => { - serv.setTime((serv.time + 20) % 24000); // Vanilla only does it every second + serv.setTime(newTime % 24000); // Vanilla only does it every second }); } }) @@ -29,7 +29,7 @@ module.exports.player=function(player,serv){ base: 'night', info: 'to change a time to night', usage: '/night', - action(params) { + action() { return player.handleCommand('time set night'); } }); @@ -68,7 +68,7 @@ module.exports.player=function(player,serv){ base: 'day', info: 'to change a time to day', usage: '/day', - action(params) { + action() { return player.handleCommand('time set day'); } }); diff --git a/src/lib/plugins/digging.js b/src/lib/plugins/digging.js index 183f0f1..67194c2 100644 --- a/src/lib/plugins/digging.js +++ b/src/lib/plugins/digging.js @@ -35,7 +35,7 @@ module.exports.player=function(player,serv) .catch((err)=> setTimeout(() => {throw err;},0)) }); - function diggingTime(location) + function diggingTime() { // assume holding nothing and usual conditions return currentlyDugBlock.digTime(); @@ -69,7 +69,7 @@ module.exports.player=function(player,serv) start: startDigging, timePassed: currentDiggingTime, position: location - }, ({lastState, state}) => { + }, ({state}) => { lastDestroyState=state; player._writeOthersNearby("block_break_animation",{ "entityId":currentAnimationId, @@ -97,7 +97,6 @@ module.exports.player=function(player,serv) var diggingTime=new Date()-startDiggingTime; var stop = false; if(expectedDiggingTime-diggingTime<100) { - stop = true; stop = player.behavior('forceCancelDig', { stop: true, start: startDiggingTime, diff --git a/src/lib/plugins/entities.js b/src/lib/plugins/entities.js index 36a8ffa..b0b580b 100644 --- a/src/lib/plugins/entities.js +++ b/src/lib/plugins/entities.js @@ -1,71 +1,6 @@ -var Entity = require("../entity"); -var Version = require("../version") var Vec3 = require("vec3").Vec3; -var ItemStack = require("prismarine-item")(Version) -var entitiesByName=require("minecraft-data")(Version).entitiesByName; - -var path = require('path'); -var requireIndex = require('requireindex'); -var plugins = requireIndex(path.join(__dirname,'..', 'plugins')); module.exports.server=function(serv,options) { - - serv.initEntity = (type, entityType, world, position) => { - serv.entityMaxId++; - var entity = new Entity(serv.entityMaxId); - - Object.keys(plugins) - .filter(pluginName => plugins[pluginName].entity!=undefined) - .forEach(pluginName => plugins[pluginName].entity(entity, serv, options)); - - entity.initEntity(type, entityType, world, position); - - serv.emit("newEntity",entity); - - return entity; - }; - - serv.spawnObject = (type, world, position, {pitch=0,yaw=0,velocity=new Vec3(0,0,0),data=1,itemId,itemDamage=0,pickupTime=undefined,deathTime=undefined}) => { - var object = serv.initEntity('object', type, world, position.scaled(32).floored()); - object.data = data; - object.velocity = velocity.scaled(32).floored(); - object.pitch = pitch; - object.yaw = yaw; - object.gravity = new Vec3(0, -20*32, 0); - object.terminalvelocity = new Vec3(27*32, 27*32, 27*32); - object.friction = new Vec3(15*32, 0, 15*32); - object.size = new Vec3(0.25*32, 0.25*32, 0.25*32); // Hardcoded, will be dependent on type! - object.deathTime = deathTime; - object.pickupTime = pickupTime; - object.itemId = itemId; - object.itemDamage = itemDamage; - - object.updateAndSpawn(); - }; - - serv.spawnMob = (type, world, position, {pitch=0,yaw=0,headPitch=0,velocity=new Vec3(0,0,0),metadata=[]}={}) => { - var mob = serv.initEntity('mob', type, world, position.scaled(32).floored()); - mob.velocity = velocity.scaled(32).floored(); - mob.pitch = pitch; - mob.headPitch = headPitch; - mob.yaw = yaw; - mob.gravity = new Vec3(0, -20*32, 0); - mob.terminalvelocity = new Vec3(27*32, 27*32, 27*32); - mob.friction = new Vec3(15*32, 0, 15*32); - mob.size = new Vec3(0.75, 1.75, 0.75); - mob.health = 20; - mob.metadata = metadata; - - mob.updateAndSpawn(); - }; - - serv.destroyEntity = entity => { - entity._writeOthersNearby('entity_destroy', { - entityIds: [entity.id] - }); - delete serv.entities[entity.id]; - }; - serv.on('tick', function(delta) { Promise.all( Object.keys(serv.entities).map(async (id) => { @@ -92,86 +27,7 @@ module.exports.server=function(serv,options) { }); }; -module.exports.player=function(player,serv){ - player.commands.add({ - base: 'spawn', - info: 'Spawn a mob', - usage: '/spawn ', - parse(str) { - var results=str.match(/(\d+)/); - if (!results) return false; - return { - id: parseInt(results[1]) - } - }, - action({id}) { - serv.spawnMob(id, player.world, player.position.scaled(1/32), { - velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10) - }); - } - }); - - player.commands.add({ - base: 'spawnObject', - info: 'Spawn an object', - usage: '/spawnObject ', - parse(str) { - var results=str.match(/(\d+)/); - if (!results) return false; - return { - id: parseInt(results[1]) - } - }, - action({id}) { - serv.spawnObject(id, player.world, player.position.scaled(1/32), { - velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10) - }); - } - }); - - player.commands.add({ - base: 'summon', - info: 'Summon an entity', - usage: '/summon ', - action(name) { - var entity=entitiesByName[name]; - if(!entity) { - player.chat("No entity named "+name); - return; - } - serv.spawnMob(entity.id, player.world, player.position.scaled(1/32), { - velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10) - }); - } - }); -}; - -module.exports.entity=function(entity,serv){ - - entity.initEntity=(type, entityType, world, position)=>{ - entity.type = type; - entity.spawnPacketName = ''; - entity.entityType = entityType; - entity.world = world; - entity.position = position; - entity.lastPositionPlayersUpdated = entity.position.clone(); - entity.nearbyEntities = []; - entity.viewDistance = 150; - - entity.bornTime = Date.now(); - serv.entities[entity.id] = entity; - - if (entity.type == 'player') entity.spawnPacketName = 'named_entity_spawn'; - else if (entity.type == 'object') entity.spawnPacketName = 'spawn_entity'; - else if (entity.type == 'mob') entity.spawnPacketName = 'spawn_entity_living'; - }; - - - entity.on("move",() => { - if(entity.position.distanceTo(entity.lastPositionPlayersUpdated)>2*32) - entity.updateAndSpawn(); - }); - +module.exports.entity=function(entity){ entity.sendMetadata = (data) => { entity._writeOthersNearby('entity_metadata', { entityId: entity.id, @@ -182,142 +38,5 @@ module.exports.entity=function(entity,serv){ entity.setAndUpdateMetadata = (data) => { entity.metadata = data; entity.sendMetadata(data); - } - - entity.destroy = () => { - serv.destroyEntity(entity); }; - - entity.getSpawnPacket = () => { - var scaledVelocity = entity.velocity.scaled(8000/32/20).floored(); // from fixed-position/second to unit => 1/8000 blocks per tick - if (entity.type == 'player') { - return { - entityId: entity.id, - playerUUID: entity._client.uuid, - x: entity.position.x, - y: entity.position.y, - z: entity.position.z, - yaw: entity.yaw, - pitch: entity.pitch, - currentItem: 0, - metadata: entity.metadata - } - } else if (entity.type == 'object') { - return { - entityId: entity.id, - type: entity.entityType, - x: entity.position.x, - y: entity.position.y, - z: entity.position.z, - pitch: entity.pitch, - yaw: entity.yaw, - objectData: { - intField: entity.data, - velocityX: scaledVelocity.x, - velocityY: scaledVelocity.y, - velocityZ: scaledVelocity.z - } - } - } else if (entity.type == 'mob') { - return { - entityId: entity.id, - type: entity.entityType, - x: entity.position.x, - y: entity.position.y, - z: entity.position.z, - yaw: entity.yaw, - pitch: entity.pitch, - headPitch: entity.headPitch, - velocityX: scaledVelocity.x, - velocityY: scaledVelocity.y, - velocityZ: scaledVelocity.z, - metadata: entity.metadata - } - } - }; - - entity.updateAndSpawn = () => { - var updatedEntities=entity.getNearby(); - var entitiesToAdd=updatedEntities.filter(e => entity.nearbyEntities.indexOf(e)==-1); - var entitiesToRemove=entity.nearbyEntities.filter(e => updatedEntities.indexOf(e)==-1); - if (entity.type == 'player') { - entity.despawnEntities(entitiesToRemove); - entitiesToAdd.forEach(entity.spawnEntity); - } - entity.lastPositionPlayersUpdated=entity.position.clone(); - - var playersToAdd = entitiesToAdd.filter(e => e.type == 'player'); - var playersToRemove = entitiesToRemove.filter(e => e.type == 'player'); - - playersToRemove.forEach(p => p.despawnEntities([entity])); - playersToRemove.forEach(p => p.nearbyEntities=p.getNearby()); - playersToAdd.forEach(p => p.spawnEntity(entity)); - playersToAdd.forEach(p => p.nearbyEntities=p.getNearby()); - - entity.nearbyEntities=updatedEntities; - }; - - entity.collect = (collectEntity) => { - if (entity.type != 'player'){ - serv.emit('error',new Error('[ERROR] Non-player entity (type ' + entity.type + ') cannot collect another entity')); - return; - } - - // Add it to a stack already in the player's inventory if possible - for(var itemKey in entity.inventory.slots){ - var item = entity.inventory.slots[itemKey] - if(item == undefined) continue; - if(item.type == collectEntity.itemId){ - item.count += 1 - entity.inventory.updateSlot(itemKey, item) - collectEntity._writeOthersNearby('collect', { - collectedEntityId: collectEntity.id, - collectorEntityId: entity.id - }); - entity.playSoundAtSelf('random.pop'); - collectEntity.destroy() - return; - } - } - - // If we couldn't add it to a already existing stack, put it in a new stack if the inventory has room - var emptySlot = entity.inventory.firstEmptyInventorySlot() - if(emptySlot != null){ - collectEntity._writeOthersNearby('collect', { - collectedEntityId: collectEntity.id, - collectorEntityId: entity.id - }); - entity.playSoundAtSelf('random.pop'); - - var newItem = new ItemStack(collectEntity.itemId, 1, collectEntity.damage) - entity.inventory.updateSlot(emptySlot, newItem) - collectEntity.destroy() - } - } - - entity.sendVelocity = (vel, maxVel) => { - var velocity = vel.scaled(32).floored(); // Make fixed point - var maxVelocity = maxVel.scaled(32).floored(); - var scaledVelocity = velocity.scaled(8000/32/20).floored(); // from fixed-position/second to unit => 1/8000 blocks per tick - entity._writeOthersNearby('entity_velocity', { - entityId: entity.id, - velocityX: scaledVelocity.x, - velocityY: scaledVelocity.y, - velocityZ: scaledVelocity.z - }); - if (entity.type != 'player') { - if (maxVelocity) entity.velocity = addVelocityWithMax(entity.velocity, velocity, maxVelocity); - else entity.velocity.add(velocity); - } - } - function addVelocityWithMax(current, newVel, max) { - var x, y, z; - if (current.x > max.x || current.x < -max.x) x = current.x; - else x = Math.max(-max.x, Math.min(max.x, current.x + newVel.x)); - if (current.y > max.y || current.y < -max.y) y = current.y; - else y = Math.max(-max.y, Math.min(max.y, current.y + newVel.y)); - if (current.z > max.z || current.z < -max.z) z = current.z; - else z = Math.max(-max.z, Math.min(max.z, current.z + newVel.z)); - return new Vec3(x, y, z); - } }; \ No newline at end of file diff --git a/src/lib/plugins/external.js b/src/lib/plugins/external.js index f711957..6bc3416 100644 --- a/src/lib/plugins/external.js +++ b/src/lib/plugins/external.js @@ -18,10 +18,10 @@ module.exports.server = function(serv, settings) { }; serv.pluginCount++; if (serv.externalPluginsLoaded && plugin.server) serv.plugins[name].server.call(p, serv, settings); - } + }; - for (var p in settings.plugins) { - if (settings.plugins[p].disabled) continue; + Object.keys(settings.plugins).forEach((p) =>{ + if (settings.plugins[p].disabled) return; try { require.resolve(p); // Check if it exists, if not do catch, otherwise jump to bottom } catch (err) { @@ -34,11 +34,11 @@ module.exports.server = function(serv, settings) { return; } serv.addPlugin(p, require(p), settings.plugins[p]); - } + }); - for (var p in serv.plugins) { + Object.keys(serv.plugins).forEach((p) =>{ if (serv.plugins[p].server) serv.plugins[p].server.call(serv.plugins[p], serv, settings); - } + }); serv.externalPluginsLoaded = true; }; @@ -59,10 +59,10 @@ module.exports.entity = function(entity, serv) { entity.getData = (pluginName) => { if (typeof pluginName == 'object') pluginName = pluginName.name; return entity.pluginData[pluginName] || null; - } + }; Object.keys(serv.plugins).forEach(p => { var plugin = serv.plugins[p]; if (plugin.entity) plugin.entity.call(plugin, entity, serv); }); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/lib/plugins/inventory.js b/src/lib/plugins/inventory.js index 28115ae..09ad44b 100644 --- a/src/lib/plugins/inventory.js +++ b/src/lib/plugins/inventory.js @@ -1,16 +1,16 @@ -var Version = require("../version") -var Windows = require("prismarine-windows")(Version).windows -var ItemStack = require("prismarine-item")(Version) +var Version = require("../version"); +var Windows = require("prismarine-windows")(Version).windows; +var ItemStack = require("prismarine-item")(Version); -module.exports.player = function(player) +module.exports.player = function(player,serv) { - player.heldItemSlot = 0 - player.heldItem = new ItemStack(256, 1) - player.inventory = new Windows.InventoryWindow(0, "Inventory", 44) + player.heldItemSlot = 0; + player.heldItem = new ItemStack(256, 1); + player.inventory = new Windows.InventoryWindow(0, "Inventory", 44); player._client.on("held_item_slot", ({slotId} = {}) => { player.heldItemSlot = slotId; - player.heldItem = player.inventory.slots[36 + player.heldItemSlot] + player.heldItem = player.inventory.slots[36 + player.heldItemSlot]; player._writeOthersNearby("entity_equipment",{ entityId: player.id, @@ -51,7 +51,7 @@ module.exports.player = function(player) // (Nothing to do with held_item_slot) // DANGER! crashes because windows.js hasn't implemented it yet. return; - break + break; case 3: // Middle click @@ -131,16 +131,16 @@ module.exports.player = function(player) catch(err) { serv.emit('error',err); } - }) + }); player._client.on("set_creative_slot", ({slot,item} ={}) => { if(item.blockId == -1){ - player.inventory.updateSlot(slot, undefined) + player.inventory.updateSlot(slot, undefined); return; } var newItem = ItemStack.fromNotch(item); - player.inventory.updateSlot(slot, newItem) + player.inventory.updateSlot(slot, newItem); if (slot==5) player._writeOthersNearby("entity_equipment",{ @@ -170,7 +170,6 @@ module.exports.player = function(player) }); player.inventory.on("windowUpdate", function(){ - var items = player.inventory.slots // Update held item player._writeOthersNearby("entity_equipment",{ @@ -180,13 +179,49 @@ module.exports.player = function(player) }); // Update slots in inventory - for(var itemIndex in items){ - var item = items[itemIndex] + for(var itemIndex=0;itemIndex { + + // Add it to a stack already in the player's inventory if possible + for(var itemKey=0;itemKey {throw new Error("username not found");}); + .catch(err => {throw err;}); }; - serv.banUsername = (username, reason, cb) => { + serv.banUsername = (username, reason) => { return serv.getUUIDFromUsername(username) .then(uuid => serv.ban(uuid, reason)); }; - serv.pardonUsername = (username, cb) => { + serv.pardonUsername = (username) => { return serv.getUUIDFromUsername(username) .then(pardon); }; diff --git a/src/lib/plugins/modpe.js b/src/lib/plugins/modpe.js index 1aff257..96fbc1d 100644 --- a/src/lib/plugins/modpe.js +++ b/src/lib/plugins/modpe.js @@ -149,7 +149,7 @@ module.exports.server=function(serv,settings) function injectPlayer(player,serv) { log("Injected into player"); - initSquid(player, serv, vec3); + initSquid(player, serv, Vec3); newLevel(); player._client.on("block_dig", function (packet) { diff --git a/src/lib/plugins/particle.js b/src/lib/plugins/particle.js index 0b7cbe3..41b4768 100644 --- a/src/lib/plugins/particle.js +++ b/src/lib/plugins/particle.js @@ -2,7 +2,7 @@ var Vec3 = require("vec3").Vec3; module.exports.server=function(serv) { serv.emitParticle = (particle, world, position, {whitelist,blacklist=[],radius=32*32,longDistance=true,size=new Vec3(1, 1, 1),count=1}={}) => { - var players = (typeof whitelist != 'undefined' ? (typeof whitelist == 'array' ? whitelist : [whitelist]) : serv.getNearby({ + var players = (typeof whitelist != 'undefined' ? (whitelist instanceof Array ? whitelist : [whitelist]) : serv.getNearby({ world: world, position: position.scaled(32).floored(), radius: radius // 32 blocks, fixed position diff --git a/src/lib/plugins/physics.js b/src/lib/plugins/physics.js index 792f7b1..896c707 100644 --- a/src/lib/plugins/physics.js +++ b/src/lib/plugins/physics.js @@ -21,7 +21,6 @@ module.exports.entity=function(entity){ var yBlock = yVec.equals(xVec) ? xBlock : blocks[await entity.world.getBlockType(yVec)].boundingBox == 'block'; var zBlock = zVec.equals(yVec) ? yBlock : (zVec.equals(xVec) ? xBlock : blocks[await entity.world.getBlockType(zVec)].boundingBox == 'block'); - var old = entity.position.clone(); if (xBlock || yBlock || zBlock) { entity.velocity.x = getFriction(entity.velocity.x, entity.friction.x, delta); diff --git a/src/lib/plugins/placeBlock.js b/src/lib/plugins/placeBlock.js index daf0265..1b4f5d7 100644 --- a/src/lib/plugins/placeBlock.js +++ b/src/lib/plugins/placeBlock.js @@ -26,8 +26,8 @@ module.exports.player=function(player,serv) position: placedPosition, reference: referencePosition, playSound: true, - sound: 'dig.' + (materialToSound[blocks[heldItem.blockId].material] || 'stone'), - }, ({direction, heldItem, position, reference, playSound, sound, id, damage}) => { + sound: 'dig.' + (materialToSound[blocks[heldItem.blockId].material] || 'stone') + }, ({direction, heldItem, position, playSound, sound, id, damage}) => { if (playSound) { serv.playSound(sound, player.world, placedPosition.clone().add(new Vec3(0.5, 0.5, 0.5)), { pitch: 0.8 diff --git a/src/lib/plugins/pvp.js b/src/lib/plugins/pvp.js index 78c5414..621addd 100644 --- a/src/lib/plugins/pvp.js +++ b/src/lib/plugins/pvp.js @@ -25,7 +25,7 @@ module.exports.player=function(player,serv) velocity: attackedEntity.position.minus(player.position).plus(new Vec3(0, 0.5, 0)).scaled(5), maxVelocity: new Vec3(4, 4, 4), animation: true - }, ({attackedEntity, sound, playSound, damage, velocity, maxVelocity, animation}) => { + }, ({attackedEntity, sound, damage, velocity, maxVelocity, animation}) => { attackedEntity.updateHealth(attackedEntity.health - damage); serv.playSound(sound, player.world, attackedEntity.position.scaled(1/32)); @@ -51,11 +51,11 @@ module.exports.player=function(player,serv) }; -module.exports.entity=function(entity,serv) +module.exports.entity=function(entity) { if (entity.type != 'player') { entity.updateHealth = (health) => { entity.health = health; } } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/lib/plugins/sound.js b/src/lib/plugins/sound.js index 1c91f20..678a698 100644 --- a/src/lib/plugins/sound.js +++ b/src/lib/plugins/sound.js @@ -2,7 +2,7 @@ var Vec3 = require('vec3').Vec3; module.exports.server=function(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({ + var players = (typeof whitelist != 'undefined' ? (typeof whitelist instanceof Array ? whitelist : [whitelist]) : serv.getNearby({ world: world, position: position.scaled(32).floored(), radius: radius // 32 blocks, fixed position @@ -40,7 +40,7 @@ module.exports.player=function(player,serv) { serv.playSound(sound, player.world, null, opt); }; - player.on('placeBlock_cancel', async ({position, reference}, cancel) => { + player.on('placeBlock_cancel', async ({reference}, cancel) => { if (player.crouching) return; var id = await player.world.getBlockType(reference); if (id != 25) return; diff --git a/src/lib/plugins/spawn.js b/src/lib/plugins/spawn.js new file mode 100644 index 0000000..cb8efb5 --- /dev/null +++ b/src/lib/plugins/spawn.js @@ -0,0 +1,223 @@ +var version = require("../version"); +var entitiesByName=require("minecraft-data")(version).entitiesByName; +var Entity = require("../entity"); +var path = require('path'); +var requireIndex = require('requireindex'); +var plugins = requireIndex(path.join(__dirname,'..', 'plugins')); + +var Vec3 = require("vec3").Vec3; + +module.exports.server=function(serv,options) { + serv.initEntity = (type, entityType, world, position) => { + serv.entityMaxId++; + var entity = new Entity(serv.entityMaxId); + + Object.keys(plugins) + .filter(pluginName => plugins[pluginName].entity!=undefined) + .forEach(pluginName => plugins[pluginName].entity(entity, serv, options)); + + entity.initEntity(type, entityType, world, position); + + serv.emit("newEntity",entity); + + return entity; + }; + + serv.spawnObject = (type, world, position, {pitch=0,yaw=0,velocity=new Vec3(0,0,0),data=1,itemId,itemDamage=0,pickupTime=undefined,deathTime=undefined}) => { + var object = serv.initEntity('object', type, world, position.scaled(32).floored()); + object.data = data; + object.velocity = velocity.scaled(32).floored(); + object.pitch = pitch; + object.yaw = yaw; + object.gravity = new Vec3(0, -20*32, 0); + object.terminalvelocity = new Vec3(27*32, 27*32, 27*32); + object.friction = new Vec3(15*32, 0, 15*32); + object.size = new Vec3(0.25*32, 0.25*32, 0.25*32); // Hardcoded, will be dependent on type! + object.deathTime = deathTime; + object.pickupTime = pickupTime; + object.itemId = itemId; + object.itemDamage = itemDamage; + + object.updateAndSpawn(); + }; + + serv.spawnMob = (type, world, position, {pitch=0,yaw=0,headPitch=0,velocity=new Vec3(0,0,0),metadata=[]}={}) => { + var mob = serv.initEntity('mob', type, world, position.scaled(32).floored()); + mob.velocity = velocity.scaled(32).floored(); + mob.pitch = pitch; + mob.headPitch = headPitch; + mob.yaw = yaw; + mob.gravity = new Vec3(0, -20*32, 0); + mob.terminalvelocity = new Vec3(27*32, 27*32, 27*32); + mob.friction = new Vec3(15*32, 0, 15*32); + mob.size = new Vec3(0.75, 1.75, 0.75); + mob.health = 20; + mob.metadata = metadata; + + mob.updateAndSpawn(); + }; + + serv.destroyEntity = entity => { + entity._writeOthersNearby('entity_destroy', { + entityIds: [entity.id] + }); + delete serv.entities[entity.id]; + }; +}; + + +module.exports.player=function(player,serv){ + player.commands.add({ + base: 'spawn', + info: 'Spawn a mob', + usage: '/spawn ', + parse(str) { + var results=str.match(/(\d+)/); + if (!results) return false; + return { + id: parseInt(results[1]) + } + }, + action({id}) { + serv.spawnMob(id, player.world, player.position.scaled(1/32), { + velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10) + }); + } + }); + + player.commands.add({ + base: 'spawnObject', + info: 'Spawn an object', + usage: '/spawnObject ', + parse(str) { + var results=str.match(/(\d+)/); + if (!results) return false; + return { + id: parseInt(results[1]) + } + }, + action({id}) { + serv.spawnObject(id, player.world, player.position.scaled(1/32), { + velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10) + }); + } + }); + + player.commands.add({ + base: 'summon', + info: 'Summon an entity', + usage: '/summon ', + action(name) { + var entity=entitiesByName[name]; + if(!entity) { + player.chat("No entity named "+name); + return; + } + serv.spawnMob(entity.id, player.world, player.position.scaled(1/32), { + velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10) + }); + } + }); +}; + +module.exports.entity=function(entity,serv) { + entity.initEntity=(type, entityType, world, position)=>{ + entity.type = type; + entity.spawnPacketName = ''; + entity.entityType = entityType; + entity.world = world; + entity.position = position; + entity.lastPositionPlayersUpdated = entity.position.clone(); + entity.nearbyEntities = []; + entity.viewDistance = 150; + + entity.bornTime = Date.now(); + serv.entities[entity.id] = entity; + + if (entity.type == 'player') entity.spawnPacketName = 'named_entity_spawn'; + else if (entity.type == 'object') entity.spawnPacketName = 'spawn_entity'; + else if (entity.type == 'mob') entity.spawnPacketName = 'spawn_entity_living'; + }; + + entity.getSpawnPacket = () => { + var scaledVelocity = entity.velocity.scaled(8000/32/20).floored(); // from fixed-position/second to unit => 1/8000 blocks per tick + if (entity.type == 'player') { + return { + entityId: entity.id, + playerUUID: entity._client.uuid, + x: entity.position.x, + y: entity.position.y, + z: entity.position.z, + yaw: entity.yaw, + pitch: entity.pitch, + currentItem: 0, + metadata: entity.metadata + } + } else if (entity.type == 'object') { + return { + entityId: entity.id, + type: entity.entityType, + x: entity.position.x, + y: entity.position.y, + z: entity.position.z, + pitch: entity.pitch, + yaw: entity.yaw, + objectData: { + intField: entity.data, + velocityX: scaledVelocity.x, + velocityY: scaledVelocity.y, + velocityZ: scaledVelocity.z + } + } + } else if (entity.type == 'mob') { + return { + entityId: entity.id, + type: entity.entityType, + x: entity.position.x, + y: entity.position.y, + z: entity.position.z, + yaw: entity.yaw, + pitch: entity.pitch, + headPitch: entity.headPitch, + velocityX: scaledVelocity.x, + velocityY: scaledVelocity.y, + velocityZ: scaledVelocity.z, + metadata: entity.metadata + } + } + }; + + + + entity.updateAndSpawn = () => { + var updatedEntities=entity.getNearby(); + var entitiesToAdd=updatedEntities.filter(e => entity.nearbyEntities.indexOf(e)==-1); + var entitiesToRemove=entity.nearbyEntities.filter(e => updatedEntities.indexOf(e)==-1); + if (entity.type == 'player') { + entity.despawnEntities(entitiesToRemove); + entitiesToAdd.forEach(entity.spawnEntity); + } + entity.lastPositionPlayersUpdated=entity.position.clone(); + + var playersToAdd = entitiesToAdd.filter(e => e.type == 'player'); + var playersToRemove = entitiesToRemove.filter(e => e.type == 'player'); + + playersToRemove.forEach(p => p.despawnEntities([entity])); + playersToRemove.forEach(p => p.nearbyEntities=p.getNearby()); + playersToAdd.forEach(p => p.spawnEntity(entity)); + playersToAdd.forEach(p => p.nearbyEntities=p.getNearby()); + + entity.nearbyEntities=updatedEntities; + }; + + + entity.on("move",() => { + if(entity.position.distanceTo(entity.lastPositionPlayersUpdated)>2*32) + entity.updateAndSpawn(); + }); + + entity.destroy = () => { + serv.destroyEntity(entity); + }; + +}; \ No newline at end of file diff --git a/src/lib/plugins/updatePositions.js b/src/lib/plugins/updatePositions.js index 6f8f823..749d77b 100644 --- a/src/lib/plugins/updatePositions.js +++ b/src/lib/plugins/updatePositions.js @@ -105,7 +105,7 @@ module.exports.entity=function(entity,serv){ old: oldPos, onGround: onGround }, ({old,onGround}) => { - var diff = entity.position.minus(oldPos); + var diff = entity.position.minus(old); if(diff.abs().x>127 || diff.abs().y>127 || diff.abs().z>127) entity._writeOthersNearby('entity_teleport', { @@ -128,4 +128,33 @@ module.exports.entity=function(entity,serv){ entity.position = oldPos; }); }; + + + + entity.sendVelocity = (vel, maxVel) => { + var velocity = vel.scaled(32).floored(); // Make fixed point + var maxVelocity = maxVel.scaled(32).floored(); + var scaledVelocity = velocity.scaled(8000/32/20).floored(); // from fixed-position/second to unit => 1/8000 blocks per tick + entity._writeOthersNearby('entity_velocity', { + entityId: entity.id, + velocityX: scaledVelocity.x, + velocityY: scaledVelocity.y, + velocityZ: scaledVelocity.z + }); + if (entity.type != 'player') { + if (maxVelocity) entity.velocity = addVelocityWithMax(entity.velocity, velocity, maxVelocity); + else entity.velocity.add(velocity); + } + }; + + function addVelocityWithMax(current, newVel, max) { + var x, y, z; + if (current.x > max.x || current.x < -max.x) x = current.x; + else x = Math.max(-max.x, Math.min(max.x, current.x + newVel.x)); + if (current.y > max.y || current.y < -max.y) y = current.y; + else y = Math.max(-max.y, Math.min(max.y, current.y + newVel.y)); + if (current.z > max.z || current.z < -max.z) z = current.z; + else z = Math.max(-max.z, Math.min(max.z, current.z + newVel.z)); + return new Vec3(x, y, z); + } }; \ No newline at end of file diff --git a/src/lib/plugins/world.js b/src/lib/plugins/world.js index 87ca495..eff2116 100644 --- a/src/lib/plugins/world.js +++ b/src/lib/plugins/world.js @@ -129,7 +129,7 @@ module.exports.player=function(player,serv,settings) { if(!loaded) player.loadedChunks[key]=1; return !loaded; }) - .reduce((acc,{chunkX,chunkZ},i)=> { + .reduce((acc,{chunkX,chunkZ})=> { var p=acc .then(() => player.world.getColumn(chunkX, chunkZ)) .then((column) => player.sendChunk(chunkX, chunkZ, column)); diff --git a/src/lib/worldGenerations/all_the_blocks.js b/src/lib/worldGenerations/all_the_blocks.js index 332db57..30bccf0 100644 --- a/src/lib/worldGenerations/all_the_blocks.js +++ b/src/lib/worldGenerations/all_the_blocks.js @@ -3,7 +3,7 @@ var Vec3 = require('vec3').Vec3; var blocks=require("minecraft-data")(require("../version")).blocks; function generation() { - function generateSimpleChunk(chunkX, chunkZ) { + function generateSimpleChunk() { var chunk = new Chunk(); var i=2; diff --git a/src/lib/worldGenerations/grass_field.js b/src/lib/worldGenerations/grass_field.js index a306272..7f4a93b 100644 --- a/src/lib/worldGenerations/grass_field.js +++ b/src/lib/worldGenerations/grass_field.js @@ -2,7 +2,7 @@ var Chunk = require('prismarine-chunk')(require("../version")); var Vec3 = require('vec3').Vec3; function generation() { - function generateSimpleChunk(chunkX, chunkZ) { + function generateSimpleChunk() { var chunk = new Chunk(); for (var x = 0; x < 16; x++) { diff --git a/src/lib/worldGenerations/nether.js b/src/lib/worldGenerations/nether.js index a091689..46bf9d6 100644 --- a/src/lib/worldGenerations/nether.js +++ b/src/lib/worldGenerations/nether.js @@ -15,7 +15,7 @@ function generation({seed,level=50}={}) { let data; if (y < bedrockheightbottom) block = 7; - else if (y < 50) block = 87; + else if (y < level) block = 87; else if (y > 127 - bedrockheighttop) block = 7; var pos = new Vec3(x, y, z); diff --git a/src/lib/worldGenerations/superflat.js b/src/lib/worldGenerations/superflat.js index 5054b22..ce9060a 100644 --- a/src/lib/worldGenerations/superflat.js +++ b/src/lib/worldGenerations/superflat.js @@ -2,7 +2,7 @@ var Chunk = require('prismarine-chunk')(require("../version")); var Vec3 = require('vec3').Vec3; function generation({opt='default',bottom_id=7,middle_id=1,top_id=2,middle_thickness=3,debug=false}={}) { - function generateChunk(chunkX,chunkZ) { + function generateChunk() { var chunk=new Chunk(); var height = middle_thickness + 1; var DEBUG_POINTS = [new Vec3(0, height, 0), new Vec3(15, height, 0), new Vec3(0, height, 15), new Vec3(15, height, 15)]; @@ -19,11 +19,8 @@ function generation({opt='default',bottom_id=7,middle_id=1,top_id=2,middle_thick } } - if (debug) { - for (var d in DEBUG_POINTS) { - chunk.setBlockType(DEBUG_POINTS[d], 35); - } - } + if (debug) + DEBUG_POINTS.forEach(p => chunk.setBlockType(p, 35)); return chunk; } return generateChunk; diff --git a/test/mineflayer.js b/test/mineflayer.js index 63e86d4..f0adf7b 100644 --- a/test/mineflayer.js +++ b/test/mineflayer.js @@ -41,7 +41,7 @@ describe("Server with mineflayer connection", function() { describe("commands",function(){ it("has an help command", function(done) { - bot.once("message",function(message){ + bot.once("message",function(){ done(); }); bot.chat("/help");