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 TilePointerIndex<TileElement> _tileIndexStash;
|
||||
static std::vector<TileElement> _tileElementsStash;
|
||||
static size_t _tileElementsInUse;
|
||||
static size_t _tileElementsInUseStash;
|
||||
static int32_t _mapSizeUnitsStash;
|
||||
static int32_t _mapSizeMinus2Stash;
|
||||
static int32_t _mapSizeStash;
|
||||
|
@ -132,6 +134,7 @@ void StashMap()
|
|||
_mapSizeMinus2Stash = gMapSizeMinus2;
|
||||
_mapSizeStash = gMapSize;
|
||||
_currentRotationStash = gCurrentRotation;
|
||||
_tileElementsInUseStash = _tileElementsInUse;
|
||||
}
|
||||
|
||||
void UnstashMap()
|
||||
|
@ -142,6 +145,7 @@ void UnstashMap()
|
|||
gMapSizeMinus2 = _mapSizeMinus2Stash;
|
||||
gMapSize = _mapSizeStash;
|
||||
gCurrentRotation = _currentRotationStash;
|
||||
_tileElementsInUse = _tileElementsInUseStash;
|
||||
}
|
||||
|
||||
const std::vector<TileElement>& GetTileElements()
|
||||
|
@ -153,6 +157,7 @@ void SetTileElements(std::vector<TileElement>&& tileElements)
|
|||
{
|
||||
_tileElements = std::move(tileElements);
|
||||
_tileIndex = TilePointerIndex<TileElement>(MAXIMUM_MAP_SIZE_TECHNICAL, _tileElements.data());
|
||||
_tileElementsInUse = _tileElements.size();
|
||||
}
|
||||
|
||||
static void ReorganiseTileElements(size_t capacity)
|
||||
|
@ -199,27 +204,39 @@ void ReorganiseTileElements()
|
|||
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)
|
||||
{
|
||||
auto freeElements = _tileElements.capacity() - _tileElements.size();
|
||||
if (freeElements >= numElements)
|
||||
// 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)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto newCapacity = std::min<size_t>(MAX_TILE_ELEMENTS, _tileElements.capacity() * 2);
|
||||
if (newCapacity - _tileElements.size() < numElements)
|
||||
{
|
||||
// Limit reached
|
||||
gGameCommandErrorText = STR_ERR_LANDSCAPE_DATA_AREA_FULL;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
||||
auto totalElementsRequired = numElementsOnTile + numNewElements;
|
||||
auto freeElements = _tileElements.capacity() - _tileElements.size();
|
||||
if (freeElements >= totalElementsRequired)
|
||||
{
|
||||
ReorganiseTileElements(newCapacity);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if space issue is due to fragmentation then Reorg Tiles without increasing capacity
|
||||
if (_tileElements.size() > totalElementsRequired + _tileElementsInUse)
|
||||
{
|
||||
ReorganiseTileElements();
|
||||
// This check is not expected to fail
|
||||
freeElements = _tileElements.capacity() - _tileElements.size();
|
||||
if (freeElements >= totalElementsRequired)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
@ -1011,7 +1028,7 @@ void tile_element_remove(TileElement* tileElement)
|
|||
// Mark the latest element with the last element flag.
|
||||
(tileElement - 1)->SetLastForTile(true);
|
||||
tileElement->base_height = MAX_ELEMENT_HEIGHT;
|
||||
|
||||
_tileElementsInUse--;
|
||||
if (tileElement == &_tileElements.back())
|
||||
{
|
||||
_tileElements.pop_back();
|
||||
|
@ -1127,16 +1144,17 @@ static size_t CountElementsOnTile(const CoordsXY& loc)
|
|||
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");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto oldSize = _tileElements.size();
|
||||
_tileElements.resize(_tileElements.size() + count);
|
||||
_tileElements.resize(_tileElements.size() + numElementsOnTile + numNewElements);
|
||||
_tileElementsInUse += numNewElements;
|
||||
return &_tileElements[oldSize];
|
||||
}
|
||||
|
||||
|
@ -1149,8 +1167,7 @@ TileElement* tile_element_insert(const CoordsXYZ& loc, int32_t occupiedQuadrants
|
|||
const auto& tileLoc = TileCoordsXYZ(loc);
|
||||
|
||||
auto numElementsOnTileOld = CountElementsOnTile(loc);
|
||||
auto numElementsOnTileNew = numElementsOnTileOld + 1;
|
||||
auto* newTileElement = AllocateTileElements(numElementsOnTileNew);
|
||||
auto* newTileElement = AllocateTileElements(numElementsOnTileOld, 1);
|
||||
auto* originalTileElement = _tileIndex.GetFirstElementAt(tileLoc);
|
||||
if (newTileElement == nullptr)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue