mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-11-06 11:57:13 +00:00
test: raw terrain reading, scene lookup, scene graph and scene commands
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
183
tests/dGameTests/dZoneManagerTests/TerrainTestWriter.h
Normal file
183
tests/dGameTests/dZoneManagerTests/TerrainTestWriter.h
Normal file
@@ -0,0 +1,183 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "NiPoint3.h"
|
||||
|
||||
// Writes .raw terrain and .luz zone files in the client's layout, for the zone manager tests
|
||||
namespace TerrainTestWriter {
|
||||
template<typename T>
|
||||
void Write(std::ostream& stream, const T& value) {
|
||||
stream.write(reinterpret_cast<const char*>(&value), sizeof(T));
|
||||
}
|
||||
|
||||
inline void WriteBytes(std::ostream& stream, size_t count, uint8_t value = 0xAB) {
|
||||
const std::string bytes(count, static_cast<char>(value));
|
||||
stream.write(bytes.data(), bytes.size());
|
||||
}
|
||||
|
||||
inline void WriteString8(std::ostream& stream, const std::string& value) {
|
||||
Write<uint8_t>(stream, static_cast<uint8_t>(value.size()));
|
||||
stream.write(value.data(), value.size());
|
||||
}
|
||||
|
||||
struct TestChunk {
|
||||
uint32_t id = 0;
|
||||
uint32_t width = 3;
|
||||
uint32_t height = 3;
|
||||
float offsetX = 0.0f;
|
||||
float offsetZ = 0.0f;
|
||||
float scale = 1.0f;
|
||||
// Version 32+: the color map resolution; older versions use width - 1
|
||||
uint32_t colorMapResolution = 2;
|
||||
// colorMapResolution^2 scene IDs ((resolution + 1)^2 for version 31); empty = all 0
|
||||
std::vector<uint8_t> sceneMap;
|
||||
// width * height heights; empty = the point index
|
||||
std::vector<float> heights;
|
||||
uint32_t lightMapSize = 5;
|
||||
uint32_t textureMapResolution = 2;
|
||||
uint32_t blendMapSize = 7;
|
||||
uint32_t flairCount = 2;
|
||||
uint32_t vertSize = 4;
|
||||
std::vector<uint16_t> triangleListSizes = { 3, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 };
|
||||
};
|
||||
|
||||
inline void WriteChunk(std::ostream& stream, const TestChunk& chunk, uint16_t version) {
|
||||
Write(stream, chunk.id);
|
||||
Write(stream, chunk.width);
|
||||
Write(stream, chunk.height);
|
||||
Write(stream, chunk.offsetX);
|
||||
Write(stream, chunk.offsetZ);
|
||||
if (version < 32) Write<uint32_t>(stream, 77); // shader ID
|
||||
for (uint32_t i = 0; i < 4; ++i) Write<uint32_t>(stream, 100 + i); // texture IDs
|
||||
Write(stream, chunk.scale);
|
||||
for (uint32_t i = 0; i < chunk.width * chunk.height; ++i) {
|
||||
Write<float>(stream, chunk.heights.empty() ? static_cast<float>(i) : chunk.heights[i]);
|
||||
}
|
||||
|
||||
const uint32_t resolution = version >= 32 ? chunk.colorMapResolution : chunk.width - 1;
|
||||
if (version >= 32) {
|
||||
Write(stream, resolution);
|
||||
WriteBytes(stream, static_cast<size_t>(resolution) * resolution * 4);
|
||||
Write(stream, chunk.lightMapSize);
|
||||
WriteBytes(stream, chunk.lightMapSize);
|
||||
} else {
|
||||
WriteBytes(stream, static_cast<size_t>(chunk.width) * chunk.width * 4);
|
||||
}
|
||||
|
||||
Write(stream, chunk.textureMapResolution);
|
||||
WriteBytes(stream, static_cast<size_t>(chunk.textureMapResolution) * chunk.textureMapResolution * 4);
|
||||
if (version >= 32) {
|
||||
Write<uint8_t>(stream, 1); // texture settings
|
||||
Write(stream, chunk.blendMapSize);
|
||||
WriteBytes(stream, chunk.blendMapSize);
|
||||
}
|
||||
|
||||
// Flair: id, scale, position, rotation, RGBA (36 bytes)
|
||||
Write(stream, chunk.flairCount);
|
||||
for (uint32_t i = 0; i < chunk.flairCount; ++i) {
|
||||
Write<uint32_t>(stream, 500 + i);
|
||||
Write<float>(stream, 1.5f);
|
||||
Write(stream, NiPoint3(1.0f + i, 2.0f, 3.0f));
|
||||
Write(stream, NiPoint3(0.0f, 90.0f, 0.0f));
|
||||
for (const uint8_t channel : { 10, 20, 30, 40 }) Write(stream, channel);
|
||||
}
|
||||
|
||||
if (version >= 31) {
|
||||
const size_t cells = version >= 32 ? static_cast<size_t>(resolution) * resolution : static_cast<size_t>(resolution + 1) * (resolution + 1);
|
||||
for (size_t i = 0; i < cells; ++i) Write<uint8_t>(stream, chunk.sceneMap.empty() ? 0 : chunk.sceneMap[i]);
|
||||
} else {
|
||||
Write<uint8_t>(stream, 0);
|
||||
}
|
||||
|
||||
if (version < 32) return;
|
||||
Write(stream, chunk.vertSize);
|
||||
if (chunk.vertSize == 0) return;
|
||||
WriteBytes(stream, static_cast<size_t>(chunk.vertSize) * sizeof(uint16_t));
|
||||
WriteBytes(stream, 16 * sizeof(uint16_t));
|
||||
for (uint32_t i = 0; i < 16; ++i) {
|
||||
const uint16_t size = i < chunk.triangleListSizes.size() ? chunk.triangleListSizes[i] : 0;
|
||||
Write(stream, size);
|
||||
WriteBytes(stream, static_cast<size_t>(size) * sizeof(uint16_t));
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string WriteRaw(const std::vector<TestChunk>& chunks, uint16_t version = 32, uint32_t chunksX = 1, uint32_t chunksZ = 1, uint8_t dev = 0) {
|
||||
std::ostringstream stream;
|
||||
Write(stream, version);
|
||||
Write(stream, dev);
|
||||
if (dev == 0) {
|
||||
Write<uint32_t>(stream, static_cast<uint32_t>(chunks.size()));
|
||||
Write(stream, chunksZ); // the header's "width" is the chunk count along Z
|
||||
Write(stream, chunksX);
|
||||
for (const auto& chunk : chunks) WriteChunk(stream, chunk, version);
|
||||
}
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
struct TestScene {
|
||||
std::string filename;
|
||||
uint32_t id = 0;
|
||||
uint32_t layer = 0;
|
||||
std::string name;
|
||||
uint8_t r = 0, g = 0, b = 0;
|
||||
};
|
||||
|
||||
struct TestTransitionPoint {
|
||||
uint32_t sceneID = 0;
|
||||
uint32_t layerID = 0;
|
||||
NiPoint3 position;
|
||||
};
|
||||
|
||||
// A Latest (41) version .luz with no paths
|
||||
inline std::string WriteLuz(uint32_t worldID, const std::vector<TestScene>& scenes, uint8_t boundaryCount, const std::string& rawName,
|
||||
const std::vector<std::pair<TestTransitionPoint, TestTransitionPoint>>& transitions) {
|
||||
std::ostringstream stream;
|
||||
Write<uint32_t>(stream, 41); // version
|
||||
Write<uint32_t>(stream, 5); // revision
|
||||
Write(stream, worldID);
|
||||
Write(stream, NiPoint3(1.0f, 2.0f, 3.0f)); // spawn position
|
||||
for (const float value : { 1.0f, 0.0f, 0.0f, 0.0f }) Write(stream, value); // spawn rotation
|
||||
Write<uint32_t>(stream, static_cast<uint32_t>(scenes.size()));
|
||||
for (const auto& scene : scenes) {
|
||||
WriteString8(stream, scene.filename);
|
||||
Write(stream, scene.id);
|
||||
Write(stream, scene.layer);
|
||||
WriteString8(stream, scene.name);
|
||||
Write(stream, scene.r);
|
||||
Write(stream, scene.b);
|
||||
Write(stream, scene.g);
|
||||
}
|
||||
|
||||
// Zone boundary lines: normal, point, destination zone, destination scene, spawn location (44 bytes)
|
||||
Write(stream, boundaryCount);
|
||||
for (uint8_t i = 0; i < boundaryCount; ++i) {
|
||||
Write(stream, NiPoint3(0.0f, 0.0f, 1.0f));
|
||||
Write(stream, NiPoint3(10.0f, 0.0f, static_cast<float>(i)));
|
||||
Write<uint32_t>(stream, 1100);
|
||||
Write<uint32_t>(stream, 2);
|
||||
Write(stream, NiPoint3(5.0f, 6.0f, 7.0f));
|
||||
}
|
||||
|
||||
WriteString8(stream, rawName);
|
||||
WriteString8(stream, "Test Zone");
|
||||
WriteString8(stream, "A zone for tests");
|
||||
|
||||
Write<uint32_t>(stream, static_cast<uint32_t>(transitions.size()));
|
||||
for (const auto& [from, to] : transitions) {
|
||||
for (const auto& point : { from, to }) {
|
||||
Write(stream, point.sceneID);
|
||||
Write(stream, point.layerID);
|
||||
Write(stream, point.position);
|
||||
}
|
||||
}
|
||||
|
||||
Write<uint32_t>(stream, 8); // path data length
|
||||
Write<uint32_t>(stream, 1); // path chunk version
|
||||
Write<uint32_t>(stream, 0); // path count
|
||||
return stream.str();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user