3#if defined(__EMSCRIPTEN__)
10 "generation request JSON codec is unavailable on the Web build",
"codec",
11 {},
"pixelworld.generation-codec");
17 const PixelWorldGenerationRequest&) {
29#include <Poco/Dynamic/Var.h>
30#include <Poco/JSON/Array.h>
31#include <Poco/JSON/Object.h>
32#include <Poco/JSON/Parser.h>
33#include <Poco/JSON/Stringifier.h>
39#include <unordered_set>
44using Object = Poco::JSON::Object;
45using Array = Poco::JSON::Array;
48 std::string
path =
"document") {
51 "pixelworld.generation-codec"));
54bool exactFields(
const Object&
object, std::initializer_list<std::string_view> allowed) {
55 std::unordered_set<std::string> names;
56 for (
const auto name : allowed) names.emplace(
name);
57 if (
object.
size() != names.size())
return false;
59 if (!names.contains(
name)) return false;
60 for (
const auto&
name : names)
67 static_assert(std::is_integral_v<T> && !std::is_same_v<T, bool>);
68 if (!
object.has(
key) ||
object.isNull(
key))
return false;
70 const auto wide =
object.get(
key).convert<std::int64_t>();
71 if constexpr (std::is_unsigned_v<T>) {
72 if (wide < 0 || std::uint64_t(wide) > std::numeric_limits<T>::max())
return false;
73 }
else if (wide < std::numeric_limits<T>::min() ||
74 wide > std::numeric_limits<T>::max()) {
77 result =
static_cast<T
>(wide);
84bool readSeed(
const Object&
object, std::uint64_t&
seed) {
85 if (!
object.has(
"seed") ||
object.isNull(
"seed"))
return false;
87 const std::string
text =
object.getValue<std::string>(
"seed");
91 return parsed.ec == std::errc{} && parsed.ptr ==
end;
97Object::Ptr cellJson(
const PixelCell&
cell) {
98 Object::Ptr out(
new Object);
99 out->set(
"material", std::uint16_t(
cell.material));
100 out->set(
"temperature",
cell.temperature);
101 out->set(
"lifetime",
cell.lifetime);
102 out->set(
"thermalRemainder",
cell.thermalRemainder);
111 root->set(
"schema",
"eve.pixelworld.generation-request");
114 Object::Ptr region(
new Object);
115 region->set(
"minX",
request.region.minX);
116 region->set(
"minY",
request.region.minY);
117 region->set(
"maxX",
request.region.maxX);
118 region->set(
"maxY",
request.region.maxY);
119 root->set(
"region", region);
121 root->set(
"terrainAmplitude",
request.terrainAmplitude);
124 Array::Ptr stamps(
new Array);
136 root->set(
"stamps", stamps);
137 std::ostringstream
text;
138 Poco::JSON::Stringifier::stringify(Poco::Dynamic::Var(
root),
text, 2, -1);
143 std::string_view json) {
146 root = Poco::JSON::Parser().parse(std::string(json)).extract<Object::Ptr>();
148 return malformed(
"generation request JSON is malformed");
150 if (!
root || !exactFields(*
root, {
"schema",
"version",
"seed",
"region",
"surfaceY",
151 "terrainAmplitude",
"waterLevel",
"caveThreshold",
"stamps"}))
152 return malformed(
"root contains missing or unknown fields");
153 if (
root->optValue<std::string>(
"schema",
"") !=
"eve.pixelworld.generation-request")
154 return malformed(
"unknown generation request schema",
"schema");
157 if (!readNumber(*
root,
"version",
request.schemaVersion) ||
159 return malformed(
"unknown generation request version",
"version");
160 if (!readSeed(*
root,
request.seed))
return malformed(
"seed is not a canonical uint64",
"seed");
164 region =
root->getObject(
"region");
165 stamps =
root->getArray(
"stamps");
167 return malformed(
"region or stamps has an invalid type");
169 if (!region || !exactFields(*region, {
"minX",
"minY",
"maxX",
"maxY"}) || !stamps ||
170 stamps->size() > 65'536U)
171 return malformed(
"region fields or stamp budget are invalid");
172 if (!readNumber(*region,
"minX",
request.region.minX) ||
173 !readNumber(*region,
"minY",
request.region.minY) ||
174 !readNumber(*region,
"maxX",
request.region.maxX) ||
175 !readNumber(*region,
"maxY",
request.region.maxY) ||
176 !readNumber(*
root,
"surfaceY",
request.surfaceY) ||
177 !readNumber(*
root,
"terrainAmplitude",
request.terrainAmplitude) ||
178 !readNumber(*
root,
"waterLevel",
request.waterLevel) ||
179 !readNumber(*
root,
"caveThreshold",
request.caveThreshold))
180 return malformed(
"generation request contains an invalid number");
182 std::uint64_t totalCells = 0;
183 request.stamps.reserve(stamps->size());
191 return malformed(
"stamp is not an object",
"stamps[" + std::to_string(
index) +
"]");
193 if (!
value || !exactFields(*
value, {
"originX",
"originY",
"width",
"height",
"cells"}) ||
195 return malformed(
"stamp contains missing or unknown fields",
196 "stamps[" + std::to_string(
index) +
"]");
198 if (!readNumber(*
value,
"originX",
stamp.originX) ||
199 !readNumber(*
value,
"originY",
stamp.originY) ||
202 std::uint64_t(
stamp.width) * std::uint64_t(
stamp.height) !=
cells->size())
203 return malformed(
"stamp dimensions are invalid",
"stamps[" + std::to_string(
index) +
"]");
204 totalCells +=
cells->size();
205 if (totalCells > 4'194'304ULL)
return malformed(
"stamp cell budget is exceeded",
"stamps");
207 for (std::size_t cellIndex = 0; cellIndex <
cells->size(); ++cellIndex) {
210 item =
cells->getObject(
unsigned(cellIndex));
212 return malformed(
"stamp cell is not an object",
"stamps.cells");
216 if (!item || !exactFields(*item, {
"material",
"temperature",
"lifetime",
"thermalRemainder"}) ||
217 !readNumber(*item,
"material",
material) ||
218 !readNumber(*item,
"temperature",
cell.temperature) ||
219 !readNumber(*item,
"lifetime",
cell.lifetime) ||
220 !readNumber(*item,
"thermalRemainder",
cell.thermalRemainder))
221 return malformed(
"stamp cell contains invalid fields",
"stamps.cells");
const GltfImportRequest & request
std::array< PixelCell, kPixelChunkSize *kPixelChunkSize > cells
A structured explanation of a failed, degraded, or noteworthy result.
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Move-only operation result carrying either a value or Status.
static Result success(T value)
Construct a successful result owning value.
static Result failure(Status status)
Construct a failed result from a structured status.
eve::Result< std::string > encodePixelWorldGenerationRequestJson(const PixelWorldGenerationRequest &request)
Encode schema eve.pixelworld.generation-request version 1 canonically.
MaterialId
Compact stable material identifier stored in each authoritative cell.
eve::Result< PixelWorldGenerationRequest > decodePixelWorldGenerationRequestJson(std::string_view json)
Decode schema eve.pixelworld.generation-request version 1.
bool readNumber(const EditorValue &value, const char *name, float &output)
enum EVENGINE_API_FOUNDATION Array
OT_ARRAY (editable via Runtime array APIs / ReflectedPropertyModel).
Compact authoritative state for one simulated world pixel.
Owning row-major material stamp applied after terrain and cave generation.
Versioned bounded request for deterministic biome and cave generation.
static constexpr std::uint32_t kSchemaVersion