744 lines
32 KiB
C++
744 lines
32 KiB
C++
#include "StarWorldParameters.hpp"
|
|
#include "StarJsonExtra.hpp"
|
|
#include "StarDataStreamExtra.hpp"
|
|
#include "StarRoot.hpp"
|
|
#include "StarAssets.hpp"
|
|
#include "StarBiomeDatabase.hpp"
|
|
#include "StarLiquidsDatabase.hpp"
|
|
|
|
namespace Star {
|
|
|
|
EnumMap<WorldParametersType> const WorldParametersTypeNames{
|
|
{WorldParametersType::TerrestrialWorldParameters, "TerrestrialWorldParameters"},
|
|
{WorldParametersType::AsteroidsWorldParameters, "AsteroidsWorldParameters"},
|
|
{WorldParametersType::FloatingDungeonWorldParameters, "FloatingDungeonWorldParameters"}};
|
|
|
|
EnumMap<BeamUpRule> const BeamUpRuleNames{
|
|
{BeamUpRule::Nowhere, "Nowhere"},
|
|
{BeamUpRule::Surface, "Surface"},
|
|
{BeamUpRule::Anywhere, "Anywhere"},
|
|
{BeamUpRule::AnywhereWithWarning, "AnywhereWithWarning"}};
|
|
|
|
EnumMap<WorldEdgeForceRegionType> const WorldEdgeForceRegionTypeNames{
|
|
{WorldEdgeForceRegionType::None, "None"},
|
|
{WorldEdgeForceRegionType::Top, "Top"},
|
|
{WorldEdgeForceRegionType::Bottom, "Bottom"},
|
|
{WorldEdgeForceRegionType::TopAndBottom, "TopAndBottom"}};
|
|
|
|
VisitableWorldParameters::VisitableWorldParameters() {
|
|
threatLevel = 0;
|
|
gravity = 0;
|
|
airless = false;
|
|
disableDeathDrops = false;
|
|
terraformed = false;
|
|
worldEdgeForceRegions = WorldEdgeForceRegionType::None;
|
|
}
|
|
|
|
VisitableWorldParameters::VisitableWorldParameters(VisitableWorldParameters const& visitableWorldParameters) {
|
|
*this = visitableWorldParameters;
|
|
}
|
|
|
|
VisitableWorldParameters::VisitableWorldParameters(Json const& store) {
|
|
typeName = store.getString("typeName", "");
|
|
threatLevel = store.getFloat("threatLevel");
|
|
worldSize = jsonToVec2U(store.get("worldSize"));
|
|
gravity = store.getFloat("gravity", 1.0f);
|
|
airless = store.getBool("airless", false);
|
|
weatherPool = jsonToWeightedPool<String>(store.getArray("weatherPool", JsonArray()));
|
|
environmentStatusEffects = store.opt("environmentStatusEffects").apply(jsonToStringList).value();
|
|
overrideTech = store.opt("overrideTech").apply(jsonToStringList);
|
|
globalDirectives = store.opt("globalDirectives").apply(jsonToDirectivesList);
|
|
beamUpRule = BeamUpRuleNames.getLeft(store.getString("beamUpRule", "Surface"));
|
|
disableDeathDrops = store.getBool("disableDeathDrops", false);
|
|
terraformed = store.getBool("terraformed", false);
|
|
worldEdgeForceRegions = WorldEdgeForceRegionTypeNames.getLeft(store.getString("worldEdgeForceRegions", "None"));
|
|
}
|
|
|
|
VisitableWorldParameters::~VisitableWorldParameters() {}
|
|
|
|
Json VisitableWorldParameters::store() const {
|
|
return JsonObject{{"typeName", typeName},
|
|
{"threatLevel", threatLevel},
|
|
{"worldSize", jsonFromVec2U(worldSize)},
|
|
{"gravity", gravity},
|
|
{"airless", airless},
|
|
{"weatherPool", jsonFromWeightedPool<String>(weatherPool)},
|
|
{"environmentStatusEffects", jsonFromStringList(environmentStatusEffects)},
|
|
{"overrideTech", jsonFromMaybe(overrideTech.apply(&jsonFromStringList))},
|
|
{"globalDirectives", jsonFromMaybe(globalDirectives.apply(&jsonFromDirectivesList))},
|
|
{"beamUpRule", BeamUpRuleNames.getRight(beamUpRule)},
|
|
{"disableDeathDrops", disableDeathDrops},
|
|
{"terraformed", terraformed},
|
|
{"worldEdgeForceRegions", WorldEdgeForceRegionTypeNames.getRight(worldEdgeForceRegions)}};
|
|
}
|
|
|
|
void VisitableWorldParameters::read(DataStream& ds) {
|
|
ds >> typeName;
|
|
ds >> threatLevel;
|
|
ds >> worldSize;
|
|
ds >> gravity;
|
|
ds >> airless;
|
|
weatherPool = WeatherPool(ds.read<WeatherPool::ItemsList>());
|
|
ds >> environmentStatusEffects;
|
|
ds >> overrideTech;
|
|
ds >> globalDirectives;
|
|
ds >> beamUpRule;
|
|
ds >> disableDeathDrops;
|
|
ds >> terraformed;
|
|
ds >> worldEdgeForceRegions;
|
|
}
|
|
|
|
void VisitableWorldParameters::write(DataStream& ds) const {
|
|
ds << typeName;
|
|
ds << threatLevel;
|
|
ds << worldSize;
|
|
ds << gravity;
|
|
ds << airless;
|
|
ds.writeContainer<WeatherPool::ItemsList>(weatherPool.items());
|
|
ds << environmentStatusEffects;
|
|
ds << overrideTech;
|
|
ds << globalDirectives;
|
|
ds << beamUpRule;
|
|
ds << disableDeathDrops;
|
|
ds << terraformed;
|
|
ds << worldEdgeForceRegions;
|
|
}
|
|
|
|
TerrestrialWorldParameters::TerrestrialWorldParameters() {
|
|
blendSize = 0;
|
|
dayLength = 0;
|
|
}
|
|
|
|
TerrestrialWorldParameters::TerrestrialWorldParameters(TerrestrialWorldParameters const& terrestrialWorldParameters) {
|
|
*this = terrestrialWorldParameters;
|
|
}
|
|
|
|
TerrestrialWorldParameters::TerrestrialWorldParameters(Json const& store) : VisitableWorldParameters(store) {
|
|
auto loadTerrestrialRegion = [](Json const& config) {
|
|
return TerrestrialRegion{config.getString("biome"),
|
|
config.getString("blockSelector"),
|
|
config.getString("fgCaveSelector"),
|
|
config.getString("bgCaveSelector"),
|
|
config.getString("fgOreSelector"),
|
|
config.getString("bgOreSelector"),
|
|
config.getString("subBlockSelector"),
|
|
(LiquidId)config.getUInt("caveLiquid"),
|
|
config.getFloat("caveLiquidSeedDensity"),
|
|
(LiquidId)config.getUInt("oceanLiquid"),
|
|
(int)config.getInt("oceanLiquidLevel"),
|
|
(bool)config.getBool("encloseLiquids"),
|
|
(bool)config.getBool("fillMicrodungeons")};
|
|
};
|
|
|
|
auto loadTerrestrialLayer = [loadTerrestrialRegion](Json const& config) {
|
|
return TerrestrialLayer{(int)config.getInt("layerMinHeight"),
|
|
(int)config.getInt("layerBaseHeight"),
|
|
jsonToStringList(config.get("dungeons")),
|
|
(int)config.getInt("dungeonXVariance"),
|
|
loadTerrestrialRegion(config.get("primaryRegion")),
|
|
loadTerrestrialRegion(config.get("primarySubRegion")),
|
|
config.getArray("secondaryRegions").transformed(loadTerrestrialRegion),
|
|
config.getArray("secondarySubRegions").transformed(loadTerrestrialRegion),
|
|
jsonToVec2F(config.get("secondaryRegionSizeRange")),
|
|
jsonToVec2F(config.get("subRegionSizeRange"))};
|
|
};
|
|
|
|
primaryBiome = store.getString("primaryBiome");
|
|
primarySurfaceLiquid = store.getUInt("surfaceLiquid");
|
|
sizeName = store.getString("sizeName");
|
|
hueShift = store.getFloat("hueShift");
|
|
skyColoring = SkyColoring(store.get("skyColoring"));
|
|
dayLength = store.getFloat("dayLength");
|
|
blockNoiseConfig = store.get("blockNoise");
|
|
blendNoiseConfig = store.get("blendNoise");
|
|
blendSize = store.getFloat("blendSize");
|
|
|
|
spaceLayer = loadTerrestrialLayer(store.get("spaceLayer"));
|
|
atmosphereLayer = loadTerrestrialLayer(store.get("atmosphereLayer"));
|
|
surfaceLayer = loadTerrestrialLayer(store.get("surfaceLayer"));
|
|
subsurfaceLayer = loadTerrestrialLayer(store.get("subsurfaceLayer"));
|
|
undergroundLayers = store.getArray("undergroundLayers").transformed(loadTerrestrialLayer);
|
|
coreLayer = loadTerrestrialLayer(store.get("coreLayer"));
|
|
}
|
|
|
|
TerrestrialWorldParameters &TerrestrialWorldParameters::operator=(TerrestrialWorldParameters const& terrestrialWorldParameters) {
|
|
this->primaryBiome = terrestrialWorldParameters.primaryBiome;
|
|
this->primarySurfaceLiquid = terrestrialWorldParameters.primarySurfaceLiquid;
|
|
this->sizeName = terrestrialWorldParameters.sizeName;
|
|
this->hueShift = terrestrialWorldParameters.hueShift;
|
|
|
|
this->skyColoring = terrestrialWorldParameters.skyColoring;
|
|
this->dayLength = terrestrialWorldParameters.dayLength;
|
|
|
|
this->blockNoiseConfig = terrestrialWorldParameters.blockNoiseConfig;
|
|
this->blendNoiseConfig = terrestrialWorldParameters.blendNoiseConfig;
|
|
this->blendSize = terrestrialWorldParameters.blendSize;
|
|
|
|
this->spaceLayer = terrestrialWorldParameters.spaceLayer;
|
|
this->atmosphereLayer = terrestrialWorldParameters.atmosphereLayer;
|
|
this->surfaceLayer = terrestrialWorldParameters.surfaceLayer;
|
|
this->subsurfaceLayer = terrestrialWorldParameters.subsurfaceLayer;
|
|
this->undergroundLayers = terrestrialWorldParameters.undergroundLayers;
|
|
this->coreLayer = terrestrialWorldParameters.coreLayer;
|
|
return *this;
|
|
}
|
|
|
|
WorldParametersType TerrestrialWorldParameters::type() const {
|
|
return WorldParametersType::TerrestrialWorldParameters;
|
|
}
|
|
|
|
Json TerrestrialWorldParameters::store() const {
|
|
auto storeTerrestrialRegion = [](TerrestrialRegion const& region) -> Json {
|
|
return JsonObject{{"biome", region.biome},
|
|
{"blockSelector", region.blockSelector},
|
|
{"fgCaveSelector", region.fgCaveSelector},
|
|
{"bgCaveSelector", region.bgCaveSelector},
|
|
{"fgOreSelector", region.fgOreSelector},
|
|
{"bgOreSelector", region.bgOreSelector},
|
|
{"subBlockSelector", region.subBlockSelector},
|
|
{"caveLiquid", region.caveLiquid},
|
|
{"caveLiquidSeedDensity", region.caveLiquidSeedDensity},
|
|
{"oceanLiquid", region.oceanLiquid},
|
|
{"oceanLiquidLevel", region.oceanLiquidLevel},
|
|
{"encloseLiquids", region.encloseLiquids},
|
|
{"fillMicrodungeons", region.fillMicrodungeons}};
|
|
};
|
|
auto storeTerrestrialLayer = [storeTerrestrialRegion](TerrestrialLayer const& layer) -> Json {
|
|
return JsonObject{{"layerMinHeight", layer.layerMinHeight},
|
|
{"layerBaseHeight", layer.layerBaseHeight},
|
|
{"dungeons", jsonFromStringList(layer.dungeons)},
|
|
{"dungeonXVariance", layer.dungeonXVariance},
|
|
{"primaryRegion", storeTerrestrialRegion(layer.primaryRegion)},
|
|
{"primarySubRegion", storeTerrestrialRegion(layer.primarySubRegion)},
|
|
{"secondaryRegions", layer.secondaryRegions.transformed(storeTerrestrialRegion)},
|
|
{"secondarySubRegions", layer.secondarySubRegions.transformed(storeTerrestrialRegion)},
|
|
{"secondaryRegionSizeRange", jsonFromVec2F(layer.secondaryRegionSizeRange)},
|
|
{"subRegionSizeRange", jsonFromVec2F(layer.subRegionSizeRange)}};
|
|
};
|
|
|
|
return VisitableWorldParameters::store().setAll(JsonObject{{"primaryBiome", primaryBiome},
|
|
{"sizeName", sizeName},
|
|
{"hueShift", hueShift},
|
|
{"surfaceLiquid", primarySurfaceLiquid},
|
|
{"skyColoring", skyColoring.toJson()},
|
|
{"dayLength", dayLength},
|
|
{"blockNoise", blockNoiseConfig},
|
|
{"blendNoise", blendNoiseConfig},
|
|
{"blendSize", blendSize},
|
|
{"spaceLayer", storeTerrestrialLayer(spaceLayer)},
|
|
{"atmosphereLayer", storeTerrestrialLayer(atmosphereLayer)},
|
|
{"surfaceLayer", storeTerrestrialLayer(surfaceLayer)},
|
|
{"subsurfaceLayer", storeTerrestrialLayer(subsurfaceLayer)},
|
|
{"undergroundLayers", undergroundLayers.transformed(storeTerrestrialLayer)},
|
|
{"coreLayer", storeTerrestrialLayer(coreLayer)}});
|
|
}
|
|
|
|
DataStream& operator>>(DataStream& ds, TerrestrialWorldParameters::TerrestrialRegion& region) {
|
|
ds >> region.biome;
|
|
ds >> region.blockSelector;
|
|
ds >> region.fgCaveSelector;
|
|
ds >> region.bgCaveSelector;
|
|
ds >> region.fgOreSelector;
|
|
ds >> region.bgOreSelector;
|
|
ds >> region.subBlockSelector;
|
|
ds >> region.caveLiquid;
|
|
ds >> region.caveLiquidSeedDensity;
|
|
ds >> region.oceanLiquid;
|
|
ds >> region.oceanLiquidLevel;
|
|
ds >> region.encloseLiquids;
|
|
ds >> region.fillMicrodungeons;
|
|
return ds;
|
|
}
|
|
|
|
void TerrestrialWorldParameters::read(DataStream& ds) {
|
|
auto readTerrestrialLayer = [](DataStream& ds, TerrestrialLayer& layer) {
|
|
ds >> layer.layerMinHeight;
|
|
ds >> layer.layerBaseHeight;
|
|
ds >> layer.dungeons;
|
|
ds >> layer.dungeonXVariance;
|
|
ds >> layer.primaryRegion;
|
|
ds >> layer.primarySubRegion;
|
|
ds >> layer.secondaryRegions;
|
|
ds >> layer.secondarySubRegions;
|
|
ds >> layer.secondaryRegionSizeRange;
|
|
ds >> layer.subRegionSizeRange;
|
|
};
|
|
|
|
VisitableWorldParameters::read(ds);
|
|
ds >> primaryBiome;
|
|
ds >> primarySurfaceLiquid;
|
|
ds >> sizeName;
|
|
ds >> hueShift;
|
|
ds >> skyColoring;
|
|
ds >> dayLength;
|
|
ds >> blendSize;
|
|
ds >> blockNoiseConfig;
|
|
ds >> blendNoiseConfig;
|
|
readTerrestrialLayer(ds, spaceLayer);
|
|
readTerrestrialLayer(ds, atmosphereLayer);
|
|
readTerrestrialLayer(ds, surfaceLayer);
|
|
readTerrestrialLayer(ds, subsurfaceLayer);
|
|
ds.readContainer(undergroundLayers, readTerrestrialLayer);
|
|
readTerrestrialLayer(ds, coreLayer);
|
|
}
|
|
|
|
DataStream& operator<<(DataStream& ds, TerrestrialWorldParameters::TerrestrialRegion const& region) {
|
|
ds << region.biome;
|
|
ds << region.blockSelector;
|
|
ds << region.fgCaveSelector;
|
|
ds << region.bgCaveSelector;
|
|
ds << region.fgOreSelector;
|
|
ds << region.bgOreSelector;
|
|
ds << region.subBlockSelector;
|
|
ds << region.caveLiquid;
|
|
ds << region.caveLiquidSeedDensity;
|
|
ds << region.oceanLiquid;
|
|
ds << region.oceanLiquidLevel;
|
|
ds << region.encloseLiquids;
|
|
ds << region.fillMicrodungeons;
|
|
return ds;
|
|
}
|
|
|
|
void TerrestrialWorldParameters::write(DataStream& ds) const {
|
|
auto writeTerrestrialLayer = [](DataStream& ds, TerrestrialLayer const& layer) {
|
|
ds << layer.layerMinHeight;
|
|
ds << layer.layerBaseHeight;
|
|
ds << layer.dungeons;
|
|
ds << layer.dungeonXVariance;
|
|
ds << layer.primaryRegion;
|
|
ds << layer.primarySubRegion;
|
|
ds << layer.secondaryRegions;
|
|
ds << layer.secondarySubRegions;
|
|
ds << layer.secondaryRegionSizeRange;
|
|
ds << layer.subRegionSizeRange;
|
|
};
|
|
|
|
VisitableWorldParameters::write(ds);
|
|
ds << primaryBiome;
|
|
ds << primarySurfaceLiquid;
|
|
ds << sizeName;
|
|
ds << hueShift;
|
|
ds << skyColoring;
|
|
ds << dayLength;
|
|
ds << blendSize;
|
|
ds << blockNoiseConfig;
|
|
ds << blendNoiseConfig;
|
|
writeTerrestrialLayer(ds, spaceLayer);
|
|
writeTerrestrialLayer(ds, atmosphereLayer);
|
|
writeTerrestrialLayer(ds, surfaceLayer);
|
|
writeTerrestrialLayer(ds, subsurfaceLayer);
|
|
ds.writeContainer(undergroundLayers, writeTerrestrialLayer);
|
|
writeTerrestrialLayer(ds, coreLayer);
|
|
}
|
|
|
|
AsteroidsWorldParameters::AsteroidsWorldParameters() {
|
|
airless = true;
|
|
asteroidTopLevel = 0;
|
|
asteroidBottomLevel = 0;
|
|
blendSize = 0;
|
|
}
|
|
|
|
AsteroidsWorldParameters::AsteroidsWorldParameters(Json const& store) : VisitableWorldParameters(store) {
|
|
asteroidTopLevel = store.getInt("asteroidTopLevel");
|
|
asteroidBottomLevel = store.getInt("asteroidBottomLevel");
|
|
blendSize = store.getFloat("blendSize");
|
|
asteroidBiome = store.getString("asteroidBiome");
|
|
ambientLightLevel = jsonToColor(store.get("ambientLightLevel"));
|
|
}
|
|
|
|
WorldParametersType AsteroidsWorldParameters::type() const {
|
|
return WorldParametersType::AsteroidsWorldParameters;
|
|
}
|
|
|
|
Json AsteroidsWorldParameters::store() const {
|
|
return VisitableWorldParameters::store().setAll(JsonObject{{"asteroidTopLevel", asteroidTopLevel},
|
|
{"asteroidBottomLevel", asteroidBottomLevel},
|
|
{"blendSize", blendSize},
|
|
{"asteroidBiome", asteroidBiome},
|
|
{"ambientLightLevel", jsonFromColor(ambientLightLevel)}});
|
|
}
|
|
|
|
void AsteroidsWorldParameters::read(DataStream& ds) {
|
|
VisitableWorldParameters::read(ds);
|
|
ds >> asteroidTopLevel;
|
|
ds >> asteroidBottomLevel;
|
|
ds >> blendSize;
|
|
ds >> asteroidBiome;
|
|
ds >> ambientLightLevel;
|
|
}
|
|
|
|
void AsteroidsWorldParameters::write(DataStream& ds) const {
|
|
VisitableWorldParameters::write(ds);
|
|
ds << asteroidTopLevel;
|
|
ds << asteroidBottomLevel;
|
|
ds << blendSize;
|
|
ds << asteroidBiome;
|
|
ds << ambientLightLevel;
|
|
}
|
|
|
|
FloatingDungeonWorldParameters::FloatingDungeonWorldParameters() {}
|
|
|
|
FloatingDungeonWorldParameters::FloatingDungeonWorldParameters(Json const& store) : VisitableWorldParameters(store) {
|
|
dungeonBaseHeight = store.getInt("dungeonBaseHeight");
|
|
dungeonSurfaceHeight = store.getInt("dungeonSurfaceHeight");
|
|
dungeonUndergroundLevel = store.getInt("dungeonUndergroundLevel");
|
|
primaryDungeon = store.getString("primaryDungeon");
|
|
biome = store.optString("biome");
|
|
ambientLightLevel = jsonToColor(store.get("ambientLightLevel"));
|
|
dayMusicTrack = store.optString("dayMusicTrack");
|
|
nightMusicTrack = store.optString("nightMusicTrack");
|
|
dayAmbientNoises = store.optString("dayAmbientNoises");
|
|
nightAmbientNoises = store.optString("nightAmbientNoises");
|
|
}
|
|
|
|
WorldParametersType FloatingDungeonWorldParameters::type() const {
|
|
return WorldParametersType::FloatingDungeonWorldParameters;
|
|
}
|
|
|
|
Json FloatingDungeonWorldParameters::store() const {
|
|
return VisitableWorldParameters::store().setAll(JsonObject{{"dungeonBaseHeight", dungeonBaseHeight},
|
|
{"dungeonSurfaceHeight", dungeonSurfaceHeight},
|
|
{"dungeonUndergroundLevel", dungeonUndergroundLevel},
|
|
{"primaryDungeon", primaryDungeon},
|
|
{"biome", jsonFromMaybe(biome)},
|
|
{"ambientLightLevel", jsonFromColor(ambientLightLevel)},
|
|
{"dayMusicTrack", jsonFromMaybe(dayMusicTrack)},
|
|
{"nightMusicTrack", jsonFromMaybe(nightMusicTrack)},
|
|
{"dayAmbientNoises", jsonFromMaybe(dayAmbientNoises)},
|
|
{"nightAmbientNoises", jsonFromMaybe(nightAmbientNoises)}});
|
|
}
|
|
|
|
void FloatingDungeonWorldParameters::read(DataStream& ds) {
|
|
VisitableWorldParameters::read(ds);
|
|
ds >> dungeonBaseHeight;
|
|
ds >> dungeonSurfaceHeight;
|
|
ds >> dungeonUndergroundLevel;
|
|
ds >> primaryDungeon;
|
|
ds >> biome;
|
|
ds >> ambientLightLevel;
|
|
ds >> dayMusicTrack;
|
|
ds >> nightMusicTrack;
|
|
ds >> dayAmbientNoises;
|
|
ds >> nightAmbientNoises;
|
|
}
|
|
|
|
void FloatingDungeonWorldParameters::write(DataStream& ds) const {
|
|
VisitableWorldParameters::write(ds);
|
|
ds << dungeonBaseHeight;
|
|
ds << dungeonSurfaceHeight;
|
|
ds << dungeonUndergroundLevel;
|
|
ds << primaryDungeon;
|
|
ds << biome;
|
|
ds << ambientLightLevel;
|
|
ds << dayMusicTrack;
|
|
ds << nightMusicTrack;
|
|
ds << dayAmbientNoises;
|
|
ds << nightAmbientNoises;
|
|
}
|
|
|
|
Json diskStoreVisitableWorldParameters(VisitableWorldParametersConstPtr const& parameters) {
|
|
if (!parameters)
|
|
return Json();
|
|
|
|
return parameters->store().setAll({{"type", WorldParametersTypeNames.getRight(parameters->type())}});
|
|
}
|
|
|
|
VisitableWorldParametersPtr diskLoadVisitableWorldParameters(Json const& store) {
|
|
if (store.isNull())
|
|
return {};
|
|
|
|
auto type = WorldParametersTypeNames.getLeft(store.getString("type"));
|
|
if (type == WorldParametersType::TerrestrialWorldParameters)
|
|
return make_shared<TerrestrialWorldParameters>(store);
|
|
else if (type == WorldParametersType::AsteroidsWorldParameters)
|
|
return make_shared<AsteroidsWorldParameters>(store);
|
|
else if (type == WorldParametersType::FloatingDungeonWorldParameters)
|
|
return make_shared<FloatingDungeonWorldParameters>(store);
|
|
throw StarException("No such WorldParametersType");
|
|
}
|
|
|
|
ByteArray netStoreVisitableWorldParameters(VisitableWorldParametersConstPtr const& parameters) {
|
|
if (!parameters)
|
|
return ByteArray();
|
|
|
|
DataStreamBuffer ds;
|
|
ds.write(parameters->type());
|
|
parameters->write(ds);
|
|
return ds.takeData();
|
|
}
|
|
|
|
VisitableWorldParametersPtr netLoadVisitableWorldParameters(ByteArray data) {
|
|
if (data.empty())
|
|
return {};
|
|
|
|
DataStreamBuffer ds(move(data));
|
|
auto type = ds.read<WorldParametersType>();
|
|
|
|
VisitableWorldParametersPtr parameters;
|
|
if (type == WorldParametersType::TerrestrialWorldParameters)
|
|
parameters = make_shared<TerrestrialWorldParameters>();
|
|
else if (type == WorldParametersType::AsteroidsWorldParameters)
|
|
parameters = make_shared<AsteroidsWorldParameters>();
|
|
else if (type == WorldParametersType::FloatingDungeonWorldParameters)
|
|
parameters = make_shared<FloatingDungeonWorldParameters>();
|
|
else
|
|
throw StarException("No such WorldParametersType");
|
|
|
|
parameters->read(ds);
|
|
|
|
return parameters;
|
|
}
|
|
|
|
TerrestrialWorldParametersPtr generateTerrestrialWorldParameters(String const& typeName, String const& sizeName, uint64_t seed) {
|
|
auto& root = Root::singleton();
|
|
auto assets = root.assets();
|
|
auto liquidsDatabase = root.liquidsDatabase();
|
|
auto biomeDatabase = root.biomeDatabase();
|
|
|
|
auto terrestrialConfig = assets->json("/terrestrial_worlds.config");
|
|
|
|
auto regionDefaults = terrestrialConfig.get("regionDefaults");
|
|
auto regionTypes = terrestrialConfig.get("regionTypes");
|
|
|
|
auto baseConfig = terrestrialConfig.get("planetDefaults");
|
|
auto sizeConfig = terrestrialConfig.get("planetSizes").get(sizeName);
|
|
auto typeConfig = terrestrialConfig.get("planetTypes").get(typeName);
|
|
auto config = jsonMerge(baseConfig, sizeConfig, typeConfig);
|
|
|
|
auto gravityRange = jsonToVec2F(config.get("gravityRange"));
|
|
auto dayLengthRange = jsonToVec2F(config.get("dayLengthRange"));
|
|
auto threatLevelRange = jsonToVec2F(config.query("threatRange"));
|
|
|
|
float threatLevel = staticRandomDouble(seed, "ThreatLevel") * (threatLevelRange[1] - threatLevelRange[0]) + threatLevelRange[0];
|
|
auto surfaceBiomeSeed = staticRandomU64(seed, "SurfaceBiomeSeed");
|
|
|
|
auto readRegion = [liquidsDatabase, threatLevel, seed](Json const& regionConfig, String const& layerName, int layerBaseHeight) {
|
|
TerrestrialWorldParameters::TerrestrialRegion region;
|
|
auto biomeChoices = jsonToStringList(binnedChoiceFromJson(regionConfig.get("biome"), threatLevel));
|
|
region.biome = staticRandomValueFrom(biomeChoices, seed, layerName.utf8Ptr());
|
|
|
|
region.blockSelector = staticRandomFrom(regionConfig.getArray("blockSelector"), seed, "blockSelector", layerName.utf8Ptr()).toString();
|
|
region.fgCaveSelector = staticRandomFrom(regionConfig.getArray("fgCaveSelector"), seed, "fgCaveSelector", layerName.utf8Ptr()).toString();
|
|
region.bgCaveSelector = staticRandomFrom(regionConfig.getArray("bgCaveSelector"), seed, "bgCaveSelector", layerName.utf8Ptr()).toString();
|
|
region.fgOreSelector = staticRandomFrom(regionConfig.getArray("fgOreSelector"), seed, "fgOreSelector", layerName.utf8Ptr()).toString();
|
|
region.bgOreSelector = staticRandomFrom(regionConfig.getArray("bgOreSelector"), seed, "bgOreSelector", layerName.utf8Ptr()).toString();
|
|
region.subBlockSelector = staticRandomFrom(regionConfig.getArray("subBlockSelector"), seed, "subBlockSelector", layerName.utf8Ptr()).toString();
|
|
|
|
if (auto caveLiquid = staticRandomValueFrom(regionConfig.getArray("caveLiquid", {}), seed, "caveLiquid").optString()) {
|
|
auto caveLiquidSeedDensityRange = jsonToVec2F(regionConfig.get("caveLiquidSeedDensityRange"));
|
|
region.caveLiquid = liquidsDatabase->liquidId(*caveLiquid);
|
|
region.caveLiquidSeedDensity = staticRandomFloatRange(caveLiquidSeedDensityRange[0],
|
|
caveLiquidSeedDensityRange[1],
|
|
seed,
|
|
"caveLiquidSeedDensity",
|
|
layerName.utf8Ptr());
|
|
} else {
|
|
region.caveLiquid = EmptyLiquidId;
|
|
region.caveLiquidSeedDensity = 0.0f;
|
|
}
|
|
|
|
if (auto oceanLiquid = staticRandomValueFrom(regionConfig.getArray("oceanLiquid", {}), seed, "oceanLiquid", layerName.utf8Ptr()).optString()) {
|
|
region.oceanLiquid = liquidsDatabase->liquidId(*oceanLiquid);
|
|
region.oceanLiquidLevel = regionConfig.getInt("oceanLevelOffset", 0) + layerBaseHeight;
|
|
} else {
|
|
region.oceanLiquid = EmptyLiquidId;
|
|
region.oceanLiquidLevel = 0;
|
|
}
|
|
region.encloseLiquids = regionConfig.getBool("encloseLiquids", false);
|
|
region.fillMicrodungeons = regionConfig.getBool("fillMicrodungeons", false);
|
|
|
|
return region;
|
|
};
|
|
|
|
auto readLayer = [readRegion, regionDefaults, regionTypes, seed, config](String const& layerName) -> Maybe<TerrestrialWorldParameters::TerrestrialLayer> {
|
|
if (!config.get("layers").contains(layerName))
|
|
return {};
|
|
|
|
auto layerConfig = jsonMerge(config.get("layerDefaults"), config.get("layers").get(layerName));
|
|
|
|
if (!layerConfig || !layerConfig.getBool("enabled"))
|
|
return {};
|
|
|
|
TerrestrialWorldParameters::TerrestrialLayer layer;
|
|
|
|
layer.layerMinHeight = layerConfig.getFloat("layerLevel");
|
|
layer.layerBaseHeight = layerConfig.getFloat("baseHeight");
|
|
|
|
auto primaryRegionList = layerConfig.getArray("primaryRegion");
|
|
auto primaryRegionConfigName = staticRandomFrom(primaryRegionList, seed, layerName.utf8Ptr(), "PrimaryRegionSelection").toString();
|
|
Json primaryRegionConfig = jsonMerge(regionDefaults, regionTypes.get(primaryRegionConfigName));
|
|
layer.primaryRegion = readRegion(primaryRegionConfig, layerName, layer.layerBaseHeight);
|
|
|
|
auto subRegionList = primaryRegionConfig.getArray("subRegion");
|
|
Json subRegionConfig;
|
|
if (subRegionList.size() > 0) {
|
|
String subRegionName = staticRandomFrom(subRegionList, seed, layerName, primaryRegionConfigName).toString();
|
|
subRegionConfig = jsonMerge(regionDefaults, regionTypes.get(subRegionName));
|
|
} else {
|
|
subRegionConfig = primaryRegionConfig;
|
|
}
|
|
layer.primarySubRegion = readRegion(subRegionConfig, layerName, layer.layerBaseHeight);
|
|
|
|
Vec2U secondaryRegionCountRange = jsonToVec2U(layerConfig.get("secondaryRegionCount"));
|
|
int secondaryRegionCount = staticRandomI32Range(secondaryRegionCountRange[0], secondaryRegionCountRange[1], seed, layerName, "SecondaryRegionCount");
|
|
auto secondaryRegionList = layerConfig.getArray("secondaryRegions");
|
|
if (secondaryRegionList.size() > 0) {
|
|
staticRandomShuffle(secondaryRegionList, seed, layerName, "SecondaryRegionShuffle");
|
|
for (auto regionName : secondaryRegionList) {
|
|
if (secondaryRegionCount <= 0)
|
|
break;
|
|
Json secondaryRegionConfig = jsonMerge(regionDefaults, regionTypes.get(regionName.toString()));
|
|
layer.secondaryRegions.append(readRegion(secondaryRegionConfig, layerName, layer.layerBaseHeight));
|
|
|
|
auto subRegionList = secondaryRegionConfig.getArray("subRegion");
|
|
Json subRegionConfig;
|
|
if (subRegionList.size() > 0) {
|
|
String subRegionName = staticRandomFrom(subRegionList, seed, layerName, regionName.toString()).toString();
|
|
subRegionConfig = jsonMerge(regionDefaults, regionTypes.get(subRegionName));
|
|
} else {
|
|
subRegionConfig = secondaryRegionConfig;
|
|
}
|
|
layer.secondarySubRegions.append(readRegion(subRegionConfig, layerName, layer.layerBaseHeight));
|
|
|
|
--secondaryRegionCount;
|
|
}
|
|
}
|
|
|
|
layer.secondaryRegionSizeRange = jsonToVec2F(layerConfig.get("secondaryRegionSize"));
|
|
layer.subRegionSizeRange = jsonToVec2F(layerConfig.get("subRegionSize"));
|
|
|
|
WeightedPool<String> dungeonPool = jsonToWeightedPool<String>(layerConfig.get("dungeons"));
|
|
Vec2U dungeonCountRange = layerConfig.opt("dungeonCountRange").apply(jsonToVec2U).value();
|
|
unsigned dungeonCount = staticRandomU32Range(dungeonCountRange[0], dungeonCountRange[1], seed, layerName, "DungeonCount");
|
|
layer.dungeons.appendAll(dungeonPool.selectUniques(dungeonCount, staticRandomHash64(seed, layerName, "DungeonChoice")));
|
|
layer.dungeonXVariance = layerConfig.getInt("dungeonXVariance", 0);
|
|
|
|
return layer;
|
|
};
|
|
|
|
auto surfaceLayer = readLayer("surface").take();
|
|
String primaryBiome = surfaceLayer.primaryRegion.biome;
|
|
|
|
auto parameters = make_shared<TerrestrialWorldParameters>();
|
|
|
|
parameters->threatLevel = threatLevel;
|
|
parameters->typeName = typeName;
|
|
parameters->worldSize = jsonToVec2U(config.get("size"));
|
|
parameters->gravity = staticRandomFloatRange(gravityRange[0], gravityRange[1], seed, "WorldGravity");
|
|
parameters->airless = biomeDatabase->biomeIsAirless(primaryBiome);
|
|
parameters->environmentStatusEffects = biomeDatabase->biomeStatusEffects(primaryBiome);
|
|
parameters->overrideTech = config.opt("overrideTech").apply(jsonToStringList);
|
|
parameters->globalDirectives = config.opt("globalDirectives").apply(jsonToDirectivesList);
|
|
parameters->beamUpRule = BeamUpRuleNames.getLeft(config.getString("beamUpRule", "Surface"));
|
|
parameters->disableDeathDrops = config.getBool("disableDeathDrops", false);
|
|
parameters->worldEdgeForceRegions = WorldEdgeForceRegionTypeNames.getLeft(config.getString("worldEdgeForceRegions", "Top"));
|
|
|
|
parameters->weatherPool = biomeDatabase->biomeWeathers(primaryBiome, seed, threatLevel);
|
|
|
|
parameters->primaryBiome = primaryBiome;
|
|
parameters->sizeName = sizeName;
|
|
parameters->hueShift = biomeDatabase->biomeHueShift(parameters->primaryBiome, surfaceBiomeSeed);
|
|
|
|
parameters->primarySurfaceLiquid = surfaceLayer.primaryRegion.oceanLiquid != EmptyLiquidId
|
|
? surfaceLayer.primaryRegion.oceanLiquid
|
|
: surfaceLayer.primaryRegion.caveLiquid;
|
|
|
|
parameters->skyColoring = biomeDatabase->biomeSkyColoring(parameters->primaryBiome, seed);
|
|
parameters->dayLength = staticRandomFloatRange(dayLengthRange[0], dayLengthRange[1], seed, "DayLength");
|
|
|
|
parameters->blockNoiseConfig = config.get("blockNoise");
|
|
parameters->blendNoiseConfig = config.get("blendNoise");
|
|
parameters->blendSize = config.getFloat("blendSize");
|
|
|
|
parameters->spaceLayer = readLayer("space").take();
|
|
parameters->atmosphereLayer = readLayer("atmosphere").take();
|
|
parameters->surfaceLayer = surfaceLayer;
|
|
parameters->subsurfaceLayer = readLayer("subsurface").take();
|
|
|
|
while (auto undergroundLayer = readLayer(strf("underground{}", parameters->undergroundLayers.size() + 1)))
|
|
parameters->undergroundLayers.append(undergroundLayer.take());
|
|
|
|
parameters->coreLayer = readLayer("core").take();
|
|
|
|
return parameters;
|
|
}
|
|
|
|
AsteroidsWorldParametersPtr generateAsteroidsWorldParameters(uint64_t seed) {
|
|
auto& root = Root::singleton();
|
|
auto assets = root.assets();
|
|
|
|
auto parameters = make_shared<AsteroidsWorldParameters>();
|
|
|
|
auto asteroidsConfig = assets->json("/asteroids_worlds.config");
|
|
String biome = asteroidsConfig.getString("biome");
|
|
auto gravityRange = jsonToVec2F(asteroidsConfig.get("gravityRange"));
|
|
|
|
auto threatLevelRange = jsonToVec2F(asteroidsConfig.get("threatRange"));
|
|
parameters->threatLevel = staticRandomDouble(seed, "ThreatLevel") * (threatLevelRange[1] - threatLevelRange[0]) + threatLevelRange[0];
|
|
parameters->typeName = "asteroids";
|
|
parameters->worldSize = jsonToVec2U(asteroidsConfig.get("worldSize"));
|
|
parameters->gravity = staticRandomFloatRange(gravityRange[0], gravityRange[1], seed, "WorldGravity");
|
|
parameters->environmentStatusEffects = jsonToStringList(asteroidsConfig.getArray("environmentStatusEffects", JsonArray()));
|
|
parameters->overrideTech = asteroidsConfig.opt("overrideTech").apply(jsonToStringList);
|
|
parameters->globalDirectives = asteroidsConfig.opt("globalDirectives").apply(jsonToDirectivesList);
|
|
parameters->beamUpRule = BeamUpRuleNames.getLeft(asteroidsConfig.getString("beamUpRule", "Surface"));
|
|
parameters->disableDeathDrops = asteroidsConfig.getBool("disableDeathDrops", false);
|
|
parameters->worldEdgeForceRegions = WorldEdgeForceRegionTypeNames.getLeft(asteroidsConfig.getString("worldEdgeForceRegions", "TopAndBottom"));
|
|
|
|
parameters->asteroidTopLevel = asteroidsConfig.getInt("asteroidsTop");
|
|
parameters->asteroidBottomLevel = asteroidsConfig.getInt("asteroidsBottom");
|
|
parameters->blendSize = asteroidsConfig.getFloat("blendSize");
|
|
parameters->asteroidBiome = biome;
|
|
parameters->ambientLightLevel = jsonToColor(asteroidsConfig.get("ambientLightLevel"));
|
|
|
|
return parameters;
|
|
}
|
|
|
|
FloatingDungeonWorldParametersPtr generateFloatingDungeonWorldParameters(String const& dungeonWorldName) {
|
|
auto& root = Root::singleton();
|
|
auto assets = root.assets();
|
|
|
|
auto worldConfig = assets->json("/dungeon_worlds.config:" + dungeonWorldName);
|
|
|
|
auto parameters = make_shared<FloatingDungeonWorldParameters>();
|
|
|
|
parameters->threatLevel = worldConfig.getFloat("threatLevel", 0);
|
|
parameters->typeName = dungeonWorldName;
|
|
parameters->worldSize = jsonToVec2U(worldConfig.get("worldSize"));
|
|
parameters->gravity = worldConfig.getFloat("gravity");
|
|
parameters->airless = worldConfig.getBool("airless", false);
|
|
parameters->environmentStatusEffects = jsonToStringList(worldConfig.getArray("environmentStatusEffects", JsonArray()));
|
|
parameters->overrideTech = worldConfig.opt("overrideTech").apply(jsonToStringList);
|
|
parameters->globalDirectives = worldConfig.opt("globalDirectives").apply(jsonToDirectivesList);
|
|
if (auto weatherPoolConfig = worldConfig.optArray("weatherPool"))
|
|
parameters->weatherPool = jsonToWeightedPool<String>(*weatherPoolConfig);
|
|
parameters->beamUpRule = BeamUpRuleNames.getLeft(worldConfig.getString("beamUpRule", "Surface"));
|
|
parameters->disableDeathDrops = worldConfig.getBool("disableDeathDrops", false);
|
|
parameters->worldEdgeForceRegions = WorldEdgeForceRegionTypeNames.getLeft(worldConfig.getString("worldEdgeForceRegions", "Top"));
|
|
|
|
parameters->dungeonBaseHeight = worldConfig.getInt("dungeonBaseHeight");
|
|
parameters->dungeonSurfaceHeight = worldConfig.getInt("dungeonSurfaceHeight", parameters->dungeonBaseHeight);
|
|
parameters->dungeonUndergroundLevel = worldConfig.getInt("dungeonUndergroundLevel", 0);
|
|
parameters->primaryDungeon = worldConfig.getString("primaryDungeon");
|
|
parameters->biome = worldConfig.optString("biome");
|
|
parameters->ambientLightLevel = jsonToColor(worldConfig.get("ambientLightLevel"));
|
|
if (worldConfig.contains("musicTrack")) {
|
|
parameters->dayMusicTrack = worldConfig.optString("musicTrack");
|
|
parameters->nightMusicTrack = worldConfig.optString("musicTrack");
|
|
} else {
|
|
parameters->dayMusicTrack = worldConfig.optString("dayMusicTrack");
|
|
parameters->nightMusicTrack = worldConfig.optString("nightMusicTrack");
|
|
}
|
|
if (worldConfig.contains("ambientNoises")) {
|
|
parameters->dayAmbientNoises = worldConfig.optString("ambientNoises");
|
|
parameters->nightAmbientNoises = worldConfig.optString("ambientNoises");
|
|
} else {
|
|
parameters->dayAmbientNoises = worldConfig.optString("dayAmbientNoises");
|
|
parameters->nightAmbientNoises = worldConfig.optString("nightAmbientNoises");
|
|
}
|
|
|
|
return parameters;
|
|
}
|
|
|
|
}
|