192 lines
8.2 KiB
C++
192 lines
8.2 KiB
C++
#pragma once
|
|
|
|
#include "editor/EditorAuthority.h"
|
|
#include "editing/EditableTarget.h"
|
|
|
|
#include <map>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace eve::editor {
|
|
|
|
/** @brief Stable map layer descriptor used by outliner presenters. */
|
|
struct MapLayerRecord {
|
|
StableId id;
|
|
std::string name;
|
|
std::string kind = "tile";
|
|
bool visible = true;
|
|
bool locked = false;
|
|
double opacity = 1.0;
|
|
int order = 0;
|
|
};
|
|
|
|
/** @brief Stable editable control point in a road or path spline. */
|
|
struct MapSplinePointRecord {
|
|
StableId id;
|
|
double x = 0.0;
|
|
double y = 0.0;
|
|
double z = 0.0;
|
|
double width = 4.0;
|
|
};
|
|
|
|
/** @brief Road spline authoring record independent from rendering/mesh generation. */
|
|
struct MapRoadRecord {
|
|
StableId id;
|
|
StableId layer;
|
|
std::string name;
|
|
std::string materialAsset;
|
|
bool closed = false;
|
|
std::vector<MapSplinePointRecord> points;
|
|
};
|
|
|
|
/** @brief Stable object placement stored on an object layer. */
|
|
struct MapPlacementRecord {
|
|
StableId id;
|
|
StableId layer;
|
|
std::string asset;
|
|
double x = 0.0;
|
|
double y = 0.0;
|
|
double z = 0.0;
|
|
double rotationX = 0.0;
|
|
double rotationY = 0.0;
|
|
double rotationZ = 0.0;
|
|
double scaleX = 1.0;
|
|
double scaleY = 1.0;
|
|
double scaleZ = 1.0;
|
|
};
|
|
|
|
/** @brief Deterministic renderer-neutral road strip preview. */
|
|
struct MapRoadPreviewResult {
|
|
EditorStatus status = EditorStatus::Failed;
|
|
Revision documentRevision = 0;
|
|
StableId road;
|
|
double centerlineLength = 0.0;
|
|
EditorValue mesh;
|
|
std::vector<EditorDiagnostic> diagnostics;
|
|
};
|
|
|
|
/** @brief Runtime-neutral sink receiving revision-tagged generated road meshes. */
|
|
class IMapRoadMeshSink {
|
|
public:
|
|
virtual ~IMapRoadMeshSink() = default;
|
|
/** @brief Atomically publish or replace one generated road mesh. */
|
|
virtual EditorResult<void> publishRoad(const std::string& document, const StableId& road,
|
|
Revision revision, const EditorValue& mesh) = 0;
|
|
/** @brief Remove a previously published road mesh. */
|
|
virtual EditorResult<void> removeRoad(const std::string& document, const StableId& road) = 0;
|
|
};
|
|
|
|
/** @brief Imported object record before stable placement ids are assigned. */
|
|
struct MapObjectImportRecord {
|
|
std::string sourceId;
|
|
std::string asset;
|
|
double x = 0.0, y = 0.0, z = 0.0;
|
|
double rotationX = 0.0, rotationY = 0.0, rotationZ = 0.0;
|
|
double scaleX = 1.0, scaleY = 1.0, scaleZ = 1.0;
|
|
};
|
|
|
|
/** @brief Side-effect-free batch import plan for map object placements. */
|
|
struct MapObjectImportPlan {
|
|
EditorStatus status = EditorStatus::Failed;
|
|
Revision documentRevision = 0;
|
|
std::vector<DomainOperation> operations;
|
|
std::vector<EditorDiagnostic> diagnostics;
|
|
};
|
|
|
|
/** @brief Layer, spline and placement editing capability for map presenters. */
|
|
class IMapStructureEditTarget {
|
|
public:
|
|
virtual ~IMapStructureEditTarget() = default;
|
|
/** @brief Stable capability id for map structure operations. */
|
|
static CapabilityId editorCapabilityId() { return CapabilityId("eve.editor.target.map-structure"); }
|
|
/** @brief Enumerate layers in visual order. */
|
|
virtual std::vector<MapLayerRecord> mapLayers() const = 0;
|
|
/** @brief Enumerate roads in stable id order. */
|
|
virtual std::vector<MapRoadRecord> mapRoads() const = 0;
|
|
/** @brief Enumerate placements in stable id order. */
|
|
virtual std::vector<MapPlacementRecord> mapPlacements() const = 0;
|
|
/** @brief Plan reversible layer creation. */
|
|
virtual EditorResult<DomainOperation> makeCreateLayer(const MapLayerRecord& layer) const = 0;
|
|
/** @brief Plan deletion of an empty layer. */
|
|
virtual EditorResult<DomainOperation> makeDeleteLayer(const StableId& layer) const = 0;
|
|
/** @brief Plan reversible layer metadata replacement. */
|
|
virtual EditorResult<DomainOperation> makeSetLayer(const MapLayerRecord& layer) const = 0;
|
|
/** @brief Plan reversible road creation or replacement. */
|
|
virtual EditorResult<DomainOperation> makeSetRoad(const MapRoadRecord& road) const = 0;
|
|
/** @brief Plan reversible road deletion. */
|
|
virtual EditorResult<DomainOperation> makeDeleteRoad(const StableId& road) const = 0;
|
|
/** @brief Plan reversible placement creation or replacement. */
|
|
virtual EditorResult<DomainOperation> makeSetPlacement(const MapPlacementRecord& placement) const = 0;
|
|
/** @brief Plan reversible placement deletion. */
|
|
virtual EditorResult<DomainOperation> makeDeletePlacement(const StableId& placement) const = 0;
|
|
};
|
|
|
|
/** @brief UI-neutral map structure document with reversible domain operations. */
|
|
class MapDocumentTarget final : public virtual IEditableTarget,
|
|
public IDomainOperationTarget,
|
|
public IDomainOperationTargetStaging,
|
|
public IMapStructureEditTarget {
|
|
public:
|
|
explicit MapDocumentTarget(std::string id);
|
|
const std::string& targetId() const override { return id_; }
|
|
unsigned long long revision() const override { return revision_; }
|
|
EditRegion dirtyRegion() const override { return dirty_; }
|
|
void clearDirtyRegion() override { dirty_.clear(); }
|
|
TargetDescriptor describe() const override;
|
|
/** @brief Query an optional target capability. @return Borrowed pointer owned by this target, or null. @lifetime Valid until this target is destroyed or mutated. */
|
|
void* queryCapability(const CapabilityId& capability) override;
|
|
EditorResult<void> applyDomainOperation(const DomainOperation& operation) override;
|
|
[[nodiscard]] std::unique_ptr<IDomainOperationTarget> cloneDomainState() const override;
|
|
[[nodiscard]] EditorResult<void> commitDomainState(
|
|
std::unique_ptr<IDomainOperationTarget> candidate) override;
|
|
|
|
std::vector<MapLayerRecord> mapLayers() const override;
|
|
std::vector<MapRoadRecord> mapRoads() const override;
|
|
std::vector<MapPlacementRecord> mapPlacements() const override;
|
|
EditorResult<DomainOperation> makeCreateLayer(const MapLayerRecord& layer) const override;
|
|
EditorResult<DomainOperation> makeDeleteLayer(const StableId& layer) const override;
|
|
EditorResult<DomainOperation> makeSetLayer(const MapLayerRecord& layer) const override;
|
|
EditorResult<DomainOperation> makeSetRoad(const MapRoadRecord& road) const override;
|
|
EditorResult<DomainOperation> makeDeleteRoad(const StableId& road) const override;
|
|
EditorResult<DomainOperation> makeSetPlacement(const MapPlacementRecord& placement) const override;
|
|
EditorResult<DomainOperation> makeDeletePlacement(const StableId& placement) const override;
|
|
|
|
/** @brief Validate layers, spline geometry and placement references. */
|
|
std::vector<EditorDiagnostic> validate() const;
|
|
/** @brief Build a deterministic XZ road strip for viewport preview and budget diagnostics. */
|
|
MapRoadPreviewResult previewRoad(const StableId& road, int triangleBudget = 10000) const;
|
|
/** @brief Capture deterministic map structure data. */
|
|
EditorValue snapshotValue() const;
|
|
/** @brief Atomically load schema-version-one map structure data. */
|
|
EditorResult<void> loadSnapshot(const EditorValue& snapshot);
|
|
|
|
private:
|
|
std::string id_;
|
|
unsigned long long revision_ = 1;
|
|
EditRegion dirty_;
|
|
std::map<StableId, MapLayerRecord> layers_;
|
|
std::map<StableId, MapRoadRecord> roads_;
|
|
std::map<StableId, MapPlacementRecord> placements_;
|
|
};
|
|
|
|
/** @brief Publishes validated road previews while rejecting stale document revisions. */
|
|
class MapRoadMeshPublisher {
|
|
public:
|
|
/** @brief Generate and publish one road mesh to the supplied host sink. */
|
|
EditorResult<void> publish(const MapDocumentTarget& document, const StableId& road,
|
|
Revision expectedRevision, IMapRoadMeshSink& sink,
|
|
int triangleBudget = 10000) const;
|
|
};
|
|
|
|
/** @brief Converts external object records into one atomic placement transaction plan. */
|
|
class MapObjectImporter {
|
|
public:
|
|
/** @brief Plan stable-id placement creation without mutating the map document. */
|
|
MapObjectImportPlan plan(const MapDocumentTarget& document, const StableId& layer,
|
|
const std::vector<MapObjectImportRecord>& records,
|
|
const std::string& idPrefix) const;
|
|
};
|
|
|
|
} // namespace eve::editor
|