X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Flibgame%2Fsetup.c;h=b116457e575d5df7addfa73e9571b0027c985395;hb=c71f734c9f306daaca1a262d9f07ddae5bc71073;hp=4f00449473f8cadcb520d70c9a0ea542c40f4797;hpb=e14251b595dcb8586f57ea78a6a52b3bd03ee272;p=rocksndiamonds.git diff --git a/src/libgame/setup.c b/src/libgame/setup.c index 4f004494..b116457e 100644 --- a/src/libgame/setup.c +++ b/src/libgame/setup.c @@ -86,12 +86,17 @@ static char *levelclass_desc[NUM_LEVELCLASS_DESC] = #define MAX_COOKIE_LEN 256 + static void setTreeInfoToDefaults(TreeInfo *, int); static int compareTreeInfoEntries(const void *, const void *); static int token_value_position = TOKEN_VALUE_POSITION_DEFAULT; static int token_comment_position = TOKEN_COMMENT_POSITION_DEFAULT; +static SetupFileHash *artworkinfo_cache_old = NULL; +static SetupFileHash *artworkinfo_cache_new = NULL; +static boolean use_artworkinfo_cache = TRUE; + /* ------------------------------------------------------------------------- */ /* file functions */ @@ -155,6 +160,16 @@ static char *getLevelSetupDir(char *level_subdir) return levelsetup_dir; } +static char *getCacheDir() +{ + static char *cache_dir = NULL; + + if (cache_dir == NULL) + cache_dir = getPath2(getUserGameDataDir(), CACHE_DIRECTORY); + + return cache_dir; +} + static char *getLevelDirFromTreeInfo(TreeInfo *node) { static char *level_dir = NULL; @@ -794,7 +809,7 @@ void InitUserLevelDirectory(char *level_subdir) { createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); createDirectory(getUserLevelDir(NULL), "main user level", PERMS_PRIVATE); - createDirectory(getUserLevelDir(level_subdir), "user level",PERMS_PRIVATE); + createDirectory(getUserLevelDir(level_subdir), "user level", PERMS_PRIVATE); SaveUserLevelInfo(); } @@ -804,7 +819,13 @@ void InitLevelSetupDirectory(char *level_subdir) { createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); createDirectory(getLevelSetupDir(NULL), "main level setup", PERMS_PRIVATE); - createDirectory(getLevelSetupDir(level_subdir), "level setup",PERMS_PRIVATE); + createDirectory(getLevelSetupDir(level_subdir), "level setup", PERMS_PRIVATE); +} + +void InitCacheDirectory() +{ + createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); + createDirectory(getCacheDir(), "cache data", PERMS_PRIVATE); } @@ -1652,7 +1673,11 @@ static void *loadSetupFileData(char *filename, boolean use_hash) /* find end of token to determine start of value */ for (line_ptr = token; *line_ptr; line_ptr++) { +#if 1 + if (*line_ptr == ':' || *line_ptr == '=') +#else if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':') +#endif { *line_ptr = '\0'; /* terminate token string */ value = line_ptr + 1; /* set beginning of value */ @@ -1661,6 +1686,11 @@ static void *loadSetupFileData(char *filename, boolean use_hash) } } + /* cut trailing whitespaces from token */ + for (line_ptr = &token[strlen(token)]; line_ptr >= token; line_ptr--) + if ((*line_ptr == ' ' || *line_ptr == '\t') && *(line_ptr + 1) == '\0') + *line_ptr = '\0'; + /* cut leading whitespaces from value */ for (; *value; value++) if (*value != ' ' && *value != '\t') @@ -1704,6 +1734,27 @@ static void *loadSetupFileData(char *filename, boolean use_hash) return setup_file_data; } +void saveSetupFileHash(SetupFileHash *hash, char *filename) +{ + FILE *file; + + if (!(file = fopen(filename, MODE_WRITE))) + { + Error(ERR_WARN, "cannot write configuration file '%s'", filename); + + return; + } + + BEGIN_HASH_ITERATION(hash, itr) + { + fprintf(file, "%s\n", getFormattedSetupEntry(HASH_ITERATION_TOKEN(itr), + HASH_ITERATION_VALUE(itr))); + } + END_HASH_ITERATION(hash, itr) + + fclose(file); +} + SetupFileList *loadSetupFileList(char *filename) { return (SetupFileList *)loadSetupFileData(filename, FALSE); @@ -1787,6 +1838,24 @@ static struct TokenInfo levelinfo_tokens[] = { TYPE_BOOLEAN, &ldi.skip_levels, "skip_levels" } }; +static struct TokenInfo artworkinfo_tokens[] = +{ + /* artwork directory info */ + { TYPE_STRING, &ldi.identifier, "identifier" }, + { TYPE_STRING, &ldi.subdir, "subdir" }, + { TYPE_STRING, &ldi.name, "name" }, + { TYPE_STRING, &ldi.name_sorting, "name_sorting" }, + { TYPE_STRING, &ldi.author, "author" }, + { TYPE_INTEGER, &ldi.sort_priority, "sort_priority" }, + { TYPE_STRING, &ldi.basepath, "basepath" }, + { TYPE_STRING, &ldi.fullpath, "fullpath" }, + { TYPE_BOOLEAN, &ldi.in_user_dir, "in_user_dir" }, + { TYPE_INTEGER, &ldi.color, "color" }, + { TYPE_STRING, &ldi.class_desc, "class_desc" }, + + { -1, NULL, NULL }, +}; + static void setTreeInfoToDefaults(TreeInfo *ti, int type) { ti->type = type; @@ -1921,6 +1990,9 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ti, TreeInfo *parent) static void freeTreeInfo(TreeInfo *ti) { + if (ti == NULL) + return; + checked_free(ti->subdir); checked_free(ti->fullpath); checked_free(ti->basepath); @@ -1952,6 +2024,8 @@ static void freeTreeInfo(TreeInfo *ti) checked_free(ti->level_filename); checked_free(ti->level_filetype); } + + checked_free(ti); } void setSetupInfo(struct TokenInfo *token_info, @@ -2059,6 +2133,221 @@ static void createParentTreeInfoNode(TreeInfo *node_parent) pushTreeInfo(&node_parent->node_group, ti_new); } + +/* -------------------------------------------------------------------------- */ +/* functions for handling level and custom artwork info cache */ +/* -------------------------------------------------------------------------- */ + +static void LoadArtworkInfoCache() +{ + InitCacheDirectory(); + + if (artworkinfo_cache_old == NULL) + { + char *filename = getPath2(getCacheDir(), ARTWORKINFO_CACHE_FILE); + + /* try to load artwork info hash from already existing cache file */ + artworkinfo_cache_old = loadSetupFileHash(filename); + + /* if no artwork info cache file was found, start with empty hash */ + if (artworkinfo_cache_old == NULL) + artworkinfo_cache_old = newSetupFileHash(); + + free(filename); + } + + if (artworkinfo_cache_new == NULL) + artworkinfo_cache_new = newSetupFileHash(); +} + +static void SaveArtworkInfoCache() +{ + char *filename = getPath2(getCacheDir(), ARTWORKINFO_CACHE_FILE); + + InitCacheDirectory(); + + saveSetupFileHash(artworkinfo_cache_new, filename); + + free(filename); +} + +static char *getCacheTokenPrefix(char *prefix1, char *prefix2) +{ + static char *prefix = NULL; + + checked_free(prefix); + + prefix = getStringCat2WithSeparator(prefix1, prefix2, "."); + + return prefix; +} + +/* (identical to above function, but separate string buffer needed -- nasty) */ +static char *getCacheToken(char *prefix, char *suffix) +{ + static char *token = NULL; + + checked_free(token); + + token = getStringCat2WithSeparator(prefix, suffix, "."); + + return token; +} + +static char *getFileTimestamp(char *filename) +{ + struct stat file_status; + + if (stat(filename, &file_status) != 0) /* cannot stat file */ + return getStringCopy(i_to_a(0)); + + return getStringCopy(i_to_a(file_status.st_mtime)); +} + +static boolean modifiedFileTimestamp(char *filename, char *timestamp_string) +{ + struct stat file_status; + + if (timestamp_string == NULL) + return TRUE; + + if (stat(filename, &file_status) != 0) /* cannot stat file */ + return TRUE; + + return (file_status.st_mtime != atoi(timestamp_string)); +} + +static TreeInfo *getArtworkInfoCacheEntry(LevelDirTree *level_node, int type) +{ + char *identifier = level_node->subdir; + char *type_string = ARTWORK_DIRECTORY(type); + char *token_prefix = getCacheTokenPrefix(type_string, identifier); + char *token_main = getCacheToken(token_prefix, "CACHED"); + char *cache_entry = getHashEntry(artworkinfo_cache_old, token_main); + boolean cached = (cache_entry != NULL && strEqual(cache_entry, "true")); + TreeInfo *artwork_info = NULL; + + if (!use_artworkinfo_cache) + return NULL; + + if (cached) + { + int i; + + artwork_info = newTreeInfo(); + setTreeInfoToDefaults(artwork_info, type); + + /* set all structure fields according to the token/value pairs */ + ldi = *artwork_info; + for (i = 0; artworkinfo_tokens[i].type != -1; i++) + { + char *token = getCacheToken(token_prefix, artworkinfo_tokens[i].text); + char *value = getHashEntry(artworkinfo_cache_old, token); + + setSetupInfo(artworkinfo_tokens, i, value); + + /* check if cache entry for this item is invalid or incomplete */ + if (value == NULL) + { +#if 1 + printf("::: - WARNING: cache entry '%s' invalid\n", token); +#endif + + cached = FALSE; + } + } + *artwork_info = ldi; + } + + if (cached) + { + char *filename_levelinfo = getPath2(getLevelDirFromTreeInfo(level_node), + LEVELINFO_FILENAME); + char *filename_artworkinfo = getPath2(getSetupArtworkDir(artwork_info), + ARTWORKINFO_FILENAME(type)); + + /* check if corresponding "levelinfo.conf" file has changed */ + token_main = getCacheToken(token_prefix, "TIMESTAMP_LEVELINFO"); + cache_entry = getHashEntry(artworkinfo_cache_old, token_main); + + if (modifiedFileTimestamp(filename_levelinfo, cache_entry)) + cached = FALSE; + + /* check if corresponding ".conf" file has changed */ + token_main = getCacheToken(token_prefix, "TIMESTAMP_ARTWORKINFO"); + cache_entry = getHashEntry(artworkinfo_cache_old, token_main); + + if (modifiedFileTimestamp(filename_artworkinfo, cache_entry)) + cached = FALSE; + +#if 0 + if (!cached) + printf("::: '%s': INVALIDATED FROM CACHE BY TIMESTAMP\n", identifier); +#endif + + checked_free(filename_levelinfo); + checked_free(filename_artworkinfo); + } + + if (!cached && artwork_info != NULL) + { + freeTreeInfo(artwork_info); + + return NULL; + } + + return artwork_info; +} + +static void setArtworkInfoCacheEntry(TreeInfo *artwork_info, + LevelDirTree *level_node, int type) +{ + char *identifier = level_node->subdir; + char *type_string = ARTWORK_DIRECTORY(type); + char *token_prefix = getCacheTokenPrefix(type_string, identifier); + char *token_main = getCacheToken(token_prefix, "CACHED"); + boolean set_cache_timestamps = TRUE; + int i; + + setHashEntry(artworkinfo_cache_new, token_main, "true"); + + if (set_cache_timestamps) + { + char *filename_levelinfo = getPath2(getLevelDirFromTreeInfo(level_node), + LEVELINFO_FILENAME); + char *filename_artworkinfo = getPath2(getSetupArtworkDir(artwork_info), + ARTWORKINFO_FILENAME(type)); + char *timestamp_levelinfo = getFileTimestamp(filename_levelinfo); + char *timestamp_artworkinfo = getFileTimestamp(filename_artworkinfo); + + token_main = getCacheToken(token_prefix, "TIMESTAMP_LEVELINFO"); + setHashEntry(artworkinfo_cache_new, token_main, timestamp_levelinfo); + + token_main = getCacheToken(token_prefix, "TIMESTAMP_ARTWORKINFO"); + setHashEntry(artworkinfo_cache_new, token_main, timestamp_artworkinfo); + + checked_free(filename_levelinfo); + checked_free(filename_artworkinfo); + checked_free(timestamp_levelinfo); + checked_free(timestamp_artworkinfo); + } + + ldi = *artwork_info; + for (i = 0; artworkinfo_tokens[i].type != -1; i++) + { + char *token = getCacheToken(token_prefix, artworkinfo_tokens[i].text); + char *value = getSetupValue(artworkinfo_tokens[i].type, + artworkinfo_tokens[i].value); + if (value != NULL) + setHashEntry(artworkinfo_cache_new, token, value); + } +} + + +/* -------------------------------------------------------------------------- */ +/* functions for loading level info and custom artwork info */ +/* -------------------------------------------------------------------------- */ + /* forward declaration for recursive call by "LoadLevelInfoFromLevelDir()" */ static void LoadLevelInfoFromLevelDir(TreeInfo **, TreeInfo *, char *); @@ -2116,8 +2405,6 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first, if (strEqual(leveldir_new->name, ANONYMOUS_NAME)) setString(&leveldir_new->name, leveldir_new->subdir); - DrawInitText(leveldir_new->name, 150, FC_YELLOW); - if (leveldir_new->identifier == NULL) leveldir_new->identifier = getStringCopy(leveldir_new->subdir); @@ -2168,6 +2455,9 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first, (leveldir_new->user_defined || !leveldir_new->handicap ? leveldir_new->last_level : leveldir_new->first_level); + if (leveldir_new->level_group) + DrawInitText(leveldir_new->name, 150, FC_YELLOW); + #if 0 /* !!! don't skip sets without levels (else artwork base sets are missing) */ #if 1 @@ -2193,7 +2483,7 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first, /* create node to link back to current level directory */ createParentTreeInfoNode(leveldir_new); - /* step into sub-directory and look for more level series */ + /* recursively step into sub-directory and look for more level series */ LoadLevelInfoFromLevelDir(&leveldir_new->node_group, leveldir_new, directory_path); } @@ -2281,7 +2571,7 @@ void LoadLevelInfo() { InitUserLevelDirectory(getLoginName()); - DrawInitText("Loading level series:", 120, FC_GREEN); + DrawInitText("Loading level series", 120, FC_GREEN); LoadLevelInfoFromLevelDir(&leveldir_first, NULL, options.level_directory); LoadLevelInfoFromLevelDir(&leveldir_first, NULL, getUserLevelDir(NULL)); @@ -2381,10 +2671,6 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first, if (strEqual(artwork_new->name, ANONYMOUS_NAME)) setString(&artwork_new->name, artwork_new->subdir); -#if 0 - DrawInitText(artwork_new->name, 150, FC_YELLOW); -#endif - if (artwork_new->identifier == NULL) artwork_new->identifier = getStringCopy(artwork_new->subdir); @@ -2441,7 +2727,9 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first, setString(&artwork_new->name_sorting, artwork_new->name); } +#if 0 DrawInitText(artwork_new->name, 150, FC_YELLOW); +#endif pushTreeInfo(node_first, artwork_new); @@ -2531,7 +2819,9 @@ static TreeInfo *getDummyArtworkInfo(int type) void LoadArtworkInfo() { - DrawInitText("Looking for custom artwork:", 120, FC_GREEN); + LoadArtworkInfoCache(); + + DrawInitText("Looking for custom artwork", 120, FC_GREEN); LoadArtworkInfoFromArtworkDir(&artwork.gfx_first, NULL, options.graphics_directory, @@ -2610,6 +2900,8 @@ void LoadArtworkInfo() void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node, LevelDirTree *level_node) { + int type = (*artwork_node)->type; + /* recursively check all level directories for artwork sub-directories */ while (level_node) @@ -2617,30 +2909,46 @@ void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node, /* check all tree entries for artwork, but skip parent link entries */ if (!level_node->parent_link) { - TreeInfo *topnode_last = *artwork_node; - char *path = getPath2(getLevelDirFromTreeInfo(level_node), - ARTWORK_DIRECTORY((*artwork_node)->type)); - - LoadArtworkInfoFromArtworkDir(artwork_node, NULL, path, - (*artwork_node)->type); + TreeInfo *artwork_new = getArtworkInfoCacheEntry(level_node, type); + boolean cached = (artwork_new != NULL); - if (topnode_last != *artwork_node) + if (cached) + { + pushTreeInfo(artwork_node, artwork_new); + } + else { - free((*artwork_node)->identifier); - free((*artwork_node)->name); - free((*artwork_node)->name_sorting); + TreeInfo *topnode_last = *artwork_node; + char *path = getPath2(getLevelDirFromTreeInfo(level_node), + ARTWORK_DIRECTORY(type)); - (*artwork_node)->identifier = getStringCopy(level_node->subdir); - (*artwork_node)->name = getStringCopy(level_node->name); - (*artwork_node)->name_sorting = getStringCopy(level_node->name); + LoadArtworkInfoFromArtworkDir(artwork_node, NULL, path, type); - (*artwork_node)->sort_priority = level_node->sort_priority; - (*artwork_node)->color = LEVELCOLOR((*artwork_node)); + if (topnode_last != *artwork_node) /* check for newly added node */ + { + artwork_new = *artwork_node; + + setString(&artwork_new->identifier, level_node->subdir); + setString(&artwork_new->name, level_node->name); + setString(&artwork_new->name_sorting, level_node->name_sorting); + + artwork_new->sort_priority = level_node->sort_priority; + artwork_new->color = LEVELCOLOR(artwork_new); + } + + free(path); } - free(path); + /* insert artwork info (from old cache or filesystem) into new cache */ + if (artwork_new != NULL) + setArtworkInfoCacheEntry(artwork_new, level_node, type); } +#if 1 + if (level_node->level_group) + DrawInitText(level_node->name, 150, FC_YELLOW); +#endif + if (level_node->node_group != NULL) LoadArtworkInfoFromLevelInfo(artwork_node, level_node->node_group); @@ -2650,12 +2958,14 @@ void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node, void LoadLevelArtworkInfo() { - DrawInitText("Looking for custom level artwork:", 120, FC_GREEN); + DrawInitText("Looking for custom level artwork", 120, FC_GREEN); LoadArtworkInfoFromLevelInfo(&artwork.gfx_first, leveldir_first_all); LoadArtworkInfoFromLevelInfo(&artwork.snd_first, leveldir_first_all); LoadArtworkInfoFromLevelInfo(&artwork.mus_first, leveldir_first_all); + SaveArtworkInfoCache(); + /* needed for reloading level artwork not known at ealier stage */ if (!strEqual(artwork.gfx_current_identifier, setup.graphics_set)) @@ -2795,6 +3105,9 @@ char *getSetupValue(int type, void *value) break; case TYPE_STRING: + if (*(char **)value == NULL) + return NULL; + strcpy(value_string, *(char **)value); break;