This commit is contained in:
mhsjlw 2015-08-25 10:25:55 -04:00
parent def7426fc5
commit bc657b0a31
4 changed files with 350 additions and 269 deletions

105
app.js
View file

@ -4,6 +4,7 @@ var settings = require('./config/settings');
var World = require('prismarine-chunk'); var World = require('prismarine-chunk');
var fs = require('fs'); var fs = require('fs');
var timeStarted = Math.floor(new Date() / 1000).toString(); var timeStarted = Math.floor(new Date() / 1000).toString();
var playersConnected = [];
var options = { var options = {
motd: settings.motd, motd: settings.motd,
@ -31,13 +32,62 @@ var server = mc.createServer(options);
server.on('login', function(client) { server.on('login', function(client) {
broadcast({ text: client.username + ' joined the game.', color: "yellow" }); playersConnected.push(client);
playersConnected.forEach(function(entry) {
// if(entry != client) {
// client.write('named_entity_spawn', {
// entityId: entry.id,
// playerUUID: entry.uuid,
// x: 0,
// y: 0,
// z: 0,
// yaw: 0,
// pitch 0,
// currentItem:
// metadata:
// });
// }
});
Object.keys(server.clients).forEach(function(clientKey) {
var otherClient=server.clients[clientKey]
otherClient.write('player_info', {
action: 0,
data: [{
UUID: otherClient.uuid.split("-").map(function(item) { return parseInt(item, 16); }),
name: otherClient.username,
properties: [],
gamemode: 0,
ping: 1,
hasDisplayName: true,
displayName: client.username
}]
});
});
playersConnected.forEach(function(entry) {
entry.write('player_info', {
action: 0,
data: [{
UUID: entry.uuid.split("-").map(function(item) { return parseInt(item, 16); }),
name: entry.username,
properties: [],
gamemode: 0,
ping: 1,
hasDisplayName: true,
displayName: client.username
}]
});
});
broadcast(client.username + ' joined the game.', "yellow");
var addr = client.socket.remoteAddress + ':' + client.socket.remotePort; var addr = client.socket.remoteAddress + ':' + client.socket.remotePort;
console.log("[INFO]: " + client.username + ' connected', '(' + addr + ')'); console.log("[INFO]: " + client.username + ' connected', '(' + addr + ')');
log("[INFO]: " + client.username + ' connected', '(' + addr + ')'); log("[INFO]: " + client.username + ' connected', '(' + addr + ')');
client.on('end', function() { client.on('end', function() {
broadcast({ text: client.username+' left the game.', color: "yellow" }); broadcast(client.username + ' joined the game.', "yellow");
console.log("[INFO]: " + client.username+' disconnected', '('+addr+')'); console.log("[INFO]: " + client.username+' disconnected', '('+addr+')');
log("[INFO]: " + client.username+' disconnected', '('+addr+')'); log("[INFO]: " + client.username+' disconnected', '('+addr+')');
}); });
@ -58,6 +108,19 @@ server.on('login', function(client) {
maxPlayers: server.maxPlayers maxPlayers: server.maxPlayers
}); });
// client.write('player_info', {
// action: 0,
// data: [{
// UUID: client.uuid.split("-").map(function(item) { return parseInt(item, 16); }),
// name: client.username,
// properties: [],
// gamemode: 0,
// ping: 1,
// hasDisplayName: false,
// //displayName: client.username
// }]
// });
var packetData = { var packetData = {
x: 0, x: 0,
z: 0, z: 0,
@ -65,6 +128,7 @@ server.on('login', function(client) {
bitMap: 0xffff, bitMap: 0xffff,
chunkData: world.dump() chunkData: world.dump()
}; };
client.write('map_chunk', packetData); client.write('map_chunk', packetData);
//client.write('map_chunk', packetData); //client.write('map_chunk', packetData);
@ -77,6 +141,7 @@ server.on('login', function(client) {
pitch: 0, pitch: 0,
flags: 0x00 flags: 0x00
}); });
console.log("[INFO]: position written, player spawning..."); console.log("[INFO]: position written, player spawning...");
log("[INFO]: position written, player spawning..."); log("[INFO]: position written, player spawning...");
@ -87,12 +152,12 @@ server.on('login', function(client) {
client.write('game_state_change', { client.write('game_state_change', {
reason: 3, reason: 3,
gameMode: 1 gameMode: 0
}); });
client.on([states.PLAY, 'chat'], function(data) { client.on('chat', function(data) {
var message = '<'+client.username+'>' + ' ' + data.message; var message = '<'+client.username+'>' + ' ' + data.message;
broadcast(message, client.username); playerChat(message, client.username);
console.log("[INFO] " + message); console.log("[INFO] " + message);
log("[INFO] " + message); log("[INFO] " + message);
}); });
@ -101,7 +166,7 @@ server.on('login', function(client) {
// we don't really need to see the server pass an object every 10nth of a second so I will just disable this // we don't really need to see the server pass an object every 10nth of a second so I will just disable this
//console.log("[INFO] " + packet); //console.log("[INFO] " + packet);
//log("[INFO] " + packet); //log("[INFO] " + packet);
}) });
}); });
server.on('error', function(error) { server.on('error', function(error) {
@ -155,23 +220,33 @@ function log(message) {
} }
} }
function broadcast(message, exclude, username) { function playerChat(message, exclude, username) {
var client, translate; var client;
translate = username ? 'chat.type.announcement' : 'chat.type.text'; //translate = username ? 'chat.type.text' : 'chat.type.text';
username = username || 'Server'; username = username || '';
for(var clientId in server.clients) { for(var clientId in server.clients) {
if(!server.clients.hasOwnProperty(clientId)) continue; if(!server.clients.hasOwnProperty(clientId)) continue;
client = server.clients[clientId]; client = server.clients[clientId];
if(client !== exclude) { if(client !== exclude) {
var msg = { var msg = {
translate: translate, "text": username + message
"with": [
username,
message
]
}; };
client.write('chat', { message: JSON.stringify(msg), position: 0 }); client.write('chat', { message: JSON.stringify(msg), position: 0 });
} }
} }
} }
function broadcast(message, color) {
var client;
for(var clientId in server.clients) {
if(!server.clients.hasOwnProperty(clientId)) continue;
client = server.clients[clientId];
var msg = {
"text": message,
"color": color
};
client.write('chat', { message: JSON.stringify(msg), position: 0 });
}
}

View file

@ -3,5 +3,5 @@
"port": 25565, "port": 25565,
"maxPlayers": 10, "maxPlayers": 10,
"onlineMode": true, "onlineMode": true,
"logging": true "logging": false
} }

