135 lines
3.3 KiB
TypeScript
135 lines
3.3 KiB
TypeScript
import { decode, encode } from "cbor-x";
|
|
import { Position } from "./classes.ts";
|
|
|
|
import { unlink, readFile, writeFile} from "node:fs/promises";
|
|
|
|
export class World {
|
|
size: Position;
|
|
data: Uint8Array;
|
|
private dataView: DataView;
|
|
name: string;
|
|
// deno-lint-ignore no-explicit-any
|
|
metadata: any = {};
|
|
|
|
constructor(size: Position, name: string) {
|
|
this.size = size;
|
|
this.name = name;
|
|
|
|
this.data = new Uint8Array(4 + size.x * size.y * size.z);
|
|
this.dataView = new DataView(this.data.buffer);
|
|
|
|
this.dataView.setInt32(0, this.size.x * this.size.y * this.size.z, false);
|
|
|
|
this.load();
|
|
}
|
|
|
|
setBlock(pos: Position, block: number) {
|
|
const szz = this.sizeToWorldSize(pos);
|
|
|
|
this.dataView.setUint8(szz, block);
|
|
}
|
|
|
|
getBlock(pos: Position) {
|
|
return this.dataView.getUint8(this.sizeToWorldSize(pos));
|
|
}
|
|
|
|
findID(block: number): Position[] {
|
|
const position: Position[] = [];
|
|
for (let z = 0; z < this.size.z; z++) {
|
|
for (let y = 0; y < this.size.y; y++) {
|
|
for (let x = 0; x < this.size.x; x++) {
|
|
if (this.getBlock({ z, y, x }) == block) {
|
|
position.push({ z, y, x });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return position;
|
|
}
|
|
|
|
private sizeToWorldSize(pos: Position): number {
|
|
return 4 + pos.x + this.size.z * (pos.z + this.size.x * pos.y);
|
|
}
|
|
|
|
getSpawn(): Position {
|
|
return {
|
|
x: Math.floor(this.size.x / 2) * 32,
|
|
y: (Math.floor(this.size.y / 2) * 32) + 32,
|
|
z: Math.floor(this.size.z / 2) * 32,
|
|
};
|
|
}
|
|
|
|
setLayer(y: number, type: number) {
|
|
for (let i = 0; i < this.size.z; i += 1) {
|
|
for (let b = 0; b < this.size.x; b += 1) {
|
|
this.setBlock({
|
|
x: b,
|
|
y,
|
|
z: i,
|
|
}, type);
|
|
}
|
|
}
|
|
}
|
|
|
|
async delete() {
|
|
try {
|
|
await unlink(`worlds/${this.name}.buf`)
|
|
} catch {
|
|
// gang
|
|
}
|
|
}
|
|
|
|
private async load() {
|
|
try {
|
|
const ungziped = Bun.gunzipSync(
|
|
await readFile(`worlds/${this.name}.buf`)
|
|
);
|
|
|
|
if (!(ungziped instanceof Uint8Array)) return;
|
|
const dv = new DataView(ungziped.buffer);
|
|
|
|
const cborSize = dv.getUint32(0);
|
|
this.metadata = decode(new Uint8Array(ungziped.buffer.slice(4, cborSize+4)));
|
|
|
|
this.size = {
|
|
x: this.metadata.x!,
|
|
y: this.metadata.y!,
|
|
z: this.metadata.z!,
|
|
};
|
|
|
|
this.data = ungziped.slice(cborSize+4);
|
|
this.dataView = new DataView(this.data.buffer);
|
|
|
|
if(4 + this.size.x * this.size.y * this.size.z == this.data.length) {
|
|
console.log('[WARNING] Encoding was wrong somewhere!')
|
|
}
|
|
} catch(e) {
|
|
const layers = Math.floor(this.size.y / 2);
|
|
|
|
for (let i = 0; i < layers; i += 1) {
|
|
if (i === layers - 1) {
|
|
this.setLayer(layers - 1, 2);
|
|
} else {
|
|
this.setLayer(i, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
async save() {
|
|
const metadata = {
|
|
x: this.size.x!,
|
|
y: this.size.y!,
|
|
z: this.size.z!,
|
|
...this.metadata
|
|
}
|
|
const cborData = encode(metadata);
|
|
const buffer = new Uint8Array(4 + cborData.byteLength + this.data.byteLength);
|
|
const dv = new DataView(buffer.buffer);
|
|
dv.setUint32(0, cborData.byteLength);
|
|
buffer.set(cborData, 4);
|
|
buffer.set(this.data, 4 + cborData.byteLength);
|
|
await writeFile(`worlds/${this.name}.buf`, Bun.gzipSync(buffer)!);
|
|
}
|
|
}
|