From d3fe31803f40042ac5998d87dbfa5e53d918432d Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sun, 12 Jan 2025 17:41:48 +0300 Subject: [PATCH] Editor: Prevent crash on smoothing undefined cell borders (#8299) --- CHANGELOG.md | 1 + apps/opencs/view/render/terrainshapemode.cpp | 95 +++++++++++--------- 2 files changed, 53 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 511b2d5dbda..68fbad95559 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -227,6 +227,7 @@ Bug #8237: Non-bipedal creatures should *not* use spellcast equip/unequip animations Bug #8252: Plugin dependencies are not required to be loaded Bug #8295: Post-processing chain is case-sensitive + Bug #8299: Crash while smoothing landscape Feature #1415: Infinite fall failsafe Feature #2566: Handle NAM9 records for manual cell references Feature #3501: OpenMW-CS: Instance Editing - Shortcuts for axial locking diff --git a/apps/opencs/view/render/terrainshapemode.cpp b/apps/opencs/view/render/terrainshapemode.cpp index b9dc301efa3..bc1c6c63652 100644 --- a/apps/opencs/view/render/terrainshapemode.cpp +++ b/apps/opencs/view/render/terrainshapemode.cpp @@ -761,18 +761,17 @@ void CSVRender::TerrainShapeMode::smoothHeight( // this = this Cell // left = x - 1, up = y - 1, right = x + 1, down = y + 1 // Altered = transient edit (in current edited) - float thisAlteredHeight = 0.0f; - if (paged->getCellAlteredHeight(cellCoords, inCellX, inCellY) != nullptr) - thisAlteredHeight = *paged->getCellAlteredHeight(cellCoords, inCellX, inCellY); float thisHeight = landShapePointer[inCellY * ESM::Land::LAND_SIZE + inCellX]; - float leftHeight = 0.0f; - float leftAlteredHeight = 0.0f; - float upAlteredHeight = 0.0f; - float rightHeight = 0.0f; - float rightAlteredHeight = 0.0f; - float downHeight = 0.0f; - float downAlteredHeight = 0.0f; - float upHeight = 0.0f; + float* thisAlteredHeightPtr = paged->getCellAlteredHeight(cellCoords, inCellX, inCellY); + float thisAlteredHeight = thisAlteredHeightPtr != nullptr ? *thisAlteredHeightPtr : 0.f; + float leftHeight = thisHeight; + float leftAlteredHeight = thisAlteredHeight; + float rightHeight = thisHeight; + float rightAlteredHeight = thisAlteredHeight; + float downHeight = thisHeight; + float downAlteredHeight = thisAlteredHeight; + float upHeight = thisHeight; + float upAlteredHeight = thisAlteredHeight; if (allowLandShapeEditing(cellId)) { @@ -780,70 +779,80 @@ void CSVRender::TerrainShapeMode::smoothHeight( if (inCellX == 0) { cellId = CSMWorld::CellCoordinates::generateId(cellCoords.getX() - 1, cellCoords.getY()); - const CSMWorld::LandHeightsColumn::DataType landLeftShapePointer - = landTable.data(landTable.getModelIndex(cellId, landshapeColumn)) - .value(); - leftHeight = landLeftShapePointer[inCellY * ESM::Land::LAND_SIZE + (ESM::Land::LAND_SIZE - 2)]; - if (paged->getCellAlteredHeight(cellCoords.move(-1, 0), inCellX, ESM::Land::LAND_SIZE - 2)) - leftAlteredHeight - = *paged->getCellAlteredHeight(cellCoords.move(-1, 0), ESM::Land::LAND_SIZE - 2, inCellY); + if (isLandLoaded(cellId)) + { + const CSMWorld::LandHeightsColumn::DataType landLeftShapePointer + = landTable.data(landTable.getModelIndex(cellId, landshapeColumn)) + .value(); + leftHeight = landLeftShapePointer[inCellY * ESM::Land::LAND_SIZE + (ESM::Land::LAND_SIZE - 2)]; + float* alteredHeightPtr + = paged->getCellAlteredHeight(cellCoords.move(-1, 0), ESM::Land::LAND_SIZE - 2, inCellY); + leftAlteredHeight = alteredHeightPtr != nullptr ? *alteredHeightPtr : 0.f; + } } if (inCellY == 0) { cellId = CSMWorld::CellCoordinates::generateId(cellCoords.getX(), cellCoords.getY() - 1); - const CSMWorld::LandHeightsColumn::DataType landUpShapePointer - = landTable.data(landTable.getModelIndex(cellId, landshapeColumn)) - .value(); - upHeight = landUpShapePointer[(ESM::Land::LAND_SIZE - 2) * ESM::Land::LAND_SIZE + inCellX]; - if (paged->getCellAlteredHeight(cellCoords.move(0, -1), inCellX, ESM::Land::LAND_SIZE - 2)) - upAlteredHeight - = *paged->getCellAlteredHeight(cellCoords.move(0, -1), inCellX, ESM::Land::LAND_SIZE - 2); + if (isLandLoaded(cellId)) + { + const CSMWorld::LandHeightsColumn::DataType landUpShapePointer + = landTable.data(landTable.getModelIndex(cellId, landshapeColumn)) + .value(); + upHeight = landUpShapePointer[(ESM::Land::LAND_SIZE - 2) * ESM::Land::LAND_SIZE + inCellX]; + float* alteredHeightPtr + = paged->getCellAlteredHeight(cellCoords.move(0, -1), inCellX, ESM::Land::LAND_SIZE - 2); + upAlteredHeight = alteredHeightPtr != nullptr ? *alteredHeightPtr : 0.f; + } } if (inCellX > 0) { leftHeight = landShapePointer[inCellY * ESM::Land::LAND_SIZE + inCellX - 1]; - leftAlteredHeight = *paged->getCellAlteredHeight(cellCoords, inCellX - 1, inCellY); + float* alteredHeightPtr = paged->getCellAlteredHeight(cellCoords, inCellX - 1, inCellY); + leftAlteredHeight = alteredHeightPtr != nullptr ? *alteredHeightPtr : 0.f; } if (inCellY > 0) { upHeight = landShapePointer[(inCellY - 1) * ESM::Land::LAND_SIZE + inCellX]; - upAlteredHeight = *paged->getCellAlteredHeight(cellCoords, inCellX, inCellY - 1); + float* alteredHeightPtr = paged->getCellAlteredHeight(cellCoords, inCellX, inCellY - 1); + upAlteredHeight = alteredHeightPtr != nullptr ? *alteredHeightPtr : 0.f; } if (inCellX == ESM::Land::LAND_SIZE - 1) { cellId = CSMWorld::CellCoordinates::generateId(cellCoords.getX() + 1, cellCoords.getY()); - const CSMWorld::LandHeightsColumn::DataType landRightShapePointer - = landTable.data(landTable.getModelIndex(cellId, landshapeColumn)) - .value(); - rightHeight = landRightShapePointer[inCellY * ESM::Land::LAND_SIZE + 1]; - if (paged->getCellAlteredHeight(cellCoords.move(1, 0), 1, inCellY)) + if (isLandLoaded(cellId)) { - rightAlteredHeight = *paged->getCellAlteredHeight(cellCoords.move(1, 0), 1, inCellY); + const CSMWorld::LandHeightsColumn::DataType landRightShapePointer + = landTable.data(landTable.getModelIndex(cellId, landshapeColumn)) + .value(); + rightHeight = landRightShapePointer[inCellY * ESM::Land::LAND_SIZE + 1]; + float* alteredHeightPtr = paged->getCellAlteredHeight(cellCoords.move(1, 0), 1, inCellY); + rightAlteredHeight = alteredHeightPtr != nullptr ? *alteredHeightPtr : 0.f; } } if (inCellY == ESM::Land::LAND_SIZE - 1) { cellId = CSMWorld::CellCoordinates::generateId(cellCoords.getX(), cellCoords.getY() + 1); - const CSMWorld::LandHeightsColumn::DataType landDownShapePointer - = landTable.data(landTable.getModelIndex(cellId, landshapeColumn)) - .value(); - downHeight = landDownShapePointer[1 * ESM::Land::LAND_SIZE + inCellX]; - if (paged->getCellAlteredHeight(cellCoords.move(0, 1), inCellX, 1)) + if (isLandLoaded(cellId)) { - downAlteredHeight = *paged->getCellAlteredHeight(cellCoords.move(0, 1), inCellX, 1); + const CSMWorld::LandHeightsColumn::DataType landDownShapePointer + = landTable.data(landTable.getModelIndex(cellId, landshapeColumn)) + .value(); + downHeight = landDownShapePointer[1 * ESM::Land::LAND_SIZE + inCellX]; + float* alteredHeightPtr = paged->getCellAlteredHeight(cellCoords.move(0, 1), inCellX, 1); + downAlteredHeight = alteredHeightPtr != nullptr ? *alteredHeightPtr : 0.f; } } if (inCellX < ESM::Land::LAND_SIZE - 1) { rightHeight = landShapePointer[inCellY * ESM::Land::LAND_SIZE + inCellX + 1]; - if (paged->getCellAlteredHeight(cellCoords, inCellX + 1, inCellY)) - rightAlteredHeight = *paged->getCellAlteredHeight(cellCoords, inCellX + 1, inCellY); + float* alteredHeightPtr = paged->getCellAlteredHeight(cellCoords, inCellX + 1, inCellY); + rightAlteredHeight = alteredHeightPtr != nullptr ? *alteredHeightPtr : 0.f; } if (inCellY < ESM::Land::LAND_SIZE - 1) { downHeight = landShapePointer[(inCellY + 1) * ESM::Land::LAND_SIZE + inCellX]; - if (paged->getCellAlteredHeight(cellCoords, inCellX, inCellY + 1)) - downAlteredHeight = *paged->getCellAlteredHeight(cellCoords, inCellX, inCellY + 1); + float* alteredHeightPtr = paged->getCellAlteredHeight(cellCoords, inCellX, inCellY + 1); + downAlteredHeight = alteredHeightPtr != nullptr ? *alteredHeightPtr : 0.f; } float averageHeight = (upHeight + downHeight + rightHeight + leftHeight + upAlteredHeight