From 19880f1e8de7a92235ecac0b1d130d91ec8964db Mon Sep 17 00:00:00 2001 From: holly Date: Thu, 12 Aug 2021 22:01:07 +0100 Subject: [PATCH] make chunk generation use the thread pool --- config.json | 3 +- server/Workers/ChunkPacketGenerator.js | 86 ++++++++++++++++---------- server/chunkManager.js | 77 ++++++++++------------- server/server.js | 14 ++++- 4 files changed, 101 insertions(+), 79 deletions(-) diff --git a/config.json b/config.json index 5db55c0..36d7812 100644 --- a/config.json +++ b/config.json @@ -1,3 +1,4 @@ { - "port": 25565 + "port": 25565, + "threadPoolCount": 8 } \ No newline at end of file diff --git a/server/Workers/ChunkPacketGenerator.js b/server/Workers/ChunkPacketGenerator.js index 9f01ec3..7328a08 100644 --- a/server/Workers/ChunkPacketGenerator.js +++ b/server/Workers/ChunkPacketGenerator.js @@ -5,36 +5,59 @@ const bufferStuff = require("../bufferStuff.js"); let chunkY = 0; let busyInterval = null; -parentPort.on("message", (chunk) => { - if (busyInterval == null) { - busyInterval = setInterval(() => {}, 86400000); +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; + } + } } - chunkY = 0; - // I couldn't figure out how to construct a chunk lmao - // __ima just send each block individually__ - // Using multi block chunks now! - // TODO: yknow, figure out how to chunk. - let chunksToSend = []; - - chunksToSend.push(doSquareChunk(chunk)); - chunkY += 16; - chunksToSend.push(doSquareChunk(chunk)); - chunkY += 16; - chunksToSend.push(doSquareChunk(chunk)); - chunkY += 16; - chunksToSend.push(doSquareChunk(chunk)); - chunkY += 16; - chunksToSend.push(doSquareChunk(chunk)); - chunkY += 16; - chunksToSend.push(doSquareChunk(chunk)); - chunkY += 16; - chunksToSend.push(doSquareChunk(chunk)); - chunkY += 16; - chunksToSend.push(doSquareChunk(chunk)); - - parentPort.postMessage([chunk[3], chunksToSend, chunk[4], chunk[5]]); -}); + return chunk; +} function doSquareChunk(chunk) { let blocksToSend = []; @@ -46,7 +69,10 @@ function doSquareChunk(chunk) { } } } - + + // 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]); @@ -65,7 +91,5 @@ function doSquareChunk(chunk) { writer.writeByte(0); } - //user.chunksToSend.add(writer.buffer) // so we don't flood the client queue these - //parentPort.postMessage(writer.buffer); return writer.buffer; } \ No newline at end of file diff --git a/server/chunkManager.js b/server/chunkManager.js index db6c192..be63b03 100644 --- a/server/chunkManager.js +++ b/server/chunkManager.js @@ -1,7 +1,9 @@ const FunkyArray = require("./Util/funkyArray.js"); const bufferStuff = require("./bufferStuff.js"); -const { Worker, isMainThread, parentPort } = require('worker_threads'); +const config = require("../config.json"); + +const { Worker } = require('worker_threads'); const workerPath = __dirname + "/Workers/ChunkPacketGenerator.js"; @@ -18,18 +20,38 @@ module.exports = class { this.toRemove = []; - for (let i = 0; i < 4; i++) { + for (let i = 0; i < config.threadPoolCount; i++) { const worker = new Worker(workerPath); this.threadPool.push([false, worker]); const myID = i; - worker.on("message", (message) => { - const user = global.getUserByKey(message[0]); + worker.on("message", (data) => { + /*const user = global.getUserByKey(message[0]); for (let square of message[1]) { user.chunksToSend.add(Buffer.from(square)); } this.threadPool[myID][0] = false; - this.toRemove.push(message[2]); + this.toRemove.push(message[2]);*/ + switch (data[0]) { + case "chunk": + const user = global.getUserByKey(data[2]); + user.chunksToSend.add(Buffer.from(data[1])); + //this.threadPool[myID][0] = false; + break; + + case "generate": + this.chunks[data[2]][data[3]] = data[1]; + this.toRemove.push(data[4]); + this.threadPool[myID][0] = false; + break; + + case "remove": + this.toRemove.push(data[1]); + this.threadPool[myID][0] = false; + break; + } }); } + console.log("Created thread pool with " + this.threadPool.length + " threads"); + setInterval(() => { if (this.workPool.getLength() > 0) { let limit = Math.min(this.workPool.getLength(), this.threadPool.length); @@ -46,8 +68,7 @@ module.exports = class { break; } item[0] = true; - item[1][4] = key; - item[1][5] = i1; + item[1][3] = key; thread[1].postMessage(item[1]); thread[0] = true; break; @@ -63,13 +84,11 @@ module.exports = class { } }, 1000 / 20); - const chunkStartTime = new Date().getTime(); for (let x = -3; x < 4; x++) { for (let z = -3; z < 4; z++) { this.createChunk(x, z); } } - console.log("Chunk generation took " + (new Date().getTime() - chunkStartTime) + "ms"); global.generatingChunks = false; } @@ -77,46 +96,12 @@ module.exports = class { // TODO: Store metadata! createChunk(cx = 0, cz = 0) { if (this.chunks[cx] == null) this.chunks[cx] = {}; - this.chunks[cx][cz] = {}; - let chunkQueuedBlocks = []; - - for (let y = 0; y < 128; y++) { - this.chunks[cx][cz][y] = {}; - for (let x = 0; x < 16; x++) { - this.chunks[cx][cz][y][x] = {}; - for (let z = 0; z < 16; z++) { - if (y == 64) { - // Make a tree :) - if (Math.random() <= 0.01) { - this.chunks[cx][cz][y][x][z] = 3; - - const newX = x + (16 * cx), newZ = z + (16 * cz); - // trunk - this.setBlock(17, newX, y + 1, newZ); - this.setBlock(17, newX, y + 2, newZ); - this.setBlock(17, newX, y + 3, newZ); - this.setBlock(17, newX, y + 4, newZ); - // leaves - // left - this.setBlock(18, newX, y + 5, newZ); - // right line - } else { - this.chunks[cx][cz][y][x][z] = 2; - } - } - else if (y == 63 || y == 62) this.chunks[cx][cz][y][x][z] = 3; - else if (y == 0) this.chunks[cx][cz][y][x][z] = 7; - else if (y < 62) this.chunks[cx][cz][y][x][z] = 1; - else this.chunks[cx][cz][y][x][z] = 0; - } - } - } + this.workPool.add([false, ["generate", cx, cz, null]]); } - async multiBlockChunk(chunkX = 0, chunkZ = 0, user) { - //worker.postMessage([chunkX, chunkZ, this.chunks[chunkX][chunkZ]]); - this.workPool.add([false, [chunkX, chunkZ, this.chunks[chunkX][chunkZ], user.id, null, null]]); + multiBlockChunk(chunkX = 0, chunkZ = 0, user) { + this.workPool.add([false, ["chunk", [chunkX, chunkZ, this.chunks[chunkX][chunkZ]], user.id, null]]); } setBlock(id = 0, x = 0, y = 0, z = 0) { diff --git a/server/server.js b/server/server.js index b59ae24..8244f59 100644 --- a/server/server.js +++ b/server/server.js @@ -49,12 +49,19 @@ module.exports.init = function(config) { console.log(`Up! Running at 0.0.0.0:${config.port}`); tickInterval = setInterval(() => { + if (tickCounter % tickRate == 0) { + for (let key of netUserKeys) { + netUsers[key].socket.write(new PacketMappingTable[NamedPackets.KeepAlive]().writePacket()); + } + } // Update Chunks if (!global.generatingChunks) { let itemsToRemove = []; 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]; + if (global.chunkManager.chunks[chunkUpdate[1]] == null) continue; + if (global.chunkManager.chunks[chunkUpdate[1]][chunkUpdate[2]] == null) continue; itemsToRemove.push(chunkUpdateKey); try { @@ -117,7 +124,12 @@ module.exports.connection = async function(socket = new Socket) { } } console.log("Chunk packet generation took " + (new Date().getTime() - dt) + "ms"); - socket.write(new PacketMappingTable[NamedPackets.BlockChange](8, 64, 8, 20, 0).writePacket()); + + for (let x = 0; x < 16; x++) { + for (let z = 0; z < 16; z++) { + socket.write(new PacketMappingTable[NamedPackets.BlockChange](x, 64, z, 20, 0).writePacket()); + } + } socket.write(new PacketMappingTable[NamedPackets.Player](true).writePacket());