载入中...
搜索中...
未找到
PlacementSystem.h
浏览该文件的文档.
1#pragma once
2#include "common/Export.h"
3
4
5// 放置操作静态入口 + 可插拔校验 / 吸附 / 变更钩子。
6//
7// C++ 侧通过 register* 扩展;脚本侧通过定义/世界上的策略名字符串选用已注册规则。
8
10#include "common/Result.h"
11
12#include <functional>
13#include <limits>
14#include <memory>
15#include <string>
16#include <unordered_map>
17#include <utility>
18#include <vector>
19
20namespace eve::building {
21
22class PlacementWorld;
23class Ghost;
24class HeightfieldSurface;
25class StaticMeshSurface;
26
29
32public:
33 using ValidateFn = std::function<bool(const PlacementWorld &world, const PlacementQuery &q,
34 std::string *reason)>;
35 using SnapFn =
37 std::function<SnapResult(const PlacementWorld &world, float worldX, float worldY)>;
38 using ChangeHook = std::function<void(const BuildingChangeEvent &ev)>;
39
41 struct PlacementHit {
42 float worldX = 0.f;
43 float worldY = 0.f;
44 float worldZ = 0.f;
45 float normalX = 0.f;
46 float normalY = 1.f;
47 float normalZ = 0.f;
48 float tangentX = 1.f;
49 float tangentY = 0.f;
50 float tangentZ = 0.f;
51 float bitangentX = 0.f;
52 float bitangentY = 0.f;
53 float bitangentZ = 1.f;
54 std::string surfaceId;
55 uint64_t surfaceRevision = 0;
56 uint64_t primitiveId = 0;
57 std::vector<std::string> tags;
58 };
61 int cellX = 0;
62 int cellY = 0;
64 };
66 struct SurfacePatch {
68 std::vector<SurfacePatchSample> samples;
69 float maxSlopeDegrees = 0.f;
70 float heightDelta = 0.f;
71 };
74 std::vector<int> instanceIds;
75 };
78 std::vector<int> instanceIds;
79 };
82 std::string buildingId;
83 int level = 0;
84 std::vector<EdgeAddress> edges;
85 };
90 std::string providerName;
91 std::string surfaceId;
92 uint64_t surfaceRevision = 0;
93 std::vector<EdgeCurveSurfaceSample> samples;
94 };
97 int cellX = 0;
98 int cellY = 0;
99 bool accepted = false;
100 std::string reason;
101 };
103 struct AreaPreview {
104 std::string buildingId;
105 int level = 0;
106 float rotationDeg = 0.f;
107 std::vector<AreaCellPreview> cells;
108 int acceptedCount = 0;
109 int rejectedCount = 0;
110 };
114 std::vector<int> instanceIds;
115 };
117 enum class PatternKind {
118 EdgeLine,
119 EdgePath,
120 EdgeCubicBezier,
121 RectangleFill,
122 RectangleOutline,
123 CircleBrush
124 };
127 PatternKind kind = PatternKind::RectangleFill;
128 std::vector<EdgeCurvePoint> points;
129 int radius = 0;
130 int subdivisions = 16;
131 float rotationDeg = 0.f;
132 std::string surfaceName;
133 };
140 int anchorCount() const {
141 return request.kind == PatternKind::EdgeLine ||
142 request.kind == PatternKind::EdgePath ||
143 request.kind == PatternKind::EdgeCubicBezier
144 ? static_cast<int>(edge.edges.size())
145 : static_cast<int>(area.cells.size());
146 }
147 };
151 std::vector<int> instanceIds;
152 };
159 using SurfaceFn = std::function<bool(const PlacementWorld &world, float x, float y,
160 PlacementHit *hit)>;
167 std::function<eve::Result<PlacementHit>(const PlacementWorld &world, float x, float y)>;
168
177 static PlacementSystem &inst();
178
179 static void registerValidateRule(const std::string &name, ValidateFn fn);
180 static void unregisterValidateRule(const std::string &name);
181 static bool hasValidateRule(const std::string &name);
182
183 static void registerSnapRule(const std::string &name, SnapFn fn);
184 static void unregisterSnapRule(const std::string &name);
185 static bool hasSnapRule(const std::string &name);
186
187 static void registerChangeHook(const std::string &name, ChangeHook fn);
188 static void unregisterChangeHook(const std::string &name);
189 static bool hasChangeHook(const std::string &name);
190
191 static void registerSurface(const std::string &name, SurfaceFn fn);
193 static void registerSurfaceProvider(const std::string &name, SurfaceProviderFn fn);
199 [[nodiscard]] static eve::Result<void>
200 registerHeightfieldSurface(const std::string &name,
201 std::shared_ptr<const HeightfieldSurface> surface);
209 [[nodiscard]] static eve::Result<void>
210 registerStaticMeshSurface(const std::string &name,
211 std::shared_ptr<const StaticMeshSurface> surface);
212 static void unregisterSurface(const std::string &name);
213 static bool hasSurface(const std::string &name);
214 static bool surfaceHit(const PlacementWorld &world, const std::string &name, float x,
215 float y, PlacementHit *hit);
221 [[nodiscard]] static eve::Result<PlacementHit>
222 sampleSurface(const PlacementWorld &world, const std::string &name, float x, float y);
227 [[nodiscard]] static eve::Result<SurfacePatch>
228 sampleSurfacePatch(const PlacementWorld &world, const std::string &buildingId,
229 const std::string &surfaceName, float x, float y,
230 float rotationDegrees = 0.f);
231 static std::vector<std::string> surfaceNames();
233 static void setPlaneSurfaceHeight(float h);
234 static float getPlaneSurfaceHeight();
235
237 static void ensureBuiltins();
238
239 static SnapResult snap(const PlacementWorld &world, const std::string &buildingId, float worldX,
240 float worldY);
242 static SnapResult snap3D(const PlacementWorld &world, const std::string &buildingId,
243 float worldX, float worldY, float worldZ);
244 static SnapResult snapWithMode(const PlacementWorld &world, const std::string &mode,
245 float worldX, float worldY);
246
248 static float normalizeRotation(const std::string &buildingId, float rotationDeg);
249
251 static void effectiveFootprint(const BuildingDefinition &def, float rotationDeg, int *outW,
252 int *outH);
253
255 static bool foreachFootprintCell(const BuildingDefinition &def, int originCellX,
256 int originCellY, float rotationDeg,
257 const std::function<bool(int cx, int cy)> &fn);
258
260 [[nodiscard]] static eve::Result<EdgeAddress> canonicalEdge(int cellX, int cellY,
261 const std::string &direction);
263 static bool canPlaceEdge(PlacementWorld *world, const std::string &buildingId, int cellX,
264 int cellY, const std::string &direction,
265 int excludeInstanceId = 0, std::string *reason = nullptr,
266 int level = std::numeric_limits<int>::min());
268 static int placeEdge(PlacementWorld *world, const std::string &buildingId, int cellX,
269 int cellY, const std::string &direction);
271 static bool canPlaceCorner(PlacementWorld *world, const std::string &buildingId, int vertexX,
272 int vertexY, int excludeInstanceId = 0,
273 std::string *reason = nullptr,
274 int level = std::numeric_limits<int>::min());
280 [[nodiscard]] static eve::Result<PlacedBuilding>
281 placeCornerResult(PlacementWorld *world, const std::string &buildingId, int vertexX,
282 int vertexY);
284 static int placeCorner(PlacementWorld *world, const std::string &buildingId, int vertexX,
285 int vertexY);
287 static bool canPlaceFree(PlacementWorld *world, const std::string &buildingId, float worldX,
288 float worldY, int excludeInstanceId = 0,
289 std::string *reason = nullptr,
290 int level = std::numeric_limits<int>::min(),
291 float rotationDeg = 0.f);
293 static bool containsFreePoint(const PlacedBuilding &placed, float worldX, float worldY);
295 [[nodiscard]] static eve::Result<PlacedBuilding>
296 placeFreeResult(PlacementWorld *world, const std::string &buildingId, float worldX,
297 float worldY, float elevation = 0.f, float rotationDeg = 0.f);
299 [[nodiscard]] static eve::Result<PlacedBuilding>
300 placeFreeSurfaceResult(PlacementWorld *world, const std::string &buildingId,
301 const SurfacePatch &patch, float rotationDeg = 0.f);
303 static int placeFree(PlacementWorld *world, const std::string &buildingId, float worldX,
304 float worldY, float elevation = 0.f, float rotationDeg = 0.f);
309 static uint8_t edgeConnectionMask(const PlacementWorld &world, int instanceId);
311 static std::string edgeVariant(const PlacementWorld &world, int instanceId);
316 [[nodiscard]] static eve::Result<EdgeLinePlacement>
317 placeEdgeLine(PlacementWorld *world, const std::string &buildingId, int startVertexX,
318 int startVertexY, int endVertexX, int endVertexY);
324 [[nodiscard]] static eve::Result<EdgePathPlacement>
325 placeEdgePath(PlacementWorld *world, const std::string &buildingId,
326 const std::vector<CornerAddress> &vertices);
328 [[nodiscard]] static eve::Result<EdgePathPreview>
329 previewEdgePath(PlacementWorld *world, const std::string &buildingId,
330 const std::vector<CornerAddress> &vertices);
335 [[nodiscard]] static eve::Result<std::vector<CornerAddress>>
336 sampleEdgeCubicBezier(const std::vector<EdgeCurvePoint> &controlPoints, int subdivisions);
338 [[nodiscard]] static eve::Result<EdgePathPreview>
339 previewEdgeCubicBezier(PlacementWorld *world, const std::string &buildingId,
340 const std::vector<EdgeCurvePoint> &controlPoints, int subdivisions);
342 [[nodiscard]] static eve::Result<EdgePathPlacement>
343 placeEdgeCubicBezier(PlacementWorld *world, const std::string &buildingId,
344 const std::vector<EdgeCurvePoint> &controlPoints, int subdivisions);
346 [[nodiscard]] static eve::Result<EdgeCurveSurface>
347 sampleEdgeCurveSurface(const PlacementWorld &world, const std::string &surfaceName,
348 const std::vector<EdgeCurvePoint> &controlPoints, int subdivisions);
350 [[nodiscard]] static eve::Result<EdgePathPlacement>
351 placeEdgeCubicBezierOnSurface(PlacementWorld *world, const std::string &buildingId,
352 const std::vector<EdgeCurvePoint> &controlPoints,
353 int subdivisions, const std::string &surfaceName);
355 [[nodiscard]] static eve::Result<AreaPreview>
356 previewRectangle(PlacementWorld *world, const std::string &buildingId, int minCellX,
357 int minCellY, int maxCellX, int maxCellY, float rotationDeg = 0.f);
359 [[nodiscard]] static eve::Result<AreaPreview>
360 previewBrush(PlacementWorld *world, const std::string &buildingId, int centerCellX,
361 int centerCellY, int radius, float rotationDeg = 0.f);
363 [[nodiscard]] static eve::Result<AreaPreview>
364 previewRectangleOutline(PlacementWorld *world, const std::string &buildingId,
365 int minCellX, int minCellY, int maxCellX, int maxCellY,
366 float rotationDeg = 0.f);
368 [[nodiscard]] static eve::Result<AreaPlacement>
369 placeRectangle(PlacementWorld *world, const std::string &buildingId, int minCellX,
370 int minCellY, int maxCellX, int maxCellY, float rotationDeg = 0.f);
372 [[nodiscard]] static eve::Result<AreaPlacement>
373 placeBrush(PlacementWorld *world, const std::string &buildingId, int centerCellX,
374 int centerCellY, int radius, float rotationDeg = 0.f);
376 [[nodiscard]] static eve::Result<AreaPlacement>
377 placeRectangleOutline(PlacementWorld *world, const std::string &buildingId,
378 int minCellX, int minCellY, int maxCellX, int maxCellY,
379 float rotationDeg = 0.f);
387 [[nodiscard]] static eve::Result<PatternPreview>
388 previewPattern(PlacementWorld *world, const std::string &buildingId,
389 const PatternRequest &request);
395 [[nodiscard]] static eve::Result<PatternPlacement>
396 placePattern(PlacementWorld *world, const std::string &buildingId,
397 const PatternRequest &request);
398
399 static bool canPlace(PlacementWorld *world, const std::string &buildingId, int cellX, int cellY,
400 float rotationDeg = 0.f, int excludeInstanceId = 0,
401 std::string *reason = nullptr);
403 static bool canPlaceElev(PlacementWorld *world, const std::string &buildingId, int cellX,
404 int cellY, float elevation, float rotationDeg = 0.f,
405 int excludeInstanceId = 0, std::string *reason = nullptr,
406 int level = std::numeric_limits<int>::min());
407
409 static int placeAt(PlacementWorld *world, const std::string &buildingId, int cellX, int cellY,
410 float rotationDeg = 0.f);
412 static int placeAtWorld(PlacementWorld *world, const std::string &buildingId, float worldX,
413 float worldY, float rotationDeg = 0.f);
415 static int placeAtWorld3D(PlacementWorld *world, const std::string &buildingId, float worldX,
416 float worldY, float worldZ, float rotationDeg = 0.f);
417 static int placeGhost(PlacementWorld *world, Ghost *ghost);
418
427 std::string *reason = nullptr);
428
436 [[nodiscard]] static eve::Result<EdgeCurveGroup>
437 restoreEdgeCurveGroupExact(PlacementWorld *world, const EdgeCurveGroup &group,
438 const std::vector<PlacedBuilding> &members);
439
440 static bool removeBuilding(PlacementWorld *world, int instanceId);
445 [[nodiscard]] static eve::Result<StructuralRemovalReceipt>
446 removeBuildingCascadeResult(PlacementWorld *world, int instanceId);
448 static int removeBuildingCascade(PlacementWorld *world, int instanceId);
457 rebuildStructuralLinksResult(PlacementWorld *world);
463 [[nodiscard]] static eve::Result<PlacementEditReceipt>
464 moveBuildingResult(PlacementWorld *world, int instanceId, int cellX, int cellY,
465 float rotationDeg = -1.f);
471 [[nodiscard]] static eve::Result<PlacementEditReceipt>
472 moveEdgeResult(PlacementWorld *world, int instanceId, int cellX, int cellY,
473 const std::string &direction);
479 [[nodiscard]] static eve::Result<PlacementEditReceipt>
480 moveCornerResult(PlacementWorld *world, int instanceId, int vertexX, int vertexY);
482 [[nodiscard]] static eve::Result<PlacementEditReceipt>
483 moveFreeResult(PlacementWorld *world, int instanceId, float worldX, float worldY,
484 float elevation, float rotationDeg);
486 [[nodiscard]] static eve::Result<PlacementEditReceipt>
487 moveFreeSurfaceResult(PlacementWorld *world, int instanceId, const SurfacePatch &patch,
488 float rotationDeg);
497 [[nodiscard]] static eve::Result<PlacementEditReceipt>
498 replaceBuildingResult(PlacementWorld *world, int instanceId,
499 const std::string &replacementBuildingId);
501 static bool moveBuilding(PlacementWorld *world, int instanceId, int cellX, int cellY,
502 float rotationDeg = -1.f);
503 static void clearBuildings(PlacementWorld *world);
504
505 static void pushEvent(BuildingChangeEvent ev);
506 static void pollEvents(std::vector<BuildingChangeEvent> &out);
507 static void clearEvents();
508 static const std::vector<BuildingChangeEvent> &events();
509
510 static int nextInstanceId();
511
512private:
513 [[nodiscard]] static eve::Result<EdgePathPlacement>
514 commitEdgePath(PlacementWorld *world, EdgePathPreview preview,
515 const std::vector<EdgeCurvePoint> *curveControls = nullptr,
516 int curveSubdivisions = 0,
517 const EdgeCurveSurface *curveSurface = nullptr);
518 static void dissolveEdgeCurveGroup(PlacementWorld *world, EdgeCurveGroupId groupId);
519 friend class Ghost;
520
521 static bool canPlaceQuery(PlacementWorld *world, const PlacementQuery &q,
522 std::string *reason);
523 static bool runValidate(const PlacementWorld &world, const BuildingDefinition &def,
524 const PlacementQuery &q, std::string *reason);
525 static bool checkBoundsAndOccupancy(const PlacementWorld &world, const BuildingDefinition &def,
526 const PlacementQuery &q, bool checkOccupancy,
527 std::string *reason);
528 static bool checkTerrain(const PlacementWorld &world, const BuildingDefinition &def,
529 const PlacementQuery &q, std::string *reason);
530 static bool checkAdjacency(const PlacementWorld &world, const BuildingDefinition &def,
531 const PlacementQuery &q, std::string *reason);
532 static bool checkSurfacePatch(const BuildingDefinition &def, const PlacementQuery &q,
533 std::string *reason);
534 static bool checkStructuralSupport(const PlacementWorld &world,
535 const BuildingDefinition &def,
536 const PlacementQuery &q, std::string *reason);
537 static std::vector<int> collectStructuralSupports(const PlacementWorld &world,
538 const BuildingDefinition &def,
539 const PlacementQuery &q);
540 static bool hasStructuralDependents(const PlacementWorld &world, int instanceId);
541 static bool replacementPreservesStructuralDependents(
542 const PlacementWorld &world, int instanceId, const BuildingDefinition &replacement);
543 static bool removeBuildingUnchecked(PlacementWorld *world, int instanceId);
544 static void writeOccupancy(PlacementWorld &world, const BuildingDefinition &def,
545 const PlacedBuilding &placed, int instanceId);
546 static void clearOccupancy(PlacementWorld &world, int instanceId);
547 static void emit(BuildingChangeEvent ev);
549 previewArea(PlacementWorld *world, const std::string &buildingId,
550 const std::vector<std::pair<int, int>> &anchors, float rotationDeg);
551 static eve::Result<AreaPlacement> commitArea(PlacementWorld *world, AreaPreview preview);
552
553 static std::unordered_map<std::string, ValidateFn> &validateRules();
554 static std::unordered_map<std::string, SnapFn> &snapRules();
555 static std::unordered_map<std::string, ChangeHook> &changeHooks();
556 static std::unordered_map<std::string, SurfaceFn> &surfaces();
557 static std::unordered_map<std::string, SurfaceProviderFn> &surfaceProviders();
558 static float &planeSurfaceHeight();
559 static std::vector<BuildingChangeEvent> &eventQueue();
560 static int &instanceCounter();
561 static bool &builtinsReady();
562
563 PlacementSystem() = default;
564 ~PlacementSystem() = default;
565 PlacementSystem(const PlacementSystem &) = delete;
566 PlacementSystem &operator=(const PlacementSystem &) = delete;
567
568 std::unordered_map<std::string, ValidateFn> validateRules_;
569 std::unordered_map<std::string, SnapFn> snapRules_;
570 std::unordered_map<std::string, ChangeHook> changeHooks_;
571 std::unordered_map<std::string, SurfaceFn> surfaces_;
572 std::unordered_map<std::string, SurfaceProviderFn> surfaceProviders_;
573 std::vector<BuildingChangeEvent> eventQueue_;
574 int instanceCounter_ = 0;
575 bool builtinsReady_ = false;
576 float planeSurfaceHeight_ = 0.f;
577};
578
579} // namespace eve::building
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float rotationDegrees
building::EdgeCurveGroup group
float cx
Definition CardTypes.cpp:33
float cy
Definition CardTypes.cpp:34
#define EVENGINE_API_WORLD
Definition Export.h:109
const GltfImportRequest & request
float area
Definition Grass.cpp:62
std::array< double, 10 > q
float elevation
int h
TokenKind kind
std::string name
int level
World3D * world
std::vector< Point > vertices
float radius
bool hit
Move-only, checked operation results for the common layer.
RoadLaneDirection direction
const RoadEdge * edge
bool placed
Battle::Events events
std::map< std::string, std::span< const std::uint8_t > > members
Move-only operation result carrying either a value or Status.
Definition Result.h:155
EVENGINE_API_WORLD public API.
Definition Ghost.h:16
EVENGINE_API_WORLD public API.
std::function< bool(const PlacementWorld &world, const PlacementQuery &q, std::string *reason)> ValidateFn
std::function< bool(const PlacementWorld &world, float x, float y, PlacementHit *hit)> SurfaceFn
std::function< SnapResult(const PlacementWorld &world, float worldX, float worldY)> SnapFn
std::function< eve::Result< PlacementHit >(const PlacementWorld &world, float x, float y)> SurfaceProviderFn
Canonical surface provider contract.
std::function< void(const BuildingChangeEvent &ev)> ChangeHook
PatternKind
Built-in geometry families accepted by the unified placement-pattern protocol.
格子型建筑放置世界(脚本可直接操作)。
建筑放置模块入口:定义 / 放置世界 / 鬼影 / 变更事件的脚本绑定点。 设计文档:docs/dev/建筑放置系统设计.md
Definition Building.cpp:7
PlacementRestoreStatus
Outcome of restoring an exact placement snapshot.
SettlementPipeline::Stage fn
一次成功放置变更的事件(供脚本 poll / C++ hook)。
建筑模板(进程级注册表中的定义)。
One cubic Bezier control point in logical grid-vertex space.
Strong world-local identity of one authoritative edge-curve group.
World-owned authoritative description and membership of one committed edge curve.
已放置的建筑实例。
校验上下文:传给可插拔规则。
One requested area anchor and its deterministic validation result.
Atomic receipt for a committed area placement.
Owning row-major preview for a rectangular or circular brush request.
Owning same-identity surface frames sampled along an analytic edge curve.
std::vector< EdgeCurveSurfaceSample > samples
Atomic result of placing one axis-aligned continuous edge line.
Atomic result of placing one multi-segment edge path.
Owning validated edge addresses for one non-mutating path preview.
Atomic placement receipt shared by every built-in pattern kind.
Owning non-mutating expansion of an edge or area pattern.
int anchorCount() const
Number of concrete edge/cell anchors expanded by the pattern.
Owning, renderer-neutral request for one atomic placement pattern.
One sampled point and orthonormal frame on a placement surface.
One footprint-relative surface sample.
Surface samples and continuity metrics for one rotated building footprint.
std::vector< SurfacePatchSample > samples