diff --git a/server/AABB.ts b/server/AABB.ts index 175f6c6..de97066 100644 --- a/server/AABB.ts +++ b/server/AABB.ts @@ -11,6 +11,8 @@ export default class AABB { public initMin:Vec3; public initMax:Vec3; + public prevMin:Vec3; + public prevMax:Vec3; public min:Vec3; public max:Vec3; @@ -28,6 +30,8 @@ export default class AABB { this.initMin = new Vec3(this.min); this.initMax = new Vec3(this.max); + this.prevMin = new Vec3(this.min); + this.prevMax = new Vec3(this.min); this.pooled = pooled; @@ -105,13 +109,63 @@ export default class AABB { return minZ <= maxZ ? maxZ - minZ : 0; } + public static copy(aabb:AABB) { + const newAABB = new AABB(new Vec3(aabb.min), new Vec3(aabb.max)); + newAABB.min.set(aabb.min); + newAABB.max.set(aabb.max); + return newAABB; + } + + public copy() { + const newAABB = new AABB(new Vec3(this.min), new Vec3(this.max)); + newAABB.min.set(this.min); + newAABB.max.set(this.max); + return newAABB; + } + + // Can only revert one step + public revert() { + this.min.set(this.prevMin); + this.max.set(this.prevMax); + } + + public set(aabb:AABB) { + this.prevMin.set(this.min); + this.prevMax.set(this.max); + + this.min.set(aabb.min); + this.max.set(aabb.min); + } + public move(xOrVec3:Vec3 | number, y?:number, z?:number) { if (this.pooled) { throw new Error(`Attempted to move a pooled AABB. This is not allowed!`); } + this.prevMin.set(this.min); + this.prevMax.set(this.max); + this.min.set(this.initMin); this.max.set(this.initMax); + if (xOrVec3 instanceof Vec3) { + //this.pos.set(xOrVec3); + this.min.add(xOrVec3); + this.max.add(xOrVec3); + } else if (typeof(xOrVec3) === "number" && typeof(y) === "number" && typeof(z) === "number") { + //this.pos.set(xOrVec3, y, z); + this.min.add(xOrVec3, y, z); + this.max.add(xOrVec3, y, z); + } + } + + public offset(xOrVec3:Vec3 | number, y?:number, z?:number) { + if (this.pooled) { + throw new Error(`Attempted to offset a pooled AABB. This is not allowed!`); + } + + this.prevMin.set(this.min); + this.prevMax.set(this.max); + if (xOrVec3 instanceof Vec3) { this.min.add(xOrVec3); this.max.add(xOrVec3); diff --git a/server/Chunk.ts b/server/Chunk.ts index daa6766..c019843 100644 --- a/server/Chunk.ts +++ b/server/Chunk.ts @@ -7,6 +7,7 @@ import { World } from "./World"; export class Chunk { private readonly MAX_HEIGHT:number = 128; + private readonly FULLBRIGHT = false; public readonly world:World; public readonly x:number; public readonly z:number; @@ -65,6 +66,18 @@ export class Chunk { } public calculateLighting() { + 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; + } + let blockId = 0; for (let x = 0; x < 16; x++) { for (let z = 0; z < 16; z++) { diff --git a/server/MinecraftServer.ts b/server/MinecraftServer.ts index 291c297..bf29d30 100644 --- a/server/MinecraftServer.ts +++ b/server/MinecraftServer.ts @@ -23,6 +23,7 @@ import { HillyGenerator } from "./generators/Hilly"; import { NetherGenerator } from "./generators/Nether"; import { PacketWindowItems } from "./packets/WindowItems"; import { getRandomValues } from "crypto"; +import { NewOverworld } from "./generators/NewOverworld"; const chunkFrom = -15; const chunkTo = 15; @@ -121,6 +122,7 @@ export class MinecraftServer { } this.worlds = new FunkyArray(); + //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))); diff --git a/server/entities/Entity.ts b/server/entities/Entity.ts index ce12231..842fe14 100644 --- a/server/entities/Entity.ts +++ b/server/entities/Entity.ts @@ -249,31 +249,40 @@ export class Entity implements IEntity { } } + private getBlockAABBFor(x:number, y:number, z:number) { + const blockId = this.chunk.getBlockId(x, y, z); + const blockEntityIsTouching = blockId > 0 ? Block.blocks[blockId] : null; + + if (blockEntityIsTouching != null) { + return blockEntityIsTouching.getBoundingBox(Math.floor(this.position.x), Math.floor(this.position.y), Math.floor(this.position.z)); + } + + return null; + } + moveEntity(motionX:number, motionY:number, motionZ:number) { this.position.add(motionX, motionY, motionZ); this.entityAABB.move(this.position); - const blockId = this.chunk.getBlockId(Math.floor(this.position.x) & 0xf, Math.floor(this.position.y), Math.floor(this.position.z) & 0xf); - const blockUnderEntity = blockId > 0 ? Block.blocks[blockId] : null; + let blockAABB = this.getBlockAABBFor(Math.floor(this.position.x) & 0xf, Math.floor(this.position.y), Math.floor(this.position.z) & 0xf); - if (blockUnderEntity !== null) { + if (blockAABB !== null) { this.moveEntityBlockPosRel.set(this.position); this.moveEntityBlockPosRel.sub(Math.floor(this.position.x), Math.floor(this.position.y), Math.floor(this.position.z)); - console.log(this.moveEntityBlockPosRel); - - const blockBoundingBox = blockUnderEntity.getBoundingBox(Math.floor(this.position.x), Math.floor(this.position.y), Math.floor(this.position.z)); // TODO: Handle X and Z collisions. - if (this.entityAABB.intersects(blockBoundingBox)) { - const intersectionY = this.entityAABB.intersectionY(blockBoundingBox); + if (this.entityAABB.intersects(blockAABB)) { + const intersectionY = this.entityAABB.intersectionY(blockAABB); if (this.moveEntityBlockPosRel.y > 0.5) { - this.position.add(0, intersectionY, 0); + motionY = intersectionY; } else { - this.position.sub(0, intersectionY, 0); + motionY = -intersectionY; } - this.motion.y = 0; - this.onGround = true; } + + this.position.add(0, motionY, 0); + this.motion.y = 0; + this.onGround = true; } } diff --git a/server/generators/NewOverworld.ts b/server/generators/NewOverworld.ts new file mode 100644 index 0000000..ca6501f --- /dev/null +++ b/server/generators/NewOverworld.ts @@ -0,0 +1,83 @@ + +import { makeNoise2D, Noise2D } from "../../external/OpenSimplex2D"; +import { makeNoise3D, Noise3D } from "../../external/OpenSimplex3D"; +import { Block } from "../blocks/Block"; +import { Chunk } from "../Chunk"; +import mulberry32 from "../mulberry32"; +import { IGenerator } from "./IGenerator"; + +export class NewOverworld implements IGenerator { + private seed:number; + seedGenerator:() => number; + + public layer1:Noise3D; + public layer2:Noise3D; + public mix:Noise3D; + public maxHeight:Noise2D; + + private createGenerator2D() { + return makeNoise2D(this.seedGenerator() * Number.MAX_SAFE_INTEGER); + } + + private createGenerator3D() { + return makeNoise3D(this.seedGenerator() * Number.MAX_SAFE_INTEGER); + } + + public constructor(seed:number) { + this.seed = seed; + this.seedGenerator = mulberry32(this.seed); + this.layer1 = this.createGenerator3D(); + this.layer2 = this.createGenerator3D(); + this.mix = this.createGenerator3D(); + this.maxHeight = this.createGenerator2D(); + } + + private noiseForCoord(chunk:Chunk, x:number, y:number, z:number) { + const mixValue = this.mix((chunk.x * 16 + x) / 16, y / 16, (chunk.z * 16 + z) / 16); + const layer1 = this.layer1((chunk.x * 16 + x) / 64, y / 64, (chunk.z * 16 + z) / 64) / 2048; + const layer2 = this.layer2((chunk.x * 16 + x) / 64, y / 64, (chunk.z * 16 + z) / 64) / 2048; + const maxHeightLayer = 80 + this.maxHeight((chunk.x * 16 + x) / 64, (chunk.z * 16 + z) / 64) * 32; + if (y > maxHeightLayer) { + return 0; + } + + if (mixValue < 0) { + return layer1; + } else if (mixValue > 1) { + return layer2; + } else { + return layer1 + (layer2 - layer1) * mixValue; + } + } + + public generate(chunk:Chunk) { + for (let y = 0; y < 128; y++) { + for (let x = 0; x < 16; x++) { + for (let z = 0; z < 16; z++) { + if (y === 0 || (y < 3 && this.layer1(x, y, z) > 0.1)) { + chunk.setBlock(Block.bedrock.blockId, x, y, z); + } else { + + if (this.noiseForCoord(chunk, x, y, z) > 0) { + chunk.setBlock(Block.stone.blockId, x, y, z); + } else if (y < 64) { + chunk.setBlock(Block.waterStill.blockId, x, y, z); + } + } + } + } + } + + for (let y = 0; y < 128; y++) { + for (let x = 0; x < 16; x++) { + for (let z = 0; z < 16; z++) { + if (y === 0 || (y < 3 && this.layer1(x, y, z) > 0.1)) { + chunk.setBlock(Block.bedrock.blockId, x, y, z); + } else { + + } + } + } + } + } +} \ No newline at end of file