From 7df47fd25c3b44096a08f429a3a4a9e0449a67d4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 16 Oct 2014 07:34:09 +0200 Subject: [PATCH 1/4] remove bad configuration caching (TODO: cache inside get_param). move remove_empty_* functions out of config.c add basic tests for remove_empty_units (no special units yet). --- src/bind_eressea.c | 1 + src/economy.c | 2 +- src/kernel/config.c | 118 +---------------------------------------- src/kernel/config.h | 4 -- src/kernel/faction.c | 54 +++++++++++++++++++ src/kernel/faction.h | 2 + src/kernel/unit.c | 47 ++++++++++++++++ src/kernel/unit.h | 2 + src/kernel/unit.test.c | 38 +++++++++++++ 9 files changed, 147 insertions(+), 121 deletions(-) diff --git a/src/bind_eressea.c b/src/bind_eressea.c index d6f1d1eb5..664808b17 100755 --- a/src/bind_eressea.c +++ b/src/bind_eressea.c @@ -4,6 +4,7 @@ #include "json.h" +#include #include #include #include diff --git a/src/economy.c b/src/economy.c index 965df6478..bb24fd5e5 100644 --- a/src/economy.c +++ b/src/economy.c @@ -57,9 +57,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include #include #include +#include #include #include diff --git a/src/kernel/config.c b/src/kernel/config.c index 7bffa0bbf..6f0004708 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -102,7 +102,6 @@ struct settings global = { bool lomem = false; FILE *logfile; -FILE *updatelog; bool battledebug = false; int turn = -1; @@ -122,17 +121,6 @@ bool IsImmune(const faction * f) return !fval(f, FFL_NPC) && f->age < NewbieImmunity(); } -static int MaxAge(void) -{ - static int value = -1; - static int gamecookie = -1; - if (value < 0 || gamecookie != global.cookie) { - gamecookie = global.cookie; - value = get_param_int(global.parameters, "MaxAge", 0); - } - return value; -} - static int ally_flag(const char *s, int help_mask) { if ((help_mask & HELP_MONEY) && strcmp(s, "money") == 0) @@ -2069,100 +2057,6 @@ char *_strdup(const char *s) } #endif -void remove_empty_factions(void) -{ - faction **fp, *f3; - - for (fp = &factions; *fp;) { - faction *f = *fp; - /* monster (0) werden nicht entfernt. alive kann beim readgame - * () auf 0 gesetzt werden, wenn monsters keine einheiten mehr - * haben. */ - if ((f->units == NULL || f->alive == 0) && !is_monsters(f)) { - ursprung *ur = f->ursprung; - while (ur && ur->id != 0) - ur = ur->next; - if (verbosity >= 2) - log_printf(stdout, "\t%s\n", factionname(f)); - - /* Einfach in eine Datei schreiben und später vermailen */ - - if (updatelog) - fprintf(updatelog, "dropout %s\n", itoa36(f->no)); - - for (f3 = factions; f3; f3 = f3->next) { - ally *sf; - group *g; - ally **sfp = &f3->allies; - while (*sfp) { - sf = *sfp; - if (sf->faction == f || sf->faction == NULL) { - *sfp = sf->next; - free(sf); - } - else - sfp = &(*sfp)->next; - } - for (g = f3->groups; g; g = g->next) { - sfp = &g->allies; - while (*sfp) { - sf = *sfp; - if (sf->faction == f || sf->faction == NULL) { - *sfp = sf->next; - free(sf); - } - else - sfp = &(*sfp)->next; - } - } - } - - *fp = f->next; - funhash(f); - free_faction(f); - free(f); - } - else - fp = &(*fp)->next; - } -} - -void remove_empty_units_in_region(region * r) -{ - unit **up = &r->units; - - while (*up) { - unit *u = *up; - - if (u->number) { - faction *f = u->faction; - if (f == NULL || !f->alive) { - set_number(u, 0); - } - if (MaxAge() > 0) { - if ((!fval(f, FFL_NOTIMEOUT) && f->age > MaxAge())) { - set_number(u, 0); - } - } - } - if ((u->number == 0 && u_race(u) != get_race(RC_SPELL)) || (u->age <= 0 - && u_race(u) == get_race(RC_SPELL))) { - remove_unit(up, u); - } - if (*up == u) - up = &u->next; - } -} - -void remove_empty_units(void) -{ - region *r; - - for (r = regions; r; r = r->next) { - remove_empty_units_in_region(r); - } -} - bool faction_id_is_unused(int id) { return findfaction(id) == NULL; @@ -2715,20 +2609,12 @@ int entertainmoney(const region * r) int rule_give(void) { - static int value = -1; - if (value < 0) { - value = get_param_int(global.parameters, "rules.give", GIVE_DEFAULT); - } - return value; + return get_param_int(global.parameters, "rules.give", GIVE_DEFAULT); } int markets_module(void) { - static int value = -1; - if (value < 0) { - value = get_param_int(global.parameters, "modules.markets", 0); - } - return value; + return get_param_int(global.parameters, "modules.markets", 0); } /** releases all memory associated with the game state. diff --git a/src/kernel/config.h b/src/kernel/config.h index 06474dd65..5f3513a72 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -107,10 +107,6 @@ extern "C" { #define i2b(i) ((bool)((i)?(true):(false))) - void remove_empty_units_in_region(struct region *r); - void remove_empty_units(void); - void remove_empty_factions(void); - typedef struct strlist { struct strlist *next; char *s; diff --git a/src/kernel/faction.c b/src/kernel/faction.c index b46848e3c..d3e3bc014 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -601,3 +601,57 @@ int skill_limit(faction * f, skill_t sk) return m; } +void remove_empty_factions(void) +{ + faction **fp, *f3; + + for (fp = &factions; *fp;) { + faction *f = *fp; + /* monster (0) werden nicht entfernt. alive kann beim readgame + * () auf 0 gesetzt werden, wenn monsters keine einheiten mehr + * haben. */ + if ((f->units == NULL || f->alive == 0) && !is_monsters(f)) { + ursprung *ur = f->ursprung; + while (ur && ur->id != 0) + ur = ur->next; + if (verbosity >= 2) + log_printf(stdout, "\t%s\n", factionname(f)); + + /* Einfach in eine Datei schreiben und später vermailen */ + + for (f3 = factions; f3; f3 = f3->next) { + ally *sf; + group *g; + ally **sfp = &f3->allies; + while (*sfp) { + sf = *sfp; + if (sf->faction == f || sf->faction == NULL) { + *sfp = sf->next; + free(sf); + } + else + sfp = &(*sfp)->next; + } + for (g = f3->groups; g; g = g->next) { + sfp = &g->allies; + while (*sfp) { + sf = *sfp; + if (sf->faction == f || sf->faction == NULL) { + *sfp = sf->next; + free(sf); + } + else + sfp = &(*sfp)->next; + } + } + } + + *fp = f->next; + funhash(f); + free_faction(f); + free(f); + } + else + fp = &(*fp)->next; + } +} diff --git a/src/kernel/faction.h b/src/kernel/faction.h index 52f3c271a..f1db53b87 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -20,6 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define H_KRNL_FACTION #include "skill.h" +#include "types.h" #ifdef __cplusplus extern "C" { @@ -136,6 +137,7 @@ void destroyfaction(faction * f); extern void renumber_faction(faction * f, int no); void free_faction(struct faction *f); + void remove_empty_factions(void); #ifdef SMART_INTERVALS extern void update_interval(struct faction *f, struct region *r); diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 09c821b70..dca02aabf 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1786,3 +1786,50 @@ int effskill(const unit * u, skill_t sk) return eff_skill(u, sk, u->region); } +static int MaxAge(void) +{ + static int value = -1; + static int gamecookie = -1; + if (value < 0 || gamecookie != global.cookie) { + gamecookie = global.cookie; + value = get_param_int(global.parameters, "MaxAge", 0); + } + return value; +} + +void remove_empty_units_in_region(region * r) +{ + unit **up = &r->units; + int max_age = MaxAge(); + + while (*up) { + unit *u = *up; + + if (u->number) { + faction *f = u->faction; + if (f == NULL || !f->alive) { + set_number(u, 0); + } + if (max_age > 0) { + if ((!fval(f, FFL_NOTIMEOUT) && f->age > max_age)) { + set_number(u, 0); + } + } + } + if ((u->number == 0 && u_race(u) != get_race(RC_SPELL)) || (u->age <= 0 + && u_race(u) == get_race(RC_SPELL))) { + remove_unit(up, u); + } + if (*up == u) + up = &u->next; + } +} + +void remove_empty_units(void) +{ + region *r; + + for (r = regions; r; r = r->next) { + remove_empty_units_in_region(r); + } +} diff --git a/src/kernel/unit.h b/src/kernel/unit.h index de90db3b2..a3db732dd 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -238,6 +238,8 @@ extern "C" { struct spellbook * unit_get_spellbook(const struct unit * u); void unit_add_spell(struct unit * u, struct sc_mage * m, struct spell * sp, int level); + void remove_empty_units_in_region(struct region * r); + void remove_empty_units(void); extern struct attrib_type at_creator; #ifdef __cplusplus diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c index 6f3618e73..3a341cce2 100644 --- a/src/kernel/unit.test.c +++ b/src/kernel/unit.test.c @@ -11,6 +11,42 @@ #include #include +static void test_remove_empty_units(CuTest *tc) { + unit *u; + int uid; + + test_cleanup(); + test_create_world(); + + u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); + uid = u->no; + remove_empty_units(); + CuAssertPtrNotNull(tc, findunit(uid)); + u->number = 0; + remove_empty_units(); + CuAssertPtrEquals(tc, 0, findunit(uid)); + test_cleanup(); +} + +static void test_remove_empty_units_in_region(CuTest *tc) { + unit *u; + int uid; + + test_cleanup(); + test_create_world(); + + u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); + uid = u->no; + remove_empty_units_in_region(u->region); + CuAssertPtrNotNull(tc, findunit(uid)); + u->number = 0; + remove_empty_units_in_region(u->region); + CuAssertPtrEquals(tc, 0, findunit(uid)); + CuAssertPtrEquals(tc, 0, u->region); + CuAssertPtrEquals(tc, 0, u->faction); + test_cleanup(); +} + static void test_scale_number(CuTest *tc) { unit *u; const struct potion_type *ptype; @@ -37,5 +73,7 @@ CuSuite *get_unit_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_scale_number); + SUITE_ADD_TEST(suite, test_remove_empty_units); + SUITE_ADD_TEST(suite, test_remove_empty_units_in_region); return suite; } From 559f1f905afacbb28a22e8d15f0d7ccb0119fa4e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 16 Oct 2014 07:46:08 +0200 Subject: [PATCH 2/4] Eliminate dead code: FFL_NOTIMEOUT. old feature for time-limited factions, not used anywhere. --- src/kernel/faction.h | 4 ++-- src/kernel/save.c | 2 +- src/kernel/unit.c | 17 ----------------- 3 files changed, 3 insertions(+), 20 deletions(-) diff --git a/src/kernel/faction.h b/src/kernel/faction.h index f1db53b87..92878ceef 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -49,10 +49,10 @@ extern "C" { #define FFL_NOIDLEOUT (1<<24) /* Partei stirbt nicht an NMRs */ #define FFL_NPC (1<<25) /* eine Partei mit Monstern */ #define FFL_DBENTRY (1<<28) /* Partei ist in Datenbank eingetragen */ -#define FFL_NOTIMEOUT (1<<29) /* ignore MaxAge() */ + #define FFL_GM (1<<30) /* eine Partei mit Sonderrechten */ -#define FFL_SAVEMASK (FFL_DEFENDER|FFL_NEWID|FFL_GM|FFL_NPC|FFL_NOTIMEOUT|FFL_DBENTRY|FFL_NOIDLEOUT) +#define FFL_SAVEMASK (FFL_DEFENDER|FFL_NEWID|FFL_GM|FFL_NPC|FFL_DBENTRY|FFL_NOIDLEOUT) #define is_monsters(f) ((f)->flags&FFL_NPC) diff --git a/src/kernel/save.c b/src/kernel/save.c index 52661ff24..9ec7d2622 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1312,7 +1312,7 @@ faction *readfaction(struct gamedata * data) READ_INT(data->store, &f->flags); if (data->version < INTFLAGS_VERSION) { if (f->no == 0 || f->no == 666) { - f->flags = FFL_NPC | FFL_NOTIMEOUT | FFL_NOIDLEOUT; + f->flags = FFL_NPC | FFL_NOIDLEOUT; } } assert((f->flags&FFL_SAVEMASK) == f->flags); diff --git a/src/kernel/unit.c b/src/kernel/unit.c index dca02aabf..b956465e2 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1786,21 +1786,9 @@ int effskill(const unit * u, skill_t sk) return eff_skill(u, sk, u->region); } -static int MaxAge(void) -{ - static int value = -1; - static int gamecookie = -1; - if (value < 0 || gamecookie != global.cookie) { - gamecookie = global.cookie; - value = get_param_int(global.parameters, "MaxAge", 0); - } - return value; -} - void remove_empty_units_in_region(region * r) { unit **up = &r->units; - int max_age = MaxAge(); while (*up) { unit *u = *up; @@ -1810,11 +1798,6 @@ void remove_empty_units_in_region(region * r) if (f == NULL || !f->alive) { set_number(u, 0); } - if (max_age > 0) { - if ((!fval(f, FFL_NOTIMEOUT) && f->age > max_age)) { - set_number(u, 0); - } - } } if ((u->number == 0 && u_race(u) != get_race(RC_SPELL)) || (u->age <= 0 && u_race(u) == get_race(RC_SPELL))) { From 440aca34ea40f06a609da6790dea6031cd836a47 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 16 Oct 2014 08:06:44 +0200 Subject: [PATCH 3/4] test special treatment for spells in remove_empty_units. --- src/kernel/unit.c | 3 +-- src/kernel/unit.test.c | 57 ++++++++++++++++++++++++++++++++++++++++++ src/tests.c | 4 +-- 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/kernel/unit.c b/src/kernel/unit.c index b956465e2..27dff7f0c 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -232,9 +232,8 @@ int gift_items(unit * u, int flags) int rule = rule_give(); assert(u->region); - assert(u->faction); - if ((u->faction->flags & FFL_QUIT) == 0 || (rule & GIVE_ONDEATH) == 0) { + if ((rule & GIVE_ONDEATH) == 0 || !u->faction || (u->faction->flags & FFL_QUIT) == 0) { if ((rule & GIVE_ALLITEMS) == 0 && (flags & GIFT_FRIENDS)) flags -= GIFT_FRIENDS; if ((rule & GIVE_PEASANTS) == 0 && (flags & GIFT_PEASANTS)) diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c index 3a341cce2..12a83d3ad 100644 --- a/src/kernel/unit.test.c +++ b/src/kernel/unit.test.c @@ -1,8 +1,10 @@ #include #include #include "alchemy.h" +#include "faction.h" #include "unit.h" #include "item.h" +#include "race.h" #include "region.h" #include @@ -47,6 +49,58 @@ static void test_remove_empty_units_in_region(CuTest *tc) { test_cleanup(); } +static void test_remove_units_without_faction(CuTest *tc) { + unit *u; + int uid; + + test_cleanup(); + test_create_world(); + + u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); + uid = u->no; + u_setfaction(u, 0); + remove_empty_units_in_region(u->region); + CuAssertPtrEquals(tc, 0, findunit(uid)); + CuAssertIntEquals(tc, 0, u->number); + test_cleanup(); +} + +static void test_remove_units_with_dead_faction(CuTest *tc) { + unit *u; + int uid; + + test_cleanup(); + test_create_world(); + + u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); + uid = u->no; + u->faction->alive = false; + remove_empty_units_in_region(u->region); + CuAssertPtrEquals(tc, 0, findunit(uid)); + CuAssertIntEquals(tc, 0, u->number); + test_cleanup(); +} + +static void test_remove_units_ignores_spells(CuTest *tc) { + unit *u; + int uid; + + test_cleanup(); + test_create_world(); + + u = create_unit(findregion(0, 0), test_create_faction(test_create_race("human")), 1, get_race(RC_SPELL), 0, 0, 0); + uid = u->no; + u->number = 0; + u->age = 1; + remove_empty_units_in_region(u->region); + CuAssertPtrNotNull(tc, findunit(uid)); + CuAssertPtrNotNull(tc, u->region); + u->age = 0; + remove_empty_units_in_region(u->region); + CuAssertPtrEquals(tc, 0, findunit(uid)); + test_cleanup(); +} + static void test_scale_number(CuTest *tc) { unit *u; const struct potion_type *ptype; @@ -74,6 +128,9 @@ CuSuite *get_unit_suite(void) CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_scale_number); SUITE_ADD_TEST(suite, test_remove_empty_units); + SUITE_ADD_TEST(suite, test_remove_units_ignores_spells); + SUITE_ADD_TEST(suite, test_remove_units_without_faction); + SUITE_ADD_TEST(suite, test_remove_units_with_dead_faction); SUITE_ADD_TEST(suite, test_remove_empty_units_in_region); return suite; } diff --git a/src/tests.c b/src/tests.c index e5017b5ad..066b93262 100644 --- a/src/tests.c +++ b/src/tests.c @@ -51,8 +51,8 @@ struct faction *test_create_faction(const struct race *rc) struct unit *test_create_unit(struct faction *f, struct region *r) { - unit *u = create_unit(r, f, 1, f?f->race:rc_find("human"), 0, 0, 0); - return u; + assert(f || !r); + return create_unit(r, f, 1, f ? f->race : rc_find("human"), 0, 0, 0); } void test_cleanup(void) From ac65d83ba24e02ceb2e581824f85fca943f6a28e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 16 Oct 2014 08:13:56 +0200 Subject: [PATCH 4/4] test that empty factions are removed, but not monsters. --- src/kernel/faction.test.c | 47 ++++++++++++++++++++++++++++++++++++++- src/tests.c | 9 ++++---- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/kernel/faction.test.c b/src/kernel/faction.test.c index a0b82f5b9..08c2df891 100644 --- a/src/kernel/faction.test.c +++ b/src/kernel/faction.test.c @@ -1,12 +1,55 @@ #include + +#include #include #include +#include #include #include -#include "faction.h" + #include +#include + +#include #include +static void test_remove_empty_factions(CuTest *tc) { + faction *f, *fm; + int fno; + + test_cleanup(); + fm = get_or_create_monsters(); + assert(fm); + f = test_create_faction(0); + fno = f->no; + remove_empty_factions(); + CuAssertPtrEquals(tc, 0, findfaction(fno)); + CuAssertPtrEquals(tc, fm, get_monsters()); + test_cleanup(); +} + +static void test_remove_dead_factions(CuTest *tc) { + faction *f, *fm; + region *r; + + test_cleanup(); + r = test_create_region(0, 0, 0); + fm = get_or_create_monsters(); + f = test_create_faction(0); + assert(fm && r && f); + test_create_unit(f, r); + test_create_unit(fm, r); + remove_empty_factions(); + CuAssertPtrEquals(tc, f, findfaction(f->no)); + CuAssertPtrNotNull(tc, get_monsters()); + fm->alive = 0; + f->alive = 0; + remove_empty_factions(); + CuAssertPtrEquals(tc, 0, findfaction(f->no)); + CuAssertPtrEquals(tc, fm, get_monsters()); + test_cleanup(); +} + static void test_addfaction(CuTest *tc) { faction *f = 0; const struct race *rc = rc_get_or_create("human"); @@ -51,6 +94,8 @@ CuSuite *get_faction_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_addfaction); + SUITE_ADD_TEST(suite, test_remove_empty_factions); + SUITE_ADD_TEST(suite, test_remove_dead_factions); SUITE_ADD_TEST(suite, test_get_monsters); return suite; } diff --git a/src/tests.c b/src/tests.c index 066b93262..ebd8c7bf4 100644 --- a/src/tests.c +++ b/src/tests.c @@ -34,25 +34,26 @@ struct race *test_create_race(const char *name) struct region *test_create_region(int x, int y, const terrain_type *terrain) { region *r = new_region(x, y, NULL, 0); - terraform_region(r, terrain); + terraform_region(r, terrain ? terrain : get_or_create_terrain("plain")); rsettrees(r, 0, 0); rsettrees(r, 1, 0); rsettrees(r, 2, 0); rsethorses(r, 0); - rsetpeasants(r, terrain->size); + rsetpeasants(r, r->terrain->size); return r; } struct faction *test_create_faction(const struct race *rc) { - faction *f = addfaction("nobody@eressea.de", NULL, rc?rc:rc_find("human"), default_locale, 0); + faction *f = addfaction("nobody@eressea.de", NULL, rc?rc:rc_get_or_create("human"), default_locale, 0); return f; } struct unit *test_create_unit(struct faction *f, struct region *r) { + const struct race * rc = f ? f->race : 0; assert(f || !r); - return create_unit(r, f, 1, f ? f->race : rc_find("human"), 0, 0, 0); + return create_unit(r, f, 1, rc ? rc : rc_get_or_create("human"), 0, 0, 0); } void test_cleanup(void)