WIP: New Overworld Generator
Some checks failed
Node.js Build / build (18.x) (push) Has been cancelled
Some checks failed
Node.js Build / build (18.x) (push) Has been cancelled
This commit is contained in:
parent
f606d1547b
commit
5c60d1d758
5 changed files with 173 additions and 12 deletions
|
@ -11,6 +11,8 @@ export default class AABB {
|
||||||
|
|
||||||
public initMin:Vec3;
|
public initMin:Vec3;
|
||||||
public initMax:Vec3;
|
public initMax:Vec3;
|
||||||
|
public prevMin:Vec3;
|
||||||
|
public prevMax:Vec3;
|
||||||
|
|
||||||
public min:Vec3;
|
public min:Vec3;
|
||||||
public max:Vec3;
|
public max:Vec3;
|
||||||
|
@ -28,6 +30,8 @@ export default class AABB {
|
||||||
|
|
||||||
this.initMin = new Vec3(this.min);
|
this.initMin = new Vec3(this.min);
|
||||||
this.initMax = new Vec3(this.max);
|
this.initMax = new Vec3(this.max);
|
||||||
|
this.prevMin = new Vec3(this.min);
|
||||||
|
this.prevMax = new Vec3(this.min);
|
||||||
|
|
||||||
this.pooled = pooled;
|
this.pooled = pooled;
|
||||||
|
|
||||||
|
@ -105,13 +109,63 @@ export default class AABB {
|
||||||
return minZ <= maxZ ? maxZ - minZ : 0;
|
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) {
|
public move(xOrVec3:Vec3 | number, y?:number, z?:number) {
|
||||||
if (this.pooled) {
|
if (this.pooled) {
|
||||||
throw new Error(`Attempted to move a pooled AABB. This is not allowed!`);
|
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.min.set(this.initMin);
|
||||||
this.max.set(this.initMax);
|
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) {
|
if (xOrVec3 instanceof Vec3) {
|
||||||
this.min.add(xOrVec3);
|
this.min.add(xOrVec3);
|
||||||
this.max.add(xOrVec3);
|
this.max.add(xOrVec3);
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { World } from "./World";
|
||||||
|
|
||||||
export class Chunk {
|
export class Chunk {
|
||||||
private readonly MAX_HEIGHT:number = 128;
|
private readonly MAX_HEIGHT:number = 128;
|
||||||
|
private readonly FULLBRIGHT = false;
|
||||||
public readonly world:World;
|
public readonly world:World;
|
||||||
public readonly x:number;
|
public readonly x:number;
|
||||||
public readonly z:number;
|
public readonly z:number;
|
||||||
|
@ -65,6 +66,18 @@ export class Chunk {
|
||||||
}
|
}
|
||||||
|
|
||||||
public calculateLighting() {
|
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;
|
let blockId = 0;
|
||||||
for (let x = 0; x < 16; x++) {
|
for (let x = 0; x < 16; x++) {
|
||||||
for (let z = 0; z < 16; z++) {
|
for (let z = 0; z < 16; z++) {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import { HillyGenerator } from "./generators/Hilly";
|
||||||
import { NetherGenerator } from "./generators/Nether";
|
import { NetherGenerator } from "./generators/Nether";
|
||||||
import { PacketWindowItems } from "./packets/WindowItems";
|
import { PacketWindowItems } from "./packets/WindowItems";
|
||||||
import { getRandomValues } from "crypto";
|
import { getRandomValues } from "crypto";
|
||||||
|
import { NewOverworld } from "./generators/NewOverworld";
|
||||||
|
|
||||||
const chunkFrom = -15;
|
const chunkFrom = -15;
|
||||||
const chunkTo = 15;
|
const chunkTo = 15;
|
||||||
|
@ -121,6 +122,7 @@ export class MinecraftServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.worlds = new FunkyArray<number, World>();
|
this.worlds = new FunkyArray<number, World>();
|
||||||
|
//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(0, new World(this.saveManager, 0, worldSeed, new HillyGenerator(worldSeed)));
|
||||||
this.worlds.set(-1, new World(this.saveManager, -1, worldSeed, new NetherGenerator(worldSeed)));
|
this.worlds.set(-1, new World(this.saveManager, -1, worldSeed, new NetherGenerator(worldSeed)));
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
moveEntity(motionX:number, motionY:number, motionZ:number) {
|
||||||
this.position.add(motionX, motionY, motionZ);
|
this.position.add(motionX, motionY, motionZ);
|
||||||
this.entityAABB.move(this.position);
|
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);
|
let blockAABB = this.getBlockAABBFor(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;
|
|
||||||
|
|
||||||
if (blockUnderEntity !== null) {
|
if (blockAABB !== null) {
|
||||||
this.moveEntityBlockPosRel.set(this.position);
|
this.moveEntityBlockPosRel.set(this.position);
|
||||||
this.moveEntityBlockPosRel.sub(Math.floor(this.position.x), Math.floor(this.position.y), Math.floor(this.position.z));
|
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.
|
// TODO: Handle X and Z collisions.
|
||||||
if (this.entityAABB.intersects(blockBoundingBox)) {
|
if (this.entityAABB.intersects(blockAABB)) {
|
||||||
const intersectionY = this.entityAABB.intersectionY(blockBoundingBox);
|
const intersectionY = this.entityAABB.intersectionY(blockAABB);
|
||||||
if (this.moveEntityBlockPosRel.y > 0.5) {
|
if (this.moveEntityBlockPosRel.y > 0.5) {
|
||||||
this.position.add(0, intersectionY, 0);
|
motionY = intersectionY;
|
||||||
} else {
|
} 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
83
server/generators/NewOverworld.ts
Normal file
83
server/generators/NewOverworld.ts
Normal file
|
@ -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 {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue