From 8c5cd61b6969ba3cfec578d4cdfea1f239985fd1 Mon Sep 17 00:00:00 2001 From: Duncan Date: Tue, 26 Jan 2021 07:42:56 +0000 Subject: [PATCH] Split free id's into seperate vector (#13924) --- .../windows/EditorBottomToolbar.cpp | 6 +-- src/openrct2/actions/StaffHireNewAction.cpp | 2 +- src/openrct2/peep/Peep.cpp | 2 +- src/openrct2/rct2/S6Exporter.cpp | 6 +-- src/openrct2/ride/Ride.cpp | 2 +- src/openrct2/world/Sprite.cpp | 54 ++++++++++++++----- src/openrct2/world/Sprite.h | 1 + 7 files changed, 48 insertions(+), 25 deletions(-) diff --git a/src/openrct2-ui/windows/EditorBottomToolbar.cpp b/src/openrct2-ui/windows/EditorBottomToolbar.cpp index 8795aa6ca3..ec10436aaa 100644 --- a/src/openrct2-ui/windows/EditorBottomToolbar.cpp +++ b/src/openrct2-ui/windows/EditorBottomToolbar.cpp @@ -286,7 +286,7 @@ static void window_editor_bottom_toolbar_mouseup([[maybe_unused]] rct_window* w, if (widgetIndex == WIDX_PREVIOUS_STEP_BUTTON) { if ((gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER) - || (GetEntityListCount(EntityListId::Free) == MAX_SPRITES && !(gParkFlags & PARK_FLAGS_SPRITES_INITIALISED))) + || (GetNumFreeEntities() == MAX_SPRITES && !(gParkFlags & PARK_FLAGS_SPRITES_INITIALISED))) { previous_button_mouseup_events[EnumValue(gS6Info.editor_step)](); } @@ -346,7 +346,7 @@ void window_editor_bottom_toolbar_invalidate(rct_window* w) } else if (!(gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER)) { - if (GetEntityListCount(EntityListId::Free) != MAX_SPRITES || gParkFlags & PARK_FLAGS_SPRITES_INITIALISED) + if (GetNumFreeEntities() != MAX_SPRITES || gParkFlags & PARK_FLAGS_SPRITES_INITIALISED) { hide_previous_step_button(); } @@ -371,7 +371,7 @@ void window_editor_bottom_toolbar_paint(rct_window* w, rct_drawpixelinfo* dpi) { drawPreviousButton = true; } - else if (GetEntityListCount(EntityListId::Free) != MAX_SPRITES) + else if (GetNumFreeEntities() != MAX_SPRITES) { drawNextButton = true; } diff --git a/src/openrct2/actions/StaffHireNewAction.cpp b/src/openrct2/actions/StaffHireNewAction.cpp index 54e849171e..75b124f2d4 100644 --- a/src/openrct2/actions/StaffHireNewAction.cpp +++ b/src/openrct2/actions/StaffHireNewAction.cpp @@ -89,7 +89,7 @@ GameActions::Result::Ptr StaffHireNewAction::QueryExecute(bool execute) const return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); } - if (GetEntityListCount(EntityListId::Free) < 400) + if (GetNumFreeEntities() < 400) { return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_PEOPLE_IN_GAME); } diff --git a/src/openrct2/peep/Peep.cpp b/src/openrct2/peep/Peep.cpp index a749787307..0d28b5c27c 100644 --- a/src/openrct2/peep/Peep.cpp +++ b/src/openrct2/peep/Peep.cpp @@ -1585,7 +1585,7 @@ void Peep::InsertNewThought(PeepThoughtType thoughtType, uint8_t thoughtArgument */ Peep* Peep::Generate(const CoordsXYZ& coords) { - if (GetEntityListCount(EntityListId::Free) < 400) + if (GetNumFreeEntities() < 400) return nullptr; Peep* peep = &create_sprite(SpriteIdentifier::Peep)->peep; diff --git a/src/openrct2/rct2/S6Exporter.cpp b/src/openrct2/rct2/S6Exporter.cpp index 3920f95761..8aebb7cc77 100644 --- a/src/openrct2/rct2/S6Exporter.cpp +++ b/src/openrct2/rct2/S6Exporter.cpp @@ -947,11 +947,6 @@ void S6Exporter::ExportSprites() ExportSprite(&_s6.sprites[i], reinterpret_cast(GetEntity(i))); } - for (int32_t i = 0; i < static_cast(EntityListId::Count); i++) - { - //_s6.sprite_lists_head[i] = gSpriteListHead[i]; - _s6.sprite_lists_count[i] = GetEntityListCount(EntityListId(i)); - } RebuildEntityLinks(); } @@ -967,6 +962,7 @@ void S6Exporter::RebuildEntityLinks() { if (entity.unknown.linked_list_type_offset == list) { + _s6.sprite_lists_count[EnumValue(list) >> 1]++; _s6.sprites[entity.unknown.sprite_index].unknown.previous = previous; if (previous != SPRITE_INDEX_NULL) { diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index fecb16669f..fa01f8fa23 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -4379,7 +4379,7 @@ static void ride_set_start_finish_points(ride_id_t rideIndex, CoordsXYE* startEl static int32_t count_free_misc_sprite_slots() { int32_t miscSpriteCount = GetEntityListCount(EntityListId::Misc); - int32_t remainingSpriteCount = GetEntityListCount(EntityListId::Free); + int32_t remainingSpriteCount = GetNumFreeEntities(); return std::max(0, miscSpriteCount + remainingSpriteCount - 300); } diff --git a/src/openrct2/world/Sprite.cpp b/src/openrct2/world/Sprite.cpp index be98cdf698..fb8d900413 100644 --- a/src/openrct2/world/Sprite.cpp +++ b/src/openrct2/world/Sprite.cpp @@ -28,6 +28,7 @@ static rct_sprite _spriteList[MAX_SPRITES]; static std::array, EnumValue(EntityListId::Count)> gEntityLists; +static std::vector _freeIdList; static bool _spriteFlashingList[MAX_SPRITES]; @@ -105,6 +106,11 @@ uint16_t GetEntityListCount(EntityListId list) return static_cast(gEntityLists[static_cast(list)].size()); } +uint16_t GetNumFreeEntities() +{ + return static_cast(_freeIdList.size()); +} + std::string rct_sprite_checksum::ToString() const { std::string result; @@ -221,11 +227,22 @@ void RebuildEntityLists() list.clear(); } + _freeIdList.clear(); + for (auto& ent : _spriteList) { - // auto listId = EntityIdentifierToListId(ent.misc.sprite_identifier); - gEntityLists[EnumValue(ent.misc.linked_list_index)].push_back(ent.misc.sprite_index); + if (ent.misc.sprite_identifier == SpriteIdentifier::Null) + { + _freeIdList.push_back(ent.misc.sprite_index); + } + else + { + // auto listId = EntityIdentifierToListId(ent.misc.sprite_identifier); + gEntityLists[EnumValue(ent.misc.linked_list_index)].push_back(ent.misc.sprite_index); + } } + // List needs to be back to front to simplify removing + std::sort(std::begin(_freeIdList), std::end(_freeIdList), std::greater()); } const std::list& GetEntityList(const EntityListId id) @@ -241,7 +258,6 @@ void reset_sprite_list() { gSavedAge = 0; std::memset(static_cast(_spriteList), 0, sizeof(_spriteList)); - for (int32_t i = 0; i < MAX_SPRITES; ++i) { auto* spr = GetEntity(i); @@ -256,7 +272,6 @@ void reset_sprite_list() _spriteFlashingList[i] = false; } - RebuildEntityLists(); reset_sprite_spatial_index(); } @@ -373,12 +388,17 @@ static void sprite_reset(SpriteBase* sprite) */ void sprite_clear_all_unused() { - for (auto sprite : EntityList(EntityListId::Free)) + for (auto index : _freeIdList) { - sprite_reset(sprite); - sprite->linked_list_index = EntityListId::Free; + auto* entity = GetEntity(index); + if (entity == nullptr) + { + continue; + } + sprite_reset(entity); + entity->linked_list_index = EntityListId::Free; - _spriteFlashingList[sprite->sprite_index] = false; + _spriteFlashingList[entity->sprite_index] = false; } } @@ -391,6 +411,12 @@ static void AddToEntityList(const EntityListId linkedListIndex, SpriteBase* enti list.insert(std::lower_bound(std::begin(list), std::end(list), entity->sprite_index), entity->sprite_index); } +static void AddToFreeList(uint16_t index) +{ + // Free list must be in reverse sprite_index order to prevent desync issues + _freeIdList.insert(std::upper_bound(std::rbegin(_freeIdList), std::rend(_freeIdList), index).base(), index); +} + static void RemoveFromEntityList(SpriteBase* entity) { auto& list = gEntityLists[EnumValue(entity->linked_list_index)]; @@ -403,7 +429,7 @@ static void RemoveFromEntityList(SpriteBase* entity) rct_sprite* create_sprite(SpriteIdentifier spriteIdentifier, EntityListId linkedListIndex) { - if (GetEntityListCount(EntityListId::Free) == 0) + if (_freeIdList.size() == 0) { // No free sprites. return nullptr; @@ -415,19 +441,19 @@ rct_sprite* create_sprite(SpriteIdentifier spriteIdentifier, EntityListId linked // free it will fail to keep slots for more relevant sprites. // Also there can't be more than MAX_MISC_SPRITES sprites in this list. uint16_t miscSlotsRemaining = MAX_MISC_SPRITES - GetEntityListCount(EntityListId::Misc); - if (miscSlotsRemaining >= GetEntityListCount(EntityListId::Free)) + if (miscSlotsRemaining >= _freeIdList.size()) { return nullptr; } } - auto* sprite = GetEntity(gEntityLists[static_cast(EntityListId::Free)].front()); + auto* sprite = GetEntity(_freeIdList.back()); if (sprite == nullptr) { return nullptr; } - gEntityLists[static_cast(EntityListId::Free)].pop_front(); - RemoveFromEntityList(sprite); // remove from Free list + _freeIdList.pop_back(); + AddToEntityList(linkedListIndex, sprite); // Need to reset all sprite data, as the uninitialised values // may contain garbage and cause a desync later on. @@ -686,7 +712,7 @@ void sprite_remove(SpriteBase* sprite) EntityTweener::Get().RemoveEntity(sprite); RemoveFromEntityList(sprite); // remove from existing list - AddToEntityList(EntityListId::Free, sprite); + AddToFreeList(sprite->sprite_index); SpriteSpatialRemove(sprite); sprite_reset(sprite); diff --git a/src/openrct2/world/Sprite.h b/src/openrct2/world/Sprite.h index d9e0e18d55..2e872f6cbc 100644 --- a/src/openrct2/world/Sprite.h +++ b/src/openrct2/world/Sprite.h @@ -228,6 +228,7 @@ template T* TryGetEntity(size_t sprite_idx) } uint16_t GetEntityListCount(EntityListId list); +uint16_t GetNumFreeEntities(); constexpr const uint32_t SPATIAL_INDEX_SIZE = (MAXIMUM_MAP_SIZE_TECHNICAL * MAXIMUM_MAP_SIZE_TECHNICAL) + 1; constexpr const uint32_t SPATIAL_INDEX_LOCATION_NULL = SPATIAL_INDEX_SIZE - 1;