Change serv.world to serv.worlds. Added playerPlugins/world.js and moved a lot of stuff from login.js there. Generating multiple worlds works and moving players there works as well. A few issues here and there.

This commit is contained in:
DemiPixel 2015-10-13 23:17:01 -07:00
parent 24370e9d0f
commit 1917165caf
11 changed files with 278 additions and 154 deletions

View file

@ -11,7 +11,7 @@
- [serv.entityMaxId](#serventitymaxid)
- [serv.players](#servplayers)
- [serv.uuidToPlayer](#servuuidtoplayer)
- [serv.world](#servworld)
- [serv.worlds](#servworlds)
- [serv.entities](#serventities)
- [serv.bannedPlayers](#servbannedplayers)
- [serv.time](#servtime)
@ -41,6 +41,7 @@
- [player.entity](#playerentity)
- [player.username](#playerusername)
- [player.view](#playerview)
- [player.world](#playerworld)
- [Events](#events-1)
- ["connected"](#connected)
- ["spawned"](#spawned)
@ -49,6 +50,7 @@
- ["chat" (message)](#chat-message)
- ["kicked" (kicker,reason)](#kicked-kickerreason)
- ["positionChanged"](#positionchanged)
- ["teleport"](#teleport)
- [Methods](#methods-1)
- [player.login()](#playerlogin)
- [player.ban(reason)](#playerbanreason)
@ -62,6 +64,8 @@
- [player.setGameMode(gameMode)](#playersetgamemodegamemode)
- [player.handleCommand(command)](#playerhandlecommandcommand)
- [player.updateHealth(health)](#playerupdatehealthhealth)
- [player.sendPosition(position, opt)](#playersendpositionposition-opt)
- [player.changeWorld(worldNumber, opt)](#playerchangeworldworldnumber-opt)
- [Low level properties](#low-level-properties)
- [player._client](#player_client)
- [Low level methods](#low-level-methods)
@ -98,9 +102,9 @@ Array of connected players
Object uuid to players
#### serv.world
#### serv.worlds
The map
Array of all worlds. By default, 0 is Overworld, 1 is Nether, and 2 is the End, however any plugin may push more worlds (`serv.worlds.push(new World(...))`) and the player can be sent there with `player.changeWorld(worldNumber, opt)`.
#### serv.entities
@ -224,6 +228,10 @@ The username of the player
The view size of the player, for example 8 for 16x16
#### player.world
Which world the player is in. Get it by using `serv.worlds[player.world]`.
### Events
#### "connected"
@ -252,7 +260,11 @@ Fires when the player says `message`.
#### "positionChanged"
fires when the position changed
fires when the position changes in small amounts (walking, running, or flying)
#### "teleport"
fires when the position changes in larger amounts (player's position set by `player.sendPosition()`)
### Methods
@ -309,6 +321,24 @@ handle `command`
update the player health.
#### player.sendPosition(position, opt)
Teleport the player to any `position` in the same world. Use `player.changeWorld` to teleport to any world. Options:
- yaw: Set the yaw, default is the current yaw of the player
- pitch: Set the pitch, default is the current pitch of the player
#### player.changeWorld(worldNumber, opt)
Change which world the player is in (Overworld, Nether, End, or any other world added to `serv.worlds`). Options:
- gamemode: Gamemode of the world (Default is player gamemode)
- difficulty: Difficulty of world. Default is 0 (easiest)
- dimension: Dimension of world. 0 is Overworld, -1 is Nether, 1 is End (Default is 0)
- position: Position player spawns, default is their default spawn point
- yaw: Yaw in which they spawn, default is 0
- pitch: Pitch in which they spawn, default is 0
### Low level properties
#### player._client

View file

@ -2,12 +2,13 @@ module.exports=inject;
function inject(serv,player)
{
function changeBlock(position,blockType)
async function changeBlock(position,blockType)
{
player.getOthers().forEach(function(player) {
player.sendBlock(position, blockType);
player.getOthers().forEach(function(p) {
if (p.world != player.world) return;
p.sendBlock(position, blockType);
});
return serv.world.setBlockType(position,blockType);
return await player.world.setBlockType(position,blockType);
}
function sendBlock(position, blockType) { // Call from serv.setBlock unless you want "local" fake blocks

View file

@ -8,8 +8,8 @@ function inject(serv, player)
var referencePosition=new vec3(packet.location.x,packet.location.y,packet.location.z);
if (player.entity.crouching) return;
try {
var id = await serv.world.getBlockType(referencePosition);
var blockAbove = await serv.world.getBlockType(referencePosition.clone().add(new vec3(0, 1, 0)));
var id = await player.world.getBlockType(referencePosition);
var blockAbove = await player.world.getBlockType(referencePosition.clone().add(new vec3(0, 1, 0)));
if (id == 54) {
if (blockAbove) {

View file

@ -6,7 +6,7 @@ function inject(serv,player)
{
player._client.on("block_dig",function(packet){
var pos=new Vec3(packet.location);
serv.world.getBlock(pos)
player.world.getBlock(pos)
.then(block => {
currentlyDugBlock=block;
if(currentlyDugBlock.type==0) return;

View file

@ -1,5 +1,4 @@
var Entity=require("prismarine-entity");
var spiralloop = require('spiralloop');
var Vec3=require("vec3");
module.exports=inject;
@ -15,6 +14,7 @@ function inject(serv,player)
player.entity.health = 20;
player.entity.food = 20;
player.view=8;
player.world=serv.overworld;
player.username=player._client.username;
serv.players.push(player);
serv.uuidToPlayer[player._client.uuid] = player;
@ -40,61 +40,16 @@ function inject(serv,player)
player.entity.position=toFixedPosition(player.spawnPoint);
}
function spiral(arr)
{
var t=[];
spiralloop(arr,function(x,z){
t.push([x,z]);
});
return t;
}
function sendChunk(chunkX,chunkZ,column)
{
player._client.write('map_chunk', {
x: chunkX,
z: chunkZ,
groundUp: true,
bitMap: 0xffff,
chunkData: column.dump()
});
return Promise.resolve();
}
function sendChunksAroundPlayer(view)
{
player.lastPositionChunkUpdated=player.entity.position;
var playerChunkX=Math.floor(player.entity.position.x/16/32);
var playerChunkZ=Math.floor(player.entity.position.z/16/32);
return spiral([view*2,view*2])
.map(t => ({
chunkX:playerChunkX+t[0]-view,
chunkZ:playerChunkZ+t[1]-view
}))
.filter(({chunkX,chunkZ}) => {
var key=chunkX+","+chunkZ;
var loaded=player.loadedChunks[key];
if(!loaded) player.loadedChunks[key]=1;
return !loaded;
})
.reduce((acc,{chunkX,chunkZ})=>
acc
//.then(() => sleep(100))
.then(() => serv.world.getColumn(chunkX,chunkZ))
.then((column) => sendChunk(chunkX,chunkZ,column))
,Promise.resolve());
}
function sendMap()
{
return sendChunksAroundPlayer(3);
return player.sendNearbyChunks(3)
.catch((err) => setTimeout(function() { throw err; }), 0);
}
function sendRestMap()
{
player.sendingChunks=true;
sendChunksAroundPlayer(player.view)
player.sendNearbyChunks(player.view)
.then(() => player.sendingChunks=false)
.catch((err)=> setTimeout(function(){throw err;},0));
@ -102,20 +57,19 @@ function inject(serv,player)
if(!player.sendingChunks && player.entity.position.distanceTo(player.lastPositionChunkUpdated)>16*32)
{
player.sendingChunks=true;
sendChunksAroundPlayer(player.view)
player.sendNearbyChunks(player.view)
.then(() => player.sendingChunks=false)
.catch((err)=> setTimeout(function(){throw err;},0));
}
});
player.on("teleport", function() {
player.sendingChunks=true;
player.sendNearbyChunks(player.view)
.then(() => player.sendingChunks=false)
.catch((err)=> setTimeout(function(){throw err;},0));
});
}
function sleep(ms = 0) {
return new Promise(r => setTimeout(r, ms));
}
function sendSpawnPosition()
{
console.log("setting spawn at "+player.spawnPoint);
@ -124,21 +78,6 @@ function inject(serv,player)
});
}
function sendInitialPosition()
{
player.entity.position=toFixedPosition(player.spawnPoint);
player.entity.yaw=0;
player.entity.pitch=0;
player._client.write('position', {
x: player.entity.position.x/32,
y: player.entity.position.y/32,
z: player.entity.position.z/32,
yaw: player.entity.yaw,
pitch: player.entity.pitch,
flags: 0x00
});
}
function updateTime()
{
player._client.write('update_time', {
@ -182,41 +121,6 @@ function inject(serv,player)
}
function spawnOthers()
{
player.getOthers().forEach(function (otherPlayer) {
player._client.write('named_entity_spawn', {
entityId: otherPlayer.entity.id,
playerUUID: otherPlayer._client.uuid,
x: otherPlayer.entity.position.x,
y: otherPlayer.entity.position.y,
z: otherPlayer.entity.position.z,
yaw: otherPlayer.entity.yaw,
pitch: otherPlayer.entity.pitch,
currentItem: 0,
metadata: otherPlayer.entity.metadata
});
});
}
function spawn()
{
player._writeOthers('named_entity_spawn',{
entityId: player.entity.id,
playerUUID: player._client.uuid,
x: player.entity.position.x,
y: player.entity.position.y,
z: player.entity.position.z,
yaw: player.entity.yaw,
pitch: player.entity.pitch,
currentItem: 0,
metadata: player.entity.metadata
});
}
function announceJoin()
{
serv.broadcast(player.username + ' joined the game.', "yellow");
@ -238,7 +142,6 @@ function inject(serv,player)
sendLogin();
await sendMap();
sendSpawnPosition();
sendInitialPosition();
player.updateHealth(player.entity.health);
player.emit("spawned");
@ -246,9 +149,8 @@ function inject(serv,player)
updateTime();
setGameMode(player.gameMode);
fillTabList();
spawnOthers();
spawn();
player.spawn();
announceJoin();
setTimeout(sendRestMap,100);
@ -256,6 +158,4 @@ function inject(serv,player)
player.setGameMode=setGameMode;
player.login=login;
player.sendInitialPosition=sendInitialPosition;
player.spawn=spawn;
}

View file

@ -82,4 +82,24 @@ function inject(serv,player)
player.entity.onGround = onGround;
player.emit("positionChanged");
}
function setPosition(pos, opt) {
opt = opt || {};
if (pos) player.entity.position = toFixedPosition(pos);
if (typeof opt.yaw != 'undefined') player.entity.yaw=opt.yaw;
if (typeof opt.pitch != 'undefined') player.entity.pitch=opt.pitch;
player._client.write('position', {
x: player.entity.position.x/32,
y: player.entity.position.y/32,
z: player.entity.position.z/32,
yaw: player.entity.yaw,
pitch: player.entity.pitch,
flags: 0x00
});
player.spawnForOthers();
player.getNearbyPlayers();
player.emit('teleport');
}
player.setPosition = setPosition;
}

View file

@ -0,0 +1,124 @@
var vec3=require("vec3");
var spiralloop = require('spiralloop');
module.exports = inject;
function inject(serv, player) {
function spawn() {
player.setPosition(player.spawnPoint, { yaw: 0, pitch: 0, exact: true });
}
function spawnForOthers() {
player._writeOthers('named_entity_spawn',{ // _writeOthersWithinDistance?
entityId: player.entity.id,
playerUUID: player._client.uuid,
x: player.entity.position.x,
y: player.entity.position.y,
z: player.entity.position.z,
yaw: player.entity.yaw,
pitch: player.entity.pitch,
currentItem: 0,
metadata: player.entity.metadata
});
}
function getNearbyPlayers() {
player.getOthers().forEach(function (otherPlayer) {
if (otherPlayer.world != player.world) return; // Also check distance from player?
player._client.write('named_entity_spawn', {
entityId: otherPlayer.entity.id,
playerUUID: otherPlayer._client.uuid,
x: otherPlayer.entity.position.x,
y: otherPlayer.entity.position.y,
z: otherPlayer.entity.position.z,
yaw: otherPlayer.entity.yaw,
pitch: otherPlayer.entity.pitch,
currentItem: 0,
metadata: otherPlayer.entity.metadata
});
});
}
function sendChunk(chunkX,chunkZ,column)
{
player._client.write('map_chunk', {
x: chunkX,
z: chunkZ,
groundUp: true,
bitMap: 0xffff,
chunkData: column.dump()
});
return Promise.resolve();
}
function spiral(arr)
{
var t=[];
spiralloop(arr,function(x,z){
t.push([x,z]);
});
return t;
}
function sendNearbyChunks(view, world)
{
world = world || player.world;
player.lastPositionChunkUpdated=player.entity.position;
var playerChunkX=Math.floor(player.entity.position.x/16/32);
var playerChunkZ=Math.floor(player.entity.position.z/16/32);
return spiral([view*2,view*2])
.map(t => ({
chunkX:playerChunkX+t[0]-view,
chunkZ:playerChunkZ+t[1]-view
}))
.filter(({chunkX,chunkZ}) => {
var key=chunkX+","+chunkZ;
var loaded=player.loadedChunks[key];
if(!loaded) player.loadedChunks[key]=1;
return !loaded;
})
.reduce((acc,{chunkX,chunkZ})=>
acc
//.then(() => sleep(100))
.then(() => world.getColumn(chunkX,chunkZ))
.then((column) => player.sendChunk(chunkX,chunkZ,column))
,Promise.resolve());
}
function sleep(ms = 0) {
return new Promise(r => setTimeout(r, ms));
}
function changeWorld(world, opt) {
opt = opt || {};
player.world = world;
player.loadedChunks={};
if (typeof opt.gamemode != 'undefined') player.gameMode = opt.gamemode;
player._client.write("respawn",{
dimension: opt.dimension || 0,
difficulty: opt.difficulty || 0,
gamemode: opt.gamemode || player.gameMode,
levelType:'default'
});
player.emit('change_world');
player.setPosition(opt.position || player.spawnPoint, { yaw: opt.yaw || 0, pitch: opt.pitch || 0 }); // Automatically sends chunks around players
}
player.spawn = spawn;
player.spawnForOthers = spawnForOthers;
player.getNearbyPlayers = getNearbyPlayers;
player.sendNearbyChunks = sendNearbyChunks;
player.changeWorld = changeWorld;
player.sendChunk = sendChunk;
player.on('chat', function(message) {
if (message == 'world') {
player.changeWorld(serv.netherworld, {
position: new vec3(0, 60, 0),
dimension: -1
});
}
});
}

View file

@ -2,22 +2,22 @@
module.exports = inject;
function inject(serv, settings) {
serv.setTime = function(time) {
serv.time = time;
serv._writeAll('update_time', {
age: [0, 0], // TODO
time: [0, serv.time]
});
}
serv.setTime = function(time) {
serv.time = time;
serv._writeAll('update_time', {
age: [0, 0], // TODO
time: [0, serv.time]
});
}
serv.doDaylightCycle = true;
serv.doDaylightCycle = true;
serv.time = 0;
serv.time = 0;
serv.on('tick', function(count) {
if (!serv.doDaylightCycle) return;
if (count % 20 == 0) {
serv.on('tick', function(count) {
if (!serv.doDaylightCycle) return;
if (count % 20 == 0) {
serv.setTime((serv.time + 20) % 24000); // Vanilla only does it every second
}
})
}
})
}

View file

@ -2,24 +2,24 @@
module.exports = inject;
function inject(serv, settings) {
serv.setTickInterval = setTickInterval;
serv.stopTickInterval = stopTickInterval;
serv.tickCount = 0;
serv.setTickInterval = setTickInterval;
serv.stopTickInterval = stopTickInterval;
serv.tickCount = 0;
serv.setTickInterval(20);
serv.setTickInterval(20);
}
function setTickInterval(ticksPerSecond) {
var serv = this;
serv.stopTickInterval();
var serv = this;
serv.stopTickInterval();
serv.tickInterval = setInterval(function() {
serv.tickCount++;
serv.emit('tick', serv.tickCount);
}, 1000/ticksPerSecond);
serv.tickInterval = setInterval(function() {
serv.tickCount++;
serv.emit('tick', serv.tickCount);
}, 1000/ticksPerSecond);
}
function stopTickInterval() {
if (this.tickInterval) clearInterval(serv.tickInterval);
this.tickInterval = null;
if (this.tickInterval) clearInterval(serv.tickInterval);
this.tickInterval = null;
}

View file

@ -7,14 +7,32 @@ var generations={
'grass_field':require("../worldGenerations/grass_field"),
'diamond_square':require("../worldGenerations/diamond_square"),
'superflat':require("../worldGenerations/superflat"),
'all_the_blocks':require("../worldGenerations/all_the_blocks")
'all_the_blocks':require("../worldGenerations/all_the_blocks"),
'nether':require("../worldGenerations/nether")
};
module.exports = inject;
function inject(serv,{regionFolder,generation={"name":"diamond_square","options":{"worldHeight":80}}}={}) {
function inject(serv,{generation={"name":"diamond_square","options":{"worldHeight":80}}}={}) {
generation.options.seed=generation.options.seed || Math.random()*Math.pow(2, 32);
serv.emit("seed",generation.options.seed);
serv.world = new World(generations[generation.name](generation.options),regionFolder);
serv._worldSync=new WorldSync(serv.world);
}
serv.overworld = new World(generations[generation.name](generation.options));
serv.netherworld = new World(generations["nether"]({}));
//serv.endworld = new World(generations["end"]({}));
//serv._worldSync=new WorldSync(serv.worlds[0]);
function pregenWorld(world, size=10) {
for (var x = -size; x < size; x++) {
for (var z = -size; z < size; z++) {
world.getColumn(x, z);
}
}
}
serv.pregenWorld = pregenWorld;
serv.pregenWorld(serv.overworld);
serv.log('Pre-Generated Overworld');
serv.pregenWorld(serv.netherworld);
serv.log('Pre-Generated Nether');
}

View file

@ -0,0 +1,31 @@
var Chunk = require('prismarine-chunk')(require("../version"));
var Vec3 = require('vec3');
function generation({level=50}={}) {
function generateChunk(chunkX, chunkZ) {
var chunk=new Chunk();
for (var x = 0; x < 16; x++) {
for (var z = 0; z < 16; z++) {
var bedrockheighttop = 1 + Math.round(Math.random()*3)
var bedrockheightbottom = 1 + Math.round(Math.random()*3)
for (var y = 0; y < 128; y++) { // Nether only goes up to 128
let block;
let data;
if (y < bedrockheightbottom) block = 7;
else if (y < 50) block = 87;
else if (y > 127 - bedrockheighttop) block = 7;
var pos = new Vec3(x, y, z);
if (block) chunk.setBlockType(pos, block);
if (data) chunk.setBlockData(pos, data);
// Don't need to set light data in nether
}
}
}
return chunk;
}
return generateChunk;
}
module.exports = generation;