lots a shit

This commit is contained in:
Holly Stubbs 2021-08-20 22:42:00 +01:00
parent 4f9d056886
commit 0b7ea5aa9a
16 changed files with 278 additions and 131 deletions

3
server/Converter.js Normal file
View file

@ -0,0 +1,3 @@
module.exports.toAbsoluteInt = function(float = 0.0) {
return Math.round(float * 32.0);
}

View file

@ -1,6 +1,6 @@
class Entity {
constructor(x = 0, y = 0, z = 0, yaw = 0, pitch = 0) {
this.EID = global.fromIDPool();
constructor(EID = 0, x = 0, y = 0, z = 0, yaw = 0, pitch = 0) {
this.EID = EID;
this.x = x;
this.y = y;

View file

@ -2,7 +2,7 @@ const Entity = require("./Entity.js");
class EntityItem extends Entity {
constructor(itemID = 0x00, x = 0, y = 0, z = 0) {
super(x, y, z);
super(global.fromIDPool(), x, y, z);
this.motionX = (Math.random() * 0.2 - 0.1);
this.motionY = 0.2;

View file

@ -1,8 +1,8 @@
const Entity = require("./Entity.js");
class EntityPlayer extends Entity {
constructor(x = 0, y = 0, z = 0) {
super(x, y, z);
class EntityLiving extends Entity {
constructor(EID = 0, x = 0, y = 0, z = 0) {
super(EID, x, y, z);
}
@ -12,4 +12,4 @@ class EntityPlayer extends Entity {
}
}
module.exports = EntityPlayer;
module.exports = EntityLiving;

View file

@ -1,12 +1,10 @@
const EntityLiving = require("./EntityLiving.js");
class EntityPlayer extends EntityLiving {
constructor(x = 0, y = 0, z = 0) {
super(x, y, z);
constructor(EID = 0, x = 0, y = 0, z = 0) {
super(EID, x, y, z);
this.motionX = (Math.random() * 0.2 - 0.1);
this.motionY = 0.2;
this.motionZ = (Math.random() * 0.2 - 0.1);
}
}

View file

@ -1,4 +1,5 @@
const namedPackets = {
"Disconnect": -1,
"KeepAlive": 0x00,
"LoginRequest": 0x01,
"Handshake": 0x02,

View file

@ -6,8 +6,11 @@ const Packet0KeepAlive = require("./Packets/Packet0KeepAlive.js"),
Packet6SpawnPosition = require("./Packets/Packet6SpawnPosition.js"),
Packet10Player = require("./Packets/Packet10Player.js"),
Packet13PlayerPositionAndLook = require("./Packets/Packet13PlayerPositionAndLook.js"),
Packet18Animation = require("./Packets/Packet18Animation.js"),
Packet20NamedEntitySpawn = require("./Packets/Packet20NamedEntitySpawn.js"),
Packet50PreChunk = require("./Packets/Packet50PreChunk.js"),
Packet53BlockChange = require("./Packets/Packet53BlockChange.js");
Packet53BlockChange = require("./Packets/Packet53BlockChange.js"),
Packet103SetSlot = require("./Packets/Packet103SetSlot.js");
const mappingTable = {
0x00: Packet0KeepAlive,
@ -18,8 +21,11 @@ const mappingTable = {
0x06: Packet6SpawnPosition,
0x0A: Packet10Player,
0x0D: Packet13PlayerPositionAndLook,
0x12: Packet18Animation,
0x14: Packet20NamedEntitySpawn,
0x32: Packet50PreChunk,
0x35: Packet53BlockChange,
0x67: Packet103SetSlot
};
module.exports = mappingTable;

View file

@ -0,0 +1,27 @@
const Packet = require("./Packet.js");
class Packet103SetSlot extends Packet {
constructor(window_id = 0, slot = 0, item_id = -1, item_count = 0, item_uses = 0) {
super(0x67);
this.window_id = window_id;
this.slot = slot;
this.item_id = item_id;
this.item_count = item_count;
this.item_uses = item_uses;
}
writePacket() {
super.writePacket();
this.writer.writeByte(this.window_id);
this.writer.writeShort(this.slot);
this.writer.writeShort(this.item_id);
this.writer.writeByte(this.item_count);
if (this.item_id != -1) this.writer.writeShort(this.item_uses);
return this.toBuffer();
}
}
module.exports = Packet103SetSlot;

View file

@ -0,0 +1,21 @@
const Packet = require("./Packet.js");
class Packet18Animation extends Packet {
constructor(EID = 0, animation = 0) {
super(0x12);
this.EID = EID;
this.animation = animation;
}
writePacket() {
super.writePacket();
this.writer.writeInt(this.EID);
this.writer.writeByte(this.animation);
return this.toBuffer();
}
}
module.exports = Packet18Animation;

View file

@ -0,0 +1,34 @@
const Packet = require("./Packet.js");
const Converter = require("../Converter.js");
class Packet20NamedEntitySpawn extends Packet {
constructor(EID = 0, entityName = "", x = 0.0, y = 0.0, z = 0.0, yaw = 0.0, pitch = 0.0, currentItem = 0) {
super(0x14);
this.EID = EID;
this.entityName = entityName;
this.absX = Converter.toAbsoluteInt(x);
this.absY = Converter.toAbsoluteInt(y);
this.absZ = Converter.toAbsoluteInt(z);
this.packedYaw = 0; // TODO: Add rotation.
this.packedPitch = 0;
this.currentItem = currentItem;
}
writePacket() {
super.writePacket();
this.writer.writeInt(this.EID);
this.writer.writeString(this.entityName);
this.writer.writeInt(this.absX);
this.writer.writeInt(this.absY);
this.writer.writeInt(this.absZ);
this.writer.writeByte(this.packedYaw);
this.writer.writeByte(this.packedPitch);
this.writer.writeShort(this.currentItem);
return this.toBuffer();
}
}
module.exports = Packet20NamedEntitySpawn;

View file

@ -7,7 +7,7 @@ class Packet2Handshake extends Packet {
this.username = username;
}
writePacket(EID = 0) {
writePacket() {
super.writePacket();
this.writer.writeString("-"); // "-" == Offline mode

View file

@ -1,95 +0,0 @@
const { Worker, MessageChannel, MessagePort, isMainThread, parentPort } = require('worker_threads');
const bufferStuff = require("../bufferStuff.js");
let chunkY = 0;
let busyInterval = null;
parentPort.on("message", (data) => {
// This stops the thread from stopping :)
if (busyInterval == null) busyInterval = setInterval(() => {}, 86400000);
switch (data[0]) {
case "chunk":
chunkY = 0;
parentPort.postMessage([data[0], doSquareChunk(data[1]), data[2]]);
chunkY += 16;
parentPort.postMessage([data[0], doSquareChunk(data[1]), data[2]]);
chunkY += 16;
parentPort.postMessage([data[0], doSquareChunk(data[1]), data[2]]);
chunkY += 16;
parentPort.postMessage([data[0], doSquareChunk(data[1]), data[2]]);
chunkY += 16;
parentPort.postMessage([data[0], doSquareChunk(data[1]), data[2]]);
chunkY += 16;
parentPort.postMessage([data[0], doSquareChunk(data[1]), data[2]]);
chunkY += 16;
parentPort.postMessage([data[0], doSquareChunk(data[1]), data[2]]);
chunkY += 16;
parentPort.postMessage([data[0], doSquareChunk(data[1]), data[2]]);
parentPort.postMessage(["remove", data[3]]);
break;
case "generate":
parentPort.postMessage([data[0], generateChunk(), data[1], data[2], data[3]]);
break;
}
});
function generateChunk() {
let chunk = {};
for (let y = 0; y < 128; y++) {
chunk[y] = {};
for (let x = 0; x < 16; x++) {
chunk[y][x] = {};
for (let z = 0; z < 16; z++) {
if (y == 64) {
chunk[y][x][z] = 2;
}
else if (y == 63 || y == 62) chunk[y][x][z] = 3;
else if (y == 0) chunk[y][x][z] = 7;
else if (y < 62) chunk[y][x][z] = 1;
else chunk[y][x][z] = 0;
}
}
}
return chunk;
}
function doSquareChunk(chunk) {
let blocksToSend = [];
for (let y = 0; y < 16; y++) {
for (let x = 0; x < 16; x++) {
for (let z = 0; z < 16; z++) {
if (chunk[2][chunkY + y][x][z] == 0) continue; // don't send air lol
blocksToSend.push([chunk[2][chunkY + y][x][z], x & 0xf, z & 0xf, chunkY + y]);
}
}
}
// I couldn't figure out how to construct a chunk lmao
// Using multi block chunks for now
// TODO: yknow, figure out how to actually chunk.
const writer = new bufferStuff.Writer();
writer.writeByte(0x34);
writer.writeInt(chunk[0]);
writer.writeInt(chunk[1]);
writer.writeShort(blocksToSend.length);
// Block coords
for (let blocks of blocksToSend) {
writer.writeShort((blocks[1] << 12 | blocks[2] << 8 | blocks[3]) - 32768);
}
// Block types
for (let blocks of blocksToSend) {
writer.writeByte(blocks[0]);
}
// Block metadata
for (let blocks of blocksToSend) {
writer.writeByte(0);
}
return writer.buffer;
}

View file

@ -0,0 +1,86 @@
const { parentPort } = require('worker_threads');
const { deflateSync } = require("zlib");
const bufferStuff = require("../bufferStuff.js");
let busyInterval = null;
parentPort.on("message", (data) => {
// This stops the thread from stopping :)
if (busyInterval == null) busyInterval = setInterval(() => {}, 86400000); // Runs once a day
switch (data[0]) {
case "chunk":
parentPort.postMessage([data[0], doChunk(data[1]), data[2]]);
break;
case "generate":
parentPort.postMessage([data[0], generateChunk(), data[1], data[2], data[3]]);
break;
}
});
function generateChunk() {
let chunk = {};
for (let y = 0; y < 128; y++) {
chunk[y] = {};
for (let x = 0; x < 16; x++) {
chunk[y][x] = {};
for (let z = 0; z < 16; z++) {
if (y == 64) {
chunk[y][x][z] = 2;
}
else if (y == 63 || y == 62) chunk[y][x][z] = 3;
else if (y == 0) chunk[y][x][z] = 7;
else if (y < 62) chunk[y][x][z] = 1;
else chunk[y][x][z] = 0;
}
}
}
return chunk;
}
function doChunk(chunk) {
const writer = new bufferStuff.Writer();
writer.writeByte(0x33); // Chunk
writer.writeInt(chunk[0] << 4); // Chunk X
writer.writeShort(0 << 7); // Chunk Y
writer.writeInt(chunk[1] << 4); // Chunk Z
writer.writeByte(15); // Size X
writer.writeByte(127); // Size Y
writer.writeByte(15); // Size Z
const blocks = new bufferStuff.Writer(32768);
const metadata = new bufferStuff.Writer(32768);
const lighting = new bufferStuff.Writer(32768);
let blockMeta = false;
for (let x = 0; x < 16; x++) {
for (let z = 0; z < 16; z++) {
for (let y = 0; y < 128; y++) {
blocks.writeByte(chunk[2][y][x][z]); // The block
if (blockMeta) {
metadata.writeByte(0x00); // TODO: Metadata
// Light level 15 for 2 blocks (1111 1111)
lighting.writeUByte(0xFF); // TODO: Lighting (Client seems to do it's own so it's not top priority)
}
// Hack for nibble stuff
blockMeta = !blockMeta;
}
}
}
// These are hacks for the nibbles
blocks.writeBuffer(metadata.buffer);
blocks.writeBuffer(lighting.buffer); // Block lighting
//blocks.writeBuffer(lighting.buffer); // Sky lighting (Looks like this isn't needed???)
// We're on another thread we don't care if we halt
const deflated = deflateSync(blocks.buffer);
writer.writeInt(deflated.length); // Compressed Size
writer.writeBuffer(deflated); // Compressed chunk data
return writer.buffer;
}

View file

@ -6,8 +6,10 @@
*/
module.exports.Writer = class {
constructor() {
this.buffer = Buffer.alloc(0);
constructor(size = 0) {
this.buffer = Buffer.alloc(size);
this.offset = 0;
this.baseSize = size;
}
reset() {
@ -23,10 +25,27 @@ module.exports.Writer = class {
}
writeByte(data = 0) {
const buff = Buffer.alloc(1);
buff.writeInt8(data, 0);
if (this.baseSize == 0) {
const buff = Buffer.alloc(1);
buff.writeInt8(data, 0);
this.writeBuffer(buff);
} else {
this.buffer.writeInt8(data, this.offset);
this.offset += 1;
}
}
this.writeBuffer(buff);
writeUByte(data = 0) {
if (this.baseSize == 0) {
const buff = Buffer.alloc(1);
buff.writeUInt8(data, 0);
this.writeBuffer(buff);
} else {
this.buffer.writeUInt8(data, this.offset);
this.offset += 1;
}
}
writeByteArray(data = [0]) {

View file

@ -1,11 +1,8 @@
const { Worker } = require('worker_threads');
const FunkyArray = require("./Util/funkyArray.js");
const bufferStuff = require("./bufferStuff.js");
const config = require("../config.json");
const { Worker } = require('worker_threads');
const workerPath = __dirname + "/Workers/ChunkPacketGenerator.js";
const workerPath = `${__dirname}/Workers/ChunkWorker.js`;
module.exports = class {
constructor() {
@ -17,7 +14,6 @@ module.exports = class {
this.threadPool = [];
this.workPool = new FunkyArray();
this.toRemove = [];
// WoAh!!! Thread pool in js!?!??!???!11!?!?!
@ -30,10 +26,6 @@ module.exports = class {
case "chunk":
const user = global.getUserByKey(data[2]);
user.chunksToSend.add(Buffer.from(data[1]));
break;
// Specific to the chunk task as multiple of them are sent before removal
case "remove":
this.toRemove.push(data[1]);
this.threadPool[myID][0] = false;
break;
@ -102,10 +94,10 @@ module.exports = class {
}
setBlock(id = 0, x = 0, y = 0, z = 0) {
if (y < 0 || y > 127) throw "Tried to set a block outside of the world!";
if (y < 0 || y > 127) return console.error("Tried to set a block outside of the world!");
const chunkX = Math.floor(x / 16);
const chunkZ = Math.floor(z / 16);
const chunkX = Math.floor(x >> 4);
const chunkZ = Math.floor(z >> 4);
const blockX = x - (16 * chunkX);
const blockZ = z - (16 * chunkZ);

View file

@ -1,8 +1,10 @@
const bufferStuff = require("./bufferStuff.js");
const ChunkManager = require("./chunkManager.js");
const User = require("./user.js");
const EntityPlayer = require("./Entities/EntityPlayer.js");
const PacketMappingTable = require("./PacketMappingTable.js");
const NamedPackets = require("./NamedPackets.js");
const Converter = require("./Converter.js");
const Socket = require("net").Socket;
const uuid = require("uuid").v4;
@ -23,6 +25,7 @@ global.getUserByKey = function(key) {
function addUser(socket) {
let user = new User(global.fromIDPool(), socket);
user.entityRef = new EntityPlayer(user.id, 8.5, 65.5, 8.5);
netUsers[user.id] = user;
netUserKeys = Object.keys(netUsers);
@ -59,12 +62,14 @@ module.exports.init = function(config) {
}
}
// Do chunk updates
// Don't update if chunk is generating
if (!global.generatingChunks) {
let itemsToRemove = [];
// Do a max of 128 chunk updates per tick
for (let i = 0; i < Math.min(global.chunkManager.queuedBlockUpdates.getLength(), 128); i++) {
const chunkUpdateKey = global.chunkManager.queuedBlockUpdates.itemKeys[i];
const chunkUpdate = global.chunkManager.queuedBlockUpdates.items[chunkUpdateKey];
// Don't update if chunk is nonexistant
if (global.chunkManager.chunks[chunkUpdate[1]] == null) continue;
if (global.chunkManager.chunks[chunkUpdate[1]][chunkUpdate[2]] == null) continue;
itemsToRemove.push(chunkUpdateKey);
@ -73,11 +78,13 @@ module.exports.init = function(config) {
global.chunkManager.chunks[chunkUpdate[1]][chunkUpdate[2]][chunkUpdate[3]][chunkUpdate[4]][chunkUpdate[5]] = chunkUpdate[0];
const packet = new PacketMappingTable[NamedPackets.BlockChange](chunkUpdate[4] + (16 * chunkUpdate[1]), chunkUpdate[3], chunkUpdate[5] + (16 * chunkUpdate[2]), chunkUpdate[0]).writePacket();
for (let userKey in netUserKeys) {
for (let userKey of netUserKeys) {
const user = netUsers[userKey];
if (user.loginFinished) user.socket.write(packet);
}
} catch (e) {}
} catch (e) {
console.error(e);
}
}
for (let item of itemsToRemove) {
@ -89,7 +96,7 @@ module.exports.init = function(config) {
for (let key of netUserKeys) {
const user = netUsers[key];
//user.entityRef.onTick();
}
// Send queued chunks to users
@ -126,8 +133,12 @@ module.exports.connection = async function(socket = new Socket) {
const packetID = reader.readByte();
switch(packetID) {
case NamedPackets.Disconnect:
removeUser(thisUser.id);
break;
case NamedPackets.KeepAlive:
socket.write(new PacketMappingTable[NamedPackets.KeepAlive]().writePacket());
break;
case NamedPackets.LoginRequest:
@ -154,15 +165,21 @@ module.exports.connection = async function(socket = new Socket) {
netUsers[key].socket.write(joinMessage);
}
socket.write(new PacketMappingTable[NamedPackets.SetSlot](0, 36, 3, 64, 0).writePacket());
socket.write(new PacketMappingTable[NamedPackets.PlayerPositionAndLook](8.5, 65 + 1.6200000047683716, 65, 8.5, 0, 0, false).writePacket());
thisUser.loginFinished = true;
// Send chunks
for (let x = -3; x < 4; x++) {
for (let z = -3; z < 4; z++) {
global.chunkManager.multiBlockChunk(x, z, thisUser);
}
}
// Send this user to other online users
break;
case NamedPackets.Handshake:
@ -211,6 +228,44 @@ module.exports.connection = async function(socket = new Socket) {
}
break;
case NamedPackets.Animation:
const EID = reader.readInt();
const cachedPacket = new PacketMappingTable[NamedPackets.Animation](thisUser.id, reader.readByte()).writePacket();
for (let key of netUserKeys) {
if (netUsers[key].id !== thisUser.id) netUsers[key].socket.write(cachedPacket);
}
break;
case NamedPackets.PlayerDigging:
const status = reader.readByte();
if (status == 2) {
const x = reader.readInt();
const y = reader.readByte();
const z = reader.readInt();
global.chunkManager.setBlock(0, x, y, z);
}
break;
case NamedPackets.PlayerBlockPlacement:
const x = reader.readInt();
const y = reader.readByte();
const z = reader.readInt();
let xOff = 0, yOff = 0, zOff = 0;
switch (reader.readByte()) { // direction
case 0: yOff = -1; break;
case 1: yOff = 1; break;
case 2: zOff = -1; break;
case 3: zOff = 1; break;
case 4: xOff = -1; break;
case 5: xOff = 1; break;
}
const block = reader.readShort();
global.chunkManager.setBlock(block, x + xOff, y + yOff, z + zOff);
break;
case NamedPackets.Player:
break;