From 0118a097c9626b3f8342dd29897392f3da4c1187 Mon Sep 17 00:00:00 2001 From: shennetsind Date: Fri, 5 Jul 2013 19:19:40 -0300 Subject: HCache | Item Packages Update http://hercules.ws/board/topic/1389-hcache-item-packages-update/ Signed-off-by: shennetsind --- src/common/core.c | 6 +- src/common/utils.c | 99 ++++++++++++- src/common/utils.h | 20 ++- src/map/itemdb.c | 427 +++++++++++++++++++++++++++++++++++++++++++---------- src/map/itemdb.h | 10 +- 5 files changed, 478 insertions(+), 84 deletions(-) (limited to 'src') diff --git a/src/common/core.c b/src/common/core.c index c53d2243b..d2f662551 100644 --- a/src/common/core.c +++ b/src/common/core.c @@ -18,6 +18,7 @@ #include "../common/sql.h" #include "../config/core.h" #include "../common/HPM.h" + #include "../common/utils.h" #endif #include @@ -281,6 +282,7 @@ void usercheck(void) { void core_defaults(void) { #ifndef MINICORE hpm_defaults(); + HCache_defaults(); #endif console_defaults(); strlib_defaults(); @@ -332,7 +334,9 @@ int main (int argc, char **argv) { iTimer->init(); console->init(); - + + HCache->init(); + #ifndef MINICORE HPM->init(); #endif diff --git a/src/common/utils.c b/src/common/utils.c index 296df7e70..3ea970a1b 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -1,10 +1,12 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #include "../common/cbasetypes.h" #include "../common/mmo.h" #include "../common/malloc.h" #include "../common/showmsg.h" +#include "../common/core.h" #include "socket.h" #include "utils.h" @@ -25,6 +27,9 @@ #include #endif +#include // cache purposes [Ind/Hercules] + +struct HCache_interface HCache_s; /// Dumps given buffer into file pointed to by a handle. void WriteDump(FILE* fp, const void* buffer, size_t length) @@ -281,3 +286,93 @@ unsigned int get_percentage(const unsigned int A, const unsigned int B) return (unsigned int)floor(result); } + +/* [Ind/Hercules] Caching */ +bool HCache_check(const char *file) { + struct stat bufa, bufb; + FILE *first, *second; + char s_path[255], dT[1]; + size_t rtime; + + if( !(first = fopen(file,"rb")) ) + return false; + + if( file[0] == '.' && file[1] == '/' ) + file += 2; + else if( file[0] == '.' ) + file++; + + snprintf(s_path, 255, "./cache/%s", file); + + if( !(second = fopen(s_path,"rb")) ) { + fclose(first); + return false; + } + + if( fread(dT,sizeof(dT),1,second) != 1 || fread(&rtime,sizeof(rtime),1,second) != 1 || dT[0] != 'k' || HCache->recompile_time > rtime ) { + fclose(first); + fclose(second); + return false; + } + + fstat(fileno(first), &bufa); + fstat(fileno(first), &bufa); + + fclose(first); + fclose(second); + + if( bufa.st_mtime > bufb.st_mtime ) + return false; + + return true; +} + +FILE *HCache_open(const char *file, const char *opt) { + FILE *first; + char s_path[255]; + + if( file[0] == '.' && file[1] == '/' ) + file += 2; + else if( file[0] == '.' ) + file++; + + snprintf(s_path, 255, "./cache/%s", file); + + if( !(first = fopen(s_path,opt)) ) { + return NULL; + } + + if( opt[0] != 'r' ) { + char dT[1] = "k";/* 1-byte key to ensure our method is the latest, we can modify to ensure the method matches */ + fwrite(dT,sizeof(dT),1,first); + fwrite(&HCache->recompile_time,sizeof(HCache->recompile_time),1,first); + } + fseek(first, 20, SEEK_SET);/* skip first 20, might wanna store something else later */ + + return first; +} +void HCache_init(void) { + FILE *server; + + if( (server = fopen(SERVER_NAME,"rb")) ) { + struct stat buf; + + fstat(fileno(server), &buf); + HCache->recompile_time = buf.st_mtime; + fclose(server); + + HCache->enabled = true; + } else + ShowWarning("Unable to open '%s', caching capabilities have been disabled!\n",SERVER_NAME); +} +void HCache_defaults(void) { + + HCache = &HCache_s; + + HCache->init = HCache_init; + + HCache->check = HCache_check; + HCache->open = HCache_open; + HCache->recompile_time = 0; + HCache->enabled = false; +} diff --git a/src/common/utils.h b/src/common/utils.h index 8e39f2655..7953d93e8 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -1,5 +1,6 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #ifndef _UTILS_H_ #define _UTILS_H_ @@ -29,4 +30,19 @@ extern uint16 GetWord(uint32 val, int idx); extern uint16 MakeWord(uint8 byte0, uint8 byte1); extern uint32 MakeDWord(uint16 word0, uint16 word1); +/* [Ind/Hercules] Caching */ +struct HCache_interface { + void (*init) (void); + /* */ + bool (*check) (const char *file); + FILE *(*open) (const char *file, const char *opt); + /* */ + size_t recompile_time; + bool enabled; +}; + +struct HCache_interface *HCache; + +void HCache_defaults(void); + #endif /* _UTILS_H_ */ diff --git a/src/map/itemdb.c b/src/map/itemdb.c index 7b6fd0ed7..7c28c6968 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -197,44 +197,46 @@ void itemdb_package_item(struct map_session_data *sd, struct item_package *packa } if( package->random_qty ) { - struct item_package_rand_entry *entry; - - entry = &package->random_list[rnd()%package->random_qty]; - - while( 1 ) { - if( rnd()%10000 >= entry->rate ) { - entry = entry->next; - continue; - } else { - struct item it; - memset(&it, 0, sizeof(it)); - - it.nameid = entry->id; - it.identify = 1; - - if( entry->hours ) { - it.expire_time = (unsigned int)(time(NULL) + ((entry->hours*60)*60)); - } - - if( entry->named ) { - it.card[0] = CARD0_FORGE; - it.card[1] = 0; - it.card[2] = GetWord(sd->status.char_id, 0); - it.card[3] = GetWord(sd->status.char_id, 1); - } - - if( entry->announce ) - clif->package_announce(sd,entry->id,package->id); - - get_count = itemdb_isstackable(entry->id) ? entry->qty : 1; - - it.amount = get_count == 1 ? 1 : get_count; - - for( j = 0; j < entry->qty; j += get_count ) { - if ( ( flag = pc->additem(sd, &it, get_count, LOG_TYPE_SCRIPT) ) ) - clif->additem(sd, 0, 0, flag); + for( i = 0; i < package->random_qty; i++ ) { + struct item_package_rand_entry *entry; + + entry = &package->random_groups[i].random_list[rnd()%package->random_groups[i].random_qty]; + + while( 1 ) { + if( rnd()%10000 >= entry->rate ) { + entry = entry->next; + continue; + } else { + struct item it; + memset(&it, 0, sizeof(it)); + + it.nameid = entry->id; + it.identify = 1; + + if( entry->hours ) { + it.expire_time = (unsigned int)(time(NULL) + ((entry->hours*60)*60)); + } + + if( entry->named ) { + it.card[0] = CARD0_FORGE; + it.card[1] = 0; + it.card[2] = GetWord(sd->status.char_id, 0); + it.card[3] = GetWord(sd->status.char_id, 1); + } + + if( entry->announce ) + clif->package_announce(sd,entry->id,package->id); + + get_count = itemdb_isstackable(entry->id) ? entry->qty : 1; + + it.amount = get_count == 1 ? 1 : get_count; + + for( j = 0; j < entry->qty; j += get_count ) { + if ( ( flag = pc->additem(sd, &it, get_count, LOG_TYPE_SCRIPT) ) ) + clif->additem(sd, 0, 0, flag); + } + break; } - break; } } } @@ -670,10 +672,9 @@ void itemdb_read_groups(void) { data->group = &itemdb->groups[count]; itemdb->groups[count].id = data->nameid; - itemdb->groups[count].qty = config_setting_length(itg); + itemdb->groups[count].qty = gsize[ count ]; CREATE(itemdb->groups[count].nameid, unsigned short, gsize[ count ] + 1); - c = 0; while( (it = config_setting_get_elem(itg,c++)) ) { int repeat = 1; @@ -705,7 +706,188 @@ void itemdb_read_groups(void) { ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, config_filename); } +/* [Ind/Hercules] - HCache for Packages */ +void itemdb_write_cached_packages(const char *config_filename) { + FILE *file; + unsigned short pcount = itemdb->package_count; + unsigned short i; + + if( !(file = HCache->open(config_filename,"wb")) ) { + return; + } + + // first 2 bytes = package count + fwrite(&pcount,sizeof(pcount),1,file); + + for(i = 0; i < pcount; i++) { + unsigned short id = itemdb->packages[i].id, random_qty = itemdb->packages[i].random_qty, must_qty = itemdb->packages[i].must_qty; + unsigned short c; + //into a package, first 2 bytes = id. + fwrite(&id,sizeof(id),1,file); + //next 2 bytes = must count + fwrite(&must_qty,sizeof(must_qty),1,file); + //next 2 bytes = random count + fwrite(&random_qty,sizeof(random_qty),1,file); + //now we loop into must + for(c = 0; c < must_qty; c++) { + struct item_package_must_entry *entry = &itemdb->packages[i].must_items[c]; + unsigned char announce = entry->announce == 1 ? 1 : 0, named = entry->named == 1 ? 1 : 0; + //first 2 byte = item id + fwrite(&entry->id,sizeof(entry->id),1,file); + //next 2 byte = qty + fwrite(&entry->qty,sizeof(entry->qty),1,file); + //next 2 byte = hours + fwrite(&entry->hours,sizeof(entry->hours),1,file); + //next 1 byte = announce (1:0) + fwrite(&announce,sizeof(announce),1,file); + //next 1 byte = named (1:0) + fwrite(&named,sizeof(announce),1,file); + } + //now we loop into random groups + for(c = 0; c < random_qty; c++) { + struct item_package_rand_group *group = &itemdb->packages[i].random_groups[c]; + unsigned short group_qty = group->random_qty, h; + + //next 2 bytes = how many entries in this group + fwrite(&group_qty,sizeof(group_qty),1,file); + //now we loop into the group's list + for(h = 0; h < group_qty; h++) { + struct item_package_rand_entry *entry = &itemdb->packages[i].random_groups[c].random_list[h]; + unsigned char announce = entry->announce == 1 ? 1 : 0, named = entry->named == 1 ? 1 : 0; + //first 2 byte = item id + fwrite(&entry->id,sizeof(entry->id),1,file); + //next 2 byte = qty + fwrite(&entry->qty,sizeof(entry->qty),1,file); + //next 2 byte = rate + fwrite(&entry->rate,sizeof(entry->rate),1,file); + //next 2 byte = hours + fwrite(&entry->hours,sizeof(entry->hours),1,file); + //next 1 byte = announce (1:0) + fwrite(&announce,sizeof(announce),1,file); + //next 1 byte = named (1:0) + fwrite(&named,sizeof(announce),1,file); + } + } + } + + fclose(file); + + return; +} +bool itemdb_read_cached_packages(const char *config_filename) { + FILE *file; + unsigned short pcount; + unsigned short i; + + if( !(file = HCache->open(config_filename,"rb")) ) { + return false; + } + + // first 2 bytes = package count + fread(&pcount,sizeof(pcount),1,file); + CREATE(itemdb->packages, struct item_package, pcount); + itemdb->package_count = pcount; + + for( i = 0; i < pcount; i++ ) { + unsigned short id = 0, random_qty = 0, must_qty = 0; + struct item_package *package = &itemdb->packages[i]; + unsigned short c; + + //into a package, first 2 bytes = id. + fread(&id,sizeof(id),1,file); + //next 2 bytes = must count + fread(&must_qty,sizeof(must_qty),1,file); + //next 2 bytes = random count + fread(&random_qty,sizeof(random_qty),1,file); + + package->id = id; + package->random_qty = random_qty; + package->must_qty = must_qty; + package->must_items = NULL; + package->random_groups = NULL; + + if( package->must_qty ) { + CREATE(package->must_items, struct item_package_must_entry, package->must_qty); + //now we loop into must + for(c = 0; c < package->must_qty; c++) { + struct item_package_must_entry *entry = &itemdb->packages[i].must_items[c]; + unsigned short mid = 0, qty = 0, hours = 0; + unsigned char announce = 0, named = 0; + struct item_data *data; + //first 2 byte = item id + fread(&mid,sizeof(mid),1,file); + //next 2 byte = qty + fread(&qty,sizeof(qty),1,file); + //next 2 byte = hours + fread(&hours,sizeof(hours),1,file); + //next 1 byte = announce (1:0) + fread(&announce,sizeof(announce),1,file); + //next 1 byte = named (1:0) + fread(&named,sizeof(announce),1,file); + + if( !(data = itemdb->exists(mid)) ) + ShowWarning("itemdb_read_packages: unknown item '%d' in package '%s'!\n",mid,itemdb_name(package->id)); + + entry->id = data ? data->nameid : 0; + entry->hours = hours; + entry->qty = qty; + entry->announce = announce ? 1 : 0; + entry->named = named ? 1 : 0; + } + } + if( package->random_qty ) { + //now we loop into random groups + CREATE(package->random_groups, struct item_package_rand_group, package->random_qty); + for(c = 0; c < package->random_qty; c++) { + unsigned short group_qty = 0, h; + + //next 2 bytes = how many entries in this group + fread(&group_qty,sizeof(group_qty),1,file); + + package->random_groups[c].random_qty = group_qty; + CREATE(package->random_groups[c].random_list, struct item_package_rand_entry, package->random_groups[c].random_qty); + + //now we loop into the group's list + for(h = 0; h < group_qty; h++) { + struct item_package_rand_entry *entry = &itemdb->packages[i].random_groups[c].random_list[h]; + unsigned short mid = 0, qty = 0, hours = 0, rate = 0; + unsigned char announce = 0, named = 0; + struct item_data *data; + + //first 2 byte = item id + fread(&mid,sizeof(mid),1,file); + //next 2 byte = qty + fread(&qty,sizeof(qty),1,file); + //next 2 byte = rate + fread(&rate,sizeof(rate),1,file); + //next 2 byte = hours + fread(&hours,sizeof(hours),1,file); + //next 1 byte = announce (1:0) + fread(&announce,sizeof(announce),1,file); + //next 1 byte = named (1:0) + fread(&named,sizeof(announce),1,file); + + if( !(data = itemdb->exists(mid)) ) + ShowWarning("itemdb_read_packages: unknown item '%d' in package '%s'!\n",mid,itemdb_name(package->id)); + + entry->id = data ? data->nameid : 0; + entry->rate = rate; + entry->hours = hours; + entry->qty = qty; + entry->announce = announce ? 1 : 0; + entry->named = named ? 1 : 0; + } + } + } + } + + fclose(file); + + ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", pcount, config_filename); + + return true; +} void itemdb_read_packages(void) { config_t item_packages_conf; config_setting_t *itg = NULL, *it = NULL, *t = NULL; @@ -715,8 +897,14 @@ void itemdb_read_packages(void) { const char *config_filename = "db/pre-re/item_packages.conf"; // FIXME hardcoded name #endif const char *itname; - int i = 0, count = 0, c = 0; - unsigned int *must = NULL, *random = NULL; + int i = 0, count = 0, c = 0, highest_gcount = 0; + unsigned int *must = NULL, *random = NULL, *rgroup = NULL, **rgroups = NULL; + struct item_package_rand_entry **prev = NULL; + + if( HCache->check(config_filename) ) { + if( itemdb->read_cached_packages(config_filename) ) + return; + } if (conf_read_file(&item_packages_conf, config_filename)) { ShowError("can't read %s\n", config_filename); @@ -725,12 +913,17 @@ void itemdb_read_packages(void) { must = aMalloc( config_setting_length(item_packages_conf.root) * sizeof(unsigned int) ); random = aMalloc( config_setting_length(item_packages_conf.root) * sizeof(unsigned int) ); + rgroup = aMalloc( config_setting_length(item_packages_conf.root) * sizeof(unsigned int) ); + rgroups = aMalloc( config_setting_length(item_packages_conf.root) * sizeof(unsigned int *) ); + for(i = 0; i < config_setting_length(item_packages_conf.root); i++) { must[i] = 0; random[i] = 0; + rgroup[i] = 0; } + /* validate tree, drop poisonous fruits! */ i = 0; while( (itg = config_setting_get_elem(item_packages_conf.root,i++)) ) { const char *name = config_setting_name(itg); @@ -744,40 +937,86 @@ void itemdb_read_packages(void) { c = 0; while( (it = config_setting_get_elem(itg,c++)) ) { - if( ( t = config_setting_get_member(it, "Random")) && !config_setting_get_bool(t) ) + int rval; + if( !( t = config_setting_get_member(it, "Random") ) || (rval = config_setting_get_int(t)) < 0 ) { + ShowWarning("itemdb_read_packages: invalid 'Random' value (%d) for item '%s' in package '%s', defaulting to must!\n",rval,config_setting_name(it),name); + config_setting_remove(it, config_setting_name(it)); + --c; + continue; + } + + if( rval == 0 ) must[ i - 1 ] += 1; - else + else { random[ i - 1 ] += 1; + if( rval > rgroup[i - 1] ) + rgroup[i - 1] = rval; + if( rval > highest_gcount ) + highest_gcount = rval; + } } - + } + + CREATE(prev, struct item_package_rand_entry *, highest_gcount); + for(i = 0; i < highest_gcount; i++) { + prev[i] = NULL; } + for(i = 0; i < config_setting_length(item_packages_conf.root); i++ ) { + rgroups[i] = aMalloc( rgroup[i] * sizeof(unsigned int) ); + for( c = 0; c < rgroup[i]; c++ ) { + rgroups[i][c] = 0; + } + } + + /* grab the known sizes */ + i = 0; + while( (itg = config_setting_get_elem(item_packages_conf.root,i++)) ) { + c = 0; + while( (it = config_setting_get_elem(itg,c++)) ) { + int rval = 0; + if( ( t = config_setting_get_member(it, "Random")) && ( rval = config_setting_get_int(t) ) > 0 ) { + rgroups[i - 1][rval - 1] += 1; + } + } + } + CREATE(itemdb->packages, struct item_package, config_setting_length(item_packages_conf.root)); itemdb->package_count = (unsigned short)config_setting_length(item_packages_conf.root); + /* write */ i = 0; while( (itg = config_setting_get_elem(item_packages_conf.root,i++)) ) { struct item_data *data = itemdb->name2id(config_setting_name(itg)); - struct item_package_rand_entry *prev = NULL; int r = 0, m = 0; + for(r = 0; r < highest_gcount; r++) { + prev[r] = NULL; + } + r = 0; + data->package = &itemdb->packages[count]; itemdb->packages[count].id = data->nameid; - itemdb->packages[count].random_list = NULL; + itemdb->packages[count].random_groups = NULL; itemdb->packages[count].must_items = NULL; - itemdb->packages[count].random_qty = random[ i - 1 ]; + itemdb->packages[count].random_qty = rgroup[ i - 1 ]; itemdb->packages[count].must_qty = must[ i - 1 ]; - - if( itemdb->packages[count].random_qty ) - CREATE(itemdb->packages[count].random_list, struct item_package_rand_entry, itemdb->packages[count].random_qty); + + if( itemdb->packages[count].random_qty ) { + CREATE(itemdb->packages[count].random_groups, struct item_package_rand_group, itemdb->packages[count].random_qty); + for( c = 0; c < itemdb->packages[count].random_qty; c++ ) { + CREATE(itemdb->packages[count].random_groups[c].random_list, struct item_package_rand_entry, rgroups[ i - 1 ][c]); + itemdb->packages[count].random_groups[c].random_qty = 0; + } + } if( itemdb->packages[count].must_qty ) CREATE(itemdb->packages[count].must_items, struct item_package_must_entry, itemdb->packages[count].must_qty); c = 0; while( (it = config_setting_get_elem(itg,c++)) ) { int icount = 1, expire = 0, rate = 10000; - bool announce = false, named = false; + bool announce = false, named = false, gid = 0; itname = config_setting_name(it); @@ -792,7 +1031,7 @@ void itemdb_read_packages(void) { if( ( t = config_setting_get_member(it, "Rate")) ) { if( (rate = (unsigned short)config_setting_get_int(t)) > 10000 ) { - ShowWarning("itemdb_read_packages: invalid rate (%d) for item '%s' in package '%s'!\n",itname,config_setting_name(itg)); + ShowWarning("itemdb_read_packages: invalid rate (%d) for item '%s' in package '%s'!\n",rate,itname,config_setting_name(itg)); rate = 10000; } } @@ -803,7 +1042,13 @@ void itemdb_read_packages(void) { if( ( t = config_setting_get_member(it, "Named")) && config_setting_get_bool(t) ) named = true; - if( ( t = config_setting_get_member(it, "Random")) && !config_setting_get_bool(t) ) { + if( !( t = config_setting_get_member(it, "Random") ) ) { + ShowWarning("itemdb_read_packages: missing 'Random' field for item '%s' in package '%s', defaulting to must!\n",itname,config_setting_name(itg)); + gid = 0; + } else + gid = config_setting_get_int(t); + + if( gid == 0 ) { itemdb->packages[count].must_items[m].id = data ? data->nameid : 0; itemdb->packages[count].must_items[m].qty = icount; itemdb->packages[count].must_items[m].hours = expire; @@ -811,41 +1056,58 @@ void itemdb_read_packages(void) { itemdb->packages[count].must_items[m].named = named == true ? 1 : 0; m++; } else { - if( prev ) - prev->next = &itemdb->packages[count].random_list[r]; + int gidx = gid - 1; + + r = itemdb->packages[count].random_groups[gidx].random_qty; - itemdb->packages[count].random_list[r].id = data ? data->nameid : 0; - itemdb->packages[count].random_list[r].qty = icount; - if( (itemdb->packages[count].random_list[r].rate = rate) == 10000 ) { - ShowWarning("itemdb_read_packages: item '%s' in '%s' has 100% drop rate!! set this item as 'Random: false' or other items won't drop!!!\n",itname,config_setting_name(itg)); + if( prev[gidx] ) + prev[gidx]->next = &itemdb->packages[count].random_groups[gidx].random_list[r]; + + itemdb->packages[count].random_groups[gidx].random_list[r].id = data ? data->nameid : 0; + itemdb->packages[count].random_groups[gidx].random_list[r].qty = icount; + if( (itemdb->packages[count].random_groups[gidx].random_list[r].rate = rate) == 10000 ) { + ShowWarning("itemdb_read_packages: item '%s' in '%s' has 100% drop rate!! set this item as 'Random: 0' or other items won't drop!!!\n",itname,config_setting_name(itg)); } - itemdb->packages[count].random_list[r].hours = expire; - itemdb->packages[count].random_list[r].announce = announce == true ? 1 : 0; - itemdb->packages[count].random_list[r].named = named == true ? 1 : 0; - - prev = &itemdb->packages[count].random_list[r]; + itemdb->packages[count].random_groups[gidx].random_list[r].hours = expire; + itemdb->packages[count].random_groups[gidx].random_list[r].announce = announce == true ? 1 : 0; + itemdb->packages[count].random_groups[gidx].random_list[r].named = named == true ? 1 : 0; + itemdb->packages[count].random_groups[gidx].random_qty += 1; - r++; + prev[gidx] = &itemdb->packages[count].random_groups[gidx].random_list[r]; } } - if( prev ) - prev->next = &itemdb->packages[count].random_list[0]; - - if( itemdb->packages[count].random_qty == 1 ) { - //item packages dont stop looping until something comes out of them, so if you have only one item in it the drop is guaranteed. - ShowWarning("itemdb_read_packages: '%s' has only 1 random option, drop rate will be 100%!\n",itemdb_name(itemdb->packages[count].id)); - itemdb->packages[count].random_list[0].rate = 10000; + for(r = 0; r < highest_gcount; r++) { + if( prev[r] ) + prev[r]->next = &itemdb->packages[count].random_groups[r].random_list[0]; } + for( r = 0; r < itemdb->packages[count].random_qty; r++ ) { + if( itemdb->packages[count].random_groups[r].random_qty == 1 ) { + //item packages dont stop looping until something comes out of them, so if you have only one item in it the drop is guaranteed. + ShowWarning("itemdb_read_packages: in '%s' 'Random: %d' group has only 1 random option, drop rate will be 100%!\n",itemdb_name(itemdb->packages[count].id),r+1); + itemdb->packages[count].random_groups[r].random_list[0].rate = 10000; + } + } + count++; } - config_destroy(&item_packages_conf); aFree(must); aFree(random); + for(i = 0; i < config_setting_length(item_packages_conf.root); i++ ) { + aFree(rgroups[i]); + } + aFree(rgroups); + aFree(rgroup); + aFree(prev); + + config_destroy(&item_packages_conf); + + if( HCache->enabled ) + itemdb->write_cached_packages(config_filename); ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, config_filename); } @@ -1648,7 +1910,7 @@ static void itemdb_read(void) { itemdb->read_groups(); itemdb->read_chains(); itemdb->read_packages(); - + sv->readdb(iMap->db_path, "item_avail.txt", ',', 2, 2, -1, &itemdb_read_itemavail); sv->readdb(iMap->db_path, DBPATH"item_trade.txt", ',', 3, 3, -1, &itemdb_read_itemtrade); sv->readdb(iMap->db_path, "item_delay.txt", ',', 2, 2, -1, &itemdb_read_itemdelay); @@ -1745,8 +2007,11 @@ void itemdb_reload(void) { itemdb->chain_count = 0; for( i = 0; i < itemdb->package_count; i++ ) { - if( itemdb->packages[i].random_list ) - aFree(itemdb->packages[i].random_list); + int c; + for( c = 0; c < itemdb->packages[i].random_qty; c++ ) + aFree(itemdb->packages[i].random_groups[c].random_list); + if( itemdb->packages[i].random_groups ) + aFree(itemdb->packages[i].random_groups); if( itemdb->packages[i].must_items ) aFree(itemdb->packages[i].must_items); } @@ -1846,8 +2111,11 @@ void do_final_itemdb(void) { aFree(itemdb->chains); for( i = 0; i < itemdb->package_count; i++ ) { - if( itemdb->packages[i].random_list ) - aFree(itemdb->packages[i].random_list); + int c; + for( c = 0; c < itemdb->packages[i].random_qty; c++ ) + aFree(itemdb->packages[i].random_groups[c].random_list); + if( itemdb->packages[i].random_groups ) + aFree(itemdb->packages[i].random_groups); if( itemdb->packages[i].must_items ) aFree(itemdb->packages[i].must_items); } @@ -1892,6 +2160,9 @@ void itemdb_defaults(void) { itemdb->read_chains = itemdb_read_chains; itemdb->read_packages = itemdb_read_packages; /* */ + itemdb->write_cached_packages = itemdb_write_cached_packages; + itemdb->read_cached_packages = itemdb_read_cached_packages; + /* */ itemdb->search_name = itemdb_searchname; itemdb->search_name_array = itemdb_searchname_array; itemdb->load = itemdb_load; diff --git a/src/map/itemdb.h b/src/map/itemdb.h index db1330344..93bb8e0b9 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -203,9 +203,14 @@ struct item_package_must_entry { unsigned int named : 1; }; +struct item_package_rand_group { + struct item_package_rand_entry *random_list; + unsigned short random_qty; +}; + struct item_package { unsigned short id; - struct item_package_rand_entry *random_list; + struct item_package_rand_group *random_groups; struct item_package_must_entry *must_items; unsigned short random_qty; unsigned short must_qty; @@ -292,6 +297,9 @@ struct itemdb_interface { void (*read_chains) (void); void (*read_packages) (void); /* */ + void (*write_cached_packages) (const char *config_filename); + bool (*read_cached_packages) (const char *config_filename); + /* */ struct item_data* (*name2id) (const char *str); struct item_data* (*search_name) (const char *name); int (*search_name_array) (struct item_data** data, int size, const char *str); -- cgit v1.2.3-60-g2f50