v1.4.4
This commit is contained in:
commit
9c94d113d3
10260 changed files with 1237388 additions and 0 deletions
233
source/game/StarBiomeDatabase.cpp
Normal file
233
source/game/StarBiomeDatabase.cpp
Normal file
|
@ -0,0 +1,233 @@
|
|||
#include "StarBiomeDatabase.hpp"
|
||||
#include "StarRoot.hpp"
|
||||
#include "StarJsonExtra.hpp"
|
||||
#include "StarStoredFunctions.hpp"
|
||||
#include "StarParallax.hpp"
|
||||
#include "StarAmbient.hpp"
|
||||
#include "StarMaterialDatabase.hpp"
|
||||
#include "StarAssets.hpp"
|
||||
#include "StarSpawnTypeDatabase.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
BiomeDatabase::BiomeDatabase() {
|
||||
auto assets = Root::singleton().assets();
|
||||
|
||||
// 'type' here is the extension of the file, and determines the selector type
|
||||
auto scanFiles = [=](String const& type, ConfigMap& map) {
|
||||
auto files = assets->scanExtension(type);
|
||||
assets->queueJsons(files);
|
||||
for (auto path : files) {
|
||||
auto parameters = assets->json(path);
|
||||
if (parameters.isNull())
|
||||
continue;
|
||||
|
||||
auto name = parameters.getString("name");
|
||||
if (map.contains(name))
|
||||
throw BiomeException(strf("Duplicate %s generator name '%s'", type, name));
|
||||
map[name] = {path, name, parameters};
|
||||
}
|
||||
};
|
||||
|
||||
scanFiles("biome", m_biomes);
|
||||
scanFiles("weather", m_weathers);
|
||||
}
|
||||
|
||||
StringList BiomeDatabase::biomeNames() const {
|
||||
return m_biomes.keys();
|
||||
}
|
||||
|
||||
float BiomeDatabase::biomeHueShift(String const& biomeName, uint64_t seed) const {
|
||||
auto const& config = m_biomes.get(biomeName);
|
||||
return pickHueShiftFromJson(config.parameters.get("hueShiftOptions", {}), seed, "BiomeHueShift");
|
||||
}
|
||||
|
||||
WeatherPool BiomeDatabase::biomeWeathers(String const& biomeName, uint64_t seed, float threatLevel) const {
|
||||
WeatherPool weatherPool;
|
||||
if (auto weatherList = binnedChoiceFromJson(m_biomes.get(biomeName).parameters.get("weather", JsonArray{}), threatLevel).optArray()) {
|
||||
auto weatherPoolPath = staticRandomFrom(*weatherList, seed, "WeatherPool");
|
||||
|
||||
auto assets = Root::singleton().assets();
|
||||
auto weatherPoolConfig = assets->fetchJson(weatherPoolPath);
|
||||
weatherPool = jsonToWeightedPool<String>(weatherPoolConfig);
|
||||
}
|
||||
|
||||
return weatherPool;
|
||||
}
|
||||
|
||||
bool BiomeDatabase::biomeIsAirless(String const& biomeName) const {
|
||||
auto const& config = m_biomes.get(biomeName);
|
||||
return config.parameters.getBool("airless", false);
|
||||
}
|
||||
|
||||
SkyColoring BiomeDatabase::biomeSkyColoring(String const& biomeName, uint64_t seed) const {
|
||||
SkyColoring skyColoring;
|
||||
|
||||
auto const& config = m_biomes.get(biomeName);
|
||||
if (auto skyOptions = config.parameters.optArray("skyOptions")) {
|
||||
auto option = staticRandomFrom(*skyOptions, seed, "BiomeSkyOption");
|
||||
|
||||
skyColoring.mainColor = jsonToColor(option.get("mainColor"));
|
||||
|
||||
skyColoring.morningColors.first = jsonToColor(option.query("morningColors[0]"));
|
||||
skyColoring.morningColors.second = jsonToColor(option.query("morningColors[1]"));
|
||||
|
||||
skyColoring.dayColors.first = jsonToColor(option.query("dayColors[0]"));
|
||||
skyColoring.dayColors.second = jsonToColor(option.query("dayColors[1]"));
|
||||
|
||||
skyColoring.eveningColors.first = jsonToColor(option.query("eveningColors[0]"));
|
||||
skyColoring.eveningColors.second = jsonToColor(option.query("eveningColors[1]"));
|
||||
|
||||
skyColoring.nightColors.first = jsonToColor(option.query("nightColors[0]"));
|
||||
skyColoring.nightColors.second = jsonToColor(option.query("nightColors[1]"));
|
||||
|
||||
skyColoring.morningLightColor = jsonToColor(option.get("morningLightColor"));
|
||||
skyColoring.dayLightColor = jsonToColor(option.get("dayLightColor"));
|
||||
skyColoring.eveningLightColor = jsonToColor(option.get("eveningLightColor"));
|
||||
skyColoring.nightLightColor = jsonToColor(option.get("nightLightColor"));
|
||||
}
|
||||
|
||||
return skyColoring;
|
||||
}
|
||||
|
||||
String BiomeDatabase::biomeFriendlyName(String const& biomeName) const {
|
||||
auto const& config = m_biomes.get(biomeName);
|
||||
return config.parameters.getString("friendlyName");
|
||||
}
|
||||
|
||||
StringList BiomeDatabase::biomeStatusEffects(String const& biomeName) const {
|
||||
auto const& config = m_biomes.get(biomeName);
|
||||
return config.parameters.opt("statusEffects").apply(jsonToStringList).value();
|
||||
}
|
||||
|
||||
StringList BiomeDatabase::biomeOres(String const& biomeName, float threatLevel) const {
|
||||
StringList res;
|
||||
|
||||
auto const& config = m_biomes.get(biomeName);
|
||||
auto oreDistribution = config.parameters.get("ores", {});
|
||||
if (!oreDistribution.isNull()) {
|
||||
auto& root = Root::singleton();
|
||||
auto functionDatabase = root.functionDatabase();
|
||||
|
||||
auto oresList = functionDatabase->configFunction(oreDistribution)->get(threatLevel);
|
||||
for (Json v : oresList.iterateArray()) {
|
||||
if (v.getFloat(1) > 0)
|
||||
res.append(v.getString(0));
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
StringList BiomeDatabase::weatherNames() const {
|
||||
return m_weathers.keys();
|
||||
}
|
||||
|
||||
WeatherType BiomeDatabase::weatherType(String const& name) const {
|
||||
if (!m_weathers.contains(name))
|
||||
throw BiomeException(strf("No such weather type '%s'", name));
|
||||
|
||||
auto config = m_weathers.get(name);
|
||||
|
||||
try {
|
||||
return WeatherType(config.parameters, config.path);
|
||||
} catch (MapException const& e) {
|
||||
throw BiomeException(strf("Required key not found in weather config %s", config.path), e);
|
||||
}
|
||||
}
|
||||
|
||||
BiomePtr BiomeDatabase::createBiome(String const& biomeName, uint64_t seed, float verticalMidPoint, float threatLevel) const {
|
||||
if (!m_biomes.contains(biomeName))
|
||||
throw BiomeException(strf("No such biome '%s'", biomeName));
|
||||
|
||||
auto& root = Root::singleton();
|
||||
auto materialDatabase = root.materialDatabase();
|
||||
|
||||
try {
|
||||
RandomSource random(seed);
|
||||
auto config = m_biomes.get(biomeName);
|
||||
|
||||
auto biome = make_shared<Biome>();
|
||||
float mainHueShift = biomeHueShift(biomeName, seed);
|
||||
|
||||
biome->baseName = biomeName;
|
||||
biome->description = config.parameters.getString("description", "");
|
||||
|
||||
if (config.parameters.contains("mainBlock"))
|
||||
biome->mainBlock = materialDatabase->materialId(config.parameters.getString("mainBlock"));
|
||||
|
||||
for (Json v : config.parameters.getArray("subBlocks", {}))
|
||||
biome->subBlocks.append(materialDatabase->materialId(v.toString()));
|
||||
|
||||
biome->ores = readOres(config.parameters.get("ores", {}), threatLevel);
|
||||
|
||||
biome->surfacePlaceables = readBiomePlaceables(config.parameters.getObject("surfacePlaceables", {}), random.randu64(), mainHueShift);
|
||||
biome->undergroundPlaceables = readBiomePlaceables(config.parameters.getObject("undergroundPlaceables", {}), random.randu64(), mainHueShift);
|
||||
|
||||
biome->hueShift = mainHueShift;
|
||||
biome->materialHueShift = materialHueFromDegrees(biome->hueShift);
|
||||
|
||||
if (config.parameters.contains("parallax")) {
|
||||
auto parallaxFile = AssetPath::relativeTo(config.path, config.parameters.getString("parallax"));
|
||||
biome->parallax = make_shared<Parallax>(parallaxFile, seed, verticalMidPoint, mainHueShift, biome->surfacePlaceables.firstTreeType());
|
||||
}
|
||||
|
||||
if (config.parameters.contains("musicTrack"))
|
||||
biome->musicTrack = make_shared<AmbientNoisesDescription>(config.parameters.getObject("musicTrack"), config.path);
|
||||
|
||||
if (config.parameters.contains("ambientNoises"))
|
||||
biome->ambientNoises = make_shared<AmbientNoisesDescription>(config.parameters.getObject("ambientNoises"), config.path);
|
||||
|
||||
if (config.parameters.contains("spawnProfile"))
|
||||
biome->spawnProfile = constructSpawnProfile(config.parameters.getObject("spawnProfile"), seed);
|
||||
|
||||
return biome;
|
||||
} catch (std::exception const& cause) {
|
||||
throw BiomeException(strf("Failed to parse biome: '%s'", biomeName), cause);
|
||||
}
|
||||
}
|
||||
|
||||
float BiomeDatabase::pickHueShiftFromJson(Json source, uint64_t seed, String const& key) {
|
||||
if (source.isNull())
|
||||
return 0;
|
||||
auto options = jsonToFloatList(source);
|
||||
if (options.size() == 0)
|
||||
return 0;
|
||||
auto t = staticRandomU32(seed, key);
|
||||
return options.at(t % options.size());
|
||||
}
|
||||
|
||||
BiomePlaceables BiomeDatabase::readBiomePlaceables(Json const& config, uint64_t seed, float biomeHueShift) const {
|
||||
auto& root = Root::singleton();
|
||||
RandomSource rand(seed);
|
||||
BiomePlaceables placeables;
|
||||
if (config.contains("grassMod") && !config.getArray("grassMod").empty())
|
||||
placeables.grassMod = root.materialDatabase()->modId(rand.randFrom(config.getArray("grassMod")).toString());
|
||||
placeables.grassModDensity = config.getFloat("grassModDensity", 0);
|
||||
if (config.contains("ceilingGrassMod") && !config.getArray("ceilingGrassMod").empty())
|
||||
placeables.ceilingGrassMod = root.materialDatabase()->modId(rand.randFrom(config.getArray("ceilingGrassMod")).toString());
|
||||
placeables.ceilingGrassModDensity = config.getFloat("ceilingGrassModDensity", 0);
|
||||
|
||||
for (auto const& itemConfig : config.getArray("items", {}))
|
||||
placeables.itemDistributions.append(BiomeItemDistribution(itemConfig, rand.randu64(), biomeHueShift));
|
||||
|
||||
return placeables;
|
||||
}
|
||||
|
||||
List<pair<ModId, float>> BiomeDatabase::readOres(Json const& oreDistribution, float threatLevel) const {
|
||||
List<pair<ModId, float>> ores;
|
||||
if (!oreDistribution.isNull()) {
|
||||
auto& root = Root::singleton();
|
||||
auto functionDatabase = root.functionDatabase();
|
||||
auto materialDatabase = root.materialDatabase();
|
||||
|
||||
auto oresList = functionDatabase->configFunction(oreDistribution)->get(threatLevel);
|
||||
for (Json v : oresList.iterateArray()) {
|
||||
if (v.getFloat(1) > 0)
|
||||
ores.append({materialDatabase->modId(v.getString(0)), v.getFloat(1)});
|
||||
}
|
||||
}
|
||||
return ores;
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue