From 45c08c0c5f137b9a96ccbc4fcf5e92a1e3d04a6d Mon Sep 17 00:00:00 2001 From: Holly Date: Thu, 17 Oct 2024 01:51:41 +0100 Subject: [PATCH] allow changing metadata directly without updating block id --- server/Chunk.ts | 10 ++++++ server/MinecraftServer.ts | 13 +------- server/Random.ts | 17 ++++++++++ server/World.ts | 39 ++++++++++++++++++++-- server/blocks/BlockBehaviorSapling.ts | 16 +++++++++ server/blocks/BlockBehaviour.ts | 2 ++ server/blocks/BlockBehaviourOre.ts | 12 +++++++ server/blocks/BlockBehaviourRedstoneOre.ts | 12 +++++++ 8 files changed, 107 insertions(+), 14 deletions(-) create mode 100644 server/Random.ts create mode 100644 server/blocks/BlockBehaviorSapling.ts create mode 100644 server/blocks/BlockBehaviourOre.ts create mode 100644 server/blocks/BlockBehaviourRedstoneOre.ts diff --git a/server/Chunk.ts b/server/Chunk.ts index c019843..b954fbd 100644 --- a/server/Chunk.ts +++ b/server/Chunk.ts @@ -123,6 +123,16 @@ export class Chunk { 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); + } + 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) { this.queueBlockUpdateForOuterChunkBlock(blockId, metadata, x, y, z); diff --git a/server/MinecraftServer.ts b/server/MinecraftServer.ts index bf29d30..4e94882 100644 --- a/server/MinecraftServer.ts +++ b/server/MinecraftServer.ts @@ -125,18 +125,7 @@ export class MinecraftServer { //this.worlds.set(0, new World(this.saveManager, 0, worldSeed, new NewOverworld(worldSeed))); this.worlds.set(0, new World(this.saveManager, 0, worldSeed, new HillyGenerator(worldSeed))); this.worlds.set(-1, new World(this.saveManager, -1, worldSeed, new NetherGenerator(worldSeed))); - - // Generate spawn area (overworld) - /*(async () => { - const generateStartTime = Date.now(); - Console.printInfo("Generating spawn area..."); - for (let x = -3; x < 3; x++) { - for (let z = -3; z < 3; z++) { - await this.overworld.getChunkSafe(x, z); - } - } - Console.printInfo(`Done! Took ${Date.now() - generateStartTime}ms`); - }).bind(this)();*/ + (async () => { const generateStartTime = Date.now(); let timer = Date.now(); diff --git a/server/Random.ts b/server/Random.ts new file mode 100644 index 0000000..025b530 --- /dev/null +++ b/server/Random.ts @@ -0,0 +1,17 @@ +import mulberry32 from "./mulberry32"; + +export default class Random { + private readonly mulberry32; + + public constructor(seed:number = Date.now()) { + this.mulberry32 = mulberry32(seed); + } + + public nextInt(bound = Number.MAX_SAFE_INTEGER) { + return Math.floor(this.mulberry32() * bound); + } + + public nextFloat() { + return this.mulberry32(); + } +} \ No newline at end of file diff --git a/server/World.ts b/server/World.ts index 0f70f52..66681a7 100644 --- a/server/World.ts +++ b/server/World.ts @@ -15,6 +15,7 @@ import { PacketPickupSpawn } from "./packets/PickupSpawn"; import { QueuedBlockUpdate } from "./queuedUpdateTypes/BlockUpdate"; import { IQueuedUpdate } from "./queuedUpdateTypes/IQueuedUpdate"; import AABB from "./AABB"; +import Random from "./Random"; export class World { public static ENTITY_MAX_SEND_DISTANCE = 50; @@ -32,6 +33,8 @@ export class World { public queuedUpdates:Array; public generator:IGenerator; + public random:Random = new Random(); + public readonly dimension:number; public constructor(saveManager:WorldSaveManager, dimension:number, seed:number, generator:IGenerator) { @@ -157,8 +160,18 @@ export class World { return this.getChunk(chunkX, chunkZ).getBlockMetadata(x & 0xf, y, z & 0xf); } - public getChunkBlockMetadata(chunk:Chunk, x:number, y:number, z:number) { - return chunk.getBlockMetadata(x & 0xf, y, z & 0xf); + public getBlockLight(x:number, y:number, z:number) { + const chunkX = x >> 4, + chunkZ = z >> 4; + + return this.getChunk(chunkX, chunkZ).getBlockLight(x & 0xf, y, z & 0xf); + } + + public getSkyLight(x:number, y:number, z:number) { + const chunkX = x >> 4, + chunkZ = z >> 4; + + return this.getChunk(chunkX, chunkZ).getSkyLight(x & 0xf, y, z & 0xf); } public setBlock(blockId:number, x:number, y:number, z:number, doBlockUpdate?:boolean) { @@ -193,11 +206,33 @@ export class World { } } + public setBlockMetadata(x:number, y:number, z:number, metadata:number, doBlockUpdate?:boolean) { + const chunkX = x >> 4, chunkZ = z >> 4; + + const chunk = this.getChunk(chunkX, chunkZ); + const xc = x & 0xf, zc = z & 0xf; + chunk.setBlockMetadata(metadata, xc, y, zc); + + if (doBlockUpdate) { + const blockId = chunk.getBlockId(xc, y, zc); + const blockUpdatePacket = new PacketBlockChange(x, y, z, blockId, metadata).writeData(); + // Send block update to all players that have this chunk loaded + chunk.playersInChunk.forEach(player => { + player.mpClient?.send(blockUpdatePacket); + }); + } + } + public setBlockWithNotify(x:number, y:number, z:number, blockId:number) { this.setBlock(blockId, x, y, z, true); this.notifyNeighborBlocksOfChange(x, y, z, blockId); } + public setBlockMetadataWithNotify(x:number, y:number, z:number, metadata:number) { + this.setBlockMetadata(x, y, z, metadata, true); + this.notifyNeighborBlocksOfChange(x, y, z, this.getBlockId(x, y, z)); + } + public setBlockAndMetadataWithNotify(x:number, y:number, z:number, blockId:number, metadata:number) { this.setBlockWithMetadata(blockId, metadata, x, y, z, true); this.notifyNeighborBlocksOfChange(x, y, z, blockId); diff --git a/server/blocks/BlockBehaviorSapling.ts b/server/blocks/BlockBehaviorSapling.ts new file mode 100644 index 0000000..289c6d0 --- /dev/null +++ b/server/blocks/BlockBehaviorSapling.ts @@ -0,0 +1,16 @@ +import Random from "../Random"; +import { World } from "../World"; +import { BlockBehaviour } from "./BlockBehaviour"; + +export class BlockBehaviourSapling extends BlockBehaviour { + public randomTick(world:World, x:number, y:number, z:number, random:Random) { + if (world.getBlockLight(x, y + 1, z) >= 9 && random.nextInt(30) === 0) { + const blockMetadata = world.getBlockMetadata(x, y, z); + if ((blockMetadata & 8) === 0) { + world.setBlockMetadataWithNotify(x, y, z, blockMetadata | 8); + } else { + console.log("UNIMPLEMENTED TREE GROW!!"); + } + } + } +} \ No newline at end of file diff --git a/server/blocks/BlockBehaviour.ts b/server/blocks/BlockBehaviour.ts index d30f59b..af76cf7 100644 --- a/server/blocks/BlockBehaviour.ts +++ b/server/blocks/BlockBehaviour.ts @@ -1,4 +1,5 @@ import AABB from "../AABB"; +import Random from "../Random"; import { World } from "../World"; import { IBlockBehaviour } from "./IBlockBehaviour"; @@ -7,4 +8,5 @@ export class BlockBehaviour implements IBlockBehaviour { public droppedItem(blockId:number) { return blockId; } public droppedCount(blockId:number) { return 1; } public getBoundingBox(x:number, y:number, z:number) { return AABB.getAABB(0 + x, 0 + y, 0 + z, 1 + x, 1 + y, 1 + z); } + public randomTick(world:World, x:number, y:number, z:number, random:Random) {} } \ No newline at end of file diff --git a/server/blocks/BlockBehaviourOre.ts b/server/blocks/BlockBehaviourOre.ts new file mode 100644 index 0000000..fea40a9 --- /dev/null +++ b/server/blocks/BlockBehaviourOre.ts @@ -0,0 +1,12 @@ +import { Item } from "../items/Item"; +import { BlockBehaviour } from "./BlockBehaviour"; + +export default class BlockBehaviourOre extends BlockBehaviour { + public droppedItem(blockId:number) { + return Item.clay.shiftedItemID; + } + + public droppedCount(blockId:number) { + return 4; + } +} \ No newline at end of file diff --git a/server/blocks/BlockBehaviourRedstoneOre.ts b/server/blocks/BlockBehaviourRedstoneOre.ts new file mode 100644 index 0000000..a369bd7 --- /dev/null +++ b/server/blocks/BlockBehaviourRedstoneOre.ts @@ -0,0 +1,12 @@ +import { Item } from "../items/Item"; +import { BlockBehaviour } from "./BlockBehaviour"; + +export default class BlockBehaviourRedstoneOre extends BlockBehaviour { + public droppedItem(blockId:number) { + return Item.clay.shiftedItemID; + } + + public droppedCount(blockId:number) { + return 4; + } +} \ No newline at end of file