From 79b1f0c0eb2512272092b87b80d7e0dee595a5f8 Mon Sep 17 00:00:00 2001 From: Holly Date: Sun, 20 Aug 2023 01:18:05 +0100 Subject: [PATCH] maintenance --- config.json | 2 +- funkyArray.ts | 4 ++-- package-lock.json | 16 ++++++++-------- package.json | 4 ++-- server/Chunk.ts | 4 +++- server/MPClient.ts | 12 +++++++----- server/MinecraftServer.ts | 28 ++++++++++++++++++++++------ server/WorldSaveManager.ts | 2 +- 8 files changed, 46 insertions(+), 26 deletions(-) diff --git a/config.json b/config.json index 4a17294..eea18b1 100644 --- a/config.json +++ b/config.json @@ -1,7 +1,7 @@ { "port": 25565, "maxPlayers": 20, - "seed": "really janky", + "seed": "fuck you boltimore", "saveCompression": "NONE", "worldName": "world" } \ No newline at end of file diff --git a/funkyArray.ts b/funkyArray.ts index f02690a..92c8e56 100644 --- a/funkyArray.ts +++ b/funkyArray.ts @@ -57,7 +57,7 @@ export class FunkyArray { } public forEach(callback: (value:TT) => void) { - return new Promise((resolve, reject) => { + return new Promise(async (resolve, reject) => { if (this.items.size === 0) { return resolve(true); } @@ -66,7 +66,7 @@ export class FunkyArray { const iterator = this.items.values(); let result:IteratorResult; while (!(result = iterator.next()).done) { - callback(result.value); + await callback(result.value); } resolve(true); } catch (e) { diff --git a/package-lock.json b/package-lock.json index 96a6887..3460125 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,8 +13,8 @@ "hsconsole": "^1.0.2" }, "devDependencies": { - "@types/node": "^20.4.5", - "check-outdated": "^2.11.0", + "@types/node": "^20.5.0", + "check-outdated": "^2.12.0", "nodemon": "^3.0.1", "npm-run-all": "^4.1.5", "terser": "^5.19.2", @@ -170,9 +170,9 @@ "peer": true }, "node_modules/@types/node": { - "version": "20.4.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", - "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.0.tgz", + "integrity": "sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==", "dev": true }, "node_modules/@webassemblyjs/ast": { @@ -605,9 +605,9 @@ } }, "node_modules/check-outdated": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/check-outdated/-/check-outdated-2.11.0.tgz", - "integrity": "sha512-YZmbRlpWCi2plPRpKLNPJLeel+86qvHMK1Tt9Dpt/APjtSCDrI9YpMvXr4lGrsx8aH0QJev7VJUyfcfwKQ/CCg==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/check-outdated/-/check-outdated-2.12.0.tgz", + "integrity": "sha512-kWThJFiqxAE09XSNJLLD4hWNvLhWdxFLKxOHhxB+XhGlZGyeELXP8V6R/dRrZ5vbjmp9VmoTYe0vp6egftKz7Q==", "dev": true, "bin": { "check-outdated": "check-outdated.js" diff --git a/package.json b/package.json index 8761629..77c9f64 100644 --- a/package.json +++ b/package.json @@ -29,8 +29,8 @@ "hsconsole": "^1.0.2" }, "devDependencies": { - "@types/node": "^20.4.5", - "check-outdated": "^2.11.0", + "@types/node": "^20.5.0", + "check-outdated": "^2.12.0", "nodemon": "^3.0.1", "npm-run-all": "^4.1.5", "terser": "^5.19.2", diff --git a/server/Chunk.ts b/server/Chunk.ts index c8dddc9..ec6bcdf 100644 --- a/server/Chunk.ts +++ b/server/Chunk.ts @@ -57,6 +57,8 @@ export class Chunk { public getTopBlockY(x:number, z:number) { let castY = this.MAX_HEIGHT; while (castY-- > 0) { + const blockId = this.getBlockId(x >>> 0, castY, z >>> 0); + console.log(blockId === 0 ? "Air" : Block.blocks[blockId].blockName); if (this.getBlockId(x >>> 0, castY, z >>> 0) !== 0) { break; } @@ -161,7 +163,7 @@ export class Chunk { return this.metadata.toBuffer(); } - public getData() { + public getBlockData() { return this.blocks; } } \ No newline at end of file diff --git a/server/MPClient.ts b/server/MPClient.ts index fcf926c..697f68d 100644 --- a/server/MPClient.ts +++ b/server/MPClient.ts @@ -67,6 +67,7 @@ export class MPClient { //case Packets.UseBed: break; case Packet.Animation: this.handlePacketAnimation(new PacketAnimation().readData(reader)); break; case Packet.EntityAction: this.handlePacketEntityAction(new PacketEntityAction().readData(reader)); break; + case Packet.DisconnectKick: this.handleDisconnectKick(); break; default: Console.printWarn(`UNIMPLEMENTED PACKET: ${Packet[packetId]}`); break; } } @@ -79,15 +80,12 @@ export class MPClient { this.send(new PacketPlayerPositionLook(parseFloat(message[1]), parseFloat(message[2]), parseFloat(message[2]) + 0.62, parseFloat(message[3]), 0, 0, false).writeData()); Console.printInfo(packet.message = `Teleported ${this.entity.username} to ${message[1]} ${message[2]} ${message[3]}`); } else if (message[0] === "/csay") { - const consoleMessage = `[CONSOLE] ${message.slice(1, message.length).join(" ")}`; - Console.printInfo(`[CHAT] ${consoleMessage}`); - this.mcServer.sendToAllClients(new PacketChat(consoleMessage).writeData()); + this.mcServer.sendChatMessage(`[CONSOLE] ${message.slice(1, message.length).join(" ")}`); } else if (message[0] === "/top") { - // TODO: Figure out why this is broken packet.message = `Woosh!`; const topBlock = this.entity.world.getChunk(this.entity.x >> 4, this.entity.z >> 4).getTopBlockY(this.entity.x & 0xf, this.entity.z & 0xf); console.log(topBlock); - this.send(new PacketPlayerPosition(this.entity.x, topBlock + 4, topBlock + 4.62, this.entity.z, false).writeData()); + this.send(new PacketPlayerPosition(this.entity.x, topBlock + 3, topBlock + 3.62, this.entity.z, false).writeData()); } if (packet.message !== "") { @@ -159,6 +157,10 @@ export class MPClient { } } + private handleDisconnectKick() { + this.socket.end(); + } + public send(buffer:Buffer) { this.socket.write(buffer); } diff --git a/server/MinecraftServer.ts b/server/MinecraftServer.ts index 6c5c911..d6ca29b 100644 --- a/server/MinecraftServer.ts +++ b/server/MinecraftServer.ts @@ -18,6 +18,7 @@ import { SaveCompressionType } from "./enums/SaveCompressionType"; import { WorldSaveManager } from "./WorldSaveManager"; import { World } from "./World"; import { Chunk } from "./Chunk"; +import { PacketTimeUpdate } from "./packets/TimeUpdate"; export class MinecraftServer { private static readonly PROTOCOL_VERSION = 14; @@ -27,7 +28,7 @@ export class MinecraftServer { private config:Config; private server:Server; - private readonly serverClock:NodeJS.Timer; + private readonly serverClock:NodeJS.Timeout; private tickCounter:number = 0; private clients:FunkyArray; private worlds:FunkyArray; @@ -52,7 +53,12 @@ export class MinecraftServer { public constructor(config:Config) { this.config = config; + let shuttingDown = false; process.on("SIGINT", async (signal) => { + if (shuttingDown) { + return; + } + shuttingDown = true; Console.printInfo("Shutting down..."); // Stop the server timer clearInterval(this.serverClock); @@ -63,6 +69,7 @@ export class MinecraftServer { this.server.close(); // Save chunks Console.printInfo("Saving worlds..."); + // There's a race condition here. oops. let savedWorldCount = 0; let savedChunkCount = 0; await this.worlds.forEach(async (world) => { @@ -118,9 +125,10 @@ export class MinecraftServer { (async () => { const generateStartTime = Date.now(); Console.printInfo("Generating spawn area..."); - for (let x = 0; x < 1; x++) { - for (let z = 0; z < 1; z++) { - await this.overworld.getChunkSafe(x, z); + for (let x = -5; x < 5; x++) { + for (let z = -5; z < 5; z++) { + const chunk = await this.overworld.getChunkSafe(x, z); + chunk.forceLoaded = true; } } Console.printInfo(`Done! Took ${Date.now() - generateStartTime}ms`); @@ -130,8 +138,11 @@ export class MinecraftServer { // Every 1 sec if (this.tickCounter % MinecraftServer.TICK_RATE === 0) { if (this.clients.length !== 0) { + const timePacket = new PacketTimeUpdate(BigInt(this.tickCounter)).writeData(); this.clients.forEach(client => { + // Keep the client happy client.send(this.keepalivePacket); + client.send(timePacket); }); } } @@ -153,6 +164,11 @@ export class MinecraftServer { }); } + sendChatMessage(text:string) { + this.sendToAllClients(new PacketChat(text).writeData()); + Console.printInfo(`[CHAT] ${text}`); + } + handleLoginRequest(reader:IReader, socket:Socket, setMPClient:(mpclient:MPClient) => void) { const loginPacket = new PacketLoginRequest().readData(reader); if (loginPacket.protocolVersion !== MinecraftServer.PROTOCOL_VERSION) { @@ -174,7 +190,7 @@ export class MinecraftServer { clientEntity.mpClient = client; this.clients.set(loginPacket.username, client); - this.sendToAllClients(new PacketChat(`\u00a7e${loginPacket.username} joined the game`).writeData()); + this.sendChatMessage(`\u00a7e${loginPacket.username} joined the game`); socket.write(new PacketLoginRequest(clientEntity.entityId, "", 0, 0).writeData()); socket.write(new PacketSpawnPosition(8, 64, 8).writeData()); @@ -207,7 +223,7 @@ export class MinecraftServer { const playerDisconnect = (err:Error) => { mpClient.entity.world.removeEntity(mpClient.entity); this.clients.remove(mpClient.entity.username); - this.sendToAllClients(new PacketChat(`\u00a7e${mpClient.entity.username} left the game`).writeData()); + this.sendChatMessage(`\u00a7e${mpClient.entity.username} left the game`); if (typeof(err) !== "boolean") { Console.printError(`Client disconnected with error: ${err.message}`); } diff --git a/server/WorldSaveManager.ts b/server/WorldSaveManager.ts index 067e544..f143b54 100644 --- a/server/WorldSaveManager.ts +++ b/server/WorldSaveManager.ts @@ -98,7 +98,7 @@ export class WorldSaveManager { chunkFileWriter.writeUByte(16); // Chunk Z const chunkData = createWriter(Endian.BE) - .writeBuffer(Buffer.from(chunk.getData())) + .writeBuffer(Buffer.from(chunk.getBlockData())) .writeBuffer(chunk.getMetadataBuffer()) .writeBuffer(chunk.getBlockLightBuffer()) .writeBuffer(chunk.getSkyLightBuffer()).toBuffer();