mc-beta-server/server/Chunk.ts

206 lines
6.4 KiB
TypeScript
Raw Normal View History

import Block from "./blocks/Block";
2024-07-08 09:56:03 +01:00
import FunkyArray from "funky-array";
import NibbleArray from "../nibbleArray";
import Player from "./entities/Player";
import QueuedBlockUpdate from "./queuedUpdateTypes/BlockUpdate";
import World from "./World";
2024-11-17 08:26:35 +00:00
import TileEntity from "./tileentities/TileEntity";
2023-04-08 20:52:47 +01:00
export default class Chunk {
2023-04-08 20:52:47 +01:00
private readonly MAX_HEIGHT:number = 128;
2024-07-09 21:52:13 +01:00
private readonly FULLBRIGHT = false;
2023-04-13 23:52:13 +01:00
public readonly world:World;
2023-04-09 04:19:10 +01:00
public readonly x:number;
public readonly z:number;
public readonly playersInChunk:FunkyArray<number, Player>;
2023-04-08 20:52:47 +01:00
2023-04-11 07:47:56 +01:00
public savingToDisk:boolean = false;
public forceLoaded:boolean = false;
public tileEntities:FunkyArray<number, TileEntity>;
2024-11-17 08:26:35 +00:00
2023-04-08 20:52:47 +01:00
private blocks:Uint8Array;
2023-04-11 07:47:56 +01:00
private metadata:NibbleArray;
2023-05-02 08:50:49 +01:00
public skyLight:NibbleArray;
public blockLight:NibbleArray;
2023-04-08 20:52:47 +01:00
public static CreateCoordPair(x:number, z:number) {
return (x >= 0 ? 0 : 2147483648) | (x & 0x7fff) << 16 | (z >= 0 ? 0 : 0x8000) | z & 0x7fff;
}
2023-05-02 08:50:49 +01:00
public constructor(world:World, x:number, z:number, generateOrBlockData?:boolean|Uint8Array, metadata?:Uint8Array, blockLight?:Uint8Array, skyLight?:Uint8Array) {
2023-04-08 20:52:47 +01:00
this.world = world;
this.x = x;
this.z = z;
2023-04-09 04:19:10 +01:00
this.playersInChunk = new FunkyArray<number, Player>();
2024-11-17 08:26:35 +00:00
this.tileEntities = new FunkyArray<number, TileEntity>();
2023-04-09 04:19:10 +01:00
2023-05-02 08:50:49 +01:00
if (generateOrBlockData instanceof Uint8Array && metadata instanceof Uint8Array && blockLight instanceof Uint8Array && skyLight instanceof Uint8Array) {
2023-04-11 07:47:56 +01:00
this.blocks = new Uint8Array(generateOrBlockData);
this.metadata = new NibbleArray(metadata);
2023-05-02 08:50:49 +01:00
this.skyLight = new NibbleArray(blockLight);
this.blockLight = new NibbleArray(skyLight);
} else if (generateOrBlockData instanceof Uint8Array && metadata instanceof Uint8Array && !(blockLight instanceof Uint8Array) && !(skyLight instanceof Uint8Array)) {
this.blocks = new Uint8Array(generateOrBlockData);
this.metadata = new NibbleArray(metadata);
this.skyLight = new NibbleArray(16 * 16 * this.MAX_HEIGHT);
this.blockLight = new NibbleArray(16 * 16 * this.MAX_HEIGHT);
2023-06-19 18:29:16 +01:00
this.calculateLighting();
2023-04-11 07:47:56 +01:00
} else {
this.blocks = new Uint8Array(16 * 16 * this.MAX_HEIGHT);
this.metadata = new NibbleArray(16 * 16 * this.MAX_HEIGHT);
2023-05-02 08:50:49 +01:00
this.skyLight = new NibbleArray(16 * 16 * this.MAX_HEIGHT);
this.blockLight = new NibbleArray(16 * 16 * this.MAX_HEIGHT);
2023-04-08 20:52:47 +01:00
if (typeof(generateOrBlockData) === "boolean" && generateOrBlockData) {
2023-04-11 07:47:56 +01:00
this.world.generator.generate(this);
2023-06-19 18:29:16 +01:00
this.calculateLighting();
2023-04-11 07:47:56 +01:00
}
}
2023-04-08 20:52:47 +01:00
}
2023-04-17 02:05:11 +01:00
public getTopBlockY(x:number, z:number) {
let castY = this.MAX_HEIGHT;
while (castY-- > 0) {
2023-06-19 18:29:16 +01:00
if (this.getBlockId(x >>> 0, castY, z >>> 0) !== 0) {
2023-04-17 02:05:11 +01:00
break;
}
}
return castY;
}
2023-04-13 23:52:13 +01:00
public calculateLighting() {
2024-07-09 21:52:13 +01:00
if (this.FULLBRIGHT) {
for (let x = 0; x < 16; x++) {
for (let z = 0; z < 16; z++) {
for (let y = this.MAX_HEIGHT - 1; y > 0; y--) {
this.setBlockLight(15, x, y, z);
this.setSkyLight(15, x, y, z);
}
}
}
return;
}
2023-05-02 08:50:49 +01:00
let blockId = 0;
2023-06-19 18:29:16 +01:00
for (let x = 0; x < 16; x++) {
for (let z = 0; z < 16; z++) {
let colLight = 255;
for (let y = this.MAX_HEIGHT - 1; y > 0; y--) {
2023-05-02 08:50:49 +01:00
blockId = this.getBlockId(x, y, z);
if (blockId == 0) {
if (colLight <= 0) {
this.setBlockLight(0, x, y, z);
this.setSkyLight(0, x, y, z);
} else {
this.setBlockLight(Math.round((colLight / 255) * 15), x, y, z);
this.setSkyLight(Math.round((colLight / 255) * 15), x, y, z);
}
} else {
2023-06-19 18:29:16 +01:00
if (colLight <= 0) {
this.setBlockLight(0, x, y, z);
} else {
this.setBlockLight(Math.round((colLight / 255) * 15), x, y, z);
colLight -= (255 - Block.blocks[blockId].lightPassage);
}
2023-05-02 08:50:49 +01:00
}
2023-06-19 18:29:16 +01:00
}
2023-05-02 08:50:49 +01:00
}
}
2023-04-13 23:52:13 +01:00
}
public queueBlockUpdateForOuterChunkBlock(blockId:number, metadata:number, x:number, y:number, z:number) {
const cPair = Chunk.CreateCoordPair(this.x + (x >> 4), this.z + (z >> 4));
if (this.world.chunks.keys.includes(cPair)) {
this.world.queuedUpdates.push(new QueuedBlockUpdate(cPair, x & 0xf, y, z & 0xf, blockId, metadata));
} else {
this.world.queuedChunkBlocks.push(new QueuedBlockUpdate(cPair, x & 0xf, y, z & 0xf, blockId, metadata));
}
}
2023-04-08 20:52:47 +01:00
public setBlock(blockId:number, x:number, y:number, z:number) {
2023-04-11 07:47:56 +01:00
if (x < 0 || x > 15 || y < 0 || y > 127 || z < 0 || z > 15) {
2023-04-13 23:52:13 +01:00
this.queueBlockUpdateForOuterChunkBlock(blockId, 0, x, y, z);
2023-04-11 07:47:56 +01:00
return;
}
2023-04-08 20:52:47 +01:00
this.blocks[x << 11 | z << 7 | y] = blockId;
}
public setBlockMetadata(metadata:number, x:number, y:number, z:number) {
const index = x << 11 | z << 7 | y;
if (x < 0 || x > 15 || y < 0 || y > 127 || z < 0 || z > 15) {
this.queueBlockUpdateForOuterChunkBlock(this.blocks[index], metadata, x, y, z);
return;
}
this.metadata.set(index, metadata);
}
2023-04-11 07:47:56 +01:00
public setBlockWithMetadata(blockId:number, metadata:number, x:number, y:number, z:number) {
if (x < 0 || x > 15 || y < 0 || y > 127 || z < 0 || z > 15) {
2023-04-13 23:52:13 +01:00
this.queueBlockUpdateForOuterChunkBlock(blockId, metadata, x, y, z);
2023-04-11 07:47:56 +01:00
return;
}
x = x << 11 | z << 7 | y;
this.blocks[x] = blockId;
this.metadata.set(x, metadata);
}
2023-04-08 20:52:47 +01:00
public getBlockId(x:number, y:number, z:number) {
return this.blocks[x << 11 | z << 7 | y];
}
2023-04-11 07:47:56 +01:00
public getBlockMetadata(x:number, y:number, z:number) {
return this.metadata.get(x << 11 | z << 7 | y);
}
2023-05-02 08:50:49 +01:00
public getBlockLight(x:number, y:number, z:number) {
return this.blockLight.get(x << 11 | z << 7 | y);
}
public setBlockLight(value:number, x:number, y:number, z:number) {
return this.blockLight.set(x << 11 | z << 7 | y, value);
}
public getSkyLight(x:number, y:number, z:number) {
return this.skyLight.get(x << 11 | z << 7 | y);
}
public setSkyLight(value:number, x:number, y:number, z:number) {
return this.skyLight.set(x << 11 | z << 7 | y, value);
}
public getTileEntity(x:number, y:number, z:number) {
return this.tileEntities.get((x & 0xf) << 11 | (z & 0xf) << 7 | y);
}
public setTileEntity(tileEntity:TileEntity, x:number, y:number, z:number) {
return this.tileEntities.set((x & 0xf) << 11 | (z & 0xf) << 7 | y, tileEntity);
}
public removeTileEntity(x:number, y:number, z:number) {
return this.tileEntities.remove((x & 0xf) << 11 | (z & 0xf) << 7 | y);
}
2023-05-02 08:50:49 +01:00
public getBlockBuffer() {
return Buffer.from(this.blocks);
}
2023-04-11 07:47:56 +01:00
public getMetadataBuffer() {
return this.metadata.toBuffer();
}
2023-05-02 08:50:49 +01:00
public getBlockLightBuffer() {
2023-10-29 05:08:26 +00:00
return this.blockLight.toBuffer();
2023-05-02 08:50:49 +01:00
}
public getSkyLightBuffer() {
2023-10-29 05:08:26 +00:00
return this.skyLight.toBuffer();
2023-05-02 08:50:49 +01:00
}
2023-08-20 01:18:05 +01:00
public getBlockData() {
2023-04-08 20:52:47 +01:00
return this.blocks;
}
}