#include "DimensionGenerator.h" #include #include "Constants.h" #include "Game.h" #include "NoBlock.h" #include "Noise.h" #include "RandNoise.h" #include "WormCaveGenerator.h" DimensionGeneratorFactory::DimensionGeneratorFactory( Framework::Text name, int dimensionId) : ReferenceCounter(), name(name), dimensionId(dimensionId) {} Framework::Text DimensionGeneratorFactory::getName() const { return name; } int DimensionGeneratorFactory::getDimensionId() const { return dimensionId; } WorldHeightLayer::WorldHeightLayer( Framework::JSON::JSONValue* zConfig, JExpressionMemory* zMemory) : ReferenceCounter() { noise = JNoise::parseNoisse(zConfig->asObject()->zValue("noise"), zMemory); name = zConfig->asObject()->zValue("name")->asString()->getString(); value = JExpressionParser::parseFloatExpression( zConfig->asObject()->zValue("value")); zMemory->setNoise(name, dynamic_cast(noise->getThis())); } WorldHeightLayer::~WorldHeightLayer() { noise->release(); value->release(); } void WorldHeightLayer::calculateValue(JExpressionMemory* zMemory) { zMemory->setFloatVariable(name, value->getValue(zMemory)); } Framework::JSON::Validator::JSONValidator* WorldHeightLayer::getValidator() { return JSON::Validator::JSONValidator::buildForObject() ->withRequiredString("name") ->finishString() ->withRequiredAttribute("noise", JNoise::getValidator(false)) ->withRequiredAttribute("value", JExpressionParser::getFloatValidator()) ->finishObject(); } DimensionGenerator::DimensionGenerator( Framework::JSON::JSONValue* zConfig, int worldSeed) : ReferenceCounter(), jExpressionMemory(new JExpressionMemory()), dimensionId(dimensionId) { jExpressionMemory->setFloatVariable("worldSeed", (float)worldSeed); JFloatExpression* expr = JExpressionParser::parseFloatExpression( zConfig->asObject()->zValue("dimensionSeed")); jExpressionMemory->setFloatVariable( "dimensionSeed", expr->getValue(jExpressionMemory)); for (Framework::JSON::JSONValue* value : *zConfig->asObject()->zValue("heightLayers")->asArray()) { heightLayers.add(new WorldHeightLayer(value, jExpressionMemory)); } } DimensionGenerator::~DimensionGenerator() { jExpressionMemory->release(); } JExpressionMemory* DimensionGenerator::zMemory() const { return jExpressionMemory; } void DimensionGenerator::calculateHeightLayers() { for (WorldHeightLayer* layer : heightLayers) { layer->calculateValue(jExpressionMemory); } } int DimensionGenerator::getDimensionId() const { return dimensionId; } BiomedCavedDimensionGenerator::BiomedCavedDimensionGenerator( Framework::JSON::JSONValue* zConfig, int worldSeed) : DimensionGenerator(zConfig, worldSeed), caveGenerator(new WormCaveGenerator(75, 150, 1, 6, 0.1f, worldSeed - 1)) { biomNoise = JNoise::parseNoisse( zConfig->asObject()->zValue("biomNoise"), zMemory()); bool first = 1; for (Framework::JSON::JSONValue* value : *zConfig->asObject()->zValue("bioms")->asArray()) { BiomGenerator* gen = new BiomGenerator(value, zMemory()); biomGenerators.add(gen); if (first) { minStructureOffset = gen->getMinStructureOffset(); maxStructureOffset = gen->getMaxStructureOffset(); first = 0; } else { Framework::Vec3 min = gen->getMinStructureOffset(); Framework::Vec3 max = gen->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; } } } BiomedCavedDimensionGenerator::~BiomedCavedDimensionGenerator() { biomNoise->release(); caveGenerator->release(); } 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(); std::cout << "generating chunk " << centerX << ", " << centerY << "\n"; double structureTime = 0; double structureTime2 = 0; double structureTime3 = 0; double caveTime = 0; double caveTime2 = 0; double blockGenTime = 0; double biomTime = 0; double layerTime = 0; ZeitMesser zm; 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(); std::cout << "structureGenerationTime: " << structureTime << "\n"; std::cout << "structure.isBlockAffected: " << structureTime2 << "\n"; std::cout << "structure.generateBlockAt: " << structureTime3 << "\n"; std::cout << "caveGenerationTime: " << caveTime << "\n"; std::cout << "caveEvaluationTime: " << caveTime2 << "\n"; std::cout << "blockGenTime: " << blockGenTime << "\n"; std::cout << "biomTime: " << biomTime << "\n"; std::cout << "layerTime: " << layerTime << "\n"; std::cout << "totalTime: " << zmGlobal.getSekunden() << "\n"; zMemory()->unlock(); return chunk; } Framework::Either BiomedCavedDimensionGenerator::generateBlock( Framework::Vec3 location) { zMemory()->lock(); Chunk* zChunk = Game::INSTANCE->zDimension(getDimensionId()) ->zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y)); zMemory()->setCurrentChunk(dynamic_cast(zChunk->getThis())); Framework::RCArray* structures = getGeneratedStructoresForArea(location, location); zMemory()->setFloatVariable("x", (float)location.x); zMemory()->setFloatVariable("y", (float)location.y); 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(); 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; }