1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
#include "StarSpawnTypeDatabase.hpp"
#include "StarJsonExtra.hpp"
#include "StarRoot.hpp"
#include "StarAssets.hpp"
namespace Star {
SpawnParameters::SpawnParameters(Set<Area> areas, Region region, Time time) : areas(areas), region(region), time(time) {}
SpawnParameters::SpawnParameters(Json const& config) {
if (config.isNull()) {
areas = {Area::Surface, Area::Ceiling, Area::Air, Area::Liquid, Area::Solid};
region = Region::All;
time = Time::All;
return;
}
if (auto areaName = config.optString("area")) {
if (*areaName == "all")
areas = {Area::Surface, Area::Ceiling, Area::Air, Area::Liquid, Area::Solid};
else
areas.add(SpawnParameters::AreaNames.getLeft(*areaName));
} else if (auto areaNames = config.optArray("areas")) {
for (auto areaName : *areaNames)
areas.add(SpawnParameters::AreaNames.getLeft(areaName.toString()));
}
region = SpawnParameters::RegionNames.getLeft(config.getString("region"));
time = SpawnParameters::TimeNames.getLeft(config.getString("time"));
}
bool SpawnParameters::compatible(SpawnParameters const& parameters) const {
return areas.hasIntersection(parameters.areas)
&& (region == Region::All || parameters.region == Region::All || region == parameters.region)
&& (time == Time::All || parameters.time == Time::All || time == parameters.time);
}
EnumMap<SpawnParameters::Area> const SpawnParameters::AreaNames{
{SpawnParameters::Area::Surface, "surface"},
{SpawnParameters::Area::Ceiling, "ceiling"},
{SpawnParameters::Area::Air, "air"},
{SpawnParameters::Area::Liquid, "liquid"},
{SpawnParameters::Area::Solid, "solid"}
};
EnumMap<SpawnParameters::Region> const SpawnParameters::RegionNames{
{SpawnParameters::Region::All, "all"},
{SpawnParameters::Region::Enclosed, "enclosed"},
{SpawnParameters::Region::Exposed, "exposed"}
};
EnumMap<SpawnParameters::Time> const SpawnParameters::TimeNames{
{SpawnParameters::Time::All, "all"},
{SpawnParameters::Time::Day, "day"},
{SpawnParameters::Time::Night, "night"}
};
SpawnType spawnTypeFromJson(Json const& config) {
SpawnType spawnType;
spawnType.typeName = config.getString("name");
spawnType.dayLevelAdjustment = jsonToVec2F(config.get("dayLevelAdjustment", JsonArray{0, 0}));
spawnType.nightLevelAdjustment = jsonToVec2F(config.get("nightLevelAdjustment", JsonArray{0, 0}));
Json monsterType = config.get("monsterType");
if (monsterType.type() == Json::Type::Array)
spawnType.monsterType = jsonToWeightedPool<String>(monsterType);
else
spawnType.monsterType = monsterType.toString();
spawnType.monsterParameters = config.get("monsterParameters", JsonObject{});
spawnType.groupSize = jsonToVec2I(config.get("groupSize", JsonArray{1, 1}));
spawnType.spawnChance = config.getFloat("spawnChance");
spawnType.spawnParameters = SpawnParameters(config.get("spawnParameters", {}));
spawnType.seedMix = config.getUInt("seedMix", 0);
return spawnType;
}
SpawnProfile::SpawnProfile() {}
SpawnProfile::SpawnProfile(Json const& config) {
spawnTypes = jsonToStringSet(config.get("spawnTypes", JsonArray()));
monsterParameters = config.get("monsterParameters", {});
}
SpawnProfile::SpawnProfile(StringSet spawnTypes, Json monsterParameters)
: spawnTypes(std::move(spawnTypes)), monsterParameters(std::move(monsterParameters)) {}
Json SpawnProfile::toJson() const {
return JsonObject{
{"spawnTypes", jsonFromStringSet(spawnTypes)},
{"monsterParameters", monsterParameters}
};
}
SpawnProfile constructSpawnProfile(Json const& config, uint64_t seed) {
SpawnProfile spawnProfile;
auto commonGroups = Root::singleton().assets()->json("/spawning.config:spawnGroups");
for (auto group : config.get("groups", JsonArray()).iterateArray()) {
auto poolNameOrConfig = group.get("pool");
WeightedPool<String> typePool;
if (poolNameOrConfig.canConvert(Json::Type::String))
typePool = jsonToWeightedPool<String>(commonGroups.get(poolNameOrConfig.toString()));
else
typePool = jsonToWeightedPool<String>(poolNameOrConfig);
spawnProfile.spawnTypes.addAll(typePool.selectUniques(group.getUInt("select"), ++seed));
}
spawnProfile.monsterParameters = config.getObject("monsterParameters", JsonObject());
return spawnProfile;
}
SpawnTypeDatabase::SpawnTypeDatabase() {
auto assets = Root::singleton().assets();
auto& files = assets->scanExtension("spawntypes");
assets->queueJsons(files);
uint64_t seedMix = 0;
for (auto const& file : files) {
try {
auto spawnTypes = assets->json(file);
for (auto const& entry : spawnTypes.iterateArray()) {
auto spawnType = spawnTypeFromJson(entry);
if (m_spawnTypes.contains(spawnType.typeName))
throw SpawnTypeDatabaseException::format("Duplicate spawnType named '{}' in config file '{}'", spawnType.typeName, file);
if (!entry.contains("seedMix"))
spawnType.seedMix = ++seedMix;
m_spawnTypes[spawnType.typeName] = spawnType;
}
} catch (std::exception const& e) {
throw SpawnTypeDatabaseException(strf("Error reading spawnType config file {}", file), e);
}
}
}
SpawnType SpawnTypeDatabase::spawnType(String const& typeName) const {
if (auto spawnType = m_spawnTypes.maybe(typeName))
return spawnType.take();
throw SpawnTypeDatabaseException::format("No such spawnType '{}'", typeName);
}
}
|