maintenance

This commit is contained in:
Holly Stubbs 2023-08-20 01:18:05 +01:00
parent 3123dac2c2
commit 79b1f0c0eb
Signed by: tgpholly
GPG key ID: B8583C4B7D18119E
8 changed files with 46 additions and 26 deletions

View file

@ -1,7 +1,7 @@
{ {
"port": 25565, "port": 25565,
"maxPlayers": 20, "maxPlayers": 20,
"seed": "really janky", "seed": "fuck you boltimore",
"saveCompression": "NONE", "saveCompression": "NONE",
"worldName": "world" "worldName": "world"
} }

View file

@ -57,7 +57,7 @@ export class FunkyArray<T, TT> {
} }
public forEach(callback: (value:TT) => void) { public forEach(callback: (value:TT) => void) {
return new Promise<boolean>((resolve, reject) => { return new Promise<boolean>(async (resolve, reject) => {
if (this.items.size === 0) { if (this.items.size === 0) {
return resolve(true); return resolve(true);
} }
@ -66,7 +66,7 @@ export class FunkyArray<T, TT> {
const iterator = this.items.values(); const iterator = this.items.values();
let result:IteratorResult<TT, TT>; let result:IteratorResult<TT, TT>;
while (!(result = iterator.next()).done) { while (!(result = iterator.next()).done) {
callback(result.value); await callback(result.value);
} }
resolve(true); resolve(true);
} catch (e) { } catch (e) {

16
package-lock.json generated
View file

@ -13,8 +13,8 @@
"hsconsole": "^1.0.2" "hsconsole": "^1.0.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.4.5", "@types/node": "^20.5.0",
"check-outdated": "^2.11.0", "check-outdated": "^2.12.0",
"nodemon": "^3.0.1", "nodemon": "^3.0.1",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"terser": "^5.19.2", "terser": "^5.19.2",
@ -170,9 +170,9 @@
"peer": true "peer": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "20.4.5", "version": "20.5.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.0.tgz",
"integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==", "integrity": "sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==",
"dev": true "dev": true
}, },
"node_modules/@webassemblyjs/ast": { "node_modules/@webassemblyjs/ast": {
@ -605,9 +605,9 @@
} }
}, },
"node_modules/check-outdated": { "node_modules/check-outdated": {
"version": "2.11.0", "version": "2.12.0",
"resolved": "https://registry.npmjs.org/check-outdated/-/check-outdated-2.11.0.tgz", "resolved": "https://registry.npmjs.org/check-outdated/-/check-outdated-2.12.0.tgz",
"integrity": "sha512-YZmbRlpWCi2plPRpKLNPJLeel+86qvHMK1Tt9Dpt/APjtSCDrI9YpMvXr4lGrsx8aH0QJev7VJUyfcfwKQ/CCg==", "integrity": "sha512-kWThJFiqxAE09XSNJLLD4hWNvLhWdxFLKxOHhxB+XhGlZGyeELXP8V6R/dRrZ5vbjmp9VmoTYe0vp6egftKz7Q==",
"dev": true, "dev": true,
"bin": { "bin": {
"check-outdated": "check-outdated.js" "check-outdated": "check-outdated.js"

View file

@ -29,8 +29,8 @@
"hsconsole": "^1.0.2" "hsconsole": "^1.0.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.4.5", "@types/node": "^20.5.0",
"check-outdated": "^2.11.0", "check-outdated": "^2.12.0",
"nodemon": "^3.0.1", "nodemon": "^3.0.1",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"terser": "^5.19.2", "terser": "^5.19.2",

View file

@ -57,6 +57,8 @@ export class Chunk {
public getTopBlockY(x:number, z:number) { public getTopBlockY(x:number, z:number) {
let castY = this.MAX_HEIGHT; let castY = this.MAX_HEIGHT;
while (castY-- > 0) { 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) { if (this.getBlockId(x >>> 0, castY, z >>> 0) !== 0) {
break; break;
} }
@ -161,7 +163,7 @@ export class Chunk {
return this.metadata.toBuffer(); return this.metadata.toBuffer();
} }
public getData() { public getBlockData() {
return this.blocks; return this.blocks;
} }
} }

View file

@ -67,6 +67,7 @@ export class MPClient {
//case Packets.UseBed: break; //case Packets.UseBed: break;
case Packet.Animation: this.handlePacketAnimation(new PacketAnimation().readData(reader)); break; case Packet.Animation: this.handlePacketAnimation(new PacketAnimation().readData(reader)); break;
case Packet.EntityAction: this.handlePacketEntityAction(new PacketEntityAction().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; 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()); 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]}`); Console.printInfo(packet.message = `Teleported ${this.entity.username} to ${message[1]} ${message[2]} ${message[3]}`);
} else if (message[0] === "/csay") { } else if (message[0] === "/csay") {
const consoleMessage = `[CONSOLE] ${message.slice(1, message.length).join(" ")}`; this.mcServer.sendChatMessage(`[CONSOLE] ${message.slice(1, message.length).join(" ")}`);
Console.printInfo(`[CHAT] ${consoleMessage}`);
this.mcServer.sendToAllClients(new PacketChat(consoleMessage).writeData());
} else if (message[0] === "/top") { } else if (message[0] === "/top") {
// TODO: Figure out why this is broken
packet.message = `Woosh!`; 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); 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); 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 !== "") { if (packet.message !== "") {
@ -159,6 +157,10 @@ export class MPClient {
} }
} }
private handleDisconnectKick() {
this.socket.end();
}
public send(buffer:Buffer) { public send(buffer:Buffer) {
this.socket.write(buffer); this.socket.write(buffer);
} }

View file

@ -18,6 +18,7 @@ import { SaveCompressionType } from "./enums/SaveCompressionType";
import { WorldSaveManager } from "./WorldSaveManager"; import { WorldSaveManager } from "./WorldSaveManager";
import { World } from "./World"; import { World } from "./World";
import { Chunk } from "./Chunk"; import { Chunk } from "./Chunk";
import { PacketTimeUpdate } from "./packets/TimeUpdate";
export class MinecraftServer { export class MinecraftServer {
private static readonly PROTOCOL_VERSION = 14; private static readonly PROTOCOL_VERSION = 14;
@ -27,7 +28,7 @@ export class MinecraftServer {
private config:Config; private config:Config;
private server:Server; private server:Server;
private readonly serverClock:NodeJS.Timer; private readonly serverClock:NodeJS.Timeout;
private tickCounter:number = 0; private tickCounter:number = 0;
private clients:FunkyArray<string, MPClient>; private clients:FunkyArray<string, MPClient>;
private worlds:FunkyArray<number, World>; private worlds:FunkyArray<number, World>;
@ -52,7 +53,12 @@ export class MinecraftServer {
public constructor(config:Config) { public constructor(config:Config) {
this.config = config; this.config = config;
let shuttingDown = false;
process.on("SIGINT", async (signal) => { process.on("SIGINT", async (signal) => {
if (shuttingDown) {
return;
}
shuttingDown = true;
Console.printInfo("Shutting down..."); Console.printInfo("Shutting down...");
// Stop the server timer // Stop the server timer
clearInterval(this.serverClock); clearInterval(this.serverClock);
@ -63,6 +69,7 @@ export class MinecraftServer {
this.server.close(); this.server.close();
// Save chunks // Save chunks
Console.printInfo("Saving worlds..."); Console.printInfo("Saving worlds...");
// There's a race condition here. oops.
let savedWorldCount = 0; let savedWorldCount = 0;
let savedChunkCount = 0; let savedChunkCount = 0;
await this.worlds.forEach(async (world) => { await this.worlds.forEach(async (world) => {
@ -118,9 +125,10 @@ export class MinecraftServer {
(async () => { (async () => {
const generateStartTime = Date.now(); const generateStartTime = Date.now();
Console.printInfo("Generating spawn area..."); Console.printInfo("Generating spawn area...");
for (let x = 0; x < 1; x++) { for (let x = -5; x < 5; x++) {
for (let z = 0; z < 1; z++) { for (let z = -5; z < 5; z++) {
await this.overworld.getChunkSafe(x, z); const chunk = await this.overworld.getChunkSafe(x, z);
chunk.forceLoaded = true;
} }
} }
Console.printInfo(`Done! Took ${Date.now() - generateStartTime}ms`); Console.printInfo(`Done! Took ${Date.now() - generateStartTime}ms`);
@ -130,8 +138,11 @@ export class MinecraftServer {
// Every 1 sec // Every 1 sec
if (this.tickCounter % MinecraftServer.TICK_RATE === 0) { if (this.tickCounter % MinecraftServer.TICK_RATE === 0) {
if (this.clients.length !== 0) { if (this.clients.length !== 0) {
const timePacket = new PacketTimeUpdate(BigInt(this.tickCounter)).writeData();
this.clients.forEach(client => { this.clients.forEach(client => {
// Keep the client happy
client.send(this.keepalivePacket); 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) { handleLoginRequest(reader:IReader, socket:Socket, setMPClient:(mpclient:MPClient) => void) {
const loginPacket = new PacketLoginRequest().readData(reader); const loginPacket = new PacketLoginRequest().readData(reader);
if (loginPacket.protocolVersion !== MinecraftServer.PROTOCOL_VERSION) { if (loginPacket.protocolVersion !== MinecraftServer.PROTOCOL_VERSION) {
@ -174,7 +190,7 @@ export class MinecraftServer {
clientEntity.mpClient = client; clientEntity.mpClient = client;
this.clients.set(loginPacket.username, 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 PacketLoginRequest(clientEntity.entityId, "", 0, 0).writeData());
socket.write(new PacketSpawnPosition(8, 64, 8).writeData()); socket.write(new PacketSpawnPosition(8, 64, 8).writeData());
@ -207,7 +223,7 @@ export class MinecraftServer {
const playerDisconnect = (err:Error) => { const playerDisconnect = (err:Error) => {
mpClient.entity.world.removeEntity(mpClient.entity); mpClient.entity.world.removeEntity(mpClient.entity);
this.clients.remove(mpClient.entity.username); 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") { if (typeof(err) !== "boolean") {
Console.printError(`Client disconnected with error: ${err.message}`); Console.printError(`Client disconnected with error: ${err.message}`);
} }

View file

@ -98,7 +98,7 @@ export class WorldSaveManager {
chunkFileWriter.writeUByte(16); // Chunk Z chunkFileWriter.writeUByte(16); // Chunk Z
const chunkData = createWriter(Endian.BE) const chunkData = createWriter(Endian.BE)
.writeBuffer(Buffer.from(chunk.getData())) .writeBuffer(Buffer.from(chunk.getBlockData()))
.writeBuffer(chunk.getMetadataBuffer()) .writeBuffer(chunk.getMetadataBuffer())
.writeBuffer(chunk.getBlockLightBuffer()) .writeBuffer(chunk.getBlockLightBuffer())
.writeBuffer(chunk.getSkyLightBuffer()).toBuffer(); .writeBuffer(chunk.getSkyLightBuffer()).toBuffer();