Change the spatial insert to make it ordered (#11252)

* Change the spatial insert to make it ordered

This is so that the spatial index can be rebuilt and gauranteed to be in the correct order

* Increment Network Version

* Make review changes

* Remove the gSpriteSpatialIndex from the network

* Use safer get function

* Final little tweak
This commit is contained in:
Duncan 2020-04-09 10:46:26 +01:00 committed by GitHub
parent c0486e250e
commit fdf98060cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 32 deletions

View File

@ -31,7 +31,7 @@
// This string specifies which version of network stream current build uses.
// It is used for making sure only compatible builds get connected, even within
// single OpenRCT2 version.
#define NETWORK_STREAM_VERSION "12"
#define NETWORK_STREAM_VERSION "13"
#define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION
static Peep* _pickup_peep = nullptr;
@ -2726,7 +2726,6 @@ bool Network::LoadMap(IStream* stream)
[[maybe_unused]] uint32_t checksum = stream->ReadValue<uint32_t>();
// Read other data not in normal save files
stream->Read(gSpriteSpatialIndex, SPATIAL_INDEX_SIZE * sizeof(uint16_t));
gGamePaused = stream->ReadValue<uint32_t>();
_guestGenerationProbability = stream->ReadValue<uint32_t>();
_suggestedGuestMaximum = stream->ReadValue<uint32_t>();
@ -2775,7 +2774,6 @@ bool Network::SaveMap(IStream* stream, const std::vector<const ObjectRepositoryI
s6exporter->SaveGame(stream);
// Write other data not in normal save files
stream->Write(gSpriteSpatialIndex, SPATIAL_INDEX_SIZE * sizeof(uint16_t));
stream->WriteValue<uint32_t>(gGamePaused);
stream->WriteValue<uint32_t>(_guestGenerationProbability);
stream->WriteValue<uint32_t>(_suggestedGuestMaximum);

View File

@ -92,8 +92,7 @@ rct_sprite* get_sprite(size_t sprite_idx)
uint16_t sprite_get_first_in_quadrant(int32_t x, int32_t y)
{
int32_t offset = ((x & 0x1FE0) << 3) | (y >> 5);
return gSpriteSpatialIndex[offset];
return gSpriteSpatialIndex[GetSpatialIndexOffset(x, y)];
}
static void invalidate_sprite_max_zoom(SpriteBase* sprite, int32_t maxZoom)
@ -220,7 +219,10 @@ static size_t GetSpatialIndexOffset(int32_t x, int32_t y)
index = (flooredX << 3) | tileY;
}
openrct2_assert(index < sizeof(gSpriteSpatialIndex), "GetSpatialIndexOffset out of range");
if (index >= sizeof(gSpriteSpatialIndex))
{
return SPATIAL_INDEX_LOCATION_NULL;
}
return index;
}
@ -352,6 +354,8 @@ void sprite_clear_all_unused()
}
}
static void SpriteSpatialInsert(SpriteBase* sprite, const CoordsXY& newLoc);
static constexpr uint16_t MAX_MISC_SPRITES = 300;
rct_sprite* create_sprite(SPRITE_IDENTIFIER spriteIdentifier)
@ -411,8 +415,7 @@ rct_sprite* create_sprite(SPRITE_IDENTIFIER spriteIdentifier)
sprite->flags = 0;
sprite->sprite_left = LOCATION_NULL;
sprite->next_in_quadrant = gSpriteSpatialIndex[SPATIAL_INDEX_LOCATION_NULL];
gSpriteSpatialIndex[SPATIAL_INDEX_LOCATION_NULL] = sprite->sprite_index;
SpriteSpatialInsert(sprite, { LOCATION_NULL, 0 });
return (rct_sprite*)sprite;
}
@ -613,6 +616,58 @@ void sprite_misc_update_all()
}
}
// Performs a search to ensure that insert keeps next_in_quadrant in sprite_index order
static void SpriteSpatialInsert(SpriteBase* sprite, const CoordsXY& newLoc)
{
size_t newIndex = GetSpatialIndexOffset(newLoc.x, newLoc.y);
auto* next = &gSpriteSpatialIndex[newIndex];
while (sprite->sprite_index < *next && *next != SPRITE_INDEX_NULL)
{
auto sprite2 = &get_sprite(*next)->generic;
next = &sprite2->next_in_quadrant;
}
sprite->next_in_quadrant = *next;
*next = sprite->sprite_index;
}
static void SpriteSpatialRemove(SpriteBase* sprite)
{
size_t currentIndex = GetSpatialIndexOffset(sprite->x, sprite->y);
auto* index = &gSpriteSpatialIndex[currentIndex];
// This indicates that the spatial index data is incorrect.
if (*index == SPRITE_INDEX_NULL)
{
log_warning("Bad sprite spatial index. Rebuilding the spatial index...");
reset_sprite_spatial_index();
}
auto* sprite2 = &get_sprite(*index)->generic;
while (sprite != sprite2)
{
index = &sprite2->next_in_quadrant;
if (*index == SPRITE_INDEX_NULL)
{
break;
}
sprite2 = &get_sprite(*index)->generic;
}
*index = sprite->next_in_quadrant;
}
static void SpriteSpatialMove(SpriteBase* sprite, const CoordsXY& newLoc)
{
size_t newIndex = GetSpatialIndexOffset(newLoc.x, newLoc.y);
size_t currentIndex = GetSpatialIndexOffset(sprite->x, sprite->y);
if (newIndex == currentIndex)
return;
SpriteSpatialRemove(sprite);
SpriteSpatialInsert(sprite, newLoc);
}
/**
* Moves a sprite to a new location.
* rct2: 0x0069E9D3
@ -629,30 +684,7 @@ void sprite_move(int16_t x, int16_t y, int16_t z, SpriteBase* sprite)
x = LOCATION_NULL;
}
size_t newIndex = GetSpatialIndexOffset(x, y);
size_t currentIndex = GetSpatialIndexOffset(sprite->x, sprite->y);
if (newIndex != currentIndex)
{
uint16_t* spriteIndex = &gSpriteSpatialIndex[currentIndex];
if (*spriteIndex != SPRITE_INDEX_NULL)
{
rct_sprite* sprite2 = get_sprite(*spriteIndex);
while (sprite != &sprite2->generic)
{
spriteIndex = &sprite2->generic.next_in_quadrant;
if (*spriteIndex == SPRITE_INDEX_NULL)
{
break;
}
sprite2 = get_sprite(*spriteIndex);
}
}
*spriteIndex = sprite->next_in_quadrant;
int32_t tempSpriteIndex = gSpriteSpatialIndex[newIndex];
gSpriteSpatialIndex[newIndex] = sprite->sprite_index;
sprite->next_in_quadrant = tempSpriteIndex;
}
SpriteSpatialMove(sprite, { x, y });
if (x == LOCATION_NULL)
{