diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 1254e56c1c..255a8c1376 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -79,6 +79,8 @@ const std::vector &GetAllGRFFiles() return _grf_files; } +static btree::btree_map _callback_result_cache; + /** Miscellaneous GRF features, set by Action 0x0D, parameter 0x9E */ byte _misc_grf_features = 0; @@ -5522,13 +5524,24 @@ static void SkipAct1(ByteReader *buf) grfmsg(3, "SkipAct1: Skipping %d sprites", _cur.skip_sprites); } +static const CallbackResultSpriteGroup *NewCallbackResultSpriteGroup(uint16 groupid) +{ + uint16 result = CallbackResultSpriteGroup::TransformResultValue(groupid, _cur.grffile->grf_version >= 8); + + const CallbackResultSpriteGroup *&ptr = _callback_result_cache[result]; + if (ptr == nullptr) { + assert(CallbackResultSpriteGroup::CanAllocateItem()); + ptr = new CallbackResultSpriteGroup(result); + } + return ptr; +} + /* Helper function to either create a callback or link to a previously * defined spritegroup. */ static const SpriteGroup *GetGroupFromGroupID(byte setid, byte type, uint16 groupid) { if (HasBit(groupid, 15)) { - assert(CallbackResultSpriteGroup::CanAllocateItem()); - return new CallbackResultSpriteGroup(groupid, _cur.grffile->grf_version >= 8); + return NewCallbackResultSpriteGroup(groupid); } if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) { @@ -5576,8 +5589,7 @@ static const SpriteGroup *GetGroupByID(uint16 groupid) static const SpriteGroup *CreateGroupFromGroupID(byte feature, byte setid, byte type, uint16 spriteid) { if (HasBit(spriteid, 15)) { - assert(CallbackResultSpriteGroup::CanAllocateItem()); - return new CallbackResultSpriteGroup(spriteid, _cur.grffile->grf_version >= 8); + return NewCallbackResultSpriteGroup(spriteid); } if (!_cur.IsValidSpriteSet(feature, spriteid)) { @@ -11195,6 +11207,7 @@ void ResetNewGRFData() InitializeSoundPool(); _spritegroup_pool.CleanPool(); + _callback_result_cache.clear(); } /** @@ -12443,6 +12456,7 @@ void LoadNewGRF(uint load_index, uint num_baseset) for (GRFFile * const file : _grf_files) { file->string_map.clear(); } + _callback_result_cache.clear(); /* Call any functions that should be run after GRFs have been loaded. */ AfterLoadGRFs(); diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp index a771185ea6..99abd01a17 100644 --- a/src/newgrf_spritegroup.cpp +++ b/src/newgrf_spritegroup.cpp @@ -259,7 +259,7 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con if (this->calculated_result) { /* nvar == 0 is a special case -- we turn our value into a callback result */ if (value != CALLBACK_FAILED) value = GB(value, 0, 15); - static CallbackResultSpriteGroup nvarzero(0, true); + static CallbackResultSpriteGroup nvarzero(0); nvarzero.result = value; return &nvarzero; } diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h index 12c0e6fa38..540a0ece5d 100644 --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -369,19 +369,25 @@ protected: struct CallbackResultSpriteGroup : SpriteGroup { /** * Creates a spritegroup representing a callback result + * @param result The result as returned from TransformResultValue + */ + CallbackResultSpriteGroup(uint16 result) : + SpriteGroup(SGT_CALLBACK), + result(result) {} + + /** + * Transforms a callback result value * @param value The value that was used to represent this callback result * @param grf_version8 True, if we are dealing with a new NewGRF which uses GRF version >= 8. */ - CallbackResultSpriteGroup(uint16 value, bool grf_version8) : - SpriteGroup(SGT_CALLBACK), - result(value) + static uint16 TransformResultValue(uint16 value, bool grf_version8) { /* Old style callback results (only valid for version < 8) have the highest byte 0xFF so signify it is a callback result. * New style ones only have the highest bit set (allows 15-bit results, instead of just 8) */ - if (!grf_version8 && (this->result >> 8) == 0xFF) { - this->result &= ~0xFF00; + if (!grf_version8 && (value >> 8) == 0xFF) { + return value & ~0xFF00; } else { - this->result &= ~0x8000; + return value & ~0x8000; } }