From 173f0f4cd56942b2706bfea88f50b4d33b4b1c1d Mon Sep 17 00:00:00 2001 From: rubidium Date: Fri, 4 Jul 2008 14:45:51 +0000 Subject: [PATCH] (svn r13674) -Fix [FS#2127]: crash when drawing a non-real sprite. The drawing of the non-real sprite is caused when two NewGRFs replace the same sprite and the first replaces it with a real sprite (and thus assumes it remains a real sprite) and the second replaces it with a non-real sprite. OpenTTD already looked at whether the sprite to load should be seen as a real or non-real sprite, but it failed to replace non-real sprites with a substitute real sprite when getting the sprite from the cache. --- src/spritecache.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/spritecache.cpp b/src/spritecache.cpp index 248a6d5ef7..811d5b5a66 100644 --- a/src/spritecache.cpp +++ b/src/spritecache.cpp @@ -24,10 +24,11 @@ uint _sprite_cache_size = 4; struct SpriteCache { void *ptr; - uint32 id; size_t file_pos; + uint32 id; uint16 file_slot; int16 lru; + bool real_sprite; ///< In some cases a single sprite is misused by two NewGRFs. Once as real sprite and once as non-real sprite. If the non-real sprite gets into the cache it might be drawn as real sprite which causes enormous trouble. }; @@ -176,6 +177,7 @@ static void* ReadSprite(SpriteCache *sc, SpriteID id, bool real_sprite) byte *dest = (byte *)AllocSprite(num); sc->ptr = dest; + sc->real_sprite = false; FioReadBlock(dest, num); return sc->ptr; @@ -217,9 +219,13 @@ static void* ReadSprite(SpriteCache *sc, SpriteID id, bool real_sprite) } } + sc->real_sprite = false; + return sc->ptr; } + sc->real_sprite = true; + if (!real_sprite) { static byte warning_level = 0; DEBUG(sprite, warning_level, "Tried to load real sprite #%d as a non sprite. Probable cause: NewGRF interference", id); @@ -255,6 +261,7 @@ bool LoadNextSprite(int load_index, byte file_slot, uint file_sprite_id) sc->ptr = NULL; sc->lru = 0; sc->id = file_sprite_id; + sc->real_sprite = false; return true; } @@ -269,6 +276,7 @@ void DupSprite(SpriteID old_spr, SpriteID new_spr) scnew->file_pos = scold->file_pos; scnew->ptr = NULL; scnew->id = scold->id; + scnew->real_sprite = scold->real_sprite; } @@ -453,7 +461,7 @@ const void *GetRawSprite(SpriteID sprite, bool real_sprite) p = sc->ptr; /* Load the sprite, if it is not loaded, yet */ - if (p == NULL) p = ReadSprite(sc, sprite, real_sprite); + if (p == NULL || sc->real_sprite != real_sprite) p = ReadSprite(sc, sprite, real_sprite); return p; }