载入中...
搜索中...
未找到
TacticsLineOfSightAdapter.cpp
浏览该文件的文档.
1
7
8#include "common/Capability.h"
9#include "common/Diagnostic.h"
11#include "tactics/LineOfSight.h"
13
14#include <utility>
15
16namespace eve::tactics {
17namespace {
18
20bool sameHandle(const ecs::EntityHandle& left, const ecs::EntityHandle& right) noexcept {
21 return left.table == right.table && left.type == right.type && left.id == right.id &&
22 left.generation == right.generation;
23}
24
26const BoardState* boundBoard(ecs::EntityHandle battle, bool bound) {
27 if (!bound) return nullptr;
28 // Resolving by handle each call is what makes a released battle safe: the ECS refuses a stale
29 // generation, so a dangling board is never read.
30 auto* resolved = dynamic_cast<Battle*>(ecs::try_get(battle));
31 return resolved != nullptr ? &resolved->board()->value : nullptr;
32}
33
35Result<Cell> toCell(const sensing::TargetLocation& location) {
36 return std::visit(
37 [](const auto& point) -> Result<Cell> {
38 using Point = std::decay_t<decltype(point)>;
39 if constexpr (std::is_same_v<Point, sensing::GridPoint>) {
40 // A 2D grid point is layer zero; a 3D one keeps its z as the tactical layer, so a
41 // layered board is reachable without converting between spaces.
42 if (point.space() == sensing::CoordinateSpace::Grid2D) return Result<Cell>::success(Cell{point.x(), point.y(), 0});
44 return Result<Cell>::success(Cell{point.x(), point.y(), point.z()});
46 "tactics line of sight answers grid coordinates only",
47 "lineOfSight.space"));
48 } else {
50 "tactics line of sight answers grid coordinates only",
51 "lineOfSight.space"));
52 }
53 },
54 location);
55}
56
57} // namespace
58
63
65 if (boundBoard(battle, true) == nullptr)
67 "line-of-sight battle binding is not a live battle", "battle"));
68 if (bound_ && sameHandle(battle_, battle)) return Result<void>::success(Status::success(StatusCode::NoOp));
69 if (bound_)
70 // One board at a time on purpose: with two bound boards the answer would depend on which
71 // was bound last, exactly the order-dependence the router exists to remove.
73 DiagnosticCode::Conflict, "another battle is already bound for grid line of sight", "battle"));
74 battle_ = battle;
75 bound_ = true;
77}
78
80 if (!bound_ || !sameHandle(battle_, battle))
82 battle_ = {};
83 bound_ = false;
85}
86
88 const sensing::TargetLocation& to) const {
89 const BoardState* board = boundBoard(battle_, bound_);
90 if (board == nullptr)
92 DiagnosticCode::Unsupported, "no tactics battle is bound for grid line of sight", "lineOfSight.battle"));
93 auto fromCell = toCell(from);
94 if (!fromCell) return Result<sensing::LineOfSightResult>::failure(fromCell.status());
95 auto toCellValue = toCell(to);
96 if (!toCellValue) return Result<sensing::LineOfSightResult>::failure(toCellValue.status());
97
98 // The same policy the module's own range query uses: a registered sight policy when a project
99 // provided one, otherwise the built-in grid rule. One authority for "what blocks sight".
100 const ILineOfSightPolicy* registered = cap::query<ILineOfSightPolicy>();
101 const ILineOfSightPolicy& policy = registered != nullptr ? *registered : *gridLineOfSightPolicy();
102 auto visible = policy.visible(*board, fromCell.value(), toCellValue.value());
104
106 result.visible = visible.value();
107 // `blocker` is left empty on purpose: the grid policy answers visibility without naming what
108 // blocked it, and reporting the target's occupant instead would be a different fact wearing
109 // the same field. A policy that can identify the blocker is free to fill it in.
110 return Result<sensing::LineOfSightResult>::success(std::move(result));
111}
112
114 auto router = sensing::ensureLineOfSightRouter();
115 if (!router) return Result<void>::failure(router.status());
117 auto grid2d = router.value()->addProvider(sensing::CoordinateSpace::Grid2D, &adapter);
118 if (!grid2d) return Result<void>::failure(grid2d.status());
119 auto grid3d = router.value()->addProvider(sensing::CoordinateSpace::Grid3D, &adapter);
120 if (!grid3d) return Result<void>::failure(grid3d.status());
122}
123
124} // namespace eve::tactics
std::string from
Stable, structured diagnostics shared by engine modules.
HexVec3 left
HexVec3 right
HexCoordinates to
Cell the unit walks towards on this segment.
Definition HexUnits.cpp:64
One registered line-of-sight provider that dispatches to backends by coordinate space.
Injectable line-of-sight and cover policies over the tactical board.
std::string_view adapter
Grid line of sight for sensing consumers, answered from a bound tactics board.
BoardState board
Deterministic board values and short-root ECS entities for tactics.
bool visible
glm::vec3 point
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
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
Authoritative board facts and occupancy indexes for one battle.
Answers "can @p from see @p to" for one board.
Definition LineOfSight.h:61
virtual Result< bool > visible(const BoardState &board, Cell from, Cell to) const =0
Report whether from can see to.
Answers grid line-of-sight queries from the bound tactics battle.
Result< sensing::LineOfSightResult > query(const sensing::TargetLocation &from, const sensing::TargetLocation &to) const override
Tests the segment between two same-space locations.
Result< void > bindBattle(ecs::EntityHandle battle)
Bind the battle this adapter answers for.
Result< void > unbindBattle(ecs::EntityHandle battle)
Release the binding when battle is the bound one; otherwise NoOp.
std::variant< WorldPoint, GridPoint > TargetLocation
Either a world point or a grid point, with the tag retained.
Definition Targeting.h:198
Result< LineOfSightRouter * > ensureLineOfSightRouter()
The process-wide router, registered as the ILineOfSightQuery capability.
std::shared_ptr< ILineOfSightPolicy > gridLineOfSightPolicy()
The process-wide built-in line-of-sight policy.
Result< void > registerTacticsLineOfSightProvider()
Claim the grid coordinate spaces for the tactics adapter.
TacticsLineOfSightAdapter & tacticsLineOfSightAdapter()
The process-wide adapter instance the capability answers with.
Result of one injected line-of-sight query.
Definition Targeting.h:417
bool visible
True when the complete segment is visible.
Definition Targeting.h:419