v1.4.4
This commit is contained in:
commit
9c94d113d3
10260 changed files with 1237388 additions and 0 deletions
267
source/game/StarWorldStructure.cpp
Normal file
267
source/game/StarWorldStructure.cpp
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
#include "StarWorldStructure.hpp"
|
||||
#include "StarRoot.hpp"
|
||||
#include "StarJsonExtra.hpp"
|
||||
#include "StarDataStreamExtra.hpp"
|
||||
#include "StarMaterialDatabase.hpp"
|
||||
#include "StarImageMetadataDatabase.hpp"
|
||||
#include "StarImage.hpp"
|
||||
#include "StarAssets.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
WorldStructure::WorldStructure() {}
|
||||
|
||||
WorldStructure::WorldStructure(String const& configPath) {
|
||||
auto assets = Root::singleton().assets();
|
||||
auto imgMetadata = Root::singleton().imageMetadataDatabase();
|
||||
auto settings = assets->json(configPath);
|
||||
|
||||
m_region = RectI::null();
|
||||
m_config = settings.getObject("config", JsonObject());
|
||||
|
||||
// Read all the background / foreground overlays, and combine the image size
|
||||
// in tiles with the full structure range
|
||||
|
||||
for (auto overlaySettings : settings.getArray("backgroundOverlays", JsonArray())) {
|
||||
Overlay overlay = Overlay{jsonToVec2F(overlaySettings.get("position")),
|
||||
AssetPath::relativeTo(configPath, overlaySettings.getString("image")),
|
||||
overlaySettings.getBool("fullbright", false)};
|
||||
m_backgroundOverlays.append(overlay);
|
||||
m_region.combine(RectI::withSize(
|
||||
Vec2I::floor(overlay.min), Vec2I::ceil(Vec2F(imgMetadata->imageSize(overlay.image)) / TilePixels)));
|
||||
}
|
||||
|
||||
for (auto overlaySettings : settings.getArray("foregroundOverlays", JsonArray())) {
|
||||
Overlay overlay = Overlay{jsonToVec2F(overlaySettings.get("position")),
|
||||
AssetPath::relativeTo(configPath, overlaySettings.getString("image")),
|
||||
overlaySettings.getBool("fullbright", false)};
|
||||
m_foregroundOverlays.append(overlay);
|
||||
m_region.combine(RectI::withSize(
|
||||
Vec2I::floor(overlay.min), Vec2I::ceil(Vec2F(imgMetadata->imageSize(overlay.image)) / TilePixels)));
|
||||
}
|
||||
|
||||
// Read block position, keys, and then use that to interpret the block image,
|
||||
// if given.
|
||||
|
||||
auto blockPosition = jsonToVec2I(settings.getArray("blocksPosition", JsonArray{0, 0}));
|
||||
HashMap<Vec4B, BlockKey> blockKeys;
|
||||
auto matDb = Root::singleton().materialDatabase();
|
||||
for (auto const& blockKeyConfig :
|
||||
assets->fetchJson(settings.get("blockKey", JsonArray()), configPath).iterateArray()) {
|
||||
auto foregroundMat = blockKeyConfig.getString("foregroundMat", "");
|
||||
MaterialId foregroundMatId;
|
||||
if (foregroundMat == "")
|
||||
foregroundMatId = StructureMaterialId;
|
||||
else
|
||||
foregroundMatId = matDb->materialId(foregroundMat);
|
||||
|
||||
auto backgroundMat = blockKeyConfig.getString("backgroundMat", "");
|
||||
MaterialId backgroundMatId;
|
||||
if (backgroundMat == "")
|
||||
backgroundMatId = StructureMaterialId;
|
||||
else
|
||||
backgroundMatId = matDb->materialId(backgroundMat);
|
||||
|
||||
BlockKey blockKey{blockKeyConfig.getBool("anchor", false),
|
||||
blockKeyConfig.getBool("foregroundBlock", false),
|
||||
foregroundMatId,
|
||||
blockKeyConfig.getBool("foregroundResidual", false),
|
||||
blockKeyConfig.getBool("backgroundBlock", false),
|
||||
backgroundMatId,
|
||||
blockKeyConfig.getBool("backgroundResidual", false),
|
||||
blockKeyConfig.getString("object", ""),
|
||||
DirectionNames.getLeft(blockKeyConfig.getString("objectDirection", "left")),
|
||||
blockKeyConfig.getObject("objectParameters", JsonObject()),
|
||||
blockKeyConfig.getBool("objectResidual", false),
|
||||
jsonToStringList(blockKeyConfig.get("flags", JsonArray()))};
|
||||
blockKeys[jsonToColor(blockKeyConfig.get("value")).toRgba()] = move(blockKey);
|
||||
}
|
||||
|
||||
Maybe<Vec2I> anchorPosition;
|
||||
if (settings.contains("blockImage")) {
|
||||
auto blocksImage = assets->image(AssetPath::relativeTo(configPath, settings.getString("blockImage")));
|
||||
const BlockKey defaultBlockKey = {false,
|
||||
false,
|
||||
StructureMaterialId,
|
||||
false,
|
||||
false,
|
||||
StructureMaterialId,
|
||||
false,
|
||||
String(),
|
||||
Direction::Left,
|
||||
Json(),
|
||||
false,
|
||||
StringList()};
|
||||
|
||||
for (size_t y = 0; y < blocksImage->height(); ++y) {
|
||||
for (size_t x = 0; x < blocksImage->width(); ++x) {
|
||||
auto blockKey = blockKeys.value(blocksImage->getrgb(x, y), defaultBlockKey);
|
||||
auto pos = blockPosition + Vec2I(x, y);
|
||||
|
||||
if (blockKey.anchor) {
|
||||
if (anchorPosition)
|
||||
throw WorldStructureException(
|
||||
strf("Multiple anchor points defined in blockImage, first point is at %s, second at %s",
|
||||
*anchorPosition,
|
||||
pos));
|
||||
anchorPosition = pos;
|
||||
}
|
||||
|
||||
if (blockKey.foregroundBlock)
|
||||
m_foregroundBlocks.append({pos, blockKey.foregroundMat, blockKey.foregroundResidual});
|
||||
if (blockKey.backgroundBlock)
|
||||
m_backgroundBlocks.append({pos, blockKey.backgroundMat, blockKey.backgroundResidual});
|
||||
|
||||
if (!blockKey.object.empty())
|
||||
m_objects.append(Object{
|
||||
pos, blockKey.object, blockKey.objectDirection, blockKey.objectParameters, blockKey.objectResidual});
|
||||
|
||||
for (auto const& flag : blockKey.flags)
|
||||
m_flaggedBlocks[flag].append(pos);
|
||||
|
||||
m_region.combine(pos);
|
||||
}
|
||||
}
|
||||
|
||||
if (anchorPosition)
|
||||
m_anchorPosition = *anchorPosition;
|
||||
else
|
||||
m_anchorPosition = m_region.center();
|
||||
|
||||
// Objects put into the list are from top to bottom, need to place them
|
||||
// from bottom to top for objects on top of other objects.
|
||||
reverse(m_objects);
|
||||
}
|
||||
}
|
||||
|
||||
WorldStructure::WorldStructure(Json const& store) {
|
||||
auto overlayFromJson = [](Json const& v) -> Overlay {
|
||||
return Overlay{jsonToVec2F(v.get("min")), v.getString("image"), v.getBool("fullbright")};
|
||||
};
|
||||
|
||||
auto blockFromJson = [](Json const& v) -> Block {
|
||||
return Block{jsonToVec2I(v.get("position")), MaterialId(v.getUInt("materialId")), v.getBool("residual")};
|
||||
};
|
||||
|
||||
auto objectFromJson = [](Json const& v) -> Object {
|
||||
return Object{jsonToVec2I(v.get("position")),
|
||||
v.getString("name"),
|
||||
DirectionNames.getLeft(v.getString("direction")),
|
||||
v.get("parameters", {}),
|
||||
v.getBool("residual", false)};
|
||||
};
|
||||
|
||||
m_region = jsonToRectI(store.get("region"));
|
||||
m_anchorPosition = jsonToVec2I(store.get("anchorPosition"));
|
||||
m_config = store.get("config");
|
||||
m_backgroundOverlays = store.getArray("backgroundOverlays").transformed(overlayFromJson);
|
||||
m_foregroundOverlays = store.getArray("foregroundOverlays").transformed(overlayFromJson);
|
||||
m_backgroundBlocks = store.getArray("backgroundBlocks").transformed(blockFromJson);
|
||||
m_foregroundBlocks = store.getArray("foregroundBlocks").transformed(blockFromJson);
|
||||
m_objects = store.getArray("objects").transformed(objectFromJson);
|
||||
m_flaggedBlocks = transform<StringMap<List<Vec2I>>>(store.getObject("flaggedBlocks"),
|
||||
[](pair<String, Json> const& p) { return make_pair(p.first, p.second.toArray().transformed(jsonToVec2I)); });
|
||||
}
|
||||
|
||||
Json WorldStructure::configValue(String const& name) const {
|
||||
return m_config.get(name, Json());
|
||||
}
|
||||
|
||||
auto WorldStructure::backgroundOverlays() const -> List<Overlay> const & {
|
||||
return m_backgroundOverlays;
|
||||
}
|
||||
|
||||
auto WorldStructure::foregroundOverlays() const -> List<Overlay> const & {
|
||||
return m_foregroundOverlays;
|
||||
}
|
||||
|
||||
auto WorldStructure::backgroundBlocks() const -> List<Block> const & {
|
||||
return m_backgroundBlocks;
|
||||
}
|
||||
|
||||
auto WorldStructure::foregroundBlocks() const -> List<Block> const & {
|
||||
return m_foregroundBlocks;
|
||||
}
|
||||
|
||||
auto WorldStructure::objects() const -> List<Object> const & {
|
||||
return m_objects;
|
||||
}
|
||||
|
||||
auto WorldStructure::flaggedBlocks(String const& flag) const -> List<Vec2I> {
|
||||
return m_flaggedBlocks.value(flag);
|
||||
}
|
||||
|
||||
RectI WorldStructure::region() const {
|
||||
return m_region;
|
||||
}
|
||||
|
||||
Vec2I WorldStructure::anchorPosition() const {
|
||||
return m_anchorPosition;
|
||||
}
|
||||
|
||||
void WorldStructure::setAnchorPosition(Vec2I const& anchorPosition) {
|
||||
translate(anchorPosition - m_anchorPosition);
|
||||
}
|
||||
|
||||
void WorldStructure::translate(Vec2I const& distance) {
|
||||
if (!m_region.isNull())
|
||||
m_region.translate(distance);
|
||||
|
||||
m_anchorPosition += distance;
|
||||
|
||||
for (auto& bg : m_backgroundOverlays)
|
||||
bg.min += Vec2F(distance);
|
||||
|
||||
for (auto& fg : m_foregroundOverlays)
|
||||
fg.min += Vec2F(distance);
|
||||
|
||||
for (auto& b : m_backgroundBlocks)
|
||||
b.position += distance;
|
||||
|
||||
for (auto& b : m_foregroundBlocks)
|
||||
b.position += distance;
|
||||
|
||||
for (auto& object : m_objects)
|
||||
object.position += distance;
|
||||
|
||||
for (auto& flagPair : m_flaggedBlocks) {
|
||||
for (auto& pos : flagPair.second)
|
||||
pos += distance;
|
||||
}
|
||||
}
|
||||
|
||||
Json WorldStructure::store() const {
|
||||
auto overlayToJson = [](Overlay const& o) -> Json {
|
||||
return JsonObject{{"min", jsonFromVec2F(o.min)}, {"image", o.image}, {"fullbright", o.fullbright}};
|
||||
};
|
||||
|
||||
auto blockToJson = [](Block const& b) -> Json {
|
||||
return JsonObject{{"position", jsonFromVec2I(b.position)}, {"materialId", b.materialId}, {"residual", b.residual}};
|
||||
};
|
||||
|
||||
auto objectToJson = [](Object const& o) -> Json {
|
||||
return JsonObject{
|
||||
{"position", jsonFromVec2I(o.position)},
|
||||
{"name", o.name},
|
||||
{"direction", DirectionNames.getRight(o.direction)},
|
||||
{"parameters", o.parameters},
|
||||
{"residual", o.residual},
|
||||
};
|
||||
};
|
||||
|
||||
return JsonObject{{"region", jsonFromRectI(m_region)},
|
||||
{"anchorPosition", jsonFromVec2I(m_anchorPosition)},
|
||||
{"config", m_config},
|
||||
{"backgroundOverlays", m_backgroundOverlays.transformed(overlayToJson)},
|
||||
{"foregroundOverlays", m_foregroundOverlays.transformed(overlayToJson)},
|
||||
{"backgroundBlocks", m_backgroundBlocks.transformed(blockToJson)},
|
||||
{"foregroundBlocks", m_foregroundBlocks.transformed(blockToJson)},
|
||||
{"objects", m_objects.transformed(objectToJson)},
|
||||
{"flaggedBlocks",
|
||||
transform<JsonObject>(m_flaggedBlocks,
|
||||
[](pair<String, List<Vec2I>> const& p) {
|
||||
return pair<String, Json>(p.first, p.second.transformed(jsonFromVec2I));
|
||||
})}};
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue