mirror of https://github.com/OpenRCT2/OpenRCT2.git
Fix #14848: incorrect tile element limit calculation
This commit is contained in:
parent
f9ad9ad3a5
commit
6b1141b5a2
|
@ -119,6 +119,8 @@ static TilePointerIndex<TileElement> _tileIndex;
|
||||||
static std::vector<TileElement> _tileElements;
|
static std::vector<TileElement> _tileElements;
|
||||||
static TilePointerIndex<TileElement> _tileIndexStash;
|
static TilePointerIndex<TileElement> _tileIndexStash;
|
||||||
static std::vector<TileElement> _tileElementsStash;
|
static std::vector<TileElement> _tileElementsStash;
|
||||||
|
static size_t _tileElementsInUse;
|
||||||
|
static size_t _tileElementsInUseStash;
|
||||||
static int32_t _mapSizeUnitsStash;
|
static int32_t _mapSizeUnitsStash;
|
||||||
static int32_t _mapSizeMinus2Stash;
|
static int32_t _mapSizeMinus2Stash;
|
||||||
static int32_t _mapSizeStash;
|
static int32_t _mapSizeStash;
|
||||||
|
@ -132,6 +134,7 @@ void StashMap()
|
||||||
_mapSizeMinus2Stash = gMapSizeMinus2;
|
_mapSizeMinus2Stash = gMapSizeMinus2;
|
||||||
_mapSizeStash = gMapSize;
|
_mapSizeStash = gMapSize;
|
||||||
_currentRotationStash = gCurrentRotation;
|
_currentRotationStash = gCurrentRotation;
|
||||||
|
_tileElementsInUseStash = _tileElementsInUse;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnstashMap()
|
void UnstashMap()
|
||||||
|
@ -142,6 +145,7 @@ void UnstashMap()
|
||||||
gMapSizeMinus2 = _mapSizeMinus2Stash;
|
gMapSizeMinus2 = _mapSizeMinus2Stash;
|
||||||
gMapSize = _mapSizeStash;
|
gMapSize = _mapSizeStash;
|
||||||
gCurrentRotation = _currentRotationStash;
|
gCurrentRotation = _currentRotationStash;
|
||||||
|
_tileElementsInUse = _tileElementsInUseStash;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<TileElement>& GetTileElements()
|
const std::vector<TileElement>& GetTileElements()
|
||||||
|
@ -153,6 +157,7 @@ void SetTileElements(std::vector<TileElement>&& tileElements)
|
||||||
{
|
{
|
||||||
_tileElements = std::move(tileElements);
|
_tileElements = std::move(tileElements);
|
||||||
_tileIndex = TilePointerIndex<TileElement>(MAXIMUM_MAP_SIZE_TECHNICAL, _tileElements.data());
|
_tileIndex = TilePointerIndex<TileElement>(MAXIMUM_MAP_SIZE_TECHNICAL, _tileElements.data());
|
||||||
|
_tileElementsInUse = _tileElements.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ReorganiseTileElements(size_t capacity)
|
static void ReorganiseTileElements(size_t capacity)
|
||||||
|
@ -199,27 +204,39 @@ void ReorganiseTileElements()
|
||||||
ReorganiseTileElements(_tileElements.size());
|
ReorganiseTileElements(_tileElements.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool map_check_free_elements_and_reorganise(size_t numElements)
|
static bool map_check_free_elements_and_reorganise(size_t numElementsOnTile, size_t numNewElements)
|
||||||
{
|
{
|
||||||
|
// Check hard cap on num in use tiles (this would be the size of _tileElements immediately after a reorg)
|
||||||
|
if (_tileElementsInUse + numNewElements > MAX_TILE_ELEMENTS)
|
||||||
|
{
|
||||||
|
gGameCommandErrorText = STR_ERR_LANDSCAPE_DATA_AREA_FULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto totalElementsRequired = numElementsOnTile + numNewElements;
|
||||||
auto freeElements = _tileElements.capacity() - _tileElements.size();
|
auto freeElements = _tileElements.capacity() - _tileElements.size();
|
||||||
if (freeElements >= numElements)
|
if (freeElements >= totalElementsRequired)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto newCapacity = std::min<size_t>(MAX_TILE_ELEMENTS, _tileElements.capacity() * 2);
|
// if space issue is due to fragmentation then Reorg Tiles without increasing capacity
|
||||||
if (newCapacity - _tileElements.size() < numElements)
|
if (_tileElements.size() > totalElementsRequired + _tileElementsInUse)
|
||||||
{
|
{
|
||||||
// Limit reached
|
ReorganiseTileElements();
|
||||||
gGameCommandErrorText = STR_ERR_LANDSCAPE_DATA_AREA_FULL;
|
// This check is not expected to fail
|
||||||
return false;
|
freeElements = _tileElements.capacity() - _tileElements.size();
|
||||||
}
|
if (freeElements >= totalElementsRequired)
|
||||||
else
|
{
|
||||||
{
|
return true;
|
||||||
ReorganiseTileElements(newCapacity);
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Capacity must increase to handle the space (Note capacity can go above MAX_TILE_ELEMENTS)
|
||||||
|
auto newCapacity = _tileElements.capacity() * 2;
|
||||||
|
ReorganiseTileElements(newCapacity);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +245,7 @@ static size_t CountElementsOnTile(const CoordsXY& loc);
|
||||||
bool MapCheckCapacityAndReorganise(const CoordsXY& loc, size_t numElements)
|
bool MapCheckCapacityAndReorganise(const CoordsXY& loc, size_t numElements)
|
||||||
{
|
{
|
||||||
auto numElementsOnTile = CountElementsOnTile(loc);
|
auto numElementsOnTile = CountElementsOnTile(loc);
|
||||||
return map_check_free_elements_and_reorganise(numElementsOnTile + numElements);
|
return map_check_free_elements_and_reorganise(numElementsOnTile, numElements);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_elements_at(const CoordsXY& loc);
|
static void clear_elements_at(const CoordsXY& loc);
|
||||||
|
@ -1011,7 +1028,7 @@ void tile_element_remove(TileElement* tileElement)
|
||||||
// Mark the latest element with the last element flag.
|
// Mark the latest element with the last element flag.
|
||||||
(tileElement - 1)->SetLastForTile(true);
|
(tileElement - 1)->SetLastForTile(true);
|
||||||
tileElement->base_height = MAX_ELEMENT_HEIGHT;
|
tileElement->base_height = MAX_ELEMENT_HEIGHT;
|
||||||
|
_tileElementsInUse--;
|
||||||
if (tileElement == &_tileElements.back())
|
if (tileElement == &_tileElements.back())
|
||||||
{
|
{
|
||||||
_tileElements.pop_back();
|
_tileElements.pop_back();
|
||||||
|
@ -1127,16 +1144,17 @@ static size_t CountElementsOnTile(const CoordsXY& loc)
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TileElement* AllocateTileElements(size_t count)
|
static TileElement* AllocateTileElements(size_t numElementsOnTile, size_t numNewElements)
|
||||||
{
|
{
|
||||||
if (!map_check_free_elements_and_reorganise(count))
|
if (!map_check_free_elements_and_reorganise(numElementsOnTile, numNewElements))
|
||||||
{
|
{
|
||||||
log_error("Cannot insert new element");
|
log_error("Cannot insert new element");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto oldSize = _tileElements.size();
|
auto oldSize = _tileElements.size();
|
||||||
_tileElements.resize(_tileElements.size() + count);
|
_tileElements.resize(_tileElements.size() + numElementsOnTile + numNewElements);
|
||||||
|
_tileElementsInUse += numNewElements;
|
||||||
return &_tileElements[oldSize];
|
return &_tileElements[oldSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1149,8 +1167,7 @@ TileElement* tile_element_insert(const CoordsXYZ& loc, int32_t occupiedQuadrants
|
||||||
const auto& tileLoc = TileCoordsXYZ(loc);
|
const auto& tileLoc = TileCoordsXYZ(loc);
|
||||||
|
|
||||||
auto numElementsOnTileOld = CountElementsOnTile(loc);
|
auto numElementsOnTileOld = CountElementsOnTile(loc);
|
||||||
auto numElementsOnTileNew = numElementsOnTileOld + 1;
|
auto* newTileElement = AllocateTileElements(numElementsOnTileOld, 1);
|
||||||
auto* newTileElement = AllocateTileElements(numElementsOnTileNew);
|
|
||||||
auto* originalTileElement = _tileIndex.GetFirstElementAt(tileLoc);
|
auto* originalTileElement = _tileIndex.GetFirstElementAt(tileLoc);
|
||||||
if (newTileElement == nullptr)
|
if (newTileElement == nullptr)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue