From e36571c70ca3abb639ef64bf6f5c924ca19e4ffa Mon Sep 17 00:00:00 2001 From: Paweł Redman Date: Tue, 20 Dec 2016 12:41:28 +0100 Subject: Implement map postprocessing fully. Postprocessing removes info_* and team_* entities from all maps but the master (the first one in the command line) and (optionally) prefixes all targets and targetnames with a prefix (set by mapcat_prefix in the master worldspawn). --- src/common.h | 1 + src/main.c | 9 ++++++- src/mapcat.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/common.h b/src/common.h index b005e2b..8acf3ba 100644 --- a/src/common.h +++ b/src/common.h @@ -132,5 +132,6 @@ void map_init(map_t *map); void map_free(map_t *map); int map_read(map_t *map, const char *path); int map_write(const map_t *map, const char *path); +int map_postprocess(map_t *map, bool filter_team_ents); int map_merge(map_t *master, map_t *slave); void map_print_stats(const char *path, const map_t *map); diff --git a/src/main.c b/src/main.c index 1b903d6..838afb5 100644 --- a/src/main.c +++ b/src/main.c @@ -108,7 +108,7 @@ int main(int argc, char **argv) map_init(&map); - elist_for (input, inputs, list) { + elist_for(input, inputs, list) { map_t part; map_init(&part); @@ -121,6 +121,13 @@ int main(int argc, char **argv) if (!quiet) map_print_stats(input->path, &part); + // team_* and info_* ents are kept only in the first part + if (map_postprocess(&part, (input != inputs))) { + map_free(&map); + map_free(&part); + goto out; + } + if (map_merge(&map, &part)) { error("error: couldn't merge %s into %s\n", input->path, output); diff --git a/src/mapcat.c b/src/mapcat.c index b33a694..7968586 100644 --- a/src/mapcat.c +++ b/src/mapcat.c @@ -617,6 +617,83 @@ out: return rv; } +int map_postprocess(map_t *map, bool filter_team_ents) +{ + entity_t *entity; + entity_key_t *key; + char *prefix = NULL; + + if (filter_team_ents) { + entity_t *next; + + for (entity = map->entities; entity; entity = next) { + next = elist_next(entity, list); + + if (strncmp(entity->classname, "team_", 5) && + strncmp(entity->classname, "info_", 5)) + continue; + + map->num_discarded_entities++; + elist_unlink(&map->entities, entity, list); + free_entity(entity); + } + } + + if (map->worldspawn) { + entity_key_t *next; + + for (key = map->worldspawn->keys; key; key = next) { + next = elist_next(key, list); + + if (!strcmp(key->key, "mapcat_prefix")) { + // shouldn't happen, but just in case + // (to prevent memory leaks) + if (prefix) + free(prefix); + + prefix = key->value; + elist_unlink(&map->worldspawn->keys, key, list); + free(key->key); + // key->value is freed later (as prefix) + free(key); + } + } + } + + if (prefix) { + size_t prefix_len = strlen(prefix); + + elist_for(entity, map->entities, list) + elist_for(key, entity->keys, list) { + char *new; + size_t value_len; + + if (strcmp(key->key, "target") && + strcmp(key->key, "targetname")) + continue; + + value_len = strlen(key->value); + + new = malloc(value_len + prefix_len + 1); + if (!new) { + fprintf(stderr, "error: out of memory\n"); + return 1; + } + + memcpy(new, prefix, prefix_len); + memcpy(new + prefix_len, key->value, value_len); + new[prefix_len + value_len] = 0; + + free(key->value); + key->value = new; + } + + free(prefix); + } + + return 0; +} + //RETURN VALUE // always 0 (this function cannot fail (yet)) // slave is left in invalid state after this function returns, do not use it @@ -643,6 +720,8 @@ int map_merge(map_t *master, map_t *slave) master->num_discarded_entities += slave->num_discarded_entities; master->num_brushes += slave->num_brushes; master->num_discarded_brushes += slave->num_discarded_brushes; + master->num_patches += slave->num_patches; + master->num_discarded_patches += slave->num_discarded_patches; return 0; } -- cgit