maintenance
This commit is contained in:
parent
3123dac2c2
commit
79b1f0c0eb
8 changed files with 46 additions and 26 deletions
|
@ -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"
|
||||||
}
|
}
|
|
@ -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
16
package-lock.json
generated
|
@ -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"
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue