From 3e54d00ad3e1f6fd56aace6f227c66a5b67eb3ea Mon Sep 17 00:00:00 2001 From: shennetsind Date: Sun, 30 Jun 2013 12:29:54 -0300 Subject: Fixed script timer problem Special Thanks to Igniz for bringing it to my attention, ALSO: over 10% script parsing speed boost!<3. Signed-off-by: shennetsind --- src/map/npc.c | 113 +++++++++++++++++++++++++------------------------------ src/map/script.c | 60 +++++++++++++++++++---------- src/map/script.h | 12 +++++- 3 files changed, 101 insertions(+), 84 deletions(-) diff --git a/src/map/npc.c b/src/map/npc.c index 77758bc00..a71bc36ca 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -1862,7 +1862,7 @@ int npc_unload(struct npc_data* nd, bool single) { aFree(nd->u.scr.timer_event); if (nd->src_id == 0) { if(nd->u.scr.script) { - script_stop_instances(nd->bl.id); + script_stop_instances(nd->u.scr.script); script_free_code(nd->u.scr.script); nd->u.scr.script = NULL; } @@ -2275,52 +2275,34 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const return strchr(start,'\n');// continue } -/** - * NPC other label - * Not sure, seem to add label in a chainlink - * @see DBApply - */ -int npc_convertlabel_db(DBKey key, DBData *data, va_list ap) -{ - const char* lname = (const char*)key.str; - int lpos = DB->data2i(data); - struct npc_label_list** label_list; - int* label_list_num; - const char* filepath; - struct npc_label_list* label; - const char *p; - int len; - - nullpo_ret(label_list = va_arg(ap,struct npc_label_list**)); - nullpo_ret(label_list_num = va_arg(ap,int*)); - nullpo_ret(filepath = va_arg(ap,const char*)); - - // In case of labels not terminated with ':', for user defined function support - p = lname; - while( ISALNUM(*p) || *p == '_' ) - ++p; - len = p-lname; - - // here we check if the label fit into the buffer - if( len > 23 ) - { - ShowError("npc_parse_script: label name longer than 23 chars! '%s'\n (%s)", lname, filepath); - return 0; - } - - if( *label_list == NULL ) - { - *label_list = (struct npc_label_list *) aCalloc (1, sizeof(struct npc_label_list)); - *label_list_num = 0; - } else - *label_list = (struct npc_label_list *) aRealloc (*label_list, sizeof(struct npc_label_list)*(*label_list_num+1)); - label = *label_list+*label_list_num; +void npc_convertlabel_db(struct npc_label_list* label_list, const char *filepath) { + int i; + + for( i = 0; i < script->label_count; i++ ) { + const char* lname = get_str(script->labels[i].key); + int lpos = script->labels[i].pos; + struct npc_label_list* label; + const char *p; + int len; + + // In case of labels not terminated with ':', for user defined function support + p = lname; - safestrncpy(label->name, lname, sizeof(label->name)); - label->pos = lpos; - ++(*label_list_num); + while( ISALNUM(*p) || *p == '_' ) + ++p; + len = p-lname; - return 0; + // here we check if the label fit into the buffer + if( len > 23 ) { + ShowError("npc_parse_script: label name longer than 23 chars! '%s'\n (%s)", lname, filepath); + return; + } + + label = &label_list[i]; + + safestrncpy(label->name, lname, sizeof(label->name)); + label->pos = lpos; + } } // Skip the contents of a script. @@ -2388,7 +2370,7 @@ static const char* npc_skip_script(const char* start, const char* buffer, const static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, bool runOnInit) { int x, y, dir = 0, m, xs = 0, ys = 0, class_ = 0; // [Valaris] thanks to fov char mapname[32]; - struct script_code *script; + struct script_code *scriptroot; int i; const char* end; const char* script_start; @@ -2426,14 +2408,13 @@ static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, cons if( end == NULL ) return NULL;// (simple) parse error, don't continue - script = parse_script(script_start, filepath, strline(buffer,script_start-buffer), SCRIPT_USE_LABEL_DB); + scriptroot = parse_script(script_start, filepath, strline(buffer,script_start-buffer), SCRIPT_USE_LABEL_DB); label_list = NULL; label_list_num = 0; - if( script ) - { - DBMap* label_db = script_get_label_db(); - label_db->foreach(label_db, npc_convertlabel_db, &label_list, &label_list_num, filepath); - db_clear(label_db); // not needed anymore, so clear the db + if( script->label_count ) { + CREATE(label_list,struct npc_label_list,script->label_count); + label_list_num = script->label_count; + npc_convertlabel_db(label_list,filepath); } CREATE(nd, struct npc_data, 1); @@ -2458,7 +2439,7 @@ static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, cons nd->bl.id = npc_get_new_npc_id(); nd->class_ = class_; nd->speed = 200; - nd->u.scr.script = script; + nd->u.scr.script = scriptroot; nd->u.scr.label_list = label_list; nd->u.scr.label_list_num = label_list_num; @@ -3782,18 +3763,22 @@ int npc_reload(void) { db_clear(npcname_db); db_clear(ev_db); + npc_last_npd = NULL; + npc_last_path = NULL; + npc_last_ref = NULL; + //Remove all npcs/mobs. [Skotlex] iter = mapit_geteachiddb(); for( bl = (struct block_list*)mapit->first(iter); mapit->exists(iter); bl = (struct block_list*)mapit->next(iter) ) { switch(bl->type) { - case BL_NPC: - if( bl->id != fake_nd->bl.id )// don't remove fake_nd - npc_unload((struct npc_data *)bl, false); - break; - case BL_MOB: - unit_free(bl,CLR_OUTSIGHT); - break; + case BL_NPC: + if( bl->id != fake_nd->bl.id )// don't remove fake_nd + npc_unload((struct npc_data *)bl, false); + break; + case BL_MOB: + unit_free(bl,CLR_OUTSIGHT); + break; } } mapit->free(iter); @@ -3970,10 +3955,14 @@ int do_init_npc(void) ev_db = strdb_alloc((DBOptions)(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA),2*NAME_LENGTH+2+1); npcname_db = strdb_alloc(DB_OPT_BASE,NAME_LENGTH); - npc_path_db = strdb_alloc(DB_OPT_BASE|DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA,80); + npc_path_db = strdb_alloc(DB_OPT_BASE|DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA,0); timer_event_ers = ers_new(sizeof(struct timer_event_data),"clif.c::timer_event_ers",ERS_OPT_NONE); + npc_last_npd = NULL; + npc_last_path = NULL; + npc_last_ref = NULL; + // process all npc files ShowStatus("Loading NPCs...\r"); for( file = npc_src_files; file != NULL; file = file->next ) { @@ -3988,7 +3977,7 @@ int do_init_npc(void) "\t-'"CL_WHITE"%d"CL_RESET"' Mobs Cached\n" "\t-'"CL_WHITE"%d"CL_RESET"' Mobs Not Cached\n", npc_id - START_NPC_NUM, npc_warp, npc_shop, npc_script, npc_mob, npc_cache_mob, npc_delay_mob); - + iMap->zone_init(); npc->motd = npc_name2id("HerculesMOTD"); /* [Ind/Hercules] */ diff --git a/src/map/script.c b/src/map/script.c index 354ec0522..858c66874 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -97,10 +97,8 @@ int str_hash[SCRIPT_HASH_SIZE]; //#define SCRIPT_HASH_SDBM #define SCRIPT_HASH_ELF -static DBMap* scriptlabel_db=NULL; // const char* label_name -> int script_pos static DBMap* userfunc_db=NULL; // const char* func_name -> struct script_code* static int parse_options=0; -DBMap* script_get_label_db(void){ return scriptlabel_db; } DBMap* script_get_userfunc_db(void){ return userfunc_db; } // important buildin function references for usage in scripts @@ -1650,7 +1648,7 @@ const char* parse_syntax(const char* p) script->str_data[l].type = C_USERFUNC; set_label(l, script_pos, p); if( parse_options&SCRIPT_USE_LABEL_DB ) - strdb_iput(scriptlabel_db, get_str(l), script_pos); + script->label_add(l,script_pos); } else disp_error_message("parse_syntax:function: function name is invalid", func_name); @@ -2090,7 +2088,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o // who called parse_script is responsible for clearing the database after using it, but just in case... lets clear it here if( options&SCRIPT_USE_LABEL_DB ) - db_clear(scriptlabel_db); + script->label_count = 0; parse_options = options; if( setjmp( error_jump ) != 0 ) { @@ -2164,7 +2162,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o i=add_word(p); set_label(i,script_pos,p); if( parse_options&SCRIPT_USE_LABEL_DB ) - strdb_iput(scriptlabel_db, get_str(i), script_pos); + script->label_add(i,script_pos); p=tmpp+1; p=skip_space(p); continue; @@ -3286,7 +3284,7 @@ void run_script(struct script_code *rootscript,int pos,int rid,int oid) { run_script_main(st); } -void script_stop_instances(int id) { +void script_stop_instances(struct script_code *code) { DBIterator *iter; struct script_state* st; @@ -3296,7 +3294,7 @@ void script_stop_instances(int id) { iter = db_iterator(script->st_db); for( st = dbi_first(iter); dbi_exists(iter); st = dbi_next(iter) ) { - if( st->oid == id ) { + if( st->script == code ) { script_free_state(st); } } @@ -3308,17 +3306,19 @@ void script_stop_instances(int id) { * Timer function for sleep *------------------------------------------*/ int run_script_timer(int tid, unsigned int tick, int id, intptr_t data) { - struct script_state *st = (struct script_state *)data; - TBL_PC *sd = iMap->id2sd(st->rid); + struct script_state *st = idb_get(script->st_db,(int)data); + if( st ) { + TBL_PC *sd = iMap->id2sd(st->rid); - if((sd && sd->status.char_id != id) || (st->rid && !sd)) { //Character mismatch. Cancel execution. - st->rid = 0; - st->state = END; + if((sd && sd->status.char_id != id) || (st->rid && !sd)) { //Character mismatch. Cancel execution. + st->rid = 0; + st->state = END; + } + st->sleep.timer = INVALID_TIMER; + if(st->state != RERUNLINE) + st->sleep.tick = 0; + run_script_main(st); } - st->sleep.timer = INVALID_TIMER; - if(st->state != RERUNLINE) - st->sleep.tick = 0; - run_script_main(st); return 0; } @@ -3514,7 +3514,7 @@ void run_script_main(struct script_state *st) sd = iMap->id2sd(st->rid); // Get sd since script might have attached someone while running. [Inkfish] st->sleep.charid = sd?sd->status.char_id:0; st->sleep.timer = iTimer->add_timer(iTimer->gettick()+st->sleep.tick, - run_script_timer, st->sleep.charid, (intptr_t)st); + run_script_timer, st->sleep.charid, (intptr_t)st->id); } else if(st->state != END && st->rid){ //Resume later (st is already attached to player). if(st->bk_st) { @@ -3761,7 +3761,6 @@ void do_final_script(void) { mapreg_final(); - db_destroy(scriptlabel_db); userfunc_db->destroy(userfunc_db, db_script_free_code_sub); autobonus_db->destroy(autobonus_db, db_script_free_code_sub); @@ -3817,6 +3816,9 @@ void do_final_script(void) { ers_destroy(script->stack_ers); db_destroy(script->st_db); + + if( script->labels != NULL ) + aFree(script->labels); } /*========================================== * Initialization @@ -3824,7 +3826,6 @@ void do_final_script(void) { void do_init_script(void) { script->st_db = idb_alloc(DB_OPT_BASE); userfunc_db = strdb_alloc(DB_OPT_DUP_KEY,0); - scriptlabel_db = strdb_alloc(DB_OPT_DUP_KEY,50); autobonus_db = strdb_alloc(DB_OPT_DUP_KEY,0); script->st_ers = ers_new(sizeof(struct script_state), "script.c::st_ers", ERS_OPT_NONE); @@ -3844,7 +3845,7 @@ int script_reload() { struct script_state *st; userfunc_db->clear(userfunc_db, db_script_free_code_sub); - db_clear(scriptlabel_db); + script->label_count = 0; for( i = 0; i < atcommand->binding_count; i++ ) { aFree(atcommand->binding[i]); @@ -18013,6 +18014,19 @@ void script_parse_builtin(void) { } } +void script_label_add(int key, int pos) { + int idx = script->label_count; + + if( script->labels_size == script->label_count ) { + script->labels_size += 1024; + RECREATE(script->labels, struct script_label_entry, script->labels_size); + } + + script->labels[idx].key = key; + script->labels[idx].pos = pos; + script->label_count++; +} + void script_defaults(void) { script = &script_s; @@ -18042,6 +18056,10 @@ void script_defaults(void) { script->current_item_id = 0; + script->labels = NULL; + script->label_count = 0; + script->labels_size = 0; + script->init = do_init_script; script->final = do_final_script; @@ -18067,4 +18085,6 @@ void script_defaults(void) { script->queue_remove = script_hqueue_remove; script->queue_create = script_hqueue_create; script->queue_clear = script_hqueue_clear; + + script->label_add = script_label_add; } diff --git a/src/map/script.h b/src/map/script.h index a77e957c0..902125681 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -191,14 +191,13 @@ int set_var(struct map_session_data *sd, char *name, void *val); int run_script_timer(int tid, unsigned int tick, int id, intptr_t data); void run_script_main(struct script_state *st); -void script_stop_instances(int id); +void script_stop_instances(struct script_code *code); struct linkdb_node* script_erase_sleepdb(struct linkdb_node *n); void script_free_code(struct script_code* code); void script_free_vars(struct DBMap *storage); struct script_state* script_alloc_state(struct script_code* rootscript, int pos, int rid, int oid); void script_free_state(struct script_state* st); -struct DBMap* script_get_label_db(void); struct DBMap* script_get_userfunc_db(void); void script_run_autobonus(const char *autobonus,int id, int pos); @@ -231,6 +230,10 @@ struct str_data_struct { int next; }; +struct script_label_entry { + int key,pos; +}; + /////////////////////////////////////////////////////////////////////////////// //## TODO possible enhancements: [FlavioJS] // - 'callfunc' supporting labels in the current npc "::LabelName" @@ -359,6 +362,10 @@ struct script_interface { int word_size; /* */ unsigned short current_item_id; + /* */ + struct script_label_entry *labels; + int label_count; + int labels_size; /* */ void (*init) (void); void (*final) (void); @@ -378,6 +385,7 @@ struct script_interface { void (*set_constant) (const char* name, int value, bool isparameter); void (*set_constant2) (const char *name, int value, bool isparameter); bool (*get_constant) (const char* name, int* value); + void (*label_add)(int key, int pos); /* */ struct hQueue *(*queue) (int idx); bool (*queue_add) (int idx, int var); -- cgit v1.2.3-70-g09d2