4
docs/README.md Normal file
View file

@ -0,0 +1,4 @@
Documentation
=============
See the [Wiki](https://github.com/mhsjlw/node-minecraft-server/wiki)

View file

@ -1,300 +1,302 @@
var util = require('util') // THIS CODE WILL BE REMOVED IN A FUTURE RELEASE!
var zlib = require('zlib')
var Buffers = require('buffers');
module.exports = World; // var util = require('util')
// var zlib = require('zlib')
// var Buffers = require('buffers');
function BiomeData() { // module.exports = World;
this.data = null;
}
BiomeData.prototype.fill = function() { // function BiomeData() {
if (!this.data) { // this.data = null;
this.data = new Buffer(256); // }
for (var i = 0;i < 256;i++) {
this.data[i] = 0;
}
}
}
BiomeData.prototype.unpack = function(buf) { // BiomeData.prototype.fill = function() {
this.data = buf.slice(0, 256); // if (!this.data) {
} // this.data = new Buffer(256);
// for (var i = 0;i < 256;i++) {
// this.data[i] = 0;
// }
// }
// }
BiomeData.prototype.pack = function() { // BiomeData.prototype.unpack = function(buf) {
this.fill(); // this.data = buf.slice(0, 256);
return this.data; // }
}
BiomeData.prototype.get = function(x, y, z) { // BiomeData.prototype.pack = function() {
this.fill(); // this.fill();
return this.data[x + ((y * 16) + z) * 16]; // return this.data;
} // }
BiomeData.prototype.put = function(x, y, z, data) { // BiomeData.prototype.get = function(x, y, z) {
this.fill(); // this.fill();
this.data[x + ((y * 16) + z) * 16] = data; // return this.data[x + ((y * 16) + z) * 16];
} // }
function ChunkData() { // BiomeData.prototype.put = function(x, y, z, data) {
this.length = 16*16*16; // this.fill();
this.data = null; // this.data[x + ((y * 16) + z) * 16] = data;
} // }
ChunkData.prototype.fill = function() { // function ChunkData() {
if (!this.data) { // this.length = 16*16*16;
this.data = new Buffer(this.length); // this.data = null;
for (var i = 0;i < this.length;i++) { // }
this.data[i] = 0;
}
}
}
ChunkData.prototype.unpack = function(buff) { // ChunkData.prototype.fill = function() {
this.data = buff.slice(0, this.length); // if (!this.data) {
} // this.data = new Buffer(this.length);
// for (var i = 0;i < this.length;i++) {
// this.data[i] = 0;
// }
// }
// }
ChunkData.prototype.pack = function() { // ChunkData.prototype.unpack = function(buff) {
this.fill(); // this.data = buff.slice(0, this.length);
return this.data; // }
}
ChunkData.prototype.get = function(x, y, z) { // ChunkData.prototype.pack = function() {
this.fill(); // this.fill();
return this.data[x + ((y * 16) + z) * 16]; // return this.data;
} // }
ChunkData.prototype.put = function(x, y, z, data) { // ChunkData.prototype.get = function(x, y, z) {
this.fill(); // this.fill();
this.data[x + ((y * 16) + z) * 16] = data; // return this.data[x + ((y * 16) + z) * 16];
} // }
function ChunkDataNibble() { // ChunkData.prototype.put = function(x, y, z, data) {
this.length = 16*16*8; // this.fill();
this.data = null; // this.data[x + ((y * 16) + z) * 16] = data;
} // }
util.inherits(ChunkDataNibble, ChunkData); // function ChunkDataNibble() {
// this.length = 16*16*8;
// this.data = null;
// }
ChunkDataNibble.prototype.get = function(x, y, z) { // util.inherits(ChunkDataNibble, ChunkData);
this.fill();
var r = x % 2;
x = Math.floor(x/2);
var i = x + ((y * 16) + z) * 16;
if (r === 0) { // ChunkDataNibble.prototype.get = function(x, y, z) {
return this.data[i] >>> 4; // this.fill();
} else { // var r = x % 2;
return this.data[i] & 0x0F; // x = Math.floor(x/2);
} // var i = x + ((y * 16) + z) * 16;
}
ChunkDataNibble.prototype.put = function(x, y, z, data) { // if (r === 0) {
this.fill(); // return this.data[i] >>> 4;
var r = x % 2; // } else {
x = Math.floor(x/2); // return this.data[i] & 0x0F;
var i = x + ((y * 16) + z) * 16; // }
// }
if (r === 0) { // ChunkDataNibble.prototype.put = function(x, y, z, data) {
this.data[i] = (this.data[i] & 0x0F) | ((data & 0x0F) << 4); // this.fill();
} else { // var r = x % 2;
this.data[i] = (this.data[i] & 0xF0) | (this.data & 0x0F); // x = Math.floor(x/2);
} // var i = x + ((y * 16) + z) * 16;
}
function Chunk() { // if (r === 0) {
this.block_data = new ChunkData(); // this.data[i] = (this.data[i] & 0x0F) | ((data & 0x0F) << 4);
this.block_meta = new ChunkDataNibble(); // } else {
this.block_add = new ChunkDataNibble(); // this.data[i] = (this.data[i] & 0xF0) | (this.data & 0x0F);
this.light_block = new ChunkDataNibble(); // }
this.light_sky = new ChunkDataNibble(); // }
}
function ChunkColumn() { // function Chunk() {
this.chunks = new Array(16); // this.block_data = new ChunkData();
for (var i = 0;i < 16;i++) this.chunks[i] = null; // this.block_meta = new ChunkDataNibble();
// this.block_add = new ChunkDataNibble();
// this.light_block = new ChunkDataNibble();
// this.light_sky = new ChunkDataNibble();
// }
this.biome = new BiomeData(); // function ChunkColumn() {
} // this.chunks = new Array(16);
// for (var i = 0;i < 16;i++) this.chunks[i] = null;
ChunkColumn.prototype.unpack = function(buff, mask1, mask2, skylight) { // this.biome = new BiomeData();
if (typeof skylight == "undefined") skylight = true; // }
this.unpack_section(buff, "block_data", mask1); // ChunkColumn.prototype.unpack = function(buff, mask1, mask2, skylight) {
this.unpack_section(buff, "block_meta", mask1); // if (typeof skylight == "undefined") skylight = true;
this.unpack_section(buff, "light_block", mask1);
if (skylight)
this.unpack_section(buff, "light_sky", mask1);
this.unpack_section(buff, "block_add", mask2);
this.biome.unpack(buff);
}
ChunkColumn.prototype.unpack_section = function(buff, section, mask) { // this.unpack_section(buff, "block_data", mask1);
for (var i = 0; i < 16; i++) { // this.unpack_section(buff, "block_meta", mask1);
if (mask & (1 << i)) { // this.unpack_section(buff, "light_block", mask1);
if (this.chunks[i] === null) { // if (skylight)
this.chunks[i] = new Chunk(); // this.unpack_section(buff, "light_sky", mask1);
} // this.unpack_section(buff, "block_add", mask2);
this.chunks[i][section].unpack(buff); // this.biome.unpack(buff);
} // }
}
}
ChunkColumn.prototype.pack = function() { // ChunkColumn.prototype.unpack_section = function(buff, section, mask) {
var bufs = []; // for (var i = 0; i < 16; i++) {
var mask1 = 0; // if (mask & (1 << i)) {
for (var i = 0; i < 16; i++) { // if (this.chunks[i] === null) {
if (this.chunks[i] !== null) { // this.chunks[i] = new Chunk();
mask1 |= 1 << i; // }
} // this.chunks[i][section].unpack(buff);
} // }
var block_data = this.pack_section("block_data"); // }
var block_meta = this.pack_section("block_meta"); // }
var light_block = this.pack_section("light_block");
var light_sky = this.pack_section("light_sky");
var mask2 = 0;
bufs.push(block_data, block_meta, light_block, light_sky);
return {
data: Buffer.concat(bufs),
mask1: mask1,
mask2: mask2,
skylight: true
};
}
ChunkColumn.prototype.pack_section = function(section) { // ChunkColumn.prototype.pack = function() {
var bufs = []; // var bufs = [];
for (var i = 0; i < 16; i++) { // var mask1 = 0;
if (this.chunks[i] !== null) // for (var i = 0; i < 16; i++) {
bufs.push(this.chunks[i][section].pack()); // if (this.chunks[i] !== null) {
} // mask1 |= 1 << i;
return Buffer.concat(bufs); // }
} // }
// var block_data = this.pack_section("block_data");
// var block_meta = this.pack_section("block_meta");
// var light_block = this.pack_section("light_block");
// var light_sky = this.pack_section("light_sky");
// var mask2 = 0;
// bufs.push(block_data, block_meta, light_block, light_sky);
// return {
// data: Buffer.concat(bufs),
// mask1: mask1,
// mask2: mask2,
// skylight: true
// };
// }
function World() { // ChunkColumn.prototype.pack_section = function(section) {
this.columns = {}; // var bufs = [];
} // for (var i = 0; i < 16; i++) {
// if (this.chunks[i] !== null)
// bufs.push(this.chunks[i][section].pack());
// }
// return Buffer.concat(bufs);
// }
World.prototype.unpack = function(packetData) { // function World() {
var data = zlib.inflate(packetData.compressedChunkData); // this.columns = {};
packetData.meta.forEach(function (meta) { // }
var key = [meta.x, meta.z];
var column;
if (key in this.columns) {
column = this.columns[key];
} else {
column = new ChunkColumn();
this.columns[key] = column;
}
column.unpack(data, meta.bitMap, meta.addMap, packetData.skyLightSent); // World.prototype.unpack = function(packetData) {
}); // var data = zlib.inflate(packetData.compressedChunkData);
} // packetData.meta.forEach(function (meta) {
// var key = [meta.x, meta.z];
// var column;
// if (key in this.columns) {
// column = this.columns[key];
// } else {
// column = new ChunkColumn();
// this.columns[key] = column;
// }
World.prototype.packMapChunkBulk = function() { // column.unpack(data, meta.bitMap, meta.addMap, packetData.skyLightSent);
var bufs = []; // });
var metadatas = []; // }
var cb = arguments[arguments.length - 1];
// First pass, get all the metadatas and buffers. // World.prototype.packMapChunkBulk = function() {
for (var i = 0;i < arguments.length - 1; i++) { // var bufs = [];
var arg = arguments[i]; // var metadatas = [];
var data = this.columns[arg]; // var cb = arguments[arguments.length - 1];
if (this.columns === null) {
continue;
}
var packetContent = data.pack(); // // First pass, get all the metadatas and buffers.
bufs.push(packetContent.data); // for (var i = 0;i < arguments.length - 1; i++) {
var metadata = { // var arg = arguments[i];
x: arg[0], // var data = this.columns[arg];
z: arg[1], // if (this.columns === null) {
bitMap: packetContent.mask1, // continue;
addBitMap: packetContent.mask2 // }
}
metadatas.push(metadata);
}
cb(null, { // var packetContent = data.pack();
skyLightSent: true, // bufs.push(packetContent.data);
meta: metadatas, // var metadata = {
data: Buffer.concat(bufs) // x: arg[0],
}); // z: arg[1],
} // bitMap: packetContent.mask1,
// addBitMap: packetContent.mask2
// }
// metadatas.push(metadata);
// }
World.prototype.get = function(x, y, z, key) { // cb(null, {
var rx = x % 16; // skyLightSent: true,
x = Math.floor(x / 16); // meta: metadatas,
var ry = y % 16; // data: Buffer.concat(bufs)
y = Math.floor(y / 16); // });
var rz = z % 16; // }
z = Math.floor(z / 16);
if (!([x,z] in this.columns)) { // World.prototype.get = function(x, y, z, key) {
return 0; // var rx = x % 16;
} // x = Math.floor(x / 16);
// var ry = y % 16;
// y = Math.floor(y / 16);
// var rz = z % 16;
// z = Math.floor(z / 16);
var column = this.columns[[x,z]]; // if (!([x,z] in this.columns)) {
var chunk = column.chunks[y]; // return 0;
// }
if (chunk == null) { // var column = this.columns[[x,z]];
return 0; // var chunk = column.chunks[y];
}
return chunk[key].get(rx, ry, rz); // if (chunk == null) {
} // return 0;
// }
World.prototype.put = function(x, y, z, key, data) { // return chunk[key].get(rx, ry, rz);
var rx = x % 16; // }
x = Math.floor(x / 16);
var ry = y % 16;
y = Math.floor(y / 16);
var rz = z % 16;
z = Math.floor(z / 16);
var column; // World.prototype.put = function(x, y, z, key, data) {
if ([x,z] in this.columns) { // var rx = x % 16;
column = this.columns[[x,z]]; // x = Math.floor(x / 16);
} else { // var ry = y % 16;
column = new ChunkColumn(); // y = Math.floor(y / 16);
this.columns[[x,z]] = column; // var rz = z % 16;
} // z = Math.floor(z / 16);
var chunk = column.chunks[y]; // var column;
if (chunk == null) { // if ([x,z] in this.columns) {
chunk = new Chunk(); // column = this.columns[[x,z]];
column.chunks[y] = chunk; // } else {
} // column = new ChunkColumn();
// this.columns[[x,z]] = column;
// }
chunk[key].put(rx, ry, rz, data); // var chunk = column.chunks[y];
} // if (chunk == null) {
// chunk = new Chunk();
// column.chunks[y] = chunk;
// }
World.prototype.get_biome = function(x, z) { // chunk[key].put(rx, ry, rz, data);
var rx = x % 16; // }
x = Math.floor(x / 16);
var rz = z % 16;
z = Math.floor(z / 16);
if (!([x,z] in this.columns)) { // World.prototype.get_biome = function(x, z) {
return 0; // var rx = x % 16;
} // x = Math.floor(x / 16);
// var rz = z % 16;
// z = Math.floor(z / 16);
return this.columns[[x,z]].biome.get(rx, rz); // if (!([x,z] in this.columns)) {
} // return 0;
// }
World.prototype.put_biome = function(x, z, data) { // return this.columns[[x,z]].biome.get(rx, rz);
var rx = x % 16; // }
x = Math.floor(x / 16);
var rz = z % 16;
z = Math.floor(z / 16);
var column; // World.prototype.put_biome = function(x, z, data) {
if ([x,z] in this.columns) { // var rx = x % 16;
column = this.columns[[x,z]]; // x = Math.floor(x / 16);
} else { // var rz = z % 16;
column = new ChunkColumn(); // z = Math.floor(z / 16);
this.columns[[x,z]] = column;
}
return column.biome.put(rx, rz, data); // var column;
} // if ([x,z] in this.columns) {
// column = this.columns[[x,z]];
// } else {
// column = new ChunkColumn();
// this.columns[[x,z]] = column;
// }
// return column.biome.put(rx, rz, data);
// }