changeset 5329:f3bebbb74f02 draft

(svn r7490) -Feature: Load a list of NewGRFs from the config (in the [newgrf-static] section) that should always be loaded. These will also be active during the intro screen, and in multiplayer games. Only "network-safe" NewGRFs are permitted, such as fonts and sprite replacement sets.
author peter1138 <peter1138@openttd.org>
date Tue, 12 Dec 2006 19:38:41 +0000
parents 2d44ef4074fb
children 0093904511a8
files newgrf.c newgrf.h newgrf_config.c newgrf_config.h newgrf_gui.c settings.c
diffstat 6 files changed, 137 insertions(+), 63 deletions(-) [+]
line wrap: on
line diff
--- a/newgrf.c
+++ b/newgrf.c
@@ -2471,8 +2471,8 @@
 }
 
 
-/* Action 0x08 (GLS_FILESCAN) */
-static void ScanInfo(byte *buf, int len)
+/* Action 0x08 (GLS_SAFETYSCAN) */
+static void SafeInfo(byte *buf, int len)
 {
 	uint8 version;
 	uint32 grfid;
@@ -2487,6 +2487,9 @@
 
 	_cur_grfconfig->grfid = grfid;
 
+	/* GRF IDs starting with 0xFF are reserved for internal TTDPatch use */
+	if (GB(grfid, 24, 8) == 0xFF) SETBIT(_cur_grfconfig->flags, GCF_SYSTEM);
+
 	len -= 6;
 	name = (const char*)buf;
 	name_len = ttd_strnlen(name, len);
@@ -2502,7 +2505,14 @@
 			_cur_grfconfig->info  = TranslateTTDPatchCodes(info);
 		}
 	}
-
+}
+
+/* Action 0x08 (GLS_INFOSCAN) */
+static void ScanInfo(byte *buf, int len)
+{
+	SafeInfo(buf, len);
+
+	/* GLS_INFOSCAN only looks for the action 8, so we can skip the rest of the file */
 	_skip_sprites = -1;
 }
 
@@ -3177,6 +3187,17 @@
 	}
 }
 
+
+/* Used during safety scan on unsafe actions */
+static void GRFUnsafe(byte *buf, int len)
+{
+	SETBIT(_cur_grfconfig->flags, GCF_UNSAFE);
+
+	/* Skip remainder of GRF if GRF ID is set */
+	if (_cur_grfconfig->grfid != 0) _skip_sprites = -1;
+}
+
+
 static void InitializeGRFSpecial(void)
 {
 	_ttdpatch_flags[0] =  ((_patches.always_small_airport ? 1 : 0) << 0x0C)  // keepsmallairport
@@ -3517,25 +3538,25 @@
 	 * is not in memory and scanning the file every time would be too expensive.
 	 * In other stages we skip action 0x10 since it's already dealt with. */
 	static const SpecialSpriteHandler handlers[][GLS_END] = {
-		/* 0x00 */ { NULL,     NULL,            NULL,       FeatureChangeInfo, },
-		/* 0x01 */ { NULL,     NULL,            NULL,       NewSpriteSet, },
-		/* 0x02 */ { NULL,     NULL,            NULL,       NewSpriteGroup, },
-		/* 0x03 */ { NULL,     NULL,            NULL,       FeatureMapSpriteGroup, },
-		/* 0x04 */ { NULL,     NULL,            NULL,       FeatureNewName, },
-		/* 0x05 */ { NULL,     NULL,            NULL,       GraphicsNew, },
-		/* 0x06 */ { NULL,     NULL,            CfgApply,   CfgApply, },
-		/* 0x07 */ { NULL,     NULL,            NULL,       SkipIf, },
-		/* 0x08 */ { ScanInfo, NULL,            GRFInfo,    GRFInfo, },
-		/* 0x09 */ { NULL,     NULL,            SkipIf,     SkipIf, },
-		/* 0x0A */ { NULL,     NULL,            NULL,       SpriteReplace, },
-		/* 0x0B */ { NULL,     NULL,            GRFError,   GRFError, },
-		/* 0x0C */ { NULL,     NULL,            GRFComment, GRFComment, },
-		/* 0x0D */ { NULL,     NULL,            ParamSet,   ParamSet, },
-		/* 0x0E */ { NULL,     NULL,            GRFInhibit, GRFInhibit, },
-		/* 0x0F */ { NULL,     NULL,            NULL,       NULL, },
-		/* 0x10 */ { NULL,     DefineGotoLabel, NULL,       NULL, },
-		/* 0x11 */ { NULL,     NULL,            NULL,       GRFSound, },
-		/* 0x12 */ { NULL,     NULL,            NULL,       LoadFontGlyph, },
+		/* 0x00 */ { NULL,     GRFUnsafe, NULL,            NULL,       FeatureChangeInfo, },
+		/* 0x01 */ { NULL,     GRFUnsafe, NULL,            NULL,       NewSpriteSet, },
+		/* 0x02 */ { NULL,     GRFUnsafe, NULL,            NULL,       NewSpriteGroup, },
+		/* 0x03 */ { NULL,     GRFUnsafe, NULL,            NULL,       FeatureMapSpriteGroup, },
+		/* 0x04 */ { NULL,     NULL,      NULL,            NULL,       FeatureNewName, },
+		/* 0x05 */ { NULL,     NULL,      NULL,            NULL,       GraphicsNew, },
+		/* 0x06 */ { NULL,     NULL,      NULL,            CfgApply,   CfgApply, },
+		/* 0x07 */ { NULL,     NULL,      NULL,            NULL,       SkipIf, },
+		/* 0x08 */ { ScanInfo, SafeInfo,  NULL,            GRFInfo,    GRFInfo, },
+		/* 0x09 */ { NULL,     NULL,      NULL,            SkipIf,     SkipIf, },
+		/* 0x0A */ { NULL,     NULL,      NULL,            NULL,       SpriteReplace, },
+		/* 0x0B */ { NULL,     NULL,      NULL,            GRFError,   GRFError, },
+		/* 0x0C */ { NULL,     NULL,      NULL,            GRFComment, GRFComment, },
+		/* 0x0D */ { NULL,     GRFUnsafe, NULL,            ParamSet,   ParamSet, },
+		/* 0x0E */ { NULL,     GRFUnsafe, NULL,            GRFInhibit, GRFInhibit, },
+		/* 0x0F */ { NULL,     NULL,      NULL,            NULL,       NULL, },
+		/* 0x10 */ { NULL,     NULL,      DefineGotoLabel, NULL,       NULL, },
+		/* 0x11 */ { NULL,     GRFUnsafe, NULL,            NULL,       GRFSound, },
+		/* 0x12 */ { NULL,     NULL,      NULL,            NULL,       LoadFontGlyph, },
 	};
 
 	byte* buf;
@@ -3591,7 +3612,7 @@
 	 * During activation, only actions 0, 1, 2, 3, 4, 5, 7, 8, 9, 0A and 0B are
 	 * carried out.  All others are ignored, because they only need to be
 	 * processed once at initialization.  */
-	if (stage != GLS_FILESCAN && stage != GLS_LABELSCAN) {
+	if (stage != GLS_FILESCAN && stage != GLS_SAFETYSCAN && stage != GLS_LABELSCAN) {
 		_cur_grffile = GetFileByFilename(filename);
 		if (_cur_grffile == NULL) error("File ``%s'' lost in cache.\n", filename);
 		if (stage == GLS_ACTIVATION && !HASBIT(config->flags, GCF_ACTIVATED)) return;
--- a/newgrf.h
+++ b/newgrf.h
@@ -8,6 +8,7 @@
 
 typedef enum GrfLoadingStage {
 	GLS_FILESCAN,
+	GLS_SAFETYSCAN,
 	GLS_LABELSCAN,
 	GLS_INIT,
 	GLS_ACTIVATION,
--- a/newgrf_config.c
+++ b/newgrf_config.c
@@ -28,6 +28,7 @@
 GRFConfig *_all_grfs;
 GRFConfig *_grfconfig;
 GRFConfig *_grfconfig_newgame;
+GRFConfig *_grfconfig_static;
 
 
 /* Calculate the MD5 Sum for a GRF */
@@ -58,7 +59,7 @@
 
 
 /* Find the GRFID and calculate the md5sum */
-bool FillGRFDetails(GRFConfig *config)
+bool FillGRFDetails(GRFConfig *config, bool is_static)
 {
 	if (!FioCheckFileExists(config->filename)) {
 		SETBIT(config->flags, GCF_NOT_FOUND);
@@ -68,7 +69,10 @@
 	/* Find and load the Action 8 information */
 	/* 62 is the last file slot before sample.cat.
 	 * Should perhaps be some "don't care" value */
-	LoadNewGRFFile(config, 62, GLS_FILESCAN);
+	LoadNewGRFFile(config, 62, is_static ? GLS_SAFETYSCAN : GLS_FILESCAN);
+
+	/* GCF_UNSAFE is set if GLS_SAFETYSCAN finds unsafe actions */
+	if (HASBIT(config->flags, GCF_UNSAFE)) return false;
 
 	/* Skip if the grfid is 0 (not read) or 0xFFFFFFFF (ttdp system grf) */
 	if (config->grfid == 0 || config->grfid == 0xFFFFFFFF) return false;
@@ -77,22 +81,28 @@
 }
 
 
+void ClearGRFConfig(GRFConfig *config)
+{
+	free(config->filename);
+	free(config->name);
+	free(config->info);
+	free(config);
+}
+
+
 /* Clear a GRF Config list */
 void ClearGRFConfigList(GRFConfig *config)
 {
 	GRFConfig *c, *next;
 	for (c = config; c != NULL; c = next) {
 		next = c->next;
-		free(c->filename);
-		free(c->name);
-		free(c->info);
-		free(c);
+		ClearGRFConfig(c);
 	}
 }
 
 
 /* Copy a GRF Config list */
-static void CopyGRFConfigList(GRFConfig **dst, GRFConfig *src)
+static GRFConfig **CopyGRFConfigList(GRFConfig **dst, GRFConfig *src)
 {
 	GRFConfig *c;
 
@@ -106,15 +116,21 @@
 		*dst = c;
 		dst = &c->next;
 	}
+
+	return dst;
 }
 
 
 /* Reset the current GRF Config to either blank or newgame settings */
 void ResetGRFConfig(bool defaults)
 {
+	GRFConfig **c = &_grfconfig;
+
 	ClearGRFConfigList(_grfconfig);
 	_grfconfig = NULL;
-	if (defaults) CopyGRFConfigList(&_grfconfig, _grfconfig_newgame);
+
+	if (defaults) c = CopyGRFConfigList(c, _grfconfig_newgame);
+	CopyGRFConfigList(c, _grfconfig_static);
 }
 
 
@@ -138,7 +154,7 @@
 
 			res = false;
 		} else {
-			DEBUG(grf, 1) ("[GRF] Loading GRF %X from %s", BSWAP32(c->grfid), f->filename);
+			DEBUG(grf, 1) ("[GRF] Loading GRF %08X from %s", BSWAP32(c->grfid), f->filename);
 			c->filename = strdup(f->filename);
 			c->name     = strdup(f->name);
 			c->info     = strdup(f->info);
@@ -186,7 +202,7 @@
 			c = calloc(1, sizeof(*c));
 			c->filename = strdup(file);
 
-			if (FillGRFDetails(c)) {
+			if (FillGRFDetails(c, false)) {
 				if (_all_grfs == NULL) {
 					_all_grfs = c;
 				} else {
@@ -294,6 +310,7 @@
 	int index = 0;
 
 	for (c = _grfconfig; c != NULL; c = c->next) {
+		if (HASBIT(c->flags, GCF_STATIC)) continue;
 		SlSetArrayIndex(index++);
 		SlObject(c, _grfconfig_desc);
 	}
@@ -314,6 +331,9 @@
 		last = &c->next;
 	}
 
+	/* Append static NewGRF configuration */
+	CopyGRFConfigList(last, _grfconfig_static);
+
 	ClearGRFConfigList(_grfconfig);
 	_grfconfig = first;
 }
--- a/newgrf_config.h
+++ b/newgrf_config.h
@@ -8,6 +8,9 @@
 	GCF_DISABLED,
 	GCF_NOT_FOUND,
 	GCF_ACTIVATED,
+	GCF_SYSTEM,
+	GCF_UNSAFE,
+	GCF_STATIC,
 };
 
 typedef struct GRFConfig {
@@ -33,13 +36,17 @@
 /* First item in list of default GRF set up */
 extern GRFConfig *_grfconfig_newgame;
 
+/* First item in list of static GRF set up */
+extern GRFConfig *_grfconfig_static;
+
 void ScanNewGRFFiles(void);
 const GRFConfig *FindGRFConfig(uint32 grfid, uint8 *md5sum);
 const GRFConfig *GetGRFConfig(uint32 grfid);
+void ClearGRFConfig(GRFConfig *config);
 void ClearGRFConfigList(GRFConfig *config);
 void ResetGRFConfig(bool defaults);
 bool IsGoodGRFConfigList(void);
-bool FillGRFDetails(GRFConfig *config);
+bool FillGRFDetails(GRFConfig *config, bool is_static);
 char *GRFBuildParamList(char *dst, const GRFConfig *c, const char *last);
 
 /* In newgrf_gui.c */
--- a/newgrf_gui.c
+++ b/newgrf_gui.c
@@ -274,6 +274,8 @@
 					/* Pick a colour */
 					if (HASBIT(c->flags, GCF_NOT_FOUND) || HASBIT(c->flags, GCF_DISABLED)) {
 						pal = PALETTE_TO_RED;
+					} else if (HASBIT(c->flags, GCF_STATIC)) {
+						pal = PALETTE_TO_YELLOW;
 					} else if (HASBIT(c->flags, GCF_ACTIVATED)) {
 						pal = PALETTE_TO_GREEN;
 					} else {
--- a/settings.c
+++ b/settings.c
@@ -1495,41 +1495,62 @@
 #undef NO
 #undef CR
 
-static const char *GRFProcessParams(const IniItem *item, uint index)
+
+/* Load a GRF configuration from the given group name */
+static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_static)
 {
-	GRFConfig *c;
+	IniGroup *group = ini_getgroup(ini, grpname, -1);
+	IniItem *item;
+	GRFConfig *first = NULL;
+	GRFConfig **curr = &first;
+
+	if (group == NULL) return NULL;
 
-	/* Saving newgrf stuff to configuration, not done since it is kept the same */
-	if (item == NULL) return NULL;
+	for (item = group->item; item != NULL; item = item->next) {
+		GRFConfig *c = calloc(1, sizeof(*c));
+		c->filename = strdup(item->name);
+
+		/* Parse parameters */
+		if (*item->value != '\0') {
+			c->num_params = parse_intlist(item->value, (int*)c->param, lengthof(c->param));
+			if (c->num_params == (byte)-1) {
+				ShowInfoF("ini: error in array '%s'", item->name);
+				c->num_params = 0;
+			}
+		}
 
-	/* Loading newgrf stuff from configuration file */
-	c = calloc(1, sizeof(*c));
-	c->filename = strdup(item->name);
-	if (!FillGRFDetails(c)) {
-		ShowInfoF("ini: ignoring invalid NewGRF '%s'", c->filename);
-		return NULL;
+		/* Check if item is valid */
+		if (!FillGRFDetails(c, is_static)) {
+			const char *msg;
+
+			if (HASBIT(c->flags, GCF_NOT_FOUND)) {
+				msg = "not found";
+			} else if (HASBIT(c->flags, GCF_UNSAFE)) {
+				msg = "unsafe for static use";
+			} else if (HASBIT(c->flags, GCF_SYSTEM)) {
+				msg = "system NewGRF";
+			} else {
+				msg = "unknown";
+			}
+
+			ShowInfoF("ini: ignoring invalid NewGRF '%s': %s", item->name, msg);
+			ClearGRFConfig(c);
+			continue;
+		}
+
+		/* Mark file as static to avoid saving in savegame. */
+		if (is_static) SETBIT(c->flags, GCF_STATIC);
+
+		/* Add item to list */
+		*curr = c;
+		curr = &c->next;
 	}
 
-	if (*item->value != '\0') {
-		c->num_params = parse_intlist(item->value, (int*)c->param, lengthof(c->param));
-		if (c->num_params == (byte)-1) {
-			ShowInfoF("ini: error in array '%s'", item->name);
-			c->num_params = 0;
-		}
-	}
-
-	if (_grfconfig_newgame == NULL) {
-		_grfconfig_newgame = c;
-	} else {
-		GRFConfig *c2;
-		/* Attach the label to the end of the list */
-		for (c2 = _grfconfig_newgame; c2->next != NULL; c2 = c2->next);
-		c2->next = c;
-	}
-
-	return c->filename;
+	return first;
 }
 
+
+/* Save a GRF configuration to the given group name */
 static void GRFSaveConfig(IniFile *ini, const char *grpname, const GRFConfig *list)
 {
 	IniGroup *group = ini_getgroup(ini, grpname, -1);
@@ -1575,7 +1596,8 @@
 {
 	IniFile *ini = ini_load(_config_file);
 	HandleSettingDescs(ini, ini_load_settings, ini_load_setting_list);
-	ini_load_setting_list(ini, "newgrf", NULL, 0, GRFProcessParams);
+	_grfconfig_newgame = GRFLoadConfig(ini, "newgrf", false);
+	_grfconfig_static  = GRFLoadConfig(ini, "newgrf-static", true);
 	ini_free(ini);
 }
 
@@ -1585,6 +1607,7 @@
 	IniFile *ini = ini_load(_config_file);
 	HandleSettingDescs(ini, ini_save_settings, ini_save_setting_list);
 	GRFSaveConfig(ini, "newgrf", _grfconfig_newgame);
+	GRFSaveConfig(ini, "newgrf-static", _grfconfig_static);
 	ini_save(_config_file, ini);
 	ini_free(ini);
 }