From 49ebe2d6aabc23180b6f7624cf3eab2869d1073c Mon Sep 17 00:00:00 2001 From: etienne Date: Tue, 14 Jan 2025 19:00:41 +0000 Subject: [PATCH] refactor(biomes): conf preprocess + renaming --- src/factory/ChunksFactory.ts | 10 +-- src/processing/BlocksProcessing.ts | 2 +- src/processing/GroundPatch.ts | 26 ++++---- src/processing/ItemsProcessing.ts | 25 +++----- src/processing/TaskProcessing.ts | 6 +- src/procgen/Biome.ts | 100 ++++++++++++++++++++--------- src/utils/misc.ts | 8 +-- src/utils/types.ts | 16 ++--- 8 files changed, 115 insertions(+), 78 deletions(-) diff --git a/src/factory/ChunksFactory.ts b/src/factory/ChunksFactory.ts index b2ff3cb..b85bf2e 100644 --- a/src/factory/ChunksFactory.ts +++ b/src/factory/ChunksFactory.ts @@ -32,19 +32,19 @@ export class GroundChunk extends ChunkContainer { const undegroundDepth = 4 const bedrock = this.dataEncoder(BlockType.BEDROCK) const bedrockIce = this.dataEncoder(BlockType.ICE) - const { biome, landscapeIndex, flags } = block.data + const { biome, landIndex, flags } = block.data const blockLocalPos = block.localPos as Vector3 - const landscapeConf = Biome.instance.mappings[biome].nth(landscapeIndex) - const groundConf = landscapeConf.data + const biomeLand = Biome.instance.mappings[biome].nth(landIndex) + const landConf = biomeLand.data const groundFlags = parseGroundFlags(flags) const blockType = - highlightPatchBorders(blockLocalPos, groundConf.type) || groundConf.type + highlightPatchBorders(blockLocalPos, landConf.type) || landConf.type const blockMode = groundFlags.boardMode ? BlockMode.CHECKERBOARD : BlockMode.REGULAR const groundSurface = this.dataEncoder(blockType, blockMode) const undergroundLayer = this.dataEncoder( - groundConf.subtype || BlockType.BEDROCK, + landConf.subtype || BlockType.BEDROCK, ) // generate ground buffer const buffSize = MathUtils.clamp(block.data.level - ymin, 0, ymax - ymin) diff --git a/src/processing/BlocksProcessing.ts b/src/processing/BlocksProcessing.ts index 482c1f2..ac7d3e5 100644 --- a/src/processing/BlocksProcessing.ts +++ b/src/processing/BlocksProcessing.ts @@ -336,7 +336,7 @@ export class BlocksProcessing extends ProcessingTask { override async process(processingParams = defaultProcessingParams) { const { recipe } = processingParams const pendingBlocks = this.input.map(async pos => { - const groundPatch = this.getGroundPatch(pos) + const groundPatch = this.getGroundPatch(asVect2(pos)) const blockProcessor = new BlockProcessor(pos, groundPatch) const block = await blockProcessor.bakeRecipe(recipe) return block as Block diff --git a/src/processing/GroundPatch.ts b/src/processing/GroundPatch.ts index 8248c71..76c9a9f 100644 --- a/src/processing/GroundPatch.ts +++ b/src/processing/GroundPatch.ts @@ -2,7 +2,7 @@ import { Box2, Vector2, Vector3 } from 'three' import { GroundBlock, - LandscapesConf, + BiomeLands, PatchBlock, PatchBoundId, PatchKey, @@ -31,7 +31,8 @@ export type GroundBlockData = { // rawVal: number, level: number biome: BiomeType - landscapeIndex: number + landIndex: number + landId?: string flags: number } @@ -44,7 +45,7 @@ export type GroundPatchStub = PatchStub & { const BitAllocation = { level: 9, // level values ranging from 0 to 512 biome: 4, // 16 biomes - landscapeIndex: 5, // 32 landscapes per biome + landIndex: 5, // 32 landscapes per biome flags: 3, // 8 additional flags } @@ -93,30 +94,28 @@ export class GroundPatch decodeBlockData(rawData: number) { const shift = BitAllocation const level = - (rawData >> (shift.biome + shift.landscapeIndex + shift.flags)) & + (rawData >> (shift.biome + shift.landIndex + shift.flags)) & ((1 << shift.level) - 1) const biomeNum = - (rawData >> (shift.landscapeIndex + shift.flags)) & - ((1 << shift.biome) - 1) + (rawData >> (shift.landIndex + shift.flags)) & ((1 << shift.biome) - 1) const biome = ReverseBiomeNumericType[biomeNum] || BiomeType.Temperate - const landscapeIndex = - (rawData >> shift.flags) & ((1 << shift.landscapeIndex) - 1) + const landIndex = (rawData >> shift.flags) & ((1 << shift.landIndex) - 1) const flags = rawData & ((1 << shift.flags) - 1) const blockData: GroundBlockData = { level, biome, - landscapeIndex, + landIndex, flags, } return blockData } encodeBlockData(groundData: GroundBlockData): number { - const { level, biome, landscapeIndex, flags } = groundData + const { level, biome, landIndex, flags } = groundData const shift = BitAllocation let blockRawVal = level blockRawVal = (blockRawVal << shift.biome) | BiomeNumericType[biome] - blockRawVal = (blockRawVal << shift.landscapeIndex) | landscapeIndex + blockRawVal = (blockRawVal << shift.landIndex) | landIndex blockRawVal = (blockRawVal << shift.flags) | (flags || BlockMode.REGULAR) return blockRawVal } @@ -277,7 +276,7 @@ export class GroundPatch const nominalConf = Biome.instance.getBiomeConf( rawVal, biomeType, - ) as LandscapesConf + ) as BiomeLands // const confIndex = Biome.instance.getConfIndex(currLevelConf.key) // const confData = Biome.instance.indexedConf.get(confIndex) const level = Heightmap.instance.getGroundLevel( @@ -320,7 +319,8 @@ export class GroundPatch const groundBlockData: GroundBlockData = { level, biome: biomeType, - landscapeIndex: usedConf.index, + landIndex: usedConf.index, + landId: usedConf.data.key, flags, } return groundBlockData diff --git a/src/processing/ItemsProcessing.ts b/src/processing/ItemsProcessing.ts index e8a773d..ad86402 100644 --- a/src/processing/ItemsProcessing.ts +++ b/src/processing/ItemsProcessing.ts @@ -1,4 +1,4 @@ -import { Box2, Box3, Vector2, Vector3 } from 'three' +import { Box2, Box3, Vector3 } from 'three' import { ChunkContainer, ChunkStub } from '../datacontainers/ChunkContainer' import { @@ -47,10 +47,10 @@ const getPatchBounds = (boundsOrPatchKey: Box2 | PatchKey) => { // takes const adjustHeight = async (itemChunk: ChunkContainer) => { - const chunkBottomBlocks: Vector2[] = [] + const chunkBottomBlocks: Vector3[] = [] // iter slice blocks for (const heightBuff of itemChunk.iterChunkSlice()) { - if (heightBuff.data[0]) chunkBottomBlocks.push(heightBuff.pos) + if (heightBuff.data[0]) chunkBottomBlocks.push(asVect3(heightBuff.pos, 0)) } // compute blocks batch to find lowest element const blocksBatch = new BlocksProcessing(chunkBottomBlocks) @@ -71,28 +71,23 @@ export const retrieveOvergroundItems = (patchBounds: Box2) => { const groundPatch = new GroundPatch(patchBounds) groundPatch.preprocess() + // take approximative item dimension until item type is known const spawnedItems: Record = {} const spawnPlaces = defaultSpawnMap.querySpawnLocations( patchBounds, asVect2(defaultItemDims), ) for (const pos of spawnPlaces) { - const { level, biome, landscapeIndex } = groundPatch.computeGroundBlock( + // console.log(pos) + const { level, biome, landId } = groundPatch.computeGroundBlock( asVect3(pos), ) - const weightedTypes = - Biome.instance.mappings[biome]?.nth(landscapeIndex)?.data?.flora - if (weightedTypes) { - const spawnableTypes: ItemType[] = [] - Object.entries(weightedTypes).forEach(([itemType, typeWeight]) => { - while (typeWeight > 0) { - spawnableTypes.push(itemType) - typeWeight-- - } - }) + const { floraItems } = + Biome.instance.getBiomeLandConf(biome, landId as string) || {} + if (floraItems && floraItems?.length > 0) { const itemType = defaultSpawnMap.getSpawnedItem( pos, - spawnableTypes, + floraItems, ) as ItemType if (itemType) { spawnedItems[itemType] = spawnedItems[itemType] || [] diff --git a/src/processing/TaskProcessing.ts b/src/processing/TaskProcessing.ts index 5262243..56edf30 100644 --- a/src/processing/TaskProcessing.ts +++ b/src/processing/TaskProcessing.ts @@ -152,7 +152,7 @@ export class ProcessingTask { ? ProcessingState.Done : this.processingState // this.pendingTask = null - this.onTaskProcessed(taskRes) + // this.onTaskProcessed(taskRes) this.resolveDeferredPromise(taskRes) return taskRes // this.reconcile(stubs) } @@ -214,9 +214,9 @@ export class ProcessingTask { console.log(processingParams) } - onTaskProcessed(taskRes: any) { + // onTaskProcessed(taskRes: any) { - } + // } // toStub(): any { // const { stubs } = this diff --git a/src/procgen/Biome.ts b/src/procgen/Biome.ts index 8cad19c..c3ef354 100644 --- a/src/procgen/Biome.ts +++ b/src/procgen/Biome.ts @@ -4,11 +4,11 @@ import { smoothstep } from 'three/src/math/MathUtils' import { LinkedList } from '../datacontainers/LinkedList' import { - BiomeLandscapeKey, + BiomeLandKey, BiomesConf, BiomesRawConf, - LandscapeFields, - LandscapesConf, + LandConfigFields, + BiomeLands, } from '../utils/types' import { WorldEnv } from '../index' import { clamp, roundToDec } from '../utils/math' @@ -18,6 +18,7 @@ import { typesNumbering, } from '../utils/misc' import { asVect3 } from '../utils/convert' +import { ItemType } from '../factory/ItemsFactory' import { ProcLayer } from './ProcLayer' @@ -135,6 +136,29 @@ const BiomesMapping: Record> = { }, } +/** + * weightedFloraTypes: weighted item types which are supposed to spawn + * at given location + */ +const expandWeightedFloraTypes = ( + weightedFloraTypes: Record, +) => { + const floraTypes: ItemType[] = [] + if (weightedFloraTypes) { + Object.entries(weightedFloraTypes).forEach(([itemType, typeWeight]) => { + while (typeWeight > 0) { + floraTypes.push(itemType) + typeWeight-- + } + }) + } + return floraTypes +} + +type PreprocessedLandConf = { + floraItems: ItemType[] +} + /** * assign block types: water, sand, grass, mud, rock, snow, .. */ @@ -166,7 +190,7 @@ export class Biome { high: 0.7, } - indexedConf = new Map() + preprocessed = new Map() constructor() { this.heatmap = new ProcLayer('heatmap') @@ -289,68 +313,80 @@ export class Biome { return biomeContribs } + preprocessLandConfig( + biomeType: BiomeType, + biomeConfig: LinkedList, + ) { + const configs = biomeConfig.first().forwardIter() + for (const conf of configs) { + const landConf = conf.data + const confKey = biomeType + '_' + landConf.key + // console.log(confKey) + const floraItems = landConf.flora + ? expandWeightedFloraTypes(landConf.flora) + : [] + this.preprocessed.set(confKey, { + floraItems, + }) + // this.indexedConf.set(conf.data.key, conf) + } + } + parseBiomesConfig(biomesRawConf: BiomesRawConf) { - // Object.entries(biomeConfigs).forEach(([biomeType, biomeConf]) => { // complete missing data - for (const [biomeType, biomeConf] of Object.entries(biomesRawConf)) { - // for (const [landId, landConf] of Object.entries(biomeConf)) { - // landConf.key = biomeType + '_' + landId - // } - - const configItems = Object.values(biomeConf) as LandscapeFields[] + for (const [biomeType, biomeLands] of Object.entries(biomesRawConf)) { + for (const [landId, landConf] of Object.entries(biomeLands)) { + landConf.key = landId + } + const configItems = Object.values(biomeLands) as LandConfigFields[] const mappingRanges = LinkedList.fromArrayAfterSorting( configItems, MappingRangeSorter, ) this.mappings[biomeType as BiomeType] = mappingRanges - // index configs - // const confIter = mappingRanges.first().forwardIter() - // for (const conf of confIter) { - // this.indexedConf.set(conf.data.key, conf) - // } + this.preprocessLandConfig(biomeType as BiomeType, mappingRanges) } - // }) } landscapeTransition = ( groundPos: Vector2, baseHeight: number, - landscapeConf: LandscapesConf, + biomeLands: BiomeLands, ) => { const period = 0.005 * Math.pow(2, 2) const mapCoords = groundPos.clone().multiplyScalar(period) const posRandomizerVal = this.posRandomizer.eval(asVect3(mapCoords)) // add some height variations to break painting monotony - const { amplitude }: any = landscapeConf.data + const { amplitude }: any = biomeLands.data const bounds = { - lower: landscapeConf.data.x, - upper: landscapeConf.next?.data.x || 1, + lower: biomeLands.data.x, + upper: biomeLands.next?.data.x || 1, } let blockType // randomize on lower side if ( - landscapeConf.prev && + biomeLands.prev && baseHeight - bounds.lower <= bounds.upper - baseHeight && baseHeight - amplitude.low < bounds.lower ) { const heightVariation = posRandomizerVal * amplitude.low const varyingHeight = baseHeight - heightVariation blockType = - varyingHeight < landscapeConf.data.x - ? landscapeConf.prev?.data.type - : landscapeConf.data.type + varyingHeight < biomeLands.data.x + ? biomeLands.prev?.data.type + : biomeLands.data.type } // randomize on upper side - else if (landscapeConf.next && baseHeight + amplitude.high > bounds.upper) { + else if (biomeLands.next && baseHeight + amplitude.high > bounds.upper) { // let heightVariation = // Utils.clamp(this.paintingRandomness.eval(groundPos), 0.5, 1) * randomness.high // heightVariation = heightVariation > 0 ? (heightVariation - 0.5) * 2 : 0 const heightVariation = posRandomizerVal * amplitude.high const varyingHeight = baseHeight + heightVariation blockType = - varyingHeight > landscapeConf.next.data.x - ? landscapeConf.next.data.type - : landscapeConf.data.type + varyingHeight > biomeLands.next.data.x + ? biomeLands.next.data.type + : biomeLands.data.type } return blockType } @@ -387,6 +423,12 @@ export class Biome { return blockLevel } + getBiomeLandConf = (biomeType: BiomeType, landId: string) => { + const confKey = biomeType + '_' + landId + const biomeConf = this.preprocessed.get(confKey) + return biomeConf + } + getBiomeConf = (rawVal: number, biomeType: BiomeType) => { const firstItem = this.mappings[biomeType] const confId = findMatchingRange(rawVal as number, firstItem) diff --git a/src/utils/misc.ts b/src/utils/misc.ts index 39a6896..6777c7a 100644 --- a/src/utils/misc.ts +++ b/src/utils/misc.ts @@ -1,9 +1,9 @@ -import { LandscapeFields, LandscapesConf } from './types' +import { BiomeLands, LandConfigFields } from './types' // const MappingRangeFinder = (item: LinkedList, inputVal: number) => item.next && inputVal > (item.next.data as MappingData).x export const MappingRangeSorter = ( - item1: LandscapeFields, - item2: LandscapeFields, + item1: LandConfigFields, + item2: LandConfigFields, ) => item1.x - item2.x /** @@ -13,7 +13,7 @@ export const MappingRangeSorter = ( */ export const findMatchingRange = ( inputVal: number, - noiseMappings: LandscapesConf, + noiseMappings: BiomeLands, ) => { let match = noiseMappings.first() let i = 1 diff --git a/src/utils/types.ts b/src/utils/types.ts index 030a058..c0a9268 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -152,11 +152,11 @@ export type ChunkIndex = Record // MOUNTAINS_TOP, // } -export type LandscapeId = string // landscape id assigned to noise level -export type BiomeLandscapeKey = string // combination of biomeType and LandscapeId +export type LandConfigId = string // landscape id assigned to noise level +export type BiomeLandKey = string // combination of BiomeType and LandId -export type LandscapeFields = { - key: BiomeLandscapeKey +export type LandConfigFields = { + key: BiomeLandKey x: number // noise value y: number // height noise mapping type: BlockType // ground surface @@ -168,7 +168,7 @@ export type LandscapeFields = { } // Biome landscapes mappings -export type LandscapesRawConf = Record> -export type BiomesRawConf = Record -export type LandscapesConf = LinkedList -export type BiomesConf = Record +export type BiomeLandsRawConf = Record> +export type BiomesRawConf = Record +export type BiomeLands = LinkedList +export type BiomesConf = Record