mirror of https://github.com/OpenTTD/OpenTTD
(svn r13686) [0.6] -Backport from trunk:
- Fix: Memory leak when NewGRFs got forcefully disabled and they defined GOTO labels (r13675) - Fix: Crash when drawing a non-real sprite caused by NewGRF interference [FS#2127] (r13674) - Fix: Disable static NewGRFs when non-static NewGRFs query them in the context of network games. This makes it impossible for static NewGRFs to disable non-static NewGRFs and 'bad' things happening because the non-static NewGRF doesn't know about the static NewGRF (r13576) - Fix: First determine where to *exactly* build a house before asking a NewGRF whether the location is good instead of possibly moving the house a tile after the NewGRF said the location is good (r13489) - Fix: Do not crash when resolving vehicle sprite groups with zero sprites (r13397) - Fix: In the purchase list, CB36 for capacity was not called for the first part of rail and road vehicles (r13385)release/0.6
parent
94ae5be42a
commit
4f76d929c6
|
@ -42,11 +42,11 @@ uint16 *GetCapacityOfArticulatedParts(EngineID engine, VehicleType type)
|
|||
|
||||
if (type == VEH_TRAIN) {
|
||||
const RailVehicleInfo *rvi = RailVehInfo(engine);
|
||||
capacity[rvi->cargo_type] = rvi->capacity;
|
||||
capacity[rvi->cargo_type] = GetEngineProperty(engine, 0x14, rvi->capacity);
|
||||
if (rvi->railveh_type == RAILVEH_MULTIHEAD) capacity[rvi->cargo_type] += rvi->capacity;
|
||||
} else if (type == VEH_ROAD) {
|
||||
const RoadVehicleInfo *rvi = RoadVehInfo(engine);
|
||||
capacity[rvi->cargo_type] = rvi->capacity;
|
||||
capacity[rvi->cargo_type] = GetEngineProperty(engine, 0x0F, rvi->capacity);
|
||||
}
|
||||
|
||||
if (!HasBit(EngInfo(engine)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) return capacity;
|
||||
|
|
|
@ -3098,6 +3098,7 @@ STR_NEWGRF_ERROR_LOAD_AFTER :{STRING} must b
|
|||
STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER :{STRING} requires OpenTTD version {STRING} or better.
|
||||
STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE :the GRF file it was designed to translate
|
||||
STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED :Too many NewGRFs are loaded.
|
||||
STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC :Loading {STRING} as static NewGRF with {STRING} could cause desyncs.
|
||||
|
||||
STR_NEWGRF_ADD :{BLACK}Add
|
||||
STR_NEWGRF_ADD_TIP :{BLACK}Add a NewGRF file to the list
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "road_func.h"
|
||||
#include "player_base.h"
|
||||
#include "settings_type.h"
|
||||
#include "network/network.h"
|
||||
#include "map_func.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
@ -224,6 +225,23 @@ static GRFFile *GetFileByFilename(const char *filename)
|
|||
return file;
|
||||
}
|
||||
|
||||
/** Reset all NewGRFData that was used only while processing data */
|
||||
static void ClearTemporaryNewGRFData()
|
||||
{
|
||||
/* Clear the GOTO labels used for GRF processing */
|
||||
for (GRFLabel *l = _cur_grffile->label; l != NULL;) {
|
||||
GRFLabel *l2 = l->next;
|
||||
free(l);
|
||||
l = l2;
|
||||
}
|
||||
_cur_grffile->label = NULL;
|
||||
|
||||
/* Clear the list of spritegroups */
|
||||
free(_cur_grffile->spritegroups);
|
||||
_cur_grffile->spritegroups = NULL;
|
||||
_cur_grffile->spritegroups_count = 0;
|
||||
}
|
||||
|
||||
|
||||
/** Used when setting an object's property to map to the GRF's strings
|
||||
* while taking in consideration the "drift" between TTDPatch string system and OpenTTD's one
|
||||
|
@ -3670,6 +3688,32 @@ static void CfgApply(byte *buf, int len)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable a static NewGRF when it is influencing another (non-static)
|
||||
* NewGRF as this could cause desyncs.
|
||||
*
|
||||
* We could just tell the NewGRF querying that the file doesn't exist,
|
||||
* but that might give unwanted results. Disabling the NewGRF gives the
|
||||
* best result as no NewGRF author can complain about that.
|
||||
* @param c the NewGRF to disable.
|
||||
*/
|
||||
static void DisableStaticNewGRFInfluencingNonStaticNewGRFs(GRFConfig *c)
|
||||
{
|
||||
if (c->error != NULL) {
|
||||
free(c->error->custom_message);
|
||||
free(c->error->data);
|
||||
free(c->error);
|
||||
}
|
||||
c->status = GCS_DISABLED;
|
||||
c->error = CallocT<GRFError>(1);
|
||||
c->error->data = strdup(_cur_grfconfig->name);
|
||||
c->error->severity = STR_NEWGRF_ERROR_MSG_FATAL;
|
||||
c->error->message = STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC;
|
||||
|
||||
ClearTemporaryNewGRFData();
|
||||
_skip_sprites = -1;
|
||||
}
|
||||
|
||||
/* Action 0x07 */
|
||||
/* Action 0x09 */
|
||||
static void SkipIf(byte *buf, int len)
|
||||
|
@ -3723,7 +3767,12 @@ static void SkipIf(byte *buf, int len)
|
|||
if (param == 0x88 && condtype != 0x0B && condtype != 0x0C) {
|
||||
/* GRF ID checks */
|
||||
|
||||
const GRFConfig *c = GetGRFConfig(cond_val);
|
||||
GRFConfig *c = GetGRFConfig(cond_val);
|
||||
|
||||
if (c != NULL && HasBit(c->flags, GCF_STATIC) && !HasBit(_cur_grfconfig->flags, GCF_STATIC) && c->status != GCS_DISABLED && _networking) {
|
||||
DisableStaticNewGRFInfluencingNonStaticNewGRFs(c);
|
||||
c = NULL;
|
||||
}
|
||||
|
||||
if (condtype != 10 && c == NULL) {
|
||||
grfmsg(7, "SkipIf: GRFID 0x%08X unknown, skipping test", BSWAP32(cond_val));
|
||||
|
@ -3821,6 +3870,7 @@ static void SkipIf(byte *buf, int len)
|
|||
/* If an action 8 hasn't been encountered yet, disable the grf. */
|
||||
if (_cur_grfconfig->status != GCS_ACTIVATED) {
|
||||
_cur_grfconfig->status = GCS_DISABLED;
|
||||
ClearTemporaryNewGRFData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3993,7 +4043,7 @@ static void GRFLoadError(byte *buf, int len)
|
|||
/* This is a fatal error, so make sure the GRF is deactivated and no
|
||||
* more of it gets loaded. */
|
||||
_cur_grfconfig->status = GCS_DISABLED;
|
||||
|
||||
ClearTemporaryNewGRFData();
|
||||
_skip_sprites = -1;
|
||||
}
|
||||
|
||||
|
@ -4176,6 +4226,7 @@ static uint32 PerformGRM(uint32 *grm, uint16 num_ids, uint16 count, uint8 op, ui
|
|||
/* Deactivate GRF */
|
||||
grfmsg(0, "ParamSet: GRM: Unable to allocate %d %s, deactivating", count, type);
|
||||
_cur_grfconfig->status = GCS_DISABLED;
|
||||
ClearTemporaryNewGRFData();
|
||||
_skip_sprites = -1;
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
@ -4266,7 +4317,7 @@ static void ParamSet(byte *buf, int len)
|
|||
if (_cur_spriteid + count >= 16384) {
|
||||
grfmsg(0, "ParamSet: GRM: Unable to allocate %d sprites; try changing NewGRF order", count);
|
||||
_cur_grfconfig->status = GCS_DISABLED;
|
||||
|
||||
ClearTemporaryNewGRFData();
|
||||
_skip_sprites = -1;
|
||||
return;
|
||||
}
|
||||
|
@ -4299,7 +4350,12 @@ static void ParamSet(byte *buf, int len)
|
|||
} else {
|
||||
/* Read another GRF File's parameter */
|
||||
const GRFFile *file = GetFileByGRFID(data);
|
||||
if (file == NULL || src1 >= file->param_end) {
|
||||
GRFConfig *c = GetGRFConfig(data);
|
||||
if (c != NULL && HasBit(c->status, GCF_STATIC) && !HasBit(_cur_grfconfig->status, GCF_STATIC) && _networking) {
|
||||
/* Disable the read GRF if it is a static NewGRF. */
|
||||
DisableStaticNewGRFInfluencingNonStaticNewGRFs(c);
|
||||
src1 = 0;
|
||||
} else if (file == NULL || src1 >= file->param_end || (c != NULL && c->status == GCS_DISABLED)) {
|
||||
src1 = 0;
|
||||
} else {
|
||||
src1 = file->param[src1];
|
||||
|
@ -4584,6 +4640,7 @@ static void FeatureTownName(byte *buf, int len)
|
|||
grfmsg(0, "FeatureTownName: definition 0x%02X doesn't exist, deactivating", ref_id);
|
||||
DelGRFTownName(grfid);
|
||||
_cur_grfconfig->status = GCS_DISABLED;
|
||||
ClearTemporaryNewGRFData();
|
||||
_skip_sprites = -1;
|
||||
return;
|
||||
}
|
||||
|
@ -4874,6 +4931,7 @@ static void TranslateGRFStrings(byte *buf, int len)
|
|||
_cur_grfconfig->error = error;
|
||||
|
||||
_cur_grfconfig->status = GCS_DISABLED;
|
||||
ClearTemporaryNewGRFData();
|
||||
_skip_sprites = -1;
|
||||
return;
|
||||
}
|
||||
|
@ -5241,23 +5299,6 @@ static void ResetNewGRFData()
|
|||
InitializeSpriteGroupPool();
|
||||
}
|
||||
|
||||
/** Reset all NewGRFData that was used only while processing data */
|
||||
static void ClearTemporaryNewGRFData()
|
||||
{
|
||||
/* Clear the GOTO labels used for GRF processing */
|
||||
for (GRFLabel *l = _cur_grffile->label; l != NULL;) {
|
||||
GRFLabel *l2 = l->next;
|
||||
free(l);
|
||||
l = l2;
|
||||
}
|
||||
_cur_grffile->label = NULL;
|
||||
|
||||
/* Clear the list of spritegroups */
|
||||
free(_cur_grffile->spritegroups);
|
||||
_cur_grffile->spritegroups = NULL;
|
||||
_cur_grffile->spritegroups_count = 0;
|
||||
}
|
||||
|
||||
static void BuildCargoTranslationMap()
|
||||
{
|
||||
memset(_cur_grffile->cargo_map, 0xFF, sizeof(_cur_grffile->cargo_map));
|
||||
|
|
|
@ -866,7 +866,7 @@ SpriteID GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction dire
|
|||
NewVehicleResolver(&object, engine, v);
|
||||
|
||||
group = Resolve(GetVehicleSpriteGroup(engine, v), &object);
|
||||
if (group == NULL || group->type != SGT_RESULT) return 0;
|
||||
if (group == NULL || group->type != SGT_RESULT || group->g.result.num_sprites == 0) return 0;
|
||||
|
||||
return group->g.result.sprite + (direction % group->g.result.num_sprites);
|
||||
}
|
||||
|
@ -890,7 +890,7 @@ SpriteID GetRotorOverrideSprite(EngineID engine, const Vehicle *v, bool info_vie
|
|||
group = GetWagonOverrideSpriteSet(engine, CT_DEFAULT, engine);
|
||||
group = Resolve(group, &object);
|
||||
|
||||
if (group == NULL || group->type != SGT_RESULT) return 0;
|
||||
if (group == NULL || group->type != SGT_RESULT || group->g.result.num_sprites == 0) return 0;
|
||||
|
||||
if (v == NULL) return group->g.result.sprite;
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ struct SpriteCache {
|
|||
uint32 file_pos;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -454,7 +462,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;
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ static bool OpenPNGFile(const char *filename, uint32 id, bool mask)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool LoadPNG(SpriteLoader::Sprite *sprite, const char *filename, uint32 id, bool mask)
|
||||
static bool LoadPNG(SpriteLoader::Sprite *sprite, const char *filename, uint32 id, volatile bool mask)
|
||||
{
|
||||
png_byte header[8];
|
||||
png_structp png_ptr;
|
||||
|
|
|
@ -1902,11 +1902,6 @@ static bool BuildTownHouse(Town *t, TileIndex tile)
|
|||
}
|
||||
|
||||
if ((hs->extra_flags & BUILDING_IS_HISTORICAL) && !_generating_world) continue;
|
||||
|
||||
if (HasBit(hs->callback_mask, CBM_HOUSE_ALLOW_CONSTRUCTION)) {
|
||||
uint16 callback_res = GetHouseCallback(CBID_HOUSE_ALLOW_CONSTRUCTION, 0, 0, house, t, tile);
|
||||
if (callback_res != CALLBACK_FAILED && GB(callback_res, 0, 8) == 0) continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (_cur_year < hs->min_date || _cur_year > hs->max_date) continue;
|
||||
|
@ -1936,6 +1931,11 @@ static bool BuildTownHouse(Town *t, TileIndex tile)
|
|||
/* 1x1 house checks are already done */
|
||||
}
|
||||
|
||||
if (HasBit(hs->callback_mask, CBM_HOUSE_ALLOW_CONSTRUCTION)) {
|
||||
uint16 callback_res = GetHouseCallback(CBID_HOUSE_ALLOW_CONSTRUCTION, 0, 0, house, t, tile);
|
||||
if (callback_res != CALLBACK_FAILED && GB(callback_res, 0, 8) == 0) continue;
|
||||
}
|
||||
|
||||
/* build the house */
|
||||
t->num_houses++;
|
||||
IncreaseBuildingCount(t, house);
|
||||
|
|
Loading…
Reference in New Issue