minecraft.js
Version:
Minecraft data serialization/deserialization and networking
138 lines (113 loc) • 4.77 kB
JavaScript
var Region = require(__dirname + '/region.js'),
Chunk = require(__dirname + '/chunk.js'),
Player = require(__dirname + '/player.js'),
Vector3 = require(__dirname + '/vector3.js'),
constants = require(__dirname + '/constants.js'),
TagFormat = require(__dirname + '/tagFormat.js');
/** @constructor */
var World = module.exports = function(args) {
args = args || {};
this.xSize = args.xSize || 1;
this.zSize = args.zSize || 1;
this.xStart = -Math.floor(this.xSize / 2);
this.zStart = -Math.floor(this.zSize / 2);
this.regions = {};
for(var i = this.xStart; i < this.xStart + this.xSize; i++) {
this.regions[i] = {};
for(var j = this.zStart; j < this.zStart + this.zSize; j++) {
this.regions[i][j] = new Region();
}
}
this.spawn = args.spawn || new Vector3(0,64,0);
this.sizeOnDisk = args.sizeOnDisk || 0;
this.randomSeed = args.randomSeed || (Math.floor(Math.random() * 99999999999999));
this.version = args.version || 19132;
this.levelName = args.levelName || "Untitled World";
this.raining = args.raining || false;
this.thundering = args.thundering || false;
this.rainTime = args.rainTime || 1000000;
this.thunderTime = args.thunderTime || 1000000;
this.gameType = args.gameType || 0;
this.mapFeatures = args.mapFeatures || true;
this.hardcore = args.hardcore || false;
this.player = args.player || new Player();
};
World.prototype.getChunk = function(x, z) {
var regionX = Math.floor(x / constants.REGION_SIZE);
var regionZ = Math.floor(z / constants.REGION_SIZE);
var region = this.regions[regionX][regionZ];
if(region != undefined)
return region.getChunk(x % constants.REGION_SIZE, z % constants.REGION_SIZE);
};
World.prototype.setChunk = function(x, z, chunk) {
var regionX = Math.floor(x / constants.REGION_SIZE);
var regionZ = Math.floor(z / constants.REGION_SIZE);
if(this.regions[regionX] == undefined) {
this.regions[regionX] = {};
}
if(this.regions[regionX][regionZ] == undefined) {
this.regions[regionX][regionZ] = new Region();
}
this.regions[regionX][regionZ].setChunk(x & constants.REGION_SIZE - 1, z & constants.REGION_SIZE - 1, chunk);
return this;
};
World.prototype.getBlock = function(x, y, z) {
var chunkX = Math.floor(x / constants.CHUNK_SIZE);
var chunkZ = Math.floor(z / constants.CHUNK_SIZE);
var chunk = this.getChunk(chunkX, chunkZ);
if(!chunk) {
throw new Error('Chunk (' + chunkX + ', ' + chunkZ + ') does not exist');
return;
}
return chunk.getBlock(x, y, z);
};
World.prototype.setBlock = function(x, y, z, value) {
var chunkX = Math.floor(x / constants.CHUNK_SIZE);
var chunkZ = Math.floor(z / constants.CHUNK_SIZE);
if(!this.getChunk(chunkX, chunkZ)) {
this.setChunk(chunkX, chunkZ, new Chunk());
}
this.getChunk(chunkX, chunkZ).setBlock(x, y, z, value);
return this;
};
World.prototype.download = function() {
var fr = new FileReader();
var worldZip = new JSZip();
worldZip.folder('region');
//add world metadata
fr.onloadend = function() {
worldZip.add('level.dat', btoa(fr.result), {base64: true});
};
fr.readAsBinaryString(this.tagFormat.encode(this).toBlob());
//for each region, build binary region file and add to world zip
for(var i = this.xStart; i < this.xStart + this.xSize; i++) {
for(var j = this.zStart; j < this.zStart + this.zSize; j++) {
var regionFr = new FileReader();
regionFr.onloadend = function() {
worldZip.add('r.' + (i >> 5) + '.' + (j >> 5) + '.mcr',
btoa(regionFr.result), {base64: true});
};
regionFr.readAsBinaryString(this.regions[x][z].toBlob());
}
}
};
World.prototype.tagFormat = new TagFormat(
'compound', 'Data', '', [
new TagFormat('long', 'Time', 'time'),
new TagFormat('long', 'LastPlayed', 'lastPlayed'),
Player.prototype.tagFormat,
new TagFormat('int', 'SpawnX', 'spawn.x'),
new TagFormat('int', 'SpawnY', 'spawn.y'),
new TagFormat('int', 'SpawnZ', 'spawn.z'),
new TagFormat('long', 'SizeOnDisk', 'sizeOnDisk'),
new TagFormat('long', 'RandomSeed', 'randomSeed'),
new TagFormat('int', 'version', 'version'),
new TagFormat('string', 'LevelName', 'levelName'),
new TagFormat('byte', 'raining', 'raining'),
new TagFormat('byte', 'thundering', 'thundering'),
new TagFormat('int', 'rainTime', 'rainTime'),
new TagFormat('int', 'thunderTime', 'thunderTime'),
new TagFormat('int', 'GameType', 'gameType'),
new TagFormat('byte', 'MapFeatures', 'mapFeatures'),
new TagFormat('byte', 'hardcore', 'hardcore')
]);