diff --git a/src/display3d.cpp b/src/display3d.cpp index b18789c9cfe..74999f6108c 100644 --- a/src/display3d.cpp +++ b/src/display3d.cpp @@ -352,7 +352,7 @@ struct Blueprint { return compare(b) == 0; } - STRUCTURE *buildBlueprint() const ///< Must delete after use. + optional buildBlueprint() const { return ::buildBlueprint(stats, pos, dir, index, state, player); } @@ -360,11 +360,9 @@ struct Blueprint { if (clipXY(pos.x, pos.y)) { - STRUCTURE *psStruct = buildBlueprint(); - ASSERT_OR_RETURN(, psStruct != nullptr, "buildBlueprint returned nullptr"); - renderStructure(psStruct, viewMatrix, perspectiveViewMatrix); - - objmemDestroy(psStruct, false); + auto optStruct = buildBlueprint(); + ASSERT_OR_RETURN(, optStruct.has_value(), "buildBlueprint returned nullopt"); + renderStructure(&*optStruct, viewMatrix, perspectiveViewMatrix); } } @@ -688,18 +686,28 @@ static Blueprint getTileBlueprint(int mapX, int mapY) STRUCTURE *getTileBlueprintStructure(int mapX, int mapY) { - static STRUCTURE *psStruct = nullptr; + static optional optStruct; Blueprint blueprint = getTileBlueprint(mapX, mapY); if (blueprint.state == SS_BLUEPRINT_PLANNED) { - if (psStruct) + if (optStruct) { // Delete previously returned structure, if any. - objmemDestroy(psStruct, false); + optStruct.reset(); + } + auto b = blueprint.buildBlueprint(); + // Don't use `operator=(optional&&)` to avoid declaring custom copy/move-assignment operators + // for `STRUCTURE` (more specifically, for `SIMPLE_OBJECT`, which has some const-qualified data members). + if (b) + { + optStruct.emplace(*b); + } + else + { + optStruct.reset(); } - psStruct = blueprint.buildBlueprint(); - return psStruct; // This blueprint was clicked on. + return optStruct.has_value() ? &optStruct.value() : nullptr; // This blueprint was clicked on. } return nullptr; diff --git a/src/structure.cpp b/src/structure.cpp index ac2ca417264..838d8a1a4cf 100644 --- a/src/structure.cpp +++ b/src/structure.cpp @@ -1829,11 +1829,11 @@ STRUCTURE *buildStructureDir(STRUCTURE_STATS *pStructureType, UDWORD x, UDWORD y return psBuilding; } -STRUCTURE *buildBlueprint(STRUCTURE_STATS const *psStats, Vector3i pos, uint16_t direction, unsigned moduleIndex, STRUCT_STATES state, uint8_t ownerPlayer) +optional buildBlueprint(STRUCTURE_STATS const *psStats, Vector3i pos, uint16_t direction, unsigned moduleIndex, STRUCT_STATES state, uint8_t ownerPlayer) { - ASSERT_OR_RETURN(nullptr, psStats != nullptr, "No blueprint stats"); - ASSERT_OR_RETURN(nullptr, psStats->pIMD[0] != nullptr, "No blueprint model for %s", getStatsName(psStats)); - ASSERT_OR_RETURN(nullptr, ownerPlayer < MAX_PLAYERS, "invalid ownerPlayer: %" PRIu8 "", ownerPlayer); + ASSERT_OR_RETURN(nullopt, psStats != nullptr, "No blueprint stats"); + ASSERT_OR_RETURN(nullopt, psStats->pIMD[0] != nullptr, "No blueprint model for %s", getStatsName(psStats)); + ASSERT_OR_RETURN(nullopt, ownerPlayer < MAX_PLAYERS, "invalid ownerPlayer: %" PRIu8 "", ownerPlayer); Rotation rot(direction, 0, 0); @@ -1909,9 +1909,7 @@ STRUCTURE *buildBlueprint(STRUCTURE_STATS const *psStats, Vector3i pos, uint16_t } } - auto& stableBlueprint = GlobalStructContainer().emplace(std::move(blueprint)); - - return &stableBlueprint; + return blueprint; } static Vector2i defaultAssemblyPointPos(STRUCTURE *psBuilding) diff --git a/src/structure.h b/src/structure.h index efe34f9bec1..e3da5150756 100644 --- a/src/structure.h +++ b/src/structure.h @@ -32,6 +32,8 @@ #include "visibility.h" #include "baseobject.h" +#include + // how long to wait between CALL_STRUCT_ATTACKED's - plus how long to flash on radar for #define ATTACK_CB_PAUSE 5000 @@ -105,7 +107,9 @@ STRUCTURE *buildStructure(STRUCTURE_STATS *pStructureType, UDWORD x, UDWORD y, U STRUCTURE *buildStructureDir(STRUCTURE_STATS *pStructureType, UDWORD x, UDWORD y, uint16_t direction, UDWORD player, bool FromSave, uint32_t id); STRUCTURE *buildStructureDir(STRUCTURE_STATS *pStructureType, UDWORD x, UDWORD y, uint16_t direction, UDWORD player, bool FromSave); /// Create a blueprint structure, with just enough information to render it -STRUCTURE *buildBlueprint(STRUCTURE_STATS const *psStats, Vector3i xy, uint16_t direction, unsigned moduleIndex, STRUCT_STATES state, uint8_t ownerPlayer); +/// IMPORTANT: Do not save the reference to this instance anywhere, since it's +/// not heap-allocated and thus doesn't have a stable address! +nonstd::optional buildBlueprint(STRUCTURE_STATS const *psStats, Vector3i xy, uint16_t direction, unsigned moduleIndex, STRUCT_STATES state, uint8_t ownerPlayer); /* The main update routine for all Structures */ void structureUpdate(STRUCTURE *psBuilding, bool bMission);