#include "DimensionGenerator.h" #include #include #include #include "Constants.h" #include "Dimension.h" #include "Game.h" #include "NoBlock.h" #include "Noise.h" #include "RandNoise.h" #include "WormCaveGenerator.h" WorldHeightLayer::WorldHeightLayer() : ReferenceCounter(), noiseConfig(0), noise(0), value(0) {} WorldHeightLayer::~WorldHeightLayer() { if (noiseConfig) noiseConfig->release(); if (noise) noise->release(); if (value) value->release(); } void WorldHeightLayer::initialize(JExpressionMemory* zMemory) { if (noise) noise->release(); noise = JNoise::parseNoise(noiseConfig, zMemory); zMemory->setNoise(name, dynamic_cast(noise->getThis())); } void WorldHeightLayer::calculateValue(JExpressionMemory* zMemory) { zMemory->setFloatVariable(name, value->getValue(zMemory)); } void WorldHeightLayer::setNoiseConfig(Framework::JSON::JSONObject* noiseConfig) { if (this->noiseConfig) this->noiseConfig->release(); this->noiseConfig = noiseConfig; } Framework::JSON::JSONObject* WorldHeightLayer::zNoiseConfig() const { return noiseConfig; } void WorldHeightLayer::setName(Framework::Text name) { this->name = name; } Framework::Text WorldHeightLayer::getName() const { return name; } void WorldHeightLayer::setValue(JFloatExpression* value) { if (this->value) this->value->release(); this->value = value; } JFloatExpression* WorldHeightLayer::zValue() const { return value; } WorldHeightLayerFactory::WorldHeightLayerFactory() {} WorldHeightLayer* WorldHeightLayerFactory::createValue( Framework::JSON::JSONObject* zJson) const { return new WorldHeightLayer(); } void WorldHeightLayerFactory::fromJson( WorldHeightLayer* zResult, Framework::JSON::JSONObject* zJson) const { zResult->setName(zJson->zValue("name")->asString()->getString()); zResult->setNoiseConfig(zJson->getValue("noise")->asObject()); zResult->setValue( Game::INSTANCE->zTypeRegistry()->fromJson( zJson->zValue("value"))); } void WorldHeightLayerFactory::toJson( WorldHeightLayer* zObject, Framework::JSON::JSONObject* zResult) const { zResult->addValue( "name", new Framework::JSON::JSONString(zObject->getName())); zResult->addValue("noise", zObject->zNoiseConfig()); zResult->addValue("value", Game::INSTANCE->zTypeRegistry()->toJson( zObject->zValue())); } JSONObjectValidationBuilder* WorldHeightLayerFactory::addToValidator( JSONObjectValidationBuilder* builder) const { return builder->withRequiredString("name") ->finishString() ->withRequiredAttribute("noise", JNoise::getValidator(false)) ->withRequiredAttribute("value", Game::INSTANCE->zTypeRegistry()->getValidator()); } DimensionGenerator::DimensionGenerator() : ReferenceCounter(), jExpressionMemory(new JExpressionMemory()), seedExpression(0), dimensionId(0) {} DimensionGenerator::~DimensionGenerator() { jExpressionMemory->release(); if (seedExpression) seedExpression->release(); } JExpressionMemory* DimensionGenerator::zMemory() const { return jExpressionMemory; } void DimensionGenerator::calculateHeightLayers() { for (WorldHeightLayer* layer : heightLayers) { layer->calculateValue(jExpressionMemory); } } Dimension* DimensionGenerator::createDimension() { return new Dimension(getId()); } void DimensionGenerator::initialize(int worldSeed) { jExpressionMemory->setFloatVariable("worldSeed", (float)worldSeed); jExpressionMemory->setFloatVariable( "dimensionSeed", seedExpression->getValue(jExpressionMemory)); for (WorldHeightLayer* layer : heightLayers) { layer->initialize(jExpressionMemory); } } int DimensionGenerator::getDimensionId() const { return dimensionId; } void DimensionGenerator::addHeightLayer(WorldHeightLayer* layer) { heightLayers.add(layer); } const Framework::RCArray& DimensionGenerator::getHeightLayers() const { return heightLayers; } void DimensionGenerator::setName(Framework::Text name) { this->name = name; } Framework::Text DimensionGenerator::getName() const { return name; } void DimensionGenerator::setId(int id) { dimensionId = id; } int DimensionGenerator::getId() const { return dimensionId; } void DimensionGenerator::setSeed(JFloatExpression* seed) { if (seedExpression) seedExpression->release(); seedExpression = seed; } JFloatExpression* DimensionGenerator::zSeed() const { return seedExpression; } BiomedCavedDimensionGenerator::BiomedCavedDimensionGenerator() : DimensionGenerator(), caveGenerator(0), noiseConfig(0), biomNoise(0) {} BiomedCavedDimensionGenerator::~BiomedCavedDimensionGenerator() { if (noiseConfig) noiseConfig->release(); if (biomNoise) biomNoise->release(); if (caveGenerator) caveGenerator->release(); } void BiomedCavedDimensionGenerator::initialize(int worldSeed) { if (biomNoise) biomNoise->release(); if (caveGenerator) caveGenerator->release(); DimensionGenerator::initialize(worldSeed); biomNoise = JNoise::parseNoise(noiseConfig, zMemory()); for (BiomGenerator* gen : biomGenerators) { gen->initialize(zMemory()); } caveGenerator = new WormCaveGenerator(75, 150, 1, 6, 0.1f, worldSeed - 1); } BiomGenerator* BiomedCavedDimensionGenerator::zBiomGenerator() { for (BiomGenerator* generator : biomGenerators) { if (generator->isApplicable(zMemory())) return generator; } return 0; } Framework::RCArray* BiomedCavedDimensionGenerator::getGeneratedStructoresForArea( Framework::Vec3 minPos, Framework::Vec3 maxPos) { int minSearchX = minPos.x - maxStructureOffset.x; int minSearchY = minPos.y - maxStructureOffset.y; int minSearchZ = MAX(minPos.z - maxStructureOffset.z, 0); int maxSearchX = maxPos.x - minStructureOffset.x; int maxSearchY = maxPos.y - minStructureOffset.y; int maxSearchZ = MIN(maxPos.z - minStructureOffset.z, WORLD_HEIGHT - 1); Framework::RCArray* result = new Framework::RCArray(); for (int x = minSearchX; x <= maxSearchX; x++) { for (int y = minSearchY; y <= maxSearchY; y++) { zMemory()->setFloatVariable("x", (float)x); zMemory()->setFloatVariable("y", (float)y); calculateHeightLayers(); BiomGenerator* gen = zBiomGenerator(); for (int z = minSearchZ; z <= maxSearchZ; z++) { zMemory()->setFloatVariable("z", (float)z); gen->generateStructures(x, y, z, getDimensionId(), zMemory(), minPos, maxPos, result); } } } return result; } Chunk* BiomedCavedDimensionGenerator::generateChunk(int centerX, int centerY) { zMemory()->lock(); Framework::Logging::debug() << "generating chunk " << centerX << ", " << centerY; double structureTime = 0; double structureTime2 = 0; double structureTime3 = 0; double caveTime = 0; double caveTime2 = 0; double blockGenTime = 0; double biomTime = 0; double layerTime = 0; Framework::ZeitMesser zm; Framework::ZeitMesser zmGlobal; zm.messungStart(); zmGlobal.messungStart(); Framework::RCArray* structures = getGeneratedStructoresForArea( Framework::Vec3( centerX - CHUNK_SIZE / 2, centerY - CHUNK_SIZE / 2, 0), Framework::Vec3(centerX + CHUNK_SIZE / 2, centerY + CHUNK_SIZE / 2, WORLD_HEIGHT - 1)); zm.messungEnde(); structureTime += zm.getSekunden(); zm.messungStart(); CaveChunkGenerator* caveGen = caveGenerator->getGeneratorForChunk(centerX, centerY); zm.messungEnde(); caveTime += zm.getSekunden(); Chunk* chunk = new Chunk(Framework::Punkt(centerX, centerY), getDimensionId()); zMemory()->setCurrentChunk(dynamic_cast(chunk->getThis())); for (int x = -CHUNK_SIZE / 2; x < CHUNK_SIZE / 2; x++) { for (int y = -CHUNK_SIZE / 2; y < CHUNK_SIZE / 2; y++) { zMemory()->setFloatVariable("x", (float)x + (float)centerX); zMemory()->setFloatVariable("y", (float)y + (float)centerY); // calculate height layers zm.messungStart(); calculateHeightLayers(); zm.messungEnde(); layerTime += zm.getSekunden(); // calculate biom zm.messungStart(); BiomGenerator* biom = zBiomGenerator(); zm.messungEnde(); biomTime += zm.getSekunden(); // generate blocks for (int z = 0; z < WORLD_HEIGHT; z++) { zMemory()->setFloatVariable("z", (float)z); Framework::Either generated = BlockTypeEnum::AIR; bool structureAffected = 0; // check if the block is inside of a structure zm.messungStart(); for (auto structure : *structures) { if (structure->isBlockAffected( Framework::Vec3(x + centerX, y + centerY, z))) { zm.messungEnde(); structureTime2 += zm.getSekunden(); zm.messungStart(); generated = structure->generateBlockAt( Framework::Vec3(x + centerX, y + centerY, z), getDimensionId()); structureAffected = 1; zm.messungEnde(); structureTime3 += zm.getSekunden(); zm.messungStart(); break; } } zm.messungEnde(); structureTime2 += zm.getSekunden(); if (!structureAffected) { // check if block is a cave block zm.messungStart(); bool inCave = caveGen->isInCave(x + centerX, y + centerY, z); zm.messungEnde(); caveTime2 += zm.getSekunden(); if (!inCave) { // generate biom block zm.messungStart(); generated = biom->generateBlock(x + centerX, y + centerY, z, getDimensionId(), zMemory(), chunk); zm.messungEnde(); blockGenTime += zm.getSekunden(); } } if (generated.isA()) chunk->putBlockAt( Framework::Vec3( x + CHUNK_SIZE / 2, y + CHUNK_SIZE / 2, z), generated); else chunk->putBlockTypeAt( Framework::Vec3( x + CHUNK_SIZE / 2, y + CHUNK_SIZE / 2, z), generated); } } } caveGen->release(); structures->release(); zmGlobal.messungEnde(); Framework::Logging::trace() << "structureGenerationTime: " << structureTime; Framework::Logging::trace() << "structure.isBlockAffected: " << structureTime2; Framework::Logging::trace() << "structure.generateBlockAt: " << structureTime3; Framework::Logging::trace() << "caveGenerationTime: " << caveTime; Framework::Logging::trace() << "caveEvaluationTime: " << caveTime2; Framework::Logging::trace() << "blockGenTime: " << blockGenTime; Framework::Logging::trace() << "biomTime: " << biomTime; Framework::Logging::trace() << "layerTime: " << layerTime; Framework::Logging::debug() << "totalTime: " << zmGlobal.getSekunden(); zMemory()->unlock(); return chunk; } void BiomedCavedDimensionGenerator::generateEntities(Chunk* zChunk) { zMemory()->lock(); zMemory()->setCurrentChunk(dynamic_cast(zChunk->getThis())); zMemory()->setFloatVariable("x", (float)zChunk->getCenter().x); zMemory()->setFloatVariable("y", (float)zChunk->getCenter().y); calculateHeightLayers(); BiomGenerator* biom = zBiomGenerator(); for (int x = -CHUNK_SIZE / 2; x < CHUNK_SIZE / 2; x++) { for (int y = -CHUNK_SIZE / 2; y < CHUNK_SIZE / 2; y++) { for (int z = 0; z < WORLD_HEIGHT; z++) { if (zChunk->getBlockTypeAt(Framework::Vec3(x, y, z)) == BlockTypeEnum::AIR) { zMemory()->setFloatVariable("x", (float)z); zMemory()->setFloatVariable("y", (float)z); zMemory()->setFloatVariable("z", (float)z); biom->generateEntities( x, y, z, getDimensionId(), zMemory()); } } } } zMemory()->unlock(); } Framework::Either BiomedCavedDimensionGenerator::generateBlock( Framework::Vec3 location) { Chunk* zChunk = Game::INSTANCE->zDimension(getDimensionId()) ->zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y)); if (!zChunk) { return BlockTypeEnum::NO_BLOCK; } zMemory()->lock(); zMemory()->setCurrentChunk(dynamic_cast(zChunk->getThis())); Framework::RCArray* structures = getGeneratedStructoresForArea(location, location); zMemory()->setFloatVariable("x", (float)location.x); zMemory()->setFloatVariable("y", (float)location.y); calculateHeightLayers(); BiomGenerator* biom = zBiomGenerator(); zMemory()->setFloatVariable("z", (float)location.z); for (auto structure : *structures) { if (structure->isBlockAffected(location)) { auto generated = structure->generateBlockAt(location, getDimensionId()); structures->release(); zMemory()->unlock(); return generated; } } structures->release(); Framework::Punkt chunkCenter = Game::getChunkCenter(location.x, location.y); CaveChunkGenerator* caveGen = caveGenerator->getGeneratorForChunk(chunkCenter.x, chunkCenter.y); if (caveGen->isInCave(location.x, location.y, location.z)) { caveGen->release(); zMemory()->unlock(); return BlockTypeEnum::AIR; } caveGen->release(); auto generated = biom->generateBlock(location.x, location.y, location.z, getDimensionId(), zMemory(), zChunk); zMemory()->unlock(); return generated; } bool BiomedCavedDimensionGenerator::spawnStructure( Framework::Vec3 location, std::function filter) { zMemory()->lock(); zMemory()->setFloatVariable("x", (float)location.x); zMemory()->setFloatVariable("y", (float)location.y); BiomGenerator* biom = zBiomGenerator(); zMemory()->unlock(); for (StructureTemplateCollection* tc : biom->getTemplates()) { for (GeneratorTemplate* t : tc->getStructures()) { if (filter(t)) { RandNoise noise((int)time(0)); GeneratedStructure* genStr = t->generateAt(location, &noise, getDimensionId()); if (genStr) { int minSearchX = location.x + t->getMinAffectedOffset().x; int minSearchY = location.y + t->getMinAffectedOffset().y; int minSearchZ = MAX(location.z + t->getMinAffectedOffset().z, 0); int maxSearchX = location.x + t->getMaxAffectedOffset().x; int maxSearchY = location.y + t->getMaxAffectedOffset().y; int maxSearchZ = MIN(location.z + t->getMaxAffectedOffset().z, WORLD_HEIGHT - 1); for (int x = minSearchX; x <= maxSearchX; x++) { for (int y = minSearchY; y <= maxSearchY; y++) { for (int z = minSearchZ; z <= maxSearchZ; z++) { if (genStr->isBlockAffected( Framework::Vec3(x, y, z))) { auto gen = genStr->generateBlockAt( Framework::Vec3(x, y, z), getDimensionId()); Game::INSTANCE->zDimension(getDimensionId()) ->placeBlock( Framework::Vec3(x, y, z), gen); } } } } genStr->release(); zMemory()->unlock(); return 1; } } } } return 0; } void BiomedCavedDimensionGenerator::addBiomGenerator( BiomGenerator* biomGenerator) { biomGenerators.add(biomGenerator); if (biomGenerators.getEintragAnzahl() == 1) { minStructureOffset = biomGenerator->getMinStructureOffset(); maxStructureOffset = biomGenerator->getMaxStructureOffset(); } else { Framework::Vec3 min = biomGenerator->getMinStructureOffset(); Framework::Vec3 max = biomGenerator->getMaxStructureOffset(); if (minStructureOffset.x > min.x) minStructureOffset.x = min.x; if (minStructureOffset.y > min.y) minStructureOffset.y = min.y; if (minStructureOffset.z > min.z) minStructureOffset.z = min.z; if (maxStructureOffset.x < max.x) maxStructureOffset.x = max.x; if (maxStructureOffset.y < max.y) maxStructureOffset.y = max.y; if (maxStructureOffset.z < max.z) maxStructureOffset.z = max.z; } } const Framework::RCArray& BiomedCavedDimensionGenerator::getBiomGenerators() const { return biomGenerators; } void BiomedCavedDimensionGenerator::setBiomNoiseConfig( Framework::JSON::JSONObject* biomNoiseConfig) { if (noiseConfig) noiseConfig->release(); noiseConfig = biomNoiseConfig; } Framework::JSON::JSONObject* BiomedCavedDimensionGenerator::zBiomNoiseConfig() const { return noiseConfig; } BiomedCavedDimensionGeneratorFactory::BiomedCavedDimensionGeneratorFactory() {} BiomedCavedDimensionGenerator* BiomedCavedDimensionGeneratorFactory::createValue( Framework::JSON::JSONObject* zJson) const { return new BiomedCavedDimensionGenerator(); } void BiomedCavedDimensionGeneratorFactory::fromJson( BiomedCavedDimensionGenerator* zResult, Framework::JSON::JSONObject* zJson) const { zResult->setBiomNoiseConfig(zJson->getValue("biomNoise")->asObject()); for (Framework::JSON::JSONValue* value : *zJson->zValue("bioms")->asArray()) { zResult->addBiomGenerator( Game::INSTANCE->zTypeRegistry()->fromJson(value)); } DimensionGeneratorFactory::fromJson(zResult, zJson); } void BiomedCavedDimensionGeneratorFactory::toJson( BiomedCavedDimensionGenerator* zObject, Framework::JSON::JSONObject* zResult) const { Framework::JSON::JSONArray* bioms = new Framework::JSON::JSONArray(); for (BiomGenerator* biom : zObject->getBiomGenerators()) { bioms->addValue( Game::INSTANCE->zTypeRegistry()->toJson(biom)); } zResult->addValue("bioms", bioms); zResult->addValue("biomNoise", dynamic_cast( zObject->zBiomNoiseConfig()->getThis())); DimensionGeneratorFactory::toJson(zObject, zResult); } JSONObjectValidationBuilder* BiomedCavedDimensionGeneratorFactory::addToValidator( JSONObjectValidationBuilder* builder) const { return DimensionGeneratorFactory::addToValidator( builder->withRequiredArray("bioms") ->addAcceptedTypeInArray( Game::INSTANCE->zTypeRegistry()->getValidator()) ->finishArray() ->withRequiredAttribute("biomNoise", JNoise::getValidator(false))); } Framework::Text BiomedCavedDimensionGeneratorFactory::getTypeToken() const { return "cavedBioms"; }