Switch to hsconsole package & add proper shutdown procedure

This commit is contained in:
Holly Stubbs 2023-08-15 10:00:12 +01:00
parent c80dcd2d4f
commit ad83454afa
7 changed files with 53 additions and 97 deletions

View file

@ -1,90 +0,0 @@
import * as dyetty from "dyetty";
import { createWriteStream, mkdirSync, existsSync } from "fs";
console.clear();
enum LogType {
INFO,
WARN,
ERROR
}
enum LogTag {
INFO,
CHAT,
WARN,
ERROR
}
const LogTags = [
dyetty.bgGreen(dyetty.black(" INFO ")),
dyetty.bgCyan(dyetty.black(" CHAT ")),
dyetty.bgYellow(dyetty.black(" WARN ")),
dyetty.bgRed(" ERRR ")
] as const;
const TagsForFile = [
"[INFO]",
"[CHAT]",
"[WARN]",
"[ERRR]"
] as const;
function correctValue(i:number) : string {
if (i <= 9) return `0${i}`;
else return i.toString();
}
function getTime() : string {
const time = new Date();
return `[${correctValue(time.getHours())}:${correctValue(time.getMinutes())}:${correctValue(time.getSeconds())}]`;
}
function log(tag:LogTag, log:string, logType:LogType = LogType.INFO) : void {
const stringTime = getTime(),
fileTag = TagsForFile[tag],
consoleTag = LogTags[tag];
Console.QUEUED_FOR_LOG += `${stringTime} ${fileTag} ${log}\n`;
switch (logType) {
case LogType.INFO:
return console.log(`${dyetty.green(stringTime)} ${consoleTag} ${log}`);
case LogType.WARN:
return console.warn(`${dyetty.green(stringTime)} ${consoleTag} ${log}`);
case LogType.ERROR:
return console.error(`${dyetty.green(stringTime)} ${consoleTag} ${log}`);
}
}
// TODO: Keep old logs, rename on startup using file header?
if (!existsSync("./logs")) {
mkdirSync("./logs/");
}
export class Console {
public static QUEUED_FOR_LOG:string = "";
private static logFileWriteStream = createWriteStream("./logs/latest.log");
private static flushTimer:NodeJS.Timer = setInterval(() => {
if (Console.QUEUED_FOR_LOG.length !== 0) {
const strRef = Console.QUEUED_FOR_LOG;
Console.QUEUED_FOR_LOG = "";
Console.logFileWriteStream.write(strRef);
}
}, 5000);
public static printInfo(s:string) : void {
log(LogTag.INFO, s);
}
public static printChat(s:string) : void {
log(LogTag.CHAT, s);
}
public static printWarn(s:string) : void {
log(LogTag.WARN, s, LogType.WARN);
}
public static printError(s:string) : void {
log(LogTag.ERROR, s, LogType.ERROR);
}
}

View file

@ -1,4 +1,5 @@
import { Config } from "./config"; import { Config } from "./config";
import { Console } from "hsconsole";
import { readFileSync } from "fs"; import { readFileSync } from "fs";
import { MinecraftServer } from "./server/MinecraftServer"; import { MinecraftServer } from "./server/MinecraftServer";
import { SaveCompressionType } from "./server/enums/SaveCompressionType"; import { SaveCompressionType } from "./server/enums/SaveCompressionType";
@ -6,4 +7,6 @@ const tempConfig = JSON.parse(readFileSync("./config.json").toString());
tempConfig.saveCompression = SaveCompressionType[tempConfig.saveCompression]; tempConfig.saveCompression = SaveCompressionType[tempConfig.saveCompression];
const config:Config = tempConfig as Config; const config:Config = tempConfig as Config;
Console.customHeader(`MC Beta Server started at ${new Date()}`);
new MinecraftServer(config); new MinecraftServer(config);

10
package-lock.json generated
View file

@ -10,7 +10,7 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"bufferstuff": "^1.3.0", "bufferstuff": "^1.3.0",
"dyetty": "^1.0.1" "hsconsole": "^1.0.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.4.5", "@types/node": "^20.4.5",
@ -1173,6 +1173,14 @@
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true "dev": true
}, },
"node_modules/hsconsole": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/hsconsole/-/hsconsole-1.0.2.tgz",
"integrity": "sha512-st+jaSpNw3uoIhE5vl2lVN8Op8yQF2FyLRdBG68s8vqjduJdKUGtoEXd8Zxe6du1zzpFHHRcU3zJbAq8BOmYQA==",
"dependencies": {
"dyetty": "^1.0.1"
}
},
"node_modules/ignore-by-default": { "node_modules/ignore-by-default": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",

View file

@ -26,7 +26,7 @@
"homepage": "https://github.com/tgpholly/mc-beta-server#readme", "homepage": "https://github.com/tgpholly/mc-beta-server#readme",
"dependencies": { "dependencies": {
"bufferstuff": "^1.3.0", "bufferstuff": "^1.3.0",
"dyetty": "^1.0.1" "hsconsole": "^1.0.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.4.5", "@types/node": "^20.4.5",

View file

@ -1,4 +1,4 @@
import { Console } from "../console"; import { Console } from "hsconsole";
import { IReader } from "bufferstuff"; import { IReader } from "bufferstuff";
import { MinecraftServer } from "./MinecraftServer"; import { MinecraftServer } from "./MinecraftServer";
import { Packet } from "./enums/Packet"; import { Packet } from "./enums/Packet";
@ -80,7 +80,7 @@ export class MPClient {
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(" ")}`; const consoleMessage = `[CONSOLE] ${message.slice(1, message.length).join(" ")}`;
Console.printChat(consoleMessage); Console.printInfo(`[CHAT] ${consoleMessage}`);
this.mcServer.sendToAllClients(new PacketChat(consoleMessage).writeData()); this.mcServer.sendToAllClients(new PacketChat(consoleMessage).writeData());
} else if (message[0] === "/top") { } else if (message[0] === "/top") {
// TODO: Figure out why this is broken // TODO: Figure out why this is broken
@ -98,7 +98,7 @@ export class MPClient {
} }
packet.message = `<${this.entity.username}> ${packet.message}`; packet.message = `<${this.entity.username}> ${packet.message}`;
Console.printChat(packet.message); Console.printInfo(`[CHAT] ${packet.message}`);
this.mcServer.sendToAllClients(packet.writeData()); this.mcServer.sendToAllClients(packet.writeData());
} }

View file

@ -1,5 +1,5 @@
import { Config } from "../config"; import { Config } from "../config";
import { Console } from "../console"; import { Console } from "hsconsole";
import { createReader, IReader, Endian } from "bufferstuff"; import { createReader, IReader, Endian } from "bufferstuff";
import { FunkyArray } from "../funkyArray"; import { FunkyArray } from "../funkyArray";
import { Server, Socket } from "net"; import { Server, Socket } from "net";
@ -17,6 +17,7 @@ import { Player } from "./entities/Player";
import { SaveCompressionType } from "./enums/SaveCompressionType"; 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";
export class MinecraftServer { export class MinecraftServer {
private static readonly PROTOCOL_VERSION = 14; private static readonly PROTOCOL_VERSION = 14;
@ -51,6 +52,37 @@ export class MinecraftServer {
public constructor(config:Config) { public constructor(config:Config) {
this.config = config; this.config = config;
process.on("SIGINT", async (signal) => {
Console.printInfo("Shutting down...");
// Stop the server timer
clearInterval(this.serverClock);
// Disconnect all players
const kickPacket = new PacketDisconnectKick("Server shutting down.").writeData();
this.sendToAllClients(kickPacket);
// Shut down the tcp server
this.server.close();
// Save chunks
Console.printInfo("Saving worlds...");
let savedWorldCount = 0;
let savedChunkCount = 0;
await this.worlds.forEach(async (world) => {
if (world.chunks.length !== 0) {
await world.chunks.forEach(async (chunk) => {
await world.unloadChunk(Chunk.CreateCoordPair(chunk.x, chunk.z));
savedChunkCount++;
});
}
savedWorldCount++;
});
Console.printInfo(`Saved ${savedChunkCount} chunks from ${savedWorldCount} world(s).`);
// Flush final console log to disk and close all writers
Console.cleanup();
// hsconsole is gone now so we have to use built in.
console.log("Goodbye");
});
if (this.config.saveCompression === SaveCompressionType.NONE) { if (this.config.saveCompression === SaveCompressionType.NONE) {
Console.printWarn("=============- WARNING -============="); Console.printWarn("=============- WARNING -=============");
Console.printWarn(" Chunk compression is disabled. This"); Console.printWarn(" Chunk compression is disabled. This");

View file

@ -7,6 +7,9 @@
"resolveJsonModule": true, "resolveJsonModule": true,
"rootDir": "./", "rootDir": "./",
"outDir": "./build", "outDir": "./build",
"strict": true "strict": true,
"lib": [
"ES2021.String"
]
} }
} }