#include "WorldGenerator.h" #include #include #include "Game.h" #include "NoiseInterpolator.h" #include "OverworldDimension.h" using namespace Framework; using namespace Framework::JSON; using namespace Framework::JSON::Validator; WorldGenerator::WorldGenerator(int seed) : Thread(), exit(0), seed(seed) { setName("World Generator"); std::cout << "loading world generator configs. Changes at the config giles " "may lead to a sudden change in landscape.\n"; JSONValidator* validator = buildConfigValidator(); loadConfig("data/generator", validator); validator->release(); addMissingDimensions(); start(); } WorldGenerator::~WorldGenerator() {} Framework::JSON::Validator::JSONValidator* WorldGenerator::buildConfigValidator() { JSONValidator* configValidator = JSONValidator::buildForArray() ->removeInvalidEntries() ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry() ->getDimensionGeneratorValidator()) ->finishArray(); Datei syntaxFile(new Text("data/syntax/generatorValidation.xml")); syntaxFile.erstellen(); Text syntaxContent = configValidator->zConstraints()->toString(); syntaxFile.open(Datei::Style::schreiben); syntaxFile.schreibe(syntaxContent, syntaxContent.getLength()); syntaxFile.close(); return configValidator; } void WorldGenerator::loadConfig( const char* path, Framework::JSON::Validator::JSONValidator* zValidator) { std::cout << "loading dimension configs from '" << path << "'" << std::endl; Datei file(new Text(path)); if (file.istOrdner()) { RCArray* fileNames = file.getDateiListe(); if (fileNames) { for (Text* name : *fileNames) { loadConfig(Text(path) + "/" + *name, zValidator); } fileNames->release(); } } else { JSONValue* json = loadJSONFromFile(path); if (!json) { std::cout << "ERROR: the file does not contain valid json\n"; } else { Framework::RCArray invalidParts; JSONValue* valid = zValidator->getValidParts(json, &invalidParts); for (JSONValidationResult* invalidPart : invalidParts) { invalidPart->printInvalidInfo(); } json->release(); if (valid) { for (JSONValue* config : *valid->asArray()) loadDimensionConfig(config); valid->release(); } } } } void WorldGenerator::loadDimensionConfig(Framework::JSON::JSONValue* zConfig) { DimensionGenerator* generator = Game::INSTANCE->zTypeRegistry()->createDimensionGenerator( zConfig, seed); if (generator) { dimensionGenerators.add(generator); } else { std::cout << "ERROR: could not find dimension factory for config \n" << zConfig->toString() << "\n"; } } void WorldGenerator::addMissingDimensions() { for (DimensionGeneratorFactory* factory : Game::INSTANCE->zTypeRegistry()->getDimensionGeneratorFactories()) { bool found = 0; for (DimensionGenerator* generator : dimensionGenerators) { if (generator->getDimensionId() == factory->getDimensionId()) { found = 1; break; } } if (!found) { std::cout << "WARNING: missing config for dimension '" << factory->getName() << "' with id " << factory->getDimensionId() << ". Default config will be used."; JSONValue* defaultConfig = factory->getDefaultConfig(); Datei file(new Text( Text("data/generator/") + factory->getName() + ".json")); if (!file.existiert()) { file.erstellen(); file.open(Datei::Style::schreiben); Text conficContent = Text("[") + defaultConfig->toString() + "]"; file.schreibe(conficContent, conficContent.getLength()); file.close(); std::cout << "Default config was written to '" << *file.zPfad() << "'\n"; } loadDimensionConfig(defaultConfig); defaultConfig->release(); } } } DimensionGenerator* WorldGenerator::zGenerator(int dimensionId) { for (DimensionGenerator* generator : dimensionGenerators) { if (generator->getDimensionId() == dimensionId) return generator; } return 0; } void WorldGenerator::thread() { while (!exit) { cs.lock(); Area next; bool hasNext = 0; if (requestQueue.getEintragAnzahl() > 0) { next = requestQueue.get(0); requestQueue.remove(0); hasNext = 1; } cs.unlock(); if (!hasNext) { Sleep(1000); continue; } Punkt start = Game::INSTANCE->getChunkCenter(next.startX, next.startY); Punkt end = Game::INSTANCE->getChunkCenter(next.endX, next.endY); int xDir = start.x > end.x ? -1 : 1; int yDir = start.y > end.y ? -1 : 1; for (int x = start.x; xDir < 0 ? x >= end.x : x <= end.x; x += CHUNK_SIZE * xDir) { for (int y = start.y; yDir < 0 ? y >= end.y : y <= end.y; y += CHUNK_SIZE * yDir) { if (!Game::INSTANCE->doesChunkExist(x, y, next.dimensionId)) { Chunk* generatedChunk = zGenerator(next.dimensionId)->generateChunk(x, y); ZeitMesser zm; zm.messungStart(); generatedChunk->initializeLightning(); zm.messungEnde(); std::cout << "light calculation: " << zm.getSekunden() << "\n"; zm.messungStart(); generatedChunk->removeUnusedBlocks(); zm.messungEnde(); std::cout << "unused block removal: " << zm.getSekunden() << "\n"; zm.messungStart(); Dimension* dim = Game::INSTANCE->zDimension(next.dimensionId); if (!dim) { dim = new Dimension(next.dimensionId); Game::INSTANCE->addDimension(dim); } dim->setChunk(generatedChunk, Punkt(x, y)); zm.messungEnde(); std::cout << "adding chunk to map: " << zm.getSekunden() << "\n"; } } } } std::cout << "World Generator thread exited\n"; } void WorldGenerator::requestGeneration(Area request) { cs.lock(); requestQueue.add(request); cs.unlock(); } void WorldGenerator::exitAndWait() { exit = 1; warteAufThread(10000); ende(); } Framework::Either WorldGenerator::generateSingleBlock( Framework::Vec3 location, int dimensionId) { return zGenerator(dimensionId)->generateBlock(location); } bool WorldGenerator::spawnStructure(Framework::Vec3 location, int dimensionId, std::function filter) { return zGenerator(dimensionId)->spawnStructure(location, filter); }