(svn r13686) [0.6] -Backport from trunk: 0.6
authorrubidium
Wed, 09 Jul 2008 19:13:21 +0000
branch0.6
changeset 11128 b62a7b45babf
parent 11127 5e9620220703
child 11129 72b8e47f86d8
(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)
src/articulated_vehicles.cpp
src/lang/english.txt
src/newgrf.cpp
src/newgrf_engine.cpp
src/spritecache.cpp
src/spriteloader/png.cpp
src/town_cmd.cpp
--- a/src/articulated_vehicles.cpp	Wed Jul 09 18:59:39 2008 +0000
+++ b/src/articulated_vehicles.cpp	Wed Jul 09 19:13:21 2008 +0000
@@ -42,11 +42,11 @@
 
 	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;
--- a/src/lang/english.txt	Wed Jul 09 18:59:39 2008 +0000
+++ b/src/lang/english.txt	Wed Jul 09 19:13:21 2008 +0000
@@ -3098,6 +3098,7 @@
 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
--- a/src/newgrf.cpp	Wed Jul 09 18:59:39 2008 +0000
+++ b/src/newgrf.cpp	Wed Jul 09 19:13:21 2008 +0000
@@ -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 @@
 	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 @@
 	}
 }
 
+/**
+ * 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 @@
 	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 @@
 		/* 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 @@
 		/* 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 @@
 		/* 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,8 +4317,8 @@
 									if (_cur_spriteid + count >= 16384) {
 										grfmsg(0, "ParamSet: GRM: Unable to allocate %d sprites; try changing NewGRF order", count);
 										_cur_grfconfig->status = GCS_DISABLED;
-
-										_skip_sprites = -1;
+										ClearTemporaryNewGRFData();
+ 										_skip_sprites = -1;
 										return;
 									}
 
@@ -4299,7 +4350,12 @@
 		} 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 @@
 					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 @@
 		_cur_grfconfig->error = error;
 
 		_cur_grfconfig->status = GCS_DISABLED;
+		ClearTemporaryNewGRFData();
 		_skip_sprites = -1;
 		return;
 	}
@@ -5241,23 +5299,6 @@
 	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));
--- a/src/newgrf_engine.cpp	Wed Jul 09 18:59:39 2008 +0000
+++ b/src/newgrf_engine.cpp	Wed Jul 09 19:13:21 2008 +0000
@@ -866,7 +866,7 @@
 	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 @@
 	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;
 
--- a/src/spritecache.cpp	Wed Jul 09 18:59:39 2008 +0000
+++ b/src/spritecache.cpp	Wed Jul 09 19:13:21 2008 +0000
@@ -28,6 +28,7 @@
  	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 @@
 		byte *dest = (byte *)AllocSprite(num);
 
 		sc->ptr = dest;
+		sc->real_sprite = false;
 		FioReadBlock(dest, num);
 
 		return sc->ptr;
@@ -217,9 +219,13 @@
 			}
 		}
 
+		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 @@
 	sc->ptr = NULL;
 	sc->lru = 0;
 	sc->id = file_sprite_id;
+	sc->real_sprite = false;
 
 	return true;
 }
@@ -269,6 +276,7 @@
 	scnew->file_pos = scold->file_pos;
 	scnew->ptr = NULL;
 	scnew->id = scold->id;
+	scnew->real_sprite = scold->real_sprite;
 }
 
 
@@ -454,7 +462,7 @@
 	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;
 }
--- a/src/spriteloader/png.cpp	Wed Jul 09 18:59:39 2008 +0000
+++ b/src/spriteloader/png.cpp	Wed Jul 09 19:13:21 2008 +0000
@@ -44,7 +44,7 @@
 	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;
--- a/src/town_cmd.cpp	Wed Jul 09 18:59:39 2008 +0000
+++ b/src/town_cmd.cpp	Wed Jul 09 19:13:21 2008 +0000
@@ -1902,11 +1902,6 @@
 			}
 
 			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;
@@ -1920,7 +1915,7 @@
 			SetBit(oneof, TOWN_HAS_STADIUM);
 		}
 
-		if (HASBITS(t->flags12 , oneof)) continue;
+		if (HASBITS(t->flags12, oneof)) continue;
 
 		/* Make sure there is no slope? */
 		bool noslope = (hs->building_flags & TILE_NOT_SLOPED) != 0;
@@ -1936,6 +1931,11 @@
 			/* 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);