Files
dota_factory/src/lib/sim/ShipLayout.h
Malte Langkabel 250da8c9aa make re-applying an unchanged ship layout a no-op
setRecipe has always returned early when the recipe is unchanged, so a
redundant selection does not reset buffers. setShipLayout had no such
guard: it cancelled the production cycle and wiped every buffer on any
call, including one that set the layout the shipyard already had. That
already contradicted REQ-BLD-SHIPYARD, which cancels a cycle only when the
player "confirms a layout change", and it becomes load-bearing for the
blueprint configuration transfer of REQ-UI-BLUEPRINT-TRANSFER, which is
meant to be clicked repeatedly onto matching shipyards.

REQ-MAT-INPUT-BUFFER now states the rule generally: setting a
configuration to the value it already holds changes nothing, whatever
path applies it.

An unset layout counts as an empty one. The two are equivalent for
buffers, production, and the spawned ship -- the spawn path already
converts nullopt to an empty layout deliberately -- so clearing an
already-unconfigured shipyard is a no-op too. That is the case a transfer
from a layout-less source produces. The only place the two differ is the
has_value() bit in StateChecksum, and record and replay take the same
branch, so determinism is unaffected.

Layout equality is order-sensitive by choice: reporting a change that is
not one costs a buffer reset, while missing a real change would leave a
shipyard building the wrong ship.

BuildingConfigTest's shipyard case used an empty layout as shorthand for
"a layout is set", which is now a no-op and left nothing to read back. It
configures a real module instead and checks it round-trips.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcReq7hVk4KUPhTDKWAG7K
2026-08-06 17:37:57 +02:00

38 lines
1.1 KiB
C++

#pragma once
#include <string>
#include <vector>
#include <QPoint>
#include "Rotation.h"
// A single module placed on a ship's layout grid (REQ-MOD-PLACEMENT).
struct PlacedModule
{
std::string moduleId;
QPoint position;
Rotation rotation;
};
inline bool operator==(const PlacedModule& a, const PlacedModule& b)
{
return a.moduleId == b.moduleId && a.position == b.position && a.rotation == b.rotation;
}
// The complete module configuration for a shipyard's current ship (REQ-MOD-CONFIG).
struct ShipLayoutConfig
{
std::vector<PlacedModule> placedModules;
};
// Deliberately order-sensitive: two layouts holding the same modules in a different
// vector order compare unequal. This only decides whether applying a layout is a no-op
// (REQ-MAT-INPUT-BUFFER), so the conservative answer is the safe one -- reporting a
// change that is not one costs a buffer reset, reporting no change when there is one
// would leave the shipyard stale.
inline bool operator==(const ShipLayoutConfig& a, const ShipLayoutConfig& b)
{
return a.placedModules == b.placedModules;
}