载入中...
搜索中...
未找到
PixelWorldGeneration.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <limits>
5#include <string>
6#include <type_traits>
7#include <utility>
8
9namespace eve::pixelworld {
10namespace {
11
12std::uint64_t mix(std::uint64_t value) noexcept {
13 value += 0x9E3779B97F4A7C15ULL;
14 value = (value ^ (value >> 30U)) * 0xBF58476D1CE4E5B9ULL;
15 value = (value ^ (value >> 27U)) * 0x94D049BB133111EBULL;
16 return value ^ (value >> 31U);
17}
18
19std::uint64_t coordinateHash(std::uint64_t seed, int x, int y, std::uint64_t stream) noexcept {
20 return mix(seed ^ (std::uint64_t(std::uint32_t(x)) << 32U) ^
21 std::uint64_t(std::uint32_t(y)) ^ stream);
22}
23
24int floorDivGeneration(int value, int divisor) noexcept {
25 return value >= 0 ? value / divisor : -((-value + divisor - 1) / divisor);
26}
27
28int interpolatedNoise(std::uint64_t seed, int coordinate, int spacing,
29 std::uint64_t stream) noexcept {
30 const int lattice = floorDivGeneration(coordinate, spacing);
31 const int offset = coordinate - lattice * spacing;
32 const int first = int(coordinateHash(seed, lattice, 0, stream) % 20001ULL) - 10000;
33 const int second = int(coordinateHash(seed, lattice + 1, 0, stream) % 20001ULL) - 10000;
34 return (first * (spacing - offset) + second * offset) / spacing;
35}
36
37PixelBiome biomeAt(std::uint64_t seed, int worldX) noexcept {
38 const int band = floorDivGeneration(worldX, 192);
39 return PixelBiome(coordinateHash(seed, band, 0, 0x42494F4D45ULL) % 4ULL);
40}
41
42PixelCell defaultCell(const MaterialCatalog& catalog, MaterialId material) {
43 PixelCell cell;
44 cell.material = material;
45 const auto& definition = catalog.definition(material);
46 cell.temperature = definition.defaultTemperature;
47 cell.lifetime = std::uint8_t(std::min<std::uint16_t>(
48 definition.defaultLifetime, std::numeric_limits<std::uint8_t>::max()));
49 return cell;
50}
51
52MaterialId terrainMaterial(PixelBiome biome, int depth, std::uint64_t feature) noexcept {
53 if (biome == PixelBiome::Desert && depth < 10) return MaterialId::Sand;
54 if (biome == PixelBiome::Fungal && depth < 4) return MaterialId::Wood;
55 if (biome == PixelBiome::Volcanic && depth > 18 && feature % 97ULL == 0)
56 return MaterialId::Lava;
57 return MaterialId::Stone;
58}
59
60eve::Result<PixelWorldGenerationOutput> invalidGeneration(std::string message,
61 std::string path) {
64 "pixelworld.generation"));
65}
66
67void hashByte(std::uint64_t& hash, std::uint8_t value) noexcept {
68 hash ^= value;
69 hash *= 1099511628211ULL;
70}
71
72template <class T>
73void hashValue(std::uint64_t& hash, T value) noexcept {
74 using Unsigned = std::make_unsigned_t<T>;
75 const Unsigned bits = static_cast<Unsigned>(value);
76 for (std::size_t index = 0; index < sizeof(T); ++index)
77 hashByte(hash, std::uint8_t(bits >> (index * 8U)));
78}
79
80} // namespace
81
84 std::uint64_t sourceRevision, eve::SimulationTick sourceTick,
85 std::uint64_t sourceLastEditSequence) {
87 return invalidGeneration("unsupported PixelWorld generation schema version", "schemaVersion");
88 if (request.region.minX > request.region.maxX || request.region.minY > request.region.maxY)
89 return invalidGeneration("generation region bounds are inverted", "region");
90 const std::int64_t width = std::int64_t(request.region.maxX) - request.region.minX + 1;
91 const std::int64_t height = std::int64_t(request.region.maxY) - request.region.minY + 1;
92 if (width * height > 65'536)
93 return invalidGeneration("generation region exceeds 65536 Chunks", "region");
94 if (sourceRevision == 0)
95 return invalidGeneration("source revision must be positive", "sourceRevision");
96 if (catalog.definitions().size() <= std::size_t(MaterialId::Lava))
97 return invalidGeneration("generation Catalog must provide the built-in terrain material ids",
98 "catalog");
99 if (request.terrainAmplitude < 0 || request.terrainAmplitude > 4096)
100 return invalidGeneration("terrain amplitude must be in [0, 4096]", "terrainAmplitude");
101 if (request.caveThreshold > 10'000)
102 return invalidGeneration("cave threshold must be in [0, 10000]", "caveThreshold");
103 std::uint64_t stampCells = 0;
104 for (std::size_t index = 0; index < request.stamps.size(); ++index) {
105 const auto& stamp = request.stamps[index];
106 if (stamp.width <= 0 || stamp.height <= 0 ||
107 std::uint64_t(stamp.width) * std::uint64_t(stamp.height) != stamp.cells.size())
108 return invalidGeneration("stamp dimensions must match its row-major cells",
109 "stamps[" + std::to_string(index) + "]");
110 stampCells += stamp.cells.size();
111 if (stampCells > 4'194'304)
112 return invalidGeneration("material stamps exceed the cell budget", "stamps");
113 for (const PixelCell cell : stamp.cells)
114 if (std::size_t(cell.material) >= catalog.definitions().size())
115 return invalidGeneration("stamp references an unknown material",
116 "stamps[" + std::to_string(index) + "].cells");
117 }
118
121 output.batch.sourceSeed = request.seed;
122 output.batch.sourceRevision = sourceRevision;
123 output.batch.sourceTick = sourceTick;
124 output.batch.sourceLastEditSequence = sourceLastEditSequence;
125 output.batch.chunks.reserve(std::size_t(width * height));
126 output.chunks.reserve(std::size_t(width * height));
127 std::uint64_t hash = 1469598103934665603ULL;
128
129 for (int chunkY = request.region.minY; chunkY <= request.region.maxY; ++chunkY)
130 for (int chunkX = request.region.minX; chunkX <= request.region.maxX; ++chunkX) {
131 PixelChunkSnapshot snapshot;
132 snapshot.x = chunkX;
133 snapshot.y = chunkY;
134 snapshot.revision = sourceRevision;
135 snapshot.cells.resize(std::size_t(kPixelChunkSize * kPixelChunkSize));
137 summary.x = chunkX;
138 summary.y = chunkY;
139 summary.biome = biomeAt(request.seed, chunkX * kPixelChunkSize + kPixelChunkSize / 2);
140 for (int localY = 0; localY < kPixelChunkSize; ++localY)
141 for (int localX = 0; localX < kPixelChunkSize; ++localX) {
142 const int worldX = chunkX * kPixelChunkSize + localX;
143 const int worldY = chunkY * kPixelChunkSize + localY;
144 const PixelBiome biome = biomeAt(request.seed, worldX);
145 const int surface = request.surfaceY +
146 interpolatedNoise(request.seed, worldX, 32, 0x53555246414345ULL) *
147 request.terrainAmplitude / 10000;
149 if (worldY >= surface) {
150 const int depth = worldY - surface;
151 const std::uint64_t caveNoise = coordinateHash(
152 request.seed, floorDivGeneration(worldX, 5),
153 floorDivGeneration(worldY, 5), 0x43415645ULL) % 10001ULL;
154 const bool cave = depth > 5 && caveNoise < request.caveThreshold;
155 if (cave) {
156 ++summary.caveCells;
157 if (worldY >= request.waterLevel &&
158 coordinateHash(request.seed, worldX, worldY, 0x5741544552ULL) % 5ULL == 0)
159 cell = defaultCell(catalog, MaterialId::Water);
160 } else {
161 const std::uint64_t feature = coordinateHash(
162 request.seed, worldX, worldY, 0x46454154555245ULL);
163 cell = defaultCell(catalog, terrainMaterial(biome, depth, feature));
164 ++summary.solidCells;
165 }
166 }
167 snapshot.cells[std::size_t(localY * kPixelChunkSize + localX)] = cell;
168 }
169
170 const int chunkMinX = chunkX * kPixelChunkSize;
171 const int chunkMinY = chunkY * kPixelChunkSize;
172 for (const PixelMaterialStamp& stamp : request.stamps)
173 for (int stampY = 0; stampY < stamp.height; ++stampY)
174 for (int stampX = 0; stampX < stamp.width; ++stampX) {
175 const int worldX = stamp.originX + stampX;
176 const int worldY = stamp.originY + stampY;
177 if (worldX < chunkMinX || worldX >= chunkMinX + kPixelChunkSize ||
178 worldY < chunkMinY || worldY >= chunkMinY + kPixelChunkSize)
179 continue;
180 snapshot.cells[std::size_t(worldY - chunkMinY) * kPixelChunkSize +
181 std::size_t(worldX - chunkMinX)] =
182 stamp.cells[std::size_t(stampY) * std::size_t(stamp.width) + stampX];
183 ++summary.stampedCells;
184 }
185
186 hashValue(hash, std::int32_t(chunkX));
187 hashValue(hash, std::int32_t(chunkY));
188 for (const PixelCell cell : snapshot.cells) {
189 hashValue(hash, std::uint16_t(cell.material));
190 hashValue(hash, cell.temperature);
191 hashValue(hash, cell.lifetime);
192 hashValue(hash, cell.thermalRemainder);
193 }
194 output.batch.chunks.push_back(std::move(snapshot));
195 output.chunks.push_back(summary);
196 }
197 output.contentHash = hash;
199}
200
201} // namespace eve::pixelworld
double value
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
std::string output
std::array< std::uint8_t, 32 > hash
Definition Evpack.cpp:172
std::string message
const GltfImportRequest & request
std::int32_t second
std::int32_t first
int biome
std::uint32_t height
std::uint32_t width
size_t offset
std::string path
Definition PlayHost.cpp:110
std::uint32_t seed
Definition PointSet.cpp:807
Material * material
Cell cell
Heightmap stamp
int spacing
uint32_t index
std::uint32_t depth
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.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
Owning immutable material and reaction table used by one PixelWorld.
std::span< const MaterialDefinition > definitions() const noexcept
Borrow immutable definitions until this catalog is destroyed.
std::uint64_t fingerprint() const noexcept
Stable deterministic fingerprint included in world snapshots.
eve::Result< PixelWorldGenerationOutput > generatePixelWorld(const PixelWorldGenerationRequest &request, const MaterialCatalog &catalog, std::uint64_t sourceRevision, eve::SimulationTick sourceTick, std::uint64_t sourceLastEditSequence)
Generate a seamless canonical Chunk batch without mutating a PixelWorld.
MaterialId
Compact stable material identifier stored in each authoritative cell.
PixelBiome
Stable coarse biome selected from deterministic world coordinates.
constexpr int kPixelChunkSize
Definition PixelWorld.h:20
Compact authoritative state for one simulated world pixel.
Definition PixelWorld.h:24
Owning, immutable projection of one authoritative simulation chunk.
Definition PixelWorld.h:77
std::vector< PixelCell > cells
Definition PixelWorld.h:82
Deterministic diagnostics for one generated Chunk.
Owning row-major material stamp applied after terrain and cave generation.
Owning generated correction plus reproducibility evidence.
Versioned bounded request for deterministic biome and cave generation